Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add the example subsystem to git

  • Loading branch information...
commit 017f15d8c1e405e1d66c1e320bb7adf7b7ee60a1 1 parent f808812
@kabir kabir authored
Showing with 1,158 additions and 0 deletions.
  1. +173 −0 jboss-as-subsystem-example/pom.xml
  2. +75 −0 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/deployment/SubsystemDeploymentProcessor.java
  3. +56 −0 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/SubsystemAdd.java
  4. +232 −0 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/SubsystemExtension.java
  5. +84 −0 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/SubsystemProviders.java
  6. +87 −0 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/TrackerService.java
  7. +62 −0 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/TrackerTickHandler.java
  8. +72 −0 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/TypeAddHandler.java
  9. +62 −0 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/TypeRemoveHandler.java
  10. +1 −0  jboss-as-subsystem-example/src/main/resources/META-INF/services/org.jboss.as.controller.Extension
  11. +16 −0 jboss-as-subsystem-example/src/main/resources/module/main/module.xml
  12. +24 −0 jboss-as-subsystem-example/src/main/resources/schema/mysubsystem.xsd
  13. +214 −0 jboss-as-subsystem-example/src/test/java/com/acme/corp/tracker/extension/SubsystemParsingTestCase.java
View
173 jboss-as-subsystem-example/pom.xml
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software 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
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- parent>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-parent</artifactId>
+ </parent -->
+
+ <groupId>com.acme.corp</groupId>
+ <artifactId>acme-subsystem</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <name>JBoss Application Server: Subsystem Artifact</name>
+
+ <packaging>jar</packaging>
+
+ <properties>
+ <version.jboss.as>7.0.1.Final</version.jboss.as>
+ <version.junit>4.8.2</version.junit>
+ <module.name>com.acme.corp.tracker</module.name>
+ </properties>
+
+
+ <build>
+ <!-- Maven will append the version to the finalName (which is the name
+ given to the generated war, and hence the context root) -->
+ <finalName>${project.artifactId}</finalName>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.8.1</version>
+ <configuration>
+ <redirectTestOutputToFile>true</redirectTestOutputToFile>
+ <enableAssertions>true</enableAssertions>
+ <argLine>-Xmx512m</argLine>
+ <systemProperties>
+ <property>
+ <name>jboss.home</name>
+ <value>${jboss.home}</value>
+ </property>
+ </systemProperties>
+ <includes>
+ <include>**/*TestCase.java</include>
+ </includes>
+ <forkMode>once</forkMode>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.2.1</version>
+ <configuration>
+ <filters>
+ <filter>src/assemble/filter.properties</filter>
+ </filters>
+ <descriptors>
+ <descriptor>src/assemble/distribution.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <inherited>false</inherited>
+ <version>1.6</version>
+ <executions>
+ <execution>
+ <id>build-dist</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <target>
+ <!-- Replace the '.' in ${module.name} with '/' to get its path -->
+ <tempfile property="temp.file" />
+ <echo message="${module.name}" file="${temp.file}" />
+ <replace file="${temp.file}" token="." value="/" />
+ <loadfile srcfile="${temp.file}" property="module.path" />
+ <delete file="${temp.file}" />
+
+ <delete dir="target/module" />
+ <property name="module.dir" value="target/module/${module.path}/main" />
+
+ <copy file="src/main/resources/module/main/module.xml" tofile="${module.dir}/module.xml" />
+ <copy file="target/${project.artifactId}.jar" todir="${module.dir}" />
+
+ <echo>Module ${module.name} has been created in the target/module directory. Copy to your JBoss AS 7 installation.</echo>
+ </target>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-controller</artifactId>
+ <version>${version.jboss.as}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-server</artifactId>
+ <version>${version.jboss.as}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-subsystem-test</artifactId>
+ <version>${version.jboss.as}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ <version>${version.junit}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-controller</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-server</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-subsystem-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
View
75 ...-example/src/main/java/com/acme/corp/tracker/deployment/SubsystemDeploymentProcessor.java
@@ -0,0 +1,75 @@
+package com.acme.corp.tracker.deployment;
+
+import org.jboss.as.server.AbstractDeploymentChainStep;
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.server.deployment.Phase;
+import org.jboss.as.server.deployment.module.ResourceRoot;
+import org.jboss.logging.Logger;
+import org.jboss.msc.service.ServiceController;
+import org.jboss.msc.service.ServiceRegistry;
+import org.jboss.vfs.VirtualFile;
+
+import com.acme.corp.tracker.extension.TrackerService;
+
+/**
+ * An example deployment unit processor that does nothing. To add more deployment
+ * processors copy this class, and add to the {@link AbstractDeploymentChainStep}
+ * {@link SubsystemAdd#performBoottime(org.jboss.as.controller.OperationContext, org.jboss.dmr.ModelNode, org.jboss.dmr.ModelNode, org.jboss.as.controller.ServiceVerificationHandler, java.util.List)}
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ */
+public class SubsystemDeploymentProcessor implements DeploymentUnitProcessor {
+
+ Logger log = Logger.getLogger(SubsystemDeploymentProcessor.class);
+
+ /**
+ * See {@link Phase} for a description of the different phases
+ */
+ public static final Phase PHASE = Phase.DEPENDENCIES;
+
+ /**
+ * The relative order of this processor within the {@link #PHASE}.
+ * The current number is large enough for it to happen after all
+ * the standard deployment unit processors that come with JBoss AS.
+ */
+ public static final int PRIORITY = 0x4000;
+
+ @Override
+ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+ String name = phaseContext.getDeploymentUnit().getName();
+ ResourceRoot root = phaseContext.getDeploymentUnit().getAttachment(Attachments.DEPLOYMENT_ROOT);
+ TrackerService service = getTrackerService(phaseContext.getServiceRegistry(), name);
+ if (service != null) {
+ VirtualFile cool = root.getRoot().getChild("META-INF/cool.txt");
+ service.addDeployment(name);
+ if (cool.exists()) {
+ service.addCoolDeployment(name);
+ }
+ }
+ }
+
+ @Override
+ public void undeploy(DeploymentUnit context) {
+ context.getServiceRegistry();
+ String name = context.getName();
+ TrackerService service = getTrackerService(context.getServiceRegistry(), name);
+ if (service != null) {
+ service.removeDeployment(name);
+ }
+ }
+
+ private TrackerService getTrackerService(ServiceRegistry registry, String name) {
+ int last = name.lastIndexOf(".");
+ String suffix = name.substring(last + 1);
+ ServiceController<?> container = registry.getService(TrackerService.createServiceName(suffix));
+ if (container != null) {
+ TrackerService service = (TrackerService)container.getValue();
+ return service;
+ }
+ return null;
+ }
+}
View
56 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/SubsystemAdd.java
@@ -0,0 +1,56 @@
+package com.acme.corp.tracker.extension;
+
+import java.util.List;
+
+import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.ServiceVerificationHandler;
+import org.jboss.as.server.AbstractDeploymentChainStep;
+import org.jboss.as.server.DeploymentProcessorTarget;
+import org.jboss.dmr.ModelNode;
+import org.jboss.logging.Logger;
+import org.jboss.msc.service.ServiceController;
+
+import com.acme.corp.tracker.deployment.SubsystemDeploymentProcessor;
+
+/**
+ * Handler responsible for adding the subsystem resource to the model
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ */
+class SubsystemAdd extends AbstractBoottimeAddStepHandler {
+
+ static final SubsystemAdd INSTANCE = new SubsystemAdd();
+
+ private final Logger log = Logger.getLogger(SubsystemAdd.class);
+
+ private SubsystemAdd() {
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
+ log.info("Populating the model");
+ //Initialize the 'type' child node
+ model.get("type").setEmptyObject();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void performBoottime(OperationContext context, ModelNode operation, ModelNode model,
+ ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers)
+ throws OperationFailedException {
+
+ //Add deployment processors here
+ //Remove this if you don't need to hook into the deployers, or you can add as many as you like
+ //see SubDeploymentProcessor for explanation of the phases
+ context.addStep(new AbstractDeploymentChainStep() {
+ public void execute(DeploymentProcessorTarget processorTarget) {
+ processorTarget.addDeploymentProcessor(SubsystemDeploymentProcessor.PHASE, SubsystemDeploymentProcessor.PRIORITY, new SubsystemDeploymentProcessor());
+
+ }
+ }, OperationContext.Stage.RUNTIME);
+
+ }
+}
View
232 ...s-subsystem-example/src/main/java/com/acme/corp/tracker/extension/SubsystemExtension.java
@@ -0,0 +1,232 @@
+/*
+* JBoss, Home of Professional Open Source.
+* Copyright 2006, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file in the
+* distribution for a full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package com.acme.corp.tracker.extension;
+
+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.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+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.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.SubsystemRegistration;
+import org.jboss.as.controller.descriptions.DescriptionProvider;
+import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
+import org.jboss.as.controller.descriptions.common.CommonDescriptions;
+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.AttributeAccess.Storage;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.as.controller.registry.OperationEntry;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.Property;
+import org.jboss.staxmapper.XMLElementReader;
+import org.jboss.staxmapper.XMLElementWriter;
+import org.jboss.staxmapper.XMLExtendedStreamReader;
+import org.jboss.staxmapper.XMLExtendedStreamWriter;
+
+
+/**
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ */
+public class SubsystemExtension implements Extension {
+
+ /** The name space used for the {@code subsystem} element */
+ public static final String NAMESPACE = "urn:com.acme.corp.tracker:1.0";
+
+ /** The name of our subsystem within the model. */
+ public static final String SUBSYSTEM_NAME = "tracker";
+
+ /** The parser used for parsing our subsystem */
+ private final SubsystemParser parser = new SubsystemParser();
+
+ @Override
+ public void initializeParsers(ExtensionParsingContext context) {
+ context.setSubsystemXmlMapping(NAMESPACE, parser);
+ }
+
+ @Override
+ public void initialize(ExtensionContext context) {
+ final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME);
+ final ManagementResourceRegistration registration = subsystem.registerSubsystemModel(SubsystemProviders.SUBSYSTEM);
+ //We always need to add an 'add' operation
+ registration.registerOperationHandler(ADD, SubsystemAdd.INSTANCE, SubsystemProviders.SUBSYSTEM_ADD, false);
+ //We always need to add a 'describe' operation
+ registration.registerOperationHandler(DESCRIBE, SubsystemDescribeHandler.INSTANCE, SubsystemDescribeHandler.INSTANCE, false, OperationEntry.EntryType.PRIVATE);
+
+ //Add the type child
+ ManagementResourceRegistration typeChild = registration.registerSubModel(PathElement.pathElement("type"), SubsystemProviders.TYPE_CHILD);
+ typeChild.registerOperationHandler(ModelDescriptionConstants.ADD, TypeAddHandler.INSTANCE, TypeAddHandler.INSTANCE);
+ typeChild.registerOperationHandler(ModelDescriptionConstants.REMOVE, TypeRemoveHandler.INSTANCE, TypeRemoveHandler.INSTANCE);
+ typeChild.registerReadWriteAttribute("tick", null, TrackerTickHandler.INSTANCE, Storage.CONFIGURATION);
+
+ subsystem.registerXMLElementWriter(parser);
+ }
+
+ private static ModelNode createAddSubsystemOperation() {
+ final ModelNode subsystem = new ModelNode();
+ subsystem.get(OP).set(ADD);
+ subsystem.get(OP_ADDR).add(SUBSYSTEM, SUBSYSTEM_NAME);
+ return subsystem;
+ }
+
+ /**
+ * 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> {
+
+ /** {@inheritDoc} */
+ @Override
+ public void readElement(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
+ // Require no attributes
+ ParseUtils.requireNoAttributes(reader);
+
+ //Add the main subsystem 'add' operation
+ list.add(createAddSubsystemOperation());
+
+ //Read the children
+ while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
+ if (!reader.getLocalName().equals("deployment-types")) {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
+ if (reader.isStartElement()) {
+ readDeploymentType(reader, list);
+ }
+ }
+ }
+ }
+
+ private void readDeploymentType(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
+ if (!reader.getLocalName().equals("deployment-type")) {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ String suffix = null;
+ Long tick = null;
+ for (int i = 0 ; i < reader.getAttributeCount() ; i++) {
+ String attr = reader.getAttributeLocalName(i);
+ if (attr.equals("tick")){
+ tick = Long.valueOf(reader.getAttributeValue(i));
+ } else if (attr.equals("suffix")){
+ suffix = reader.getAttributeValue(i);
+ } else {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ }
+ ParseUtils.requireNoContent(reader);
+ if (suffix == null) {
+ throw ParseUtils.missingRequiredElement(reader, Collections.singleton("suffix"));
+ }
+
+ //Add the 'add' operation for each 'type' child
+ ModelNode addType = new ModelNode();
+ addType.get(OP).set(ModelDescriptionConstants.ADD);
+ PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME), PathElement.pathElement("type", suffix));
+ addType.get(OP_ADDR).set(addr.toModelNode());
+ if (tick != null) {
+ addType.get("tick").set(tick);
+ }
+ list.add(addType);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
+
+ //Write out the main subsystem element
+ context.startSubsystemElement(SubsystemExtension.NAMESPACE, false);
+
+ writer.writeStartElement("deployment-types");
+
+ ModelNode node = context.getModelNode();
+ ModelNode type = node.get("type");
+ for (Property property : type.asPropertyList()) {
+
+ //write each child element to xml
+ writer.writeStartElement("deployment-type");
+ writer.writeAttribute("suffix", property.getName());
+ ModelNode entry = property.getValue();
+ if (entry.hasDefined("tick")) {
+ writer.writeAttribute("tick", entry.get("tick").asString());
+ }
+ writer.writeEndElement();
+ }
+
+ //End deployment-types
+ writer.writeEndElement();
+ //End subsystem
+ writer.writeEndElement();
+ }
+ }
+
+
+ /**
+ * Recreate the steps to put the subsystem in the same state it was in.
+ * This is used in domain mode to query the profile being used, in order to
+ * get the steps needed to create the servers
+ */
+ private static class SubsystemDescribeHandler implements OperationStepHandler, DescriptionProvider {
+ static final SubsystemDescribeHandler INSTANCE = new SubsystemDescribeHandler();
+
+ public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
+ //Add the main operation
+ context.getResult().add(createAddSubsystemOperation());
+
+ //Add the operations to create each child
+
+ ModelNode node = context.readModel(PathAddress.EMPTY_ADDRESS);
+ for (Property property : node.get("type").asPropertyList()) {
+
+ ModelNode addType = new ModelNode();
+ addType.get(OP).set(ModelDescriptionConstants.ADD);
+ PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME), PathElement.pathElement("type", property.getName()));
+ addType.get(OP_ADDR).set(addr.toModelNode());
+ if (property.getValue().hasDefined("tick")) {
+ addType.get("tick").set(property.getValue().get("tick").asLong());
+ }
+ context.getResult().add(addType);
+ }
+ context.completeStep();
+ }
+
+ @Override
+ public ModelNode getModelDescription(Locale locale) {
+ return CommonDescriptions.getSubsystemDescribeOperation(locale);
+ }
+ }
+
+}
View
84 ...s-subsystem-example/src/main/java/com/acme/corp/tracker/extension/SubsystemProviders.java
@@ -0,0 +1,84 @@
+package com.acme.corp.tracker.extension;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ATTRIBUTES;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CHILDREN;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEFAULT;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESCRIPTION;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HEAD_COMMENT_ALLOWED;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MAX_OCCURS;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MIN_OCCURS;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MODEL_DESCRIPTION;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAMESPACE;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REQUIRED;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.TAIL_COMMENT_ALLOWED;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.TYPE;
+
+import java.util.Locale;
+
+import org.jboss.as.controller.descriptions.DescriptionProvider;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+/**
+ * Contains the description providers. The description providers are what print out the
+ * information when you execute the {@code read-resource-description} operation.
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ */
+class SubsystemProviders {
+
+ /**
+ * Used to create the description of the subsystem
+ */
+ public static DescriptionProvider SUBSYSTEM = new DescriptionProvider() {
+ public ModelNode getModelDescription(Locale locale) {
+ //The locale is passed in so you can internationalize the strings used in the descriptions
+
+ final ModelNode subsystem = new ModelNode();
+ //Change the description
+ subsystem.get(DESCRIPTION).set("This subsystem tracks deployments of a given type");
+ subsystem.get(HEAD_COMMENT_ALLOWED).set(true);
+ subsystem.get(TAIL_COMMENT_ALLOWED).set(true);
+ subsystem.get(NAMESPACE).set(SubsystemExtension.NAMESPACE);
+
+ //Add information about the 'type' child
+ subsystem.get(CHILDREN, "type", DESCRIPTION).set("Deployment types that should be tracked");
+ subsystem.get(CHILDREN, "type", MIN_OCCURS).set(0);
+ subsystem.get(CHILDREN, "type", MAX_OCCURS).set(Integer.MAX_VALUE);
+ subsystem.get(CHILDREN, "type", MODEL_DESCRIPTION);
+
+ return subsystem;
+ }
+ };
+
+ /**
+ * Used to create the description of the subsystem add method
+ */
+ public static DescriptionProvider SUBSYSTEM_ADD = new DescriptionProvider() {
+ public ModelNode getModelDescription(Locale locale) {
+ //The locale is passed in so you can internationalize the strings used in the descriptions
+
+ final ModelNode subsystem = new ModelNode();
+ subsystem.get(DESCRIPTION).set("Adds the tracker subsystem");
+
+ return subsystem;
+ }
+ };
+
+ /**
+ * Used to create the description of the {@code type} child
+ */
+ public static DescriptionProvider TYPE_CHILD = new DescriptionProvider() {
+ @Override
+ public ModelNode getModelDescription(Locale locale) {
+ ModelNode node = new ModelNode();
+ node.get(DESCRIPTION).set("Contains information about a tracked deployment type");
+ node.get(ATTRIBUTES, "tick", DESCRIPTION).set("How often in milliseconds to output the information about the tracked deployments");
+ node.get(ATTRIBUTES, "tick", TYPE).set(ModelType.LONG);
+ node.get(ATTRIBUTES, "tick", REQUIRED).set(true);
+ node.get(ATTRIBUTES, "tick", DEFAULT).set(10000);
+ return node;
+ }
+ };
+
+}
View
87 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/TrackerService.java
@@ -0,0 +1,87 @@
+package com.acme.corp.tracker.extension;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.jboss.msc.service.Service;
+import org.jboss.msc.service.ServiceName;
+import org.jboss.msc.service.StartContext;
+import org.jboss.msc.service.StartException;
+import org.jboss.msc.service.StopContext;
+
+/**
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ */
+public class TrackerService implements Service<TrackerService>{
+
+ private AtomicLong tick = new AtomicLong(10000);
+
+ private Set<String> deployments = Collections.synchronizedSet(new HashSet<String>());
+
+ private Set<String> coolDeployments = Collections.synchronizedSet(new HashSet<String>());
+
+ private final String suffix;
+
+ private Thread OUTPUT = new Thread() {
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ Thread.sleep(tick.get());
+ System.out.println("Current deployments deployed while " + suffix + " tracking active:\n" + deployments + "\nCool: " + coolDeployments.size());
+ } catch (InterruptedException e) {
+ interrupted();
+ break;
+ }
+ }
+ }
+ };
+
+ public TrackerService(String suffix, long tick) {
+ this.suffix = suffix;
+ this.tick.set(tick);
+ }
+
+ @Override
+ public TrackerService getValue() throws IllegalStateException, IllegalArgumentException {
+ return this;
+ }
+
+ @Override
+ public void start(StartContext context) throws StartException {
+ OUTPUT.start();
+ }
+
+ @Override
+ public void stop(StopContext context) {
+ OUTPUT.interrupt();
+ }
+
+ public static ServiceName createServiceName(String suffix) {
+ return ServiceName.JBOSS.append("tracker", suffix);
+ }
+
+ public void addDeployment(String name) {
+ deployments.add(name);
+ }
+
+ public void addCoolDeployment(String name) {
+ coolDeployments.add(name);
+ }
+
+ public void removeDeployment(String name) {
+ deployments.remove(name);
+ coolDeployments.remove(name);
+ }
+
+ void setTick(long tick) {
+ this.tick.set(tick);
+ }
+
+ public long getTick() {
+ return this.tick.get();
+ }
+}
View
62 ...s-subsystem-example/src/main/java/com/acme/corp/tracker/extension/TrackerTickHandler.java
@@ -0,0 +1,62 @@
+/*
+* JBoss, Home of Professional Open Source.
+* Copyright 2011, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file in the
+* distribution for a full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package com.acme.corp.tracker.extension;
+
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationContext.Stage;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
+import org.jboss.dmr.ModelNode;
+
+/**
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ */
+class TrackerTickHandler implements OperationStepHandler {
+
+ public static final TrackerTickHandler INSTANCE = new TrackerTickHandler();
+
+ private TrackerTickHandler() {
+ }
+
+ @Override
+ public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
+ //Update the model
+ final String suffix = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.ADDRESS)).getLastElement().getValue();
+ final long tick = operation.require("value").asLong();
+ ModelNode node = context.readResourceForUpdate(PathAddress.EMPTY_ADDRESS).getModel();
+ node.get("tick").set(tick);
+
+ //Add a step to perform the runtime update
+ context.addStep(new OperationStepHandler() {
+ @Override
+ public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
+ TrackerService service = (TrackerService)context.getServiceRegistry(true).getRequiredService(TrackerService.createServiceName(suffix)).getValue();
+ service.setTick(tick);
+ context.completeStep();
+ }
+ }, Stage.RUNTIME);
+ context.completeStep();
+ }
+}
View
72 jboss-as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/TypeAddHandler.java
@@ -0,0 +1,72 @@
+package com.acme.corp.tracker.extension;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEFAULT;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESCRIPTION;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REQUEST_PROPERTIES;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REQUIRED;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.TYPE;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.ServiceVerificationHandler;
+import org.jboss.as.controller.descriptions.DescriptionProvider;
+import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+import org.jboss.msc.service.ServiceController;
+import org.jboss.msc.service.ServiceController.Mode;
+import org.jboss.msc.service.ServiceName;
+
+/**
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ */
+class TypeAddHandler extends AbstractAddStepHandler implements DescriptionProvider {
+
+ public static final TypeAddHandler INSTANCE = new TypeAddHandler();
+
+ private TypeAddHandler() {
+ }
+
+ @Override
+ public ModelNode getModelDescription(Locale locale) {
+ ModelNode node = new ModelNode();
+ node.get(DESCRIPTION).set("Adds a tracked deployment type");
+ node.get(REQUEST_PROPERTIES, "tick", DESCRIPTION).set("How often to output information about a tracked deployment");
+ node.get(REQUEST_PROPERTIES, "tick", TYPE).set(ModelType.LONG);
+ node.get(REQUEST_PROPERTIES, "tick", REQUIRED).set(false);
+ node.get(REQUEST_PROPERTIES, "tick", DEFAULT).set(10000);
+ return node;
+ }
+
+ @Override
+ protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
+ //The default value is 10000 if it has not been specified
+ long tick = 10000;
+ //Read the value from the operation
+ if (operation.hasDefined("tick")) {
+ tick = operation.get("tick").asLong();
+ }
+ model.get("tick").set(tick);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model,
+ ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers)
+ throws OperationFailedException {
+ String suffix = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.ADDRESS)).getLastElement().getValue();
+ TrackerService service = new TrackerService(suffix, model.get("tick").asLong());
+ ServiceName name = TrackerService.createServiceName(suffix);
+ ServiceController<TrackerService> controller = context.getServiceTarget()
+ .addService(name, service)
+ .addListener(verificationHandler)
+ .setInitialMode(Mode.ACTIVE)
+ .install();
+ newControllers.add(controller);
+ }
+}
View
62 ...as-subsystem-example/src/main/java/com/acme/corp/tracker/extension/TypeRemoveHandler.java
@@ -0,0 +1,62 @@
+/*
+* JBoss, Home of Professional Open Source.
+* Copyright 2011, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file in the
+* distribution for a full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package com.acme.corp.tracker.extension;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESCRIPTION;
+
+import java.util.Locale;
+
+import org.jboss.as.controller.AbstractRemoveStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.descriptions.DescriptionProvider;
+import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.ServiceName;
+
+/**
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ */
+class TypeRemoveHandler extends AbstractRemoveStepHandler implements DescriptionProvider {
+
+ public static final TypeRemoveHandler INSTANCE = new TypeRemoveHandler();
+
+ private TypeRemoveHandler() {
+ }
+
+ @Override
+ public ModelNode getModelDescription(Locale locale) {
+ ModelNode node = new ModelNode();
+ node.get(DESCRIPTION).set("Removes a tracked deployment type");
+ return node;
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ String suffix = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.ADDRESS)).getLastElement().getValue();
+ ServiceName name = TrackerService.createServiceName(suffix);
+ context.removeService(name);
+ }
+
+}
View
1  ...-subsystem-example/src/main/resources/META-INF/services/org.jboss.as.controller.Extension
@@ -0,0 +1 @@
+com.acme.corp.tracker.extension.SubsystemExtension
View
16 jboss-as-subsystem-example/src/main/resources/module/main/module.xml
@@ -0,0 +1,16 @@
+<module xmlns="urn:jboss:module:1.0" name="com.acme.corp.tracker">
+ <resources>
+ <resource-root path="acme-subsystem.jar"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.jboss.staxmapper"/>
+ <module name="org.jboss.as.controller"/>
+ <module name="org.jboss.as.server"/>
+ <module name="org.jboss.modules"/>
+ <module name="org.jboss.msc"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.jboss.vfs"/>
+ </dependencies>
+</module>
View
24 jboss-as-subsystem-example/src/main/resources/schema/mysubsystem.xsd
@@ -0,0 +1,24 @@
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="urn:com.acme.corp.tracker:1.0"
+ xmlns="urn:com.acme.corp.tracker:1.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ version="1.0">
+
+ <!-- The subsystem root element -->
+ <xs:element name="subsystem" type="subsystemType"/>
+ <xs:complexType name="subsystemType">
+ <xs:all>
+ <xs:element name="deployment-types" type="deploymemt-typesType">
+ </xs:all>
+ </xs:complexType>
+ <xs:complexType name="subsystemType">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="deploymemt-type" type="deployment-typeType"/>
+ </xs:choice>
+ </xs:complexType>
+ <xs:complexType name="deploymemt-typeType">
+ <xs:attribute name="suffix" use="required"/>
+ <xs:attribute name="tick" type="xs:long" use="optional" default="10000"/>
+ </xs:complexType>
+</xs:schema>
View
214 ...ystem-example/src/test/java/com/acme/corp/tracker/extension/SubsystemParsingTestCase.java
@@ -0,0 +1,214 @@
+package com.acme.corp.tracker.extension;
+
+
+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.NAME;
+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.OUTCOME;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_ATTRIBUTE_OPERATION;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.WRITE_ATTRIBUTE_OPERATION;
+
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.subsystem.test.AbstractSubsystemTest;
+import org.jboss.as.subsystem.test.KernelServices;
+import org.jboss.dmr.ModelNode;
+import org.junit.Test;
+
+
+
+/**
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ */
+public class SubsystemParsingTestCase extends AbstractSubsystemTest {
+
+ public SubsystemParsingTestCase() {
+ super(SubsystemExtension.SUBSYSTEM_NAME, new SubsystemExtension());
+ }
+
+ /**
+ * Tests that the xml is parsed into the correct operations
+ */
+ @Test
+ public void testParseSubsystem() throws Exception {
+ //Parse the subsystem xml into operations
+ String subsystemXml =
+ "<subsystem xmlns=\"" + SubsystemExtension.NAMESPACE + "\">" +
+ " <deployment-types>" +
+ " <deployment-type suffix=\"tst\" tick=\"12345\"/>" +
+ " </deployment-types>" +
+ "</subsystem>";
+ List<ModelNode> operations = super.parse(subsystemXml);
+
+ ///Check that we have the expected number of operations
+ Assert.assertEquals(2, operations.size());
+
+ //Check that each operation has the correct content
+ //The add subsystem operation will happen first
+ ModelNode addSubsystem = operations.get(0);
+ Assert.assertEquals(ADD, addSubsystem.get(OP).asString());
+ PathAddress addr = PathAddress.pathAddress(addSubsystem.get(OP_ADDR));
+ Assert.assertEquals(1, addr.size());
+ PathElement element = addr.getElement(0);
+ Assert.assertEquals(SUBSYSTEM, element.getKey());
+ Assert.assertEquals(SubsystemExtension.SUBSYSTEM_NAME, element.getValue());
+
+ //Then we will get the add type operation
+ ModelNode addType = operations.get(1);
+ Assert.assertEquals(ADD, addType.get(OP).asString());
+ Assert.assertEquals(12345, addType.get("tick").asLong());
+ addr = PathAddress.pathAddress(addType.get(OP_ADDR));
+ Assert.assertEquals(2, addr.size());
+ element = addr.getElement(0);
+ Assert.assertEquals(SUBSYSTEM, element.getKey());
+ Assert.assertEquals(SubsystemExtension.SUBSYSTEM_NAME, element.getValue());
+ element = addr.getElement(1);
+ Assert.assertEquals("type", element.getKey());
+ Assert.assertEquals("tst", element.getValue());
+ }
+
+ /**
+ * Test that the model created from the xml looks as expected
+ */
+ @Test
+ public void testInstallIntoController() throws Exception {
+ //Parse the subsystem xml and install into the controller
+ String subsystemXml =
+ "<subsystem xmlns=\"" + SubsystemExtension.NAMESPACE + "\">" +
+ " <deployment-types>" +
+ " <deployment-type suffix=\"tst\" tick=\"12345\"/>" +
+ " </deployment-types>" +
+ "</subsystem>";
+ KernelServices services = super.installInController(subsystemXml);
+
+ //Read the whole model and make sure it looks as expected
+ ModelNode model = services.readWholeModel();
+ //Useful for debugging :-)
+ //System.out.println(model);
+ Assert.assertTrue(model.get(SUBSYSTEM).hasDefined(SubsystemExtension.SUBSYSTEM_NAME));
+ Assert.assertTrue(model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME).hasDefined("type"));
+ Assert.assertTrue(model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME, "type").hasDefined("tst"));
+ Assert.assertTrue(model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME, "type", "tst").hasDefined("tick"));
+ Assert.assertEquals(12345, model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME, "type", "tst", "tick").asLong());
+ }
+
+ /**
+ * Starts a controller with a given subsystem xml and then checks that a second
+ * controller started with the xml marshalled from the first one results in the same model
+ */
+ @Test
+ public void testParseAndMarshalModel() throws Exception {
+ //Parse the subsystem xml and install into the first controller
+ String subsystemXml =
+ "<subsystem xmlns=\"" + SubsystemExtension.NAMESPACE + "\">" +
+ " <deployment-types>" +
+ " <deployment-type suffix=\"tst\" tick=\"12345\"/>" +
+ " </deployment-types>" +
+ "</subsystem>";
+ KernelServices servicesA = super.installInController(subsystemXml);
+ //Get the model and the persisted xml from the first controller
+ ModelNode modelA = servicesA.readWholeModel();
+ String marshalled = servicesA.getPersistedSubsystemXml();
+
+ //Install the persisted xml from the first controller into a second controller
+ KernelServices servicesB = super.installInController(marshalled);
+ ModelNode modelB = servicesB.readWholeModel();
+
+ //Make sure the models from the two controllers are identical
+ super.compare(modelA, modelB);
+ }
+
+ /**
+ * Starts a controller with the given subsystem xml and then checks that a second
+ * controller started with the operations from its describe action results in the same model
+ */
+ @Test
+ public void testDescribeHandler() throws Exception {
+ //Parse the subsystem xml and install into the first controller
+ String subsystemXml =
+ "<subsystem xmlns=\"" + SubsystemExtension.NAMESPACE + "\">" +
+ "</subsystem>";
+ KernelServices servicesA = super.installInController(subsystemXml);
+ //Get the model and the describe operations from the first controller
+ ModelNode modelA = servicesA.readWholeModel();
+ ModelNode describeOp = new ModelNode();
+ describeOp.get(OP).set(DESCRIBE);
+ describeOp.get(OP_ADDR).set(
+ PathAddress.pathAddress(
+ PathElement.pathElement(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME)).toModelNode());
+ List<ModelNode> operations = super.checkResultAndGetContents(servicesA.executeOperation(describeOp)).asList();
+
+
+ //Install the describe options from the first controller into a second controller
+ KernelServices servicesB = super.installInController(operations);
+ ModelNode modelB = servicesB.readWholeModel();
+
+ //Make sure the models from the two controllers are identical
+ super.compare(modelA, modelB);
+
+ }
+
+ @Test
+ public void testExecuteOperations() throws Exception {
+ String subsystemXml =
+ "<subsystem xmlns=\"" + SubsystemExtension.NAMESPACE + "\">" +
+ " <deployment-types>" +
+ " <deployment-type suffix=\"tst\" tick=\"12345\"/>" +
+ " </deployment-types>" +
+ "</subsystem>";
+ KernelServices services = super.installInController(subsystemXml);
+
+ //Add another type
+ PathAddress fooTypeAddr = PathAddress.pathAddress(
+ PathElement.pathElement(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME),
+ PathElement.pathElement("type", "foo"));
+ ModelNode addOp = new ModelNode();
+ addOp.get(OP).set(ADD);
+ addOp.get(OP_ADDR).set(fooTypeAddr.toModelNode());
+ addOp.get("tick").set(1000);
+ ModelNode result = services.executeOperation(addOp);
+ Assert.assertEquals(SUCCESS, result.get(OUTCOME).asString());
+
+
+ ModelNode model = services.readWholeModel();
+ Assert.assertTrue(model.get(SUBSYSTEM).hasDefined(SubsystemExtension.SUBSYSTEM_NAME));
+ Assert.assertTrue(model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME).hasDefined("type"));
+ Assert.assertTrue(model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME, "type").hasDefined("tst"));
+ Assert.assertTrue(model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME, "type", "tst").hasDefined("tick"));
+ Assert.assertEquals(12345, model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME, "type", "tst", "tick").asLong());
+
+ Assert.assertTrue(model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME, "type").hasDefined("foo"));
+ Assert.assertTrue(model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME, "type", "foo").hasDefined("tick"));
+ Assert.assertEquals(1000, model.get(SUBSYSTEM, SubsystemExtension.SUBSYSTEM_NAME, "type", "foo", "tick").asLong());
+
+ //Call write-attribute
+ ModelNode writeOp = new ModelNode();
+ writeOp.get(OP).set(WRITE_ATTRIBUTE_OPERATION);
+ writeOp.get(OP_ADDR).set(fooTypeAddr.toModelNode());
+ writeOp.get(NAME).set("tick");
+ writeOp.get(VALUE).set(3456);
+ result = services.executeOperation(writeOp);
+ Assert.assertEquals(SUCCESS, result.get(OUTCOME).asString());
+
+ //Check that write attribute took effect, this time by calling read-attribute instead of reading the whole model
+ ModelNode readOp = new ModelNode();
+ readOp.get(OP).set(READ_ATTRIBUTE_OPERATION);
+ readOp.get(OP_ADDR).set(fooTypeAddr.toModelNode());
+ readOp.get(NAME).set("tick");
+ result = services.executeOperation(readOp);
+ Assert.assertEquals(3456, checkResultAndGetContents(result).asLong());
+
+ TrackerService service = (TrackerService)services.getContainer().getService(TrackerService.createServiceName("foo")).getValue();
+ Assert.assertEquals(3456, service.getTick());
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.