/* * RHQ Management Platform * Copyright (C) 2005-2013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.enterprise.startup; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESCRIBE; 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.io.File; 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.PathElement; import org.jboss.as.controller.SubsystemRegistration; import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver; import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler; 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.as.controller.registry.OperationEntry; import org.jboss.dmr.ModelNode; import org.jboss.staxmapper.XMLElementReader; import org.jboss.staxmapper.XMLElementWriter; import org.jboss.staxmapper.XMLExtendedStreamReader; import org.jboss.staxmapper.XMLExtendedStreamWriter; /** * A JBoss AS7 subsystem extension that starts up the RHQ deployment applications. * * @author Ian Springer * @author John Mazzitelli */ public class StartupExtension implements Extension { // The namespace used for the subsystem XML element public static final String NAMESPACE = "urn:org.rhq:startup:1.0"; // The name of our subsystem within the model public static final String SUBSYSTEM_NAME = "rhq-startup"; // The path of our subsystem within the model static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME); // the deployments we are managing public static final String DEPLOYMENT_APP_EAR = "rhq.ear"; // our management API version private static final int API_MAJOR_VERSION = 1; private static final int API_MINOR_VERSION = 0; // location in the classloader of the description messages private static final String RESOURCE_NAME = StartupExtension.class.getPackage().getName() + ".LocalDescriptions"; // used to read and write the XML of our subsystem config private static final StartupSubsystemParser parser = new StartupSubsystemParser(); private static final String RHQ_SERVER_HOME_ENVVAR = "RHQ_SERVER_HOME"; private static final String RHQ_SERVER_HOME_SYSPROP = "rhq.server.home"; static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) { StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME); for (String kp : keyPrefix) { prefix.append('.').append(kp); } return new StandardResourceDescriptionResolver(prefix.toString(), RESOURCE_NAME, StartupExtension.class.getClassLoader(), true, false); } @Override public void initializeParsers(ExtensionParsingContext context) { context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE, parser); } @Override public void initialize(ExtensionContext context) { // we know our app needs to know where RHQ is installed, so setup our sys prop now String serverHome = System.getProperty(RHQ_SERVER_HOME_SYSPROP); if (serverHome == null) { serverHome = System.getenv(RHQ_SERVER_HOME_ENVVAR); if (serverHome == null) { // assume we are running our own embedded AS, so RHQ home is the parent dir of the AS home try { serverHome = new File(System.getProperty("jboss.home.dir"), "..").getCanonicalPath(); } catch (Exception e) { throw new RuntimeException("Failed to locate server home", e); } } System.setProperty(RHQ_SERVER_HOME_SYSPROP, serverHome); } File modulesDir = new File(serverHome, "modules"); // if this is a correct home dir, RHQ's modules directory should be here if (!modulesDir.isDirectory()) { throw new IllegalStateException("Invalid RHQ server home dir: " + serverHome); } // register subsystem with its model version final SubsystemRegistration subsystem; subsystem = context.registerSubsystem(SUBSYSTEM_NAME, API_MAJOR_VERSION, API_MINOR_VERSION); // register subsystem model with subsystem definition that defines all attributes and operations final ManagementResourceRegistration registration; registration = subsystem.registerSubsystemModel(StartupSubsystemDefinition.INSTANCE); // register describe operation registration.registerOperationHandler(DESCRIBE, GenericSubsystemDescribeHandler.INSTANCE, GenericSubsystemDescribeHandler.INSTANCE, false, OperationEntry.EntryType.PRIVATE); // register the object that persists our subsystem XML config subsystem.registerXMLElementWriter(parser); } /** * The subsystem reader/writer, which uses STAX to read and write the subsystem XML. */ private static class StartupSubsystemParser implements XMLStreamConstants, XMLElementReader<List<ModelNode>>, XMLElementWriter<SubsystemMarshallingContext> { @Override public void readElement(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException { // Parse the 'subsystem' element... ParseUtils.requireNoAttributes(reader); // (I think we are required to add this) list.add(createAddSubsystemOperation()); // // Read the child elements // while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { // if (reader.getLocalName().equals("some-xml-element-name")) { // status = reader.getElementText(); // } else { // throw ParseUtils.unexpectedElement(reader); // } // } ParseUtils.requireNoContent(reader); return; } private static ModelNode createAddSubsystemOperation() { final ModelNode subsystem = new ModelNode(); subsystem.get(OP).set(ADD); subsystem.get(OP_ADDR).add(SUBSYSTEM, SUBSYSTEM_NAME); return subsystem; } @Override public void writeContent(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException { //TODO seems to be a problem with empty elements //context.startSubsystemElement(StartupExtension.NAMESPACE, true); // <subsystem/> context.startSubsystemElement(StartupExtension.NAMESPACE, false); // <subsystem> // writer.writeStartElement("some-xml-element-name"); // <xml-element-name> // writer.writeCharacters(something); // writer.writeEndElement(); // </xml-element-name> writer.writeEndElement(); // </subsystem> } } }