package org.rhq.embeddedagent.extension;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
import java.util.Collections;
import java.util.List;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import org.jboss.as.controller.Extension;
import org.jboss.as.controller.ExtensionContext;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SubsystemRegistration;
import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
import org.jboss.as.controller.parsing.Attribute;
import org.jboss.as.controller.parsing.ExtensionParsingContext;
import org.jboss.as.controller.parsing.ParseUtils;
import org.jboss.as.controller.persistence.SubsystemMarshallingContext;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
import org.jboss.logging.Logger;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLElementWriter;
import org.jboss.staxmapper.XMLExtendedStreamReader;
import org.jboss.staxmapper.XMLExtendedStreamWriter;
import org.rhq.enterprise.agent.AgentConfigurationConstants;
import org.rhq.enterprise.communications.ServiceContainerConfigurationConstants;
public class AgentSubsystemExtension implements Extension {
private final Logger log = Logger.getLogger(AgentSubsystemExtension.class);
public static final String NAMESPACE = "urn:org.rhq:embeddedagent:1.0";
public static final String SUBSYSTEM_NAME = "embeddedagent";
private final SubsystemParser parser = new SubsystemParser();
private static final String RESOURCE_NAME = AgentSubsystemExtension.class.getPackage().getName()
+ ".LocalDescriptions";
protected static final String PLUGINS_ELEMENT = "plugins";
protected static final String PLUGIN_ELEMENT = "plugin";
protected static final String PLUGIN_NAME = "name";
protected static final String PLUGIN_ENABLED = "enabled";
protected static final String AGENT_ENABLED = "enabled";
protected static final boolean AGENT_ENABLED_DEFAULT = false;
protected static final boolean PLUGIN_ENABLED_DEFAULT = true;
protected static final String AGENT_CONFIG_ELEMENT = "extra-configuration";
protected static final String PREFERENCE_ELEMENT = "preference";
protected static final String SERVER_ENDPOINT_ELEMENT = "server-endpoint";
protected static final String SERVER_ENDPOINT_ADDRESS_XML = "address";
protected static final String SERVER_ENDPOINT_PORT_XML = "port";
protected static final String SERVER_ENDPOINT_TRANSPORT_XML = "transport";
protected static final String SERVER_ENDPOINT_TRANSPORT_PARAMS_XML = "transport-params";
protected static final String AGENT_ENDPOINT_ELEMENT = "agent-endpoint";
protected static final String AGENT_ENDPOINT_SOCKET_BINDING_XML = "socket-binding";
protected static final String AGENT_ENDPOINT_TRANSPORT_XML = "transport";
protected static final String AGENT_ENDPOINT_TRANSPORT_PARAMS_XML = "transport-params";
protected static final String AGENT_RESTART_OP = "restart";
protected static final String AGENT_STOP_OP = "stop";
protected static final String AGENT_STATUS_OP = "status";
protected static final String AGENT_EXECUTE_PROMPT_CMD_OP = "execute-prompt-command";
protected static final String ATTRIB_AGENT_NAME = AgentConfigurationConstants.NAME;
protected static final String ATTRIB_DISABLE_NATIVE = AgentConfigurationConstants.DISABLE_NATIVE_SYSTEM;
protected static final String ATTRIB_SERVER_TRANSPORT = AgentConfigurationConstants.SERVER_TRANSPORT;
protected static final String ATTRIB_SERVER_BIND_PORT = AgentConfigurationConstants.SERVER_BIND_PORT;
protected static final String ATTRIB_SERVER_BIND_ADDRESS = AgentConfigurationConstants.SERVER_BIND_ADDRESS;
protected static final String ATTRIB_SERVER_TRANSPORT_PARAMS = AgentConfigurationConstants.SERVER_TRANSPORT_PARAMS;
protected static final String ATTRIB_SERVER_ALIAS = AgentConfigurationConstants.SERVER_ALIAS;
protected static final String ATTRIB_SOCKET_BINDING = AGENT_ENDPOINT_SOCKET_BINDING_XML;
protected static final String ATTRIB_AGENT_TRANSPORT = ServiceContainerConfigurationConstants.CONNECTOR_TRANSPORT;
protected static final String ATTRIB_AGENT_TRANSPORT_PARAMS = ServiceContainerConfigurationConstants.CONNECTOR_TRANSPORT_PARAMS;
protected static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String keyPrefix) {
String prefix = SUBSYSTEM_NAME + (keyPrefix == null ? "" : "." + keyPrefix);
return new StandardResourceDescriptionResolver(prefix, RESOURCE_NAME,
AgentSubsystemExtension.class.getClassLoader(), true, false);
}
@Override
public void initializeParsers(ExtensionParsingContext context) {
context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE, parser);
}
@Override
public void initialize(ExtensionContext context) {
log.info("Initializing embedded agent subsystem");
final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, 1, 0);
final ManagementResourceRegistration registration = subsystem
.registerSubsystemModel(AgentSubsystemDefinition.INSTANCE);
subsystem.registerXMLElementWriter(parser);
}
/**
* The subsystem parser, which uses stax to read and write to and from xml
*/
private static class SubsystemParser implements XMLStreamConstants, XMLElementReader<List<ModelNode>>,
XMLElementWriter<SubsystemMarshallingContext> {
@Override
public void readElement(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
// The agent "enabled" attribute is required
ParseUtils.requireSingleAttribute(reader, AGENT_ENABLED);
// Add the main subsystem 'add' operation
final ModelNode opAdd = new ModelNode();
opAdd.get(OP).set(ADD);
opAdd.get(OP_ADDR).set(PathAddress.pathAddress(SUBSYSTEM_PATH).toModelNode());
String agentEnabledValue = reader.getAttributeValue(null, AGENT_ENABLED);
if (agentEnabledValue != null) {
opAdd.get(AGENT_ENABLED).setExpression(agentEnabledValue);
}
// Read the children elements
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
String elementName = reader.getLocalName();
if (elementName.equals(PLUGINS_ELEMENT)) {
ModelNode pluginsAttributeNode = opAdd.get(PLUGINS_ELEMENT);
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
if (reader.isStartElement()) {
readPlugin(reader, pluginsAttributeNode);
}
}
} else if (elementName.equals(AGENT_CONFIG_ELEMENT)) {
ModelNode configAttributeNode = opAdd.get(AGENT_CONFIG_ELEMENT);
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
if (reader.isStartElement()) {
readPreference(reader, configAttributeNode);
}
}
} else if (elementName.equals(SERVER_ENDPOINT_ELEMENT)) {
String val = reader.getAttributeValue(null, SERVER_ENDPOINT_ADDRESS_XML);
if (val != null) {
opAdd.get(ATTRIB_SERVER_BIND_ADDRESS).setExpression(val);
}
val = reader.getAttributeValue(null, SERVER_ENDPOINT_PORT_XML);
if (val != null) {
opAdd.get(ATTRIB_SERVER_BIND_PORT).setExpression(val);
}
val = reader.getAttributeValue(null, SERVER_ENDPOINT_TRANSPORT_XML);
if (val != null) {
opAdd.get(ATTRIB_SERVER_TRANSPORT).setExpression(val);
}
val = reader.getAttributeValue(null, SERVER_ENDPOINT_TRANSPORT_PARAMS_XML);
if (val != null) {
opAdd.get(ATTRIB_SERVER_TRANSPORT_PARAMS).setExpression(val);
}
ParseUtils.requireNoContent(reader);
} else if (elementName.equals(AGENT_ENDPOINT_ELEMENT)) {
String val = reader.getAttributeValue(null, AGENT_ENDPOINT_SOCKET_BINDING_XML);
if (val != null) {
opAdd.get(ATTRIB_SOCKET_BINDING).set(val); // we don't support expression here, must be the actual name
}
val = reader.getAttributeValue(null, AGENT_ENDPOINT_TRANSPORT_XML);
if (val != null) {
opAdd.get(ATTRIB_AGENT_TRANSPORT).setExpression(val);
}
val = reader.getAttributeValue(null, AGENT_ENDPOINT_TRANSPORT_PARAMS_XML);
if (val != null) {
opAdd.get(ATTRIB_AGENT_TRANSPORT_PARAMS).setExpression(val);
}
ParseUtils.requireNoContent(reader);
} else if (elementName.equals(ATTRIB_AGENT_NAME)) {
opAdd.get(ATTRIB_AGENT_NAME).setExpression(reader.getElementText());
} else if (elementName.equals(ATTRIB_DISABLE_NATIVE)) {
opAdd.get(ATTRIB_DISABLE_NATIVE).setExpression(reader.getElementText());
} else if (elementName.equals(ATTRIB_SERVER_ALIAS)) {
opAdd.get(ATTRIB_SERVER_ALIAS).setExpression(reader.getElementText());
} else {
throw ParseUtils.unexpectedElement(reader);
}
}
list.add(opAdd);
}
private void readPlugin(XMLExtendedStreamReader reader, ModelNode pluginsAttributeNode)
throws XMLStreamException {
if (!reader.getLocalName().equals(PLUGIN_ELEMENT)) {
throw ParseUtils.unexpectedElement(reader);
}
String pluginName = null;
boolean pluginEnabled = PLUGIN_ENABLED_DEFAULT;
for (int i = 0; i < reader.getAttributeCount(); i++) {
String attr = reader.getAttributeLocalName(i);
String value = reader.getAttributeValue(i);
if (attr.equals(PLUGIN_ENABLED)) {
pluginEnabled = Boolean.parseBoolean(value);
} else if (attr.equals(PLUGIN_NAME)) {
pluginName = value;
} else {
throw ParseUtils.unexpectedAttribute(reader, i);
}
}
ParseUtils.requireNoContent(reader);
if (pluginName == null) {
throw ParseUtils.missingRequiredElement(reader, Collections.singleton(PLUGIN_NAME));
}
// Add the plugin to the plugins attribute node
pluginsAttributeNode.add(pluginName, pluginEnabled);
}
private void readPreference(XMLExtendedStreamReader reader, ModelNode configAttributeNode)
throws XMLStreamException {
if (!reader.getLocalName().equals(PREFERENCE_ELEMENT)) {
throw ParseUtils.unexpectedElement(reader);
}
ParseUtils.requireAttributes(reader, Attribute.NAME.getLocalName(), Attribute.VALUE.getLocalName());
String attr = reader.getAttributeValue(null, Attribute.NAME.getLocalName());
String val = reader.getAttributeValue(null, Attribute.VALUE.getLocalName());
ParseUtils.requireNoContent(reader);
configAttributeNode.add(attr, val);
}
@Override
public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context)
throws XMLStreamException {
ModelNode node = context.getModelNode();
// <subsystem>
context.startSubsystemElement(AgentSubsystemExtension.NAMESPACE, false);
writer.writeAttribute(AGENT_ENABLED, node.get(AGENT_ENABLED).asString());
// our config elements
writeElement(writer, node, ATTRIB_AGENT_NAME);
writeElement(writer, node, ATTRIB_DISABLE_NATIVE);
writeElement(writer, node, ATTRIB_SERVER_ALIAS);
// <server-endpoint>
writer.writeStartElement(SERVER_ENDPOINT_ELEMENT);
ModelNode serverAddressNode = node.get(ATTRIB_SERVER_BIND_ADDRESS);
ModelNode serverPortNode = node.get(ATTRIB_SERVER_BIND_PORT);
ModelNode serverTransportNode = node.get(ATTRIB_SERVER_TRANSPORT);
ModelNode serverTransportParamsNode = node.get(ATTRIB_SERVER_TRANSPORT_PARAMS);
if (serverPortNode.isDefined()) {
writer.writeAttribute(SERVER_ENDPOINT_PORT_XML, serverPortNode.asString());
}
if (serverAddressNode.isDefined()) {
writer.writeAttribute(SERVER_ENDPOINT_ADDRESS_XML, serverAddressNode.asString());
}
if (serverTransportNode.isDefined()) {
writer.writeAttribute(SERVER_ENDPOINT_TRANSPORT_XML, serverTransportNode.asString());
}
if (serverTransportParamsNode.isDefined()) {
writer.writeAttribute(SERVER_ENDPOINT_TRANSPORT_PARAMS_XML, serverTransportParamsNode.asString());
}
// </server-endpoint>
writer.writeEndElement();
// <agent-endpoint>
writer.writeStartElement(AGENT_ENDPOINT_ELEMENT);
ModelNode agentSocketBindingNode = node.get(ATTRIB_SOCKET_BINDING);
ModelNode agentTransportNode = node.get(ATTRIB_AGENT_TRANSPORT);
ModelNode agentTransportParamsNode = node.get(ATTRIB_AGENT_TRANSPORT_PARAMS);
if (agentSocketBindingNode.isDefined()) {
writer.writeAttribute(AGENT_ENDPOINT_SOCKET_BINDING_XML, agentSocketBindingNode.asString());
}
if (agentTransportNode.isDefined()) {
writer.writeAttribute(AGENT_ENDPOINT_TRANSPORT_XML, agentTransportNode.asString());
}
if (agentTransportParamsNode.isDefined()) {
writer.writeAttribute(AGENT_ENDPOINT_TRANSPORT_PARAMS_XML, agentTransportParamsNode.asString());
}
// </agent-endpoint>
writer.writeEndElement();
// <extra-configuration>
writer.writeStartElement(AGENT_CONFIG_ELEMENT);
ModelNode configNode = node.get(AGENT_CONFIG_ELEMENT);
if (configNode != null && configNode.isDefined()) {
for (Property property : configNode.asPropertyList()) {
// <preference>
writer.writeStartElement(PREFERENCE_ELEMENT);
writer.writeAttribute(Attribute.NAME.getLocalName(), property.getName());
writer.writeAttribute(Attribute.VALUE.getLocalName(), property.getValue().asString());
// </preference>
writer.writeEndElement();
}
}
// </extra-configuration>
writer.writeEndElement();
// <plugins>
writer.writeStartElement(PLUGINS_ELEMENT);
ModelNode plugins = node.get(PLUGINS_ELEMENT);
if (plugins != null && plugins.isDefined()) {
for (Property property : plugins.asPropertyList()) {
// <plugin>
writer.writeStartElement(PLUGIN_ELEMENT);
writer.writeAttribute(PLUGIN_NAME, property.getName());
writer.writeAttribute(PLUGIN_ENABLED, property.getValue().asString());
// </plugin>
writer.writeEndElement();
}
}
// </plugins>
writer.writeEndElement();
// </subsystem>
writer.writeEndElement();
}
private void writeElement(final XMLExtendedStreamWriter writer, ModelNode node, String attribName)
throws XMLStreamException {
ModelNode attribNode = node.get(attribName);
if (attribNode.isDefined()) {
writer.writeStartElement(attribName);
writer.writeCharacters(attribNode.asString());
writer.writeEndElement();
}
}
}
}