From f814cfc9207caa9400e2a237a3530769617570c1 Mon Sep 17 00:00:00 2001 From: "Aaron D. Fernandes" Date: Fri, 19 Feb 2016 11:16:49 -0500 Subject: [PATCH 1/8] Replace wildfly-controller dependencies with jboss-as-controller equivalents --- pom.xml | 17 ++++++++--------- .../extension/cassandra/CassandraExtension.java | 3 ++- .../wildfly/extension/cassandra/ClusterAdd.java | 13 +++---------- .../extension/cassandra/ClusterDefinition.java | 1 - 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index 250028f..510b89c 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,7 @@ 2.1.5 UTF-8 org.wildfly.extension.cassandra + 7.1.2.Final @@ -119,11 +120,6 @@ - - org.wildfly - wildfly-controller - ${version.wildfly} - org.wildfly wildfly-server @@ -136,12 +132,16 @@ test ${version.wildfly} + + org.jboss.as + jboss-as-controller + ${version.jboss} + org.jboss.logging jboss-logging ${version.org.jboss.logging.jboss-logging} - org.jboss.logging jboss-logging-annotations @@ -192,8 +192,8 @@ - org.wildfly - wildfly-controller + org.jboss.as + jboss-as-controller org.wildfly @@ -205,7 +205,6 @@ pom test - org.jboss.logging jboss-logging-annotations diff --git a/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java b/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java index 3ae3e0f..d5a20c7 100644 --- a/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java +++ b/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java @@ -21,6 +21,7 @@ import org.jboss.as.controller.ExtensionContext; import org.jboss.as.controller.PathElement; import org.jboss.as.controller.SubsystemRegistration; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver; import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler; import org.jboss.as.controller.parsing.ExtensionParsingContext; @@ -68,7 +69,7 @@ public void initializeParsers(ExtensionParsingContext context) { public void initialize(ExtensionContext context) { final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, 1, 0); final ManagementResourceRegistration registration = subsystem.registerSubsystemModel(RootDefinition.INSTANCE); - registration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE); + registration.registerOperationHandler(ModelDescriptionConstants.DESCRIBE, GenericSubsystemDescribeHandler.INSTANCE, GenericSubsystemDescribeHandler.INSTANCE); subsystem.registerXMLElementWriter(SubsystemParser.INSTANCE); } diff --git a/src/main/java/org/wildfly/extension/cassandra/ClusterAdd.java b/src/main/java/org/wildfly/extension/cassandra/ClusterAdd.java index 46af740..e6702f0 100644 --- a/src/main/java/org/wildfly/extension/cassandra/ClusterAdd.java +++ b/src/main/java/org/wildfly/extension/cassandra/ClusterAdd.java @@ -94,13 +94,6 @@ static void installRuntimeServices(OperationContext context, PathAddress address private static Config createServiceConfig(final OperationContext context, PathAddress address, ModelNode fullModel) throws OperationFailedException { - final ExpressionResolver expressionResolver = new ExpressionResolver() { - @Override - public ModelNode resolveExpressions(ModelNode node) throws OperationFailedException { - return context.resolveExpressions(node); - } - }; - // create the actual cassandra config singleton final Config cassandraConfig = new Config(); cassandraConfig.cluster_name = address.getLastElement().getValue(); @@ -115,7 +108,7 @@ public ModelNode resolveExpressions(ModelNode node) throws OperationFailedExcept LinkedHashMap providerConfig = new LinkedHashMap(); providerConfig.put("class_name", ClusterDefinition.SEED_PROVIDER.resolveModelAttribute(context, fullModel).asString()); HashMap params = new HashMap(); - params.put("seeds", ClusterDefinition.SEEDS.resolveModelAttribute(expressionResolver, fullModel).asString()); + params.put("seeds", ClusterDefinition.SEEDS.resolveModelAttribute(context, fullModel).asString()); ArrayList wrapper = new ArrayList(); wrapper.add(params); providerConfig.put("parameters", wrapper); @@ -123,8 +116,8 @@ public ModelNode resolveExpressions(ModelNode node) throws OperationFailedExcept SeedProviderDef providerDef = new SeedProviderDef(providerConfig); cassandraConfig.seed_provider = providerDef; - cassandraConfig.listen_address = ClusterDefinition.LISTEN_ADDRESS.resolveModelAttribute(expressionResolver, fullModel).asString(); - cassandraConfig.broadcast_address = ClusterDefinition.BROADCAST_ADDRESS.resolveModelAttribute(expressionResolver, fullModel).asString(); + cassandraConfig.listen_address = ClusterDefinition.LISTEN_ADDRESS.resolveModelAttribute(context, fullModel).asString(); + cassandraConfig.broadcast_address = ClusterDefinition.BROADCAST_ADDRESS.resolveModelAttribute(context, fullModel).asString(); cassandraConfig.start_native_transport = ClusterDefinition.START_NATIVE_TRANSPORT.resolveModelAttribute(context, fullModel).asBoolean(); cassandraConfig.start_rpc = ClusterDefinition.START_RPC.resolveModelAttribute(context, fullModel).asBoolean(); diff --git a/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java b/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java index 8a12418..c4e276c 100644 --- a/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java +++ b/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java @@ -261,7 +261,6 @@ protected List getChildren() { return CHILDREN; } - @Override public List getAccessConstraints() { return accessConstraints; } From 90828e3de49fef98b632d093861bdb3a2f726393 Mon Sep 17 00:00:00 2001 From: "Aaron D. Fernandes" Date: Fri, 19 Feb 2016 15:22:48 -0500 Subject: [PATCH 2/8] Brought in some classes from Wildfly --- .gitignore | 3 + pom.xml | 24 +- .../extension/cassandra/AttributeParser.java | 186 ++++++++++ .../cassandra/ClusterDefinition.java | 15 - .../PersistentResourceDefinition.java | 54 +++ .../PersistentResourceXMLDescription.java | 339 ++++++++++++++++++ .../extension/cassandra/RootDefinition.java | 1 - .../cassandra/ServiceRemoveStepHandler.java | 71 ++++ .../extension/cassandra/SubsystemParser.java | 3 +- .../cassandra/SubsystemParsingTestCase.java | 8 +- 10 files changed, 668 insertions(+), 36 deletions(-) create mode 100644 src/main/java/org/wildfly/extension/cassandra/AttributeParser.java create mode 100644 src/main/java/org/wildfly/extension/cassandra/PersistentResourceDefinition.java create mode 100644 src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java create mode 100644 src/main/java/org/wildfly/extension/cassandra/ServiceRemoveStepHandler.java diff --git a/.gitignore b/.gitignore index 2610f3c..3662d59 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ target .idea *.iml +/.settings/ +/.classpath +/.project diff --git a/pom.xml b/pom.xml index 510b89c..e63f573 100644 --- a/pom.xml +++ b/pom.xml @@ -121,16 +121,14 @@ - org.wildfly - wildfly-server - ${version.wildfly} + org.jboss.as + jboss-as-server + ${version.jboss} - org.wildfly - wildfly-subsystem-test - pom - test - ${version.wildfly} + org.jboss.as + jboss-as-subsystem-test + ${version.jboss} org.jboss.as @@ -196,14 +194,12 @@ jboss-as-controller - org.wildfly - wildfly-server + org.jboss.as + jboss-as-subsystem-test - org.wildfly - wildfly-subsystem-test - pom - test + org.jboss.as + jboss-as-server org.jboss.logging diff --git a/src/main/java/org/wildfly/extension/cassandra/AttributeParser.java b/src/main/java/org/wildfly/extension/cassandra/AttributeParser.java new file mode 100644 index 0000000..58ae4b6 --- /dev/null +++ b/src/main/java/org/wildfly/extension/cassandra/AttributeParser.java @@ -0,0 +1,186 @@ +package org.wildfly.extension.cassandra; + +/* +* +* JBoss, Home of Professional Open Source. +* Copyright 2014, 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. +* / +*/ + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.ListAttributeDefinition; +import org.jboss.as.controller.MapAttributeDefinition; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.operations.validation.ParameterValidator; +import org.jboss.as.controller.parsing.ParseUtils; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; + +/** +* @author Tomaz Cerar (c) 2014 Red Hat Inc. +*/ +public abstract class AttributeParser { + + /** + * Creates a {@link org.jboss.dmr.ModelNode} using the given {@code value} after first validating the node + * against {@link org.jboss.as.controller.AttributeDefinition#getValidator() this object's validator}., and then stores it in the given {@code operation} + * model node as a key/value pair whose key is this attribute's getName() name}. + *

+ * If {@code value} is {@code null} an {@link org.jboss.dmr.ModelType#UNDEFINED undefined} node will be stored if such a value + * is acceptable to the validator. + *

+ *

+ * The expected usage of this method is in parsers seeking to build up an operation to store their parsed data + * into the configuration. + *

+ * + * @param value the value. Will be {@link String#trim() trimmed} before use if not {@code null}. + * @param operation model node of type {@link org.jboss.dmr.ModelType#OBJECT} into which the parsed value should be stored + * @param reader {@link javax.xml.stream.XMLStreamReader} from which the {@link javax.xml.stream.XMLStreamReader#getLocation() location} from which + * the attribute value was read can be obtained and used in any {@code XMLStreamException}, in case + * the given value is invalid. + * @throws javax.xml.stream.XMLStreamException if {@code value} is not valid + */ + public void parseAndSetParameter(final AttributeDefinition attribute, final String value, final ModelNode operation, final XMLStreamReader reader) throws XMLStreamException { + ModelNode paramVal = parse(attribute, value, reader); + operation.get(attribute.getName()).set(paramVal); + } + + /** + * Creates and returns a {@link org.jboss.dmr.ModelNode} using the given {@code value} after first validating the node + * against {@link org.jboss.as.controller.AttributeDefinition#getValidator() this object's validator}. + *

+ * If {@code value} is {@code null} an {@link org.jboss.dmr.ModelType#UNDEFINED undefined} node will be returned. + *

+ * + * @param value the value. Will be {@link String#trim() trimmed} before use if not {@code null}. + * @param reader {@link XMLStreamReader} from which the {@link XMLStreamReader#getLocation() location} from which + * the attribute value was read can be obtained and used in any {@code XMLStreamException}, in case + * the given value is invalid. + * @return {@code ModelNode} representing the parsed value + * @throws javax.xml.stream.XMLStreamException if {@code value} is not valid + * @see #parseAndSetParameter(org.jboss.as.controller.AttributeDefinition, String, ModelNode, XMLStreamReader) + */ + public ModelNode parse(final AttributeDefinition attribute, final String value, final XMLStreamReader reader) throws XMLStreamException { + try { + return parse(attribute, value); + } catch (OperationFailedException e) { + throw new XMLStreamException(e.getFailureDescription().toString(), reader.getLocation()); + } + } + + private ModelNode parse(final AttributeDefinition attribute, final String value) throws OperationFailedException { + final String trimmed = value == null ? null : value.trim(); + ModelNode node; + if (trimmed != null) { + if (attribute.isAllowExpression()) { + node = ParseUtils.parsePossibleExpression(trimmed); + } else { + node = new ModelNode().set(trimmed); + } + if (node.getType() != ModelType.EXPRESSION) { + // Convert the string to the expected type + switch (attribute.getType()) { + case BIG_DECIMAL: + node.set(node.asBigDecimal()); + break; + case BIG_INTEGER: + node.set(node.asBigInteger()); + break; + case BOOLEAN: + node.set(node.asBoolean()); + break; + case BYTES: + node.set(node.asBytes()); + break; + case DOUBLE: + node.set(node.asDouble()); + break; + case INT: + node.set(node.asInt()); + break; + case LONG: + node.set(node.asLong()); + break; + } + } + } else { + node = new ModelNode(); + } + + final ParameterValidator validator; + // A bit yuck, but I didn't want to introduce a new type just for this + if (attribute instanceof ListAttributeDefinition) { + validator = ((ListAttributeDefinition) attribute).getElementValidator(); + } else if (attribute instanceof MapAttributeDefinition) { + validator = ((MapAttributeDefinition) attribute).getValidator(); + } else { + validator = attribute.getValidator(); + } + validator.validateParameter(attribute.getXmlName(), node); + + return node; + } + + public static final AttributeParser SIMPLE = new AttributeParser() { + }; + + public static final AttributeParser LIST = new AttributeParser() { + @Override + public void parseAndSetParameter(AttributeDefinition attribute, String value, ModelNode operation, XMLStreamReader reader) throws XMLStreamException { + ModelNode paramVal = parse(attribute, value, reader); + operation.get(attribute.getName()).add(paramVal); + } + }; + + public static final AttributeParser STRING_LIST = new AttributeParser() { + @Override + public void parseAndSetParameter(AttributeDefinition attribute, String value, ModelNode operation, XMLStreamReader reader) throws XMLStreamException { + if (value == null) { return; } + for (String element : value.split(",")) { + parseAndAddParameterElement(attribute, element, operation, reader); + } + } + + private void parseAndAddParameterElement(AttributeDefinition attribute, String value, ModelNode operation, XMLStreamReader reader) throws XMLStreamException { + ModelNode paramVal = parse(attribute, value, reader); + operation.get(attribute.getName()).add(paramVal); + } + }; + + public static final class DiscardOldDefaultValueParser extends AttributeParser{ + private final String value; + + public DiscardOldDefaultValueParser(String value) { + this.value = value; + } + + @Override + public ModelNode parse(AttributeDefinition attribute, String value, XMLStreamReader reader) throws XMLStreamException { + if (!this.value.equals(value)) { //if default value set, ignore it! + return super.parse(attribute, value, reader); + } + return new ModelNode(); + } + } +} diff --git a/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java b/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java index c4e276c..faf8f98 100644 --- a/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java +++ b/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java @@ -18,13 +18,8 @@ package org.wildfly.extension.cassandra; import org.jboss.as.controller.AttributeDefinition; -import org.jboss.as.controller.PersistentResourceDefinition; -import org.jboss.as.controller.ServiceRemoveStepHandler; import org.jboss.as.controller.SimpleAttributeDefinition; import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; -import org.jboss.as.controller.access.constraint.ApplicationTypeConfig; -import org.jboss.as.controller.access.management.AccessConstraintDefinition; -import org.jboss.as.controller.access.management.ApplicationTypeAccessConstraintDefinition; import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; @@ -42,16 +37,11 @@ */ public class ClusterDefinition extends PersistentResourceDefinition { - private final List accessConstraints; - private ClusterDefinition() { super(CassandraExtension.CLUSTER_PATH, CassandraExtension.getResourceDescriptionResolver(CassandraModel.CLUSTER), ClusterAdd.INSTANCE, new ServiceRemoveStepHandler(ClusterAdd.SERVICE_NAME, ClusterAdd.INSTANCE)); - - ApplicationTypeConfig atc = new ApplicationTypeConfig(CassandraExtension.SUBSYSTEM_NAME, CassandraModel.CLUSTER); - accessConstraints = new ApplicationTypeAccessConstraintDefinition(atc).wrapAsList(); } // ----------- @@ -261,9 +251,4 @@ protected List getChildren() { return CHILDREN; } - public List getAccessConstraints() { - return accessConstraints; - } - - } diff --git a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceDefinition.java b/src/main/java/org/wildfly/extension/cassandra/PersistentResourceDefinition.java new file mode 100644 index 0000000..0cd7301 --- /dev/null +++ b/src/main/java/org/wildfly/extension/cassandra/PersistentResourceDefinition.java @@ -0,0 +1,54 @@ +package org.wildfly.extension.cassandra; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationStepHandler; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.descriptions.ResourceDescriptionResolver; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; + +public abstract class PersistentResourceDefinition extends SimpleResourceDefinition { + protected PersistentResourceDefinition(PathElement pathElement, ResourceDescriptionResolver descriptionResolver) { + super(pathElement, descriptionResolver); + } + + protected PersistentResourceDefinition(PathElement pathElement, ResourceDescriptionResolver descriptionResolver, OperationStepHandler addHandler, OperationStepHandler removeHandler) { + super(pathElement, descriptionResolver, addHandler, removeHandler); + } + + protected PersistentResourceDefinition(PathElement pathElement, ResourceDescriptionResolver descriptionResolver, OperationStepHandler addHandler, OperationStepHandler removeHandler, OperationEntry.Flag addRestartLevel, OperationEntry.Flag removeRestartLevel) { + super(pathElement, descriptionResolver, addHandler, removeHandler, addRestartLevel, removeRestartLevel); + } + + + @Override + public void registerChildren(ManagementResourceRegistration resourceRegistration) { + super.registerChildren(resourceRegistration); + for (PersistentResourceDefinition child : getChildren()) { + resourceRegistration.registerSubModel(child); + } + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + super.registerAttributes(resourceRegistration); + Collection attributeDefinitions = getAttributes(); + AttributeDefinition[] attributes = attributeDefinitions.toArray(new AttributeDefinition[attributeDefinitions.size()]); + ReloadRequiredWriteAttributeHandler handler = new ReloadRequiredWriteAttributeHandler(attributes); + for (AttributeDefinition attr : getAttributes()) { + resourceRegistration.registerReadWriteAttribute(attr, null, handler); + } + } + + protected List getChildren() { + return Collections.emptyList(); + } + + public abstract Collection getAttributes(); +} diff --git a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java b/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java new file mode 100644 index 0000000..904d2c3 --- /dev/null +++ b/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java @@ -0,0 +1,339 @@ +package org.wildfly.extension.cassandra; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; +import org.jboss.as.controller.operations.common.Util; +import org.jboss.as.controller.parsing.Element; +import org.jboss.as.controller.parsing.ParseUtils; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.Property; +import org.jboss.staxmapper.XMLExtendedStreamReader; +import org.jboss.staxmapper.XMLExtendedStreamWriter; + +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static org.jboss.as.controller.ControllerMessages.MESSAGES; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME; + +/** + * A representation of a resource as needed by the XML parser. + * + * @author Tomaz Cerar + * @author Stuart Douglas + */ +public class PersistentResourceXMLDescription { + + protected final PersistentResourceDefinition resourceDefinition; + protected final String xmlElementName; + protected final String xmlWrapperElement; + protected final LinkedHashMap attributes; + protected final List children; + protected final boolean useValueAsElementName; + protected final boolean noAddOperation; + protected final AdditionalOperationsGenerator additionalOperationsGenerator; + private boolean flushRequired = true; + private final Map attributeParsers; + + protected PersistentResourceXMLDescription(final PersistentResourceDefinition resourceDefinition, final String xmlElementName, final String xmlWrapperElement, final LinkedHashMap attributes, final List children, final boolean useValueAsElementName, final boolean noAddOperation, final AdditionalOperationsGenerator additionalOperationsGenerator, Map attributeParsers) { + this.resourceDefinition = resourceDefinition; + this.xmlElementName = xmlElementName; + this.xmlWrapperElement = xmlWrapperElement; + this.attributes = attributes; + this.children = children; + this.useValueAsElementName = useValueAsElementName; + this.noAddOperation = noAddOperation; + this.additionalOperationsGenerator = additionalOperationsGenerator; + this.attributeParsers = attributeParsers; + } + + public void parse(final XMLExtendedStreamReader reader, PathAddress parentAddress, List list) throws XMLStreamException { + if (xmlWrapperElement != null) { + if (reader.getLocalName().equals(xmlWrapperElement)) { + if (reader.hasNext()) { + if (reader.nextTag() == END_ELEMENT) { + return; + } + } + } else { + throw ParseUtils.unexpectedElement(reader); + } + + } + boolean wildcard = resourceDefinition.getPathElement().isWildcard(); + String name = null; + ModelNode op = Util.createAddOperation(parentAddress); + for (int i = 0; i < reader.getAttributeCount(); i++) { + String attributeName = reader.getAttributeLocalName(i); + String value = reader.getAttributeValue(i); + if (wildcard && NAME.equals(attributeName)) { + name = value; + } else if (attributes.containsKey(attributeName)) { + AttributeDefinition def = attributes.get(attributeName); + AttributeParser parser = attributeParsers.containsKey(attributeName)? attributeParsers.get(attributeName) : def.getParser(); + assert parser != null; + parser.parseAndSetParameter(def,value,op,reader); + } else { + throw ParseUtils.unexpectedAttribute(reader, i); + } + } + for (AttributeDefinition attributeDefinition: attributes.values()){ + if (attributeDefinition instanceof PropertiesAttributeDefinition){ + PropertiesAttributeDefinition attribute = (PropertiesAttributeDefinition) attributeDefinition; + attribute.parse(reader,op); + flushRequired = false; + } + } + if (wildcard && name == null) { + throw MESSAGES.missingRequiredAttributes(new StringBuilder(NAME), reader.getLocation()); + } + PathElement path = wildcard ? PathElement.pathElement(resourceDefinition.getPathElement().getKey(), name) : resourceDefinition.getPathElement(); + PathAddress address = parentAddress.append(path); + if(!noAddOperation) { + op.get(ADDRESS).set(address.toModelNode()); + list.add(op); + } + if(additionalOperationsGenerator != null) { + additionalOperationsGenerator.additionalOperations(address, op, list); + } + parseChildren(reader, address, list); + if (xmlWrapperElement != null) { + ParseUtils.requireNoContent(reader); + } + } + + private Map getChildrenMap() { + Map res = new HashMap<>(); + for (PersistentResourceXMLDescription child : children) { + if (child.xmlWrapperElement != null) { + res.put(child.xmlWrapperElement, child); + } else { + res.put(child.xmlElementName, child); + } + } + return res; + } + + public void parseChildren(final XMLExtendedStreamReader reader, PathAddress parentAddress, List list) throws XMLStreamException { + if (children.size() == 0) { + if (flushRequired){ + ParseUtils.requireNoContent(reader); + } + } else { + Map children = getChildrenMap(); + while (reader.hasNext() && reader.nextTag() != XMLStreamConstants.END_ELEMENT) { + PersistentResourceXMLDescription child = children.get(reader.getLocalName()); + if (child != null) { + child.parse(reader, parentAddress, list); + } else { + throw ParseUtils.unexpectedElement(reader); + } + } + } + } + + + public void persist(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException { + persist(writer, model, null); + } + + private void writeStartElement(XMLExtendedStreamWriter writer, String namespaceURI, String localName) throws XMLStreamException { + if (namespaceURI != null) { + writer.writeStartElement(namespaceURI, localName); + } else { + writer.writeStartElement(localName); + } + } + + public void startSubsystemElement(XMLExtendedStreamWriter writer, String namespaceURI, boolean empty) throws XMLStreamException { + + if (writer.getNamespaceContext().getPrefix(namespaceURI) == null) { + // Unknown namespace; it becomes default + writer.setDefaultNamespace(namespaceURI); + if (empty) { + writer.writeEmptyElement(Element.SUBSYSTEM.getLocalName()); + } else { + writer.writeStartElement(Element.SUBSYSTEM.getLocalName()); + } + writer.writeNamespace(null, namespaceURI); + } else { + if (empty) { + writer.writeEmptyElement(namespaceURI, Element.SUBSYSTEM.getLocalName()); + } else { + writer.writeStartElement(namespaceURI, Element.SUBSYSTEM.getLocalName()); + } + } + + } + + public void persist(XMLExtendedStreamWriter writer, ModelNode model, String namespaceURI) throws XMLStreamException { + boolean wildcard = resourceDefinition.getPathElement().isWildcard(); + model = wildcard ? model.get(resourceDefinition.getPathElement().getKey()) : model.get(resourceDefinition.getPathElement().getKeyValuePair()); + boolean isSubsystem = resourceDefinition.getPathElement().getKey().equals(ModelDescriptionConstants.SUBSYSTEM); + if (!isSubsystem && !model.isDefined() && !useValueAsElementName) { + return; + } + + boolean writeWrapper = xmlWrapperElement != null; + if (writeWrapper) { + writeStartElement(writer, namespaceURI, xmlWrapperElement); + } + + if (wildcard) { + for (Property p : model.asPropertyList()) { + if (useValueAsElementName) { + writeStartElement(writer, namespaceURI, p.getName()); + } else { + writeStartElement(writer, namespaceURI, xmlElementName); + writer.writeAttribute(NAME, p.getName()); + } + for (Map.Entry def : attributes.entrySet()) { + def.getValue().getAttributeMarshaller().marshallAsAttribute(def.getValue(), p.getValue(), false, writer); + } + persistChildren(writer, p.getValue()); + writer.writeEndElement(); + } + } else { + if (useValueAsElementName) { + writeStartElement(writer, namespaceURI, resourceDefinition.getPathElement().getValue()); + } else if (isSubsystem) { + startSubsystemElement(writer, namespaceURI, children.isEmpty()); + } else { + writeStartElement(writer, namespaceURI, xmlElementName); + + } + for (Map.Entry def : attributes.entrySet()) { + def.getValue().getAttributeMarshaller().marshallAsAttribute(def.getValue(), model, true, writer); + } + persistChildren(writer, model); + + // Do not attempt to write end element if the has no elements! + if (!isSubsystem || !children.isEmpty()) { + writer.writeEndElement(); + } + } + + if (writeWrapper) { + writer.writeEndElement(); + } + } + + public void persistChildren(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException { + for (PersistentResourceXMLDescription child : children) { + child.persist(writer, model); + } + } + + public static PersistentResourceXMLBuilder builder(PersistentResourceDefinition resource) { + return new PersistentResourceXMLBuilder(resource); + } + + public static class PersistentResourceXMLBuilder { + + + protected final PersistentResourceDefinition resourceDefinition; + protected String xmlElementName; + protected String xmlWrapperElement; + protected boolean useValueAsElementName; + protected boolean noAddOperation; + protected AdditionalOperationsGenerator additionalOperationsGenerator; + protected final LinkedHashMap attributes = new LinkedHashMap<>(); + protected final List children = new ArrayList<>(); + protected final LinkedHashMap attributeParsers = new LinkedHashMap<>(); + + protected PersistentResourceXMLBuilder(final PersistentResourceDefinition resourceDefinition) { + this.resourceDefinition = resourceDefinition; + this.xmlElementName = resourceDefinition.getPathElement().isWildcard() ? resourceDefinition.getPathElement().getKey() : resourceDefinition.getPathElement().getValue(); + } + + public PersistentResourceXMLBuilder addChild(PersistentResourceXMLBuilder builder) { + this.children.add(builder); + return this; + } + + public PersistentResourceXMLBuilder addAttribute(AttributeDefinition attribute) { + this.attributes.put(attribute.getXmlName(), attribute); + return this; + } + public PersistentResourceXMLBuilder addAttribute(AttributeDefinition attribute, AttributeParser attributeParser) { + this.attributes.put(attribute.getXmlName(), attribute); + this.attributeParsers.put(attribute.getXmlName(),attributeParser); + return this; + } + + public PersistentResourceXMLBuilder addAttributes(AttributeDefinition... attributes) { + for (final AttributeDefinition at : attributes) { + this.attributes.put(at.getXmlName(), at); + } + return this; + } + + @Deprecated + public PersistentResourceXMLBuilder addAttributes(Collection attributes) { + for (final AttributeDefinition at : attributes) { + this.attributes.put(at.getXmlName(), at); + } + return this; + } + + public PersistentResourceXMLBuilder setXmlWrapperElement(final String xmlWrapperElement) { + this.xmlWrapperElement = xmlWrapperElement; + return this; + } + + public PersistentResourceXMLBuilder setXmlElementName(final String xmlElementName) { + this.xmlElementName = xmlElementName; + return this; + } + + public PersistentResourceXMLBuilder setUseValueAsElementName(final boolean useValueAsElementName) { + this.useValueAsElementName = useValueAsElementName; + return this; + } + + public PersistentResourceXMLBuilder setNoAddOperation(final boolean noAddOperation) { + this.noAddOperation = noAddOperation; + return this; + } + + public PersistentResourceXMLBuilder setAdditionalOperationsGenerator(final AdditionalOperationsGenerator additionalOperationsGenerator) { + this.additionalOperationsGenerator = additionalOperationsGenerator; + return this; + } + + public PersistentResourceXMLDescription build() { + + List builtChildren = new ArrayList<>(); + for (PersistentResourceXMLBuilder b : children) { + builtChildren.add(b.build()); + } + return new PersistentResourceXMLDescription(resourceDefinition, xmlElementName, xmlWrapperElement, attributes, builtChildren, useValueAsElementName, noAddOperation, additionalOperationsGenerator, attributeParsers); + } + } + + /** + * Some resources require more operations that just a simple add. This interface provides a hook for these to be plugged in. + */ + public interface AdditionalOperationsGenerator { + + /** + * Generates any additional operations required by the resource + * @param address The address of the resource + * @param addOperation The add operation for the resource + * @param operations The operation list + */ + void additionalOperations(final PathAddress address, final ModelNode addOperation, final List operations); + + } +} diff --git a/src/main/java/org/wildfly/extension/cassandra/RootDefinition.java b/src/main/java/org/wildfly/extension/cassandra/RootDefinition.java index b044339..b381b27 100644 --- a/src/main/java/org/wildfly/extension/cassandra/RootDefinition.java +++ b/src/main/java/org/wildfly/extension/cassandra/RootDefinition.java @@ -18,7 +18,6 @@ package org.wildfly.extension.cassandra; import org.jboss.as.controller.AttributeDefinition; -import org.jboss.as.controller.PersistentResourceDefinition; import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; import java.util.Arrays; diff --git a/src/main/java/org/wildfly/extension/cassandra/ServiceRemoveStepHandler.java b/src/main/java/org/wildfly/extension/cassandra/ServiceRemoveStepHandler.java new file mode 100644 index 0000000..8aedbe8 --- /dev/null +++ b/src/main/java/org/wildfly/extension/cassandra/ServiceRemoveStepHandler.java @@ -0,0 +1,71 @@ +package org.wildfly.extension.cassandra; + +import java.util.ArrayList; + +import org.jboss.as.controller.AbstractAddStepHandler; +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.ServiceVerificationHandler; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; + +/** + * Abstract remove step handler that simply removes a service. If the operation is rolled + * back it delegates the rollback to the corresponding add operations + * {@link AbstractAddStepHandler#performRuntime(OperationContext, org.jboss.dmr.ModelNode, org.jboss.dmr.ModelNode, ServiceVerificationHandler, java.util.List)} + * method + * + * @author Stuart Douglas + */ +public class ServiceRemoveStepHandler extends AbstractRemoveStepHandler { + + private final ServiceName baseServiceName; + private final AbstractAddStepHandler addOperation; + + public ServiceRemoveStepHandler(final ServiceName baseServiceName, final AbstractAddStepHandler addOperation) { + this.baseServiceName = baseServiceName; + this.addOperation = addOperation; + } + + protected ServiceRemoveStepHandler(final AbstractAddStepHandler addOperation) { + this(null, addOperation); + } + + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) { + if (context.isResourceServiceRestartAllowed()) { + final PathAddress address = PathAddress.pathAddress(operation.require(OP_ADDR)); + final String name = address.getLastElement().getValue(); + context.removeService(serviceName(name, address)); + } else { + context.reloadRequired(); + } + } + + /** + * The service name to be removed. Can be overridden for unusual service naming patterns + * @param name The name of the resource being removed + * @param address The address of the resource being removed + * @return The service name to remove + */ + protected ServiceName serviceName(String name, PathAddress address) { + return serviceName(name); + } + + /** + * The service name to be removed. Can be overridden for unusual service naming patterns + * @param name The name of the resource being removed + * @return The service name to remove + */ + protected ServiceName serviceName(final String name) { + return baseServiceName.append(name); + } + + protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + context.revertReloadRequired(); + } +} diff --git a/src/main/java/org/wildfly/extension/cassandra/SubsystemParser.java b/src/main/java/org/wildfly/extension/cassandra/SubsystemParser.java index 9e6bf90..de379b9 100644 --- a/src/main/java/org/wildfly/extension/cassandra/SubsystemParser.java +++ b/src/main/java/org/wildfly/extension/cassandra/SubsystemParser.java @@ -18,7 +18,6 @@ package org.wildfly.extension.cassandra; import org.jboss.as.controller.PathAddress; -import org.jboss.as.controller.PersistentResourceXMLDescription; import org.jboss.as.controller.persistence.SubsystemMarshallingContext; import org.jboss.dmr.ModelNode; import org.jboss.staxmapper.XMLElementReader; @@ -30,7 +29,7 @@ import javax.xml.stream.XMLStreamException; import java.util.List; -import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; +import static org.wildfly.extension.cassandra.PersistentResourceXMLDescription.builder; /** diff --git a/src/test/java/org/wildfly/extension/cassandra/SubsystemParsingTestCase.java b/src/test/java/org/wildfly/extension/cassandra/SubsystemParsingTestCase.java index bda4307..412189c 100644 --- a/src/test/java/org/wildfly/extension/cassandra/SubsystemParsingTestCase.java +++ b/src/test/java/org/wildfly/extension/cassandra/SubsystemParsingTestCase.java @@ -82,7 +82,7 @@ public void testParseSubsystem() throws Exception { public void testInstallIntoController() throws Exception { //Parse the subsystem xml and install into the controller String subsystemXml = getSubsystemXml(); - KernelServices services = super.createKernelServicesBuilder(null).setSubsystemXml(subsystemXml).build(); + KernelServices services = super.installInController(subsystemXml); //Read the whole model and make sure it looks as expected ModelNode model = services.readWholeModel(); @@ -97,13 +97,13 @@ public void testInstallIntoController() throws Exception { public void testParseAndMarshalModel() throws Exception { //Parse the subsystem xml and install into the first controller String subsystemXml = getSubsystemXml(); - KernelServices servicesA = super.createKernelServicesBuilder(null).setSubsystemXml(subsystemXml).build(); + 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.createKernelServicesBuilder(null).setSubsystemXml(marshalled).build(); + KernelServices servicesB = super.installInController(marshalled); ModelNode modelB = servicesB.readWholeModel(); //Make sure the models from the two controllers are identical @@ -117,7 +117,7 @@ public void testParseAndMarshalModel() throws Exception { public void testSubsystemRemoval() throws Exception { //Parse the subsystem xml and install into the first controller String subsystemXml = getSubsystemXml(); - KernelServices services = super.createKernelServicesBuilder(null).setSubsystemXml(subsystemXml).build(); + KernelServices services = super.installInController(subsystemXml); //Checks that the subsystem was removed from the model super.assertRemoveSubsystemResources(services); From 881d41c5ef995a968cc2a3adc7672d19feb1db26 Mon Sep 17 00:00:00 2001 From: "Aaron D. Fernandes" Date: Fri, 19 Feb 2016 15:55:04 -0500 Subject: [PATCH 3/8] Made some simplifying assumptions: 1. All attribute definitions are "Simple" (or at least not "Properties") 2. Simple attribute definitions should use the SIMPLE attribute parser --- .../cassandra/PersistentResourceXMLDescription.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java b/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java index 904d2c3..79d9b04 100644 --- a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java +++ b/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java @@ -81,20 +81,13 @@ public void parse(final XMLExtendedStreamReader reader, PathAddress parentAddres name = value; } else if (attributes.containsKey(attributeName)) { AttributeDefinition def = attributes.get(attributeName); - AttributeParser parser = attributeParsers.containsKey(attributeName)? attributeParsers.get(attributeName) : def.getParser(); + AttributeParser parser = attributeParsers.containsKey(attributeName)? attributeParsers.get(attributeName) : AttributeParser.SIMPLE; assert parser != null; parser.parseAndSetParameter(def,value,op,reader); } else { throw ParseUtils.unexpectedAttribute(reader, i); } } - for (AttributeDefinition attributeDefinition: attributes.values()){ - if (attributeDefinition instanceof PropertiesAttributeDefinition){ - PropertiesAttributeDefinition attribute = (PropertiesAttributeDefinition) attributeDefinition; - attribute.parse(reader,op); - flushRequired = false; - } - } if (wildcard && name == null) { throw MESSAGES.missingRequiredAttributes(new StringBuilder(NAME), reader.getLocation()); } From 55b52a0aba43b99a7db4c1ca40e5ae4a2fdb2ea4 Mon Sep 17 00:00:00 2001 From: "Aaron D. Fernandes" Date: Fri, 19 Feb 2016 16:10:40 -0500 Subject: [PATCH 4/8] Pulled in more classes from Wildfly --- .../cassandra/AttributeMarshaller.java | 85 +++++++++++++++++++ .../cassandra/DefaultAttributeMarshaller.java | 63 ++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 src/main/java/org/wildfly/extension/cassandra/AttributeMarshaller.java create mode 100644 src/main/java/org/wildfly/extension/cassandra/DefaultAttributeMarshaller.java diff --git a/src/main/java/org/wildfly/extension/cassandra/AttributeMarshaller.java b/src/main/java/org/wildfly/extension/cassandra/AttributeMarshaller.java new file mode 100644 index 0000000..dab977a --- /dev/null +++ b/src/main/java/org/wildfly/extension/cassandra/AttributeMarshaller.java @@ -0,0 +1,85 @@ +package org.wildfly.extension.cassandra; + +/* + * JBoss, Home of Professional Open Source. + * Copyright 2012, 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. + */ + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.ControllerMessages; +import org.jboss.dmr.ModelNode; + +/** + * @author Tomaz Cerar + */ +public abstract class AttributeMarshaller { + + /** + * Gets whether the given {@code resourceModel} has a value for this attribute that should be marshalled to XML. + *

+ * This is the same as {@code isMarshallable(resourceModel, true)}. + *

+ * @param attribute - attribute for which marshaling is being done + * @param resourceModel the model, a non-null node of {@link org.jboss.dmr.ModelType#OBJECT}. + * @return {@code true} if the given {@code resourceModel} has a defined value under this attribute's {@link AttributeDefinition#getName()} () name}. + */ + public boolean isMarshallable(final AttributeDefinition attribute,final ModelNode resourceModel) { + return isMarshallable(attribute,resourceModel, true); + } + + /** + * Gets whether the given {@code resourceModel} has a value for this attribute that should be marshalled to XML. + * + * @param attribute - attribute for which marshaling is being done + * @param resourceModel the model, a non-null node of {@link org.jboss.dmr.ModelType#OBJECT}. + * @param marshallDefault {@code true} if the value should be marshalled even if it matches the default value + * @return {@code true} if the given {@code resourceModel} has a defined value under this attribute's {@link AttributeDefinition#getName()} () name} + * and {@code marshallDefault} is {@code true} or that value differs from this attribute's {@link AttributeDefinition#getDefaultValue() default value}. + */ + public boolean isMarshallable(final AttributeDefinition attribute, final ModelNode resourceModel, final boolean marshallDefault) { + return resourceModel.hasDefined(attribute.getName()) && (marshallDefault || !resourceModel.get(attribute.getName()).equals(attribute.getDefaultValue())); + } + + /** + * Marshalls the value from the given {@code resourceModel} as an xml element, if it + * {@link #isMarshallable(AttributeDefinition, org.jboss.dmr.ModelNode, boolean) is marshallable}. + * + * @param attribute - attribute for which marshaling is being done + * @param resourceModel the model, a non-null node of {@link org.jboss.dmr.ModelType#OBJECT}. + * @param writer stream writer to use for writing the attribute + * @throws javax.xml.stream.XMLStreamException + * if thrown by {@code writer} + */ + + public void marshallAsAttribute(final AttributeDefinition attribute,final ModelNode resourceModel, final boolean marshallDefault, final XMLStreamWriter writer) throws XMLStreamException{ + throw ControllerMessages.MESSAGES.cannotWriteTo(attribute.getName()); + } + + public void marshallAsElement(final AttributeDefinition attribute, final ModelNode resourceModel, final boolean marshallDefault, final XMLStreamWriter writer) throws XMLStreamException{ + throw ControllerMessages.MESSAGES.cannotWriteTo(attribute.getName()); + } + + public boolean isMarshallableAsElement(){ + return false; + } +} diff --git a/src/main/java/org/wildfly/extension/cassandra/DefaultAttributeMarshaller.java b/src/main/java/org/wildfly/extension/cassandra/DefaultAttributeMarshaller.java new file mode 100644 index 0000000..385e9c6 --- /dev/null +++ b/src/main/java/org/wildfly/extension/cassandra/DefaultAttributeMarshaller.java @@ -0,0 +1,63 @@ +package org.wildfly.extension.cassandra; + +/* + * JBoss, Home of Professional Open Source. + * Copyright 2012, 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. + */ + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.dmr.ModelNode; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class DefaultAttributeMarshaller extends AttributeMarshaller { + + + public void marshallAsAttribute(final AttributeDefinition attribute, final ModelNode resourceModel, final boolean marshallDefault, final XMLStreamWriter writer) throws XMLStreamException { + if (isMarshallable(attribute, resourceModel, marshallDefault)) { + writer.writeAttribute(attribute.getXmlName(), resourceModel.get(attribute.getName()).asString()); + } + } + + public void marshallAsElement(AttributeDefinition attribute, ModelNode resourceModel, XMLStreamWriter writer) throws XMLStreamException { + marshallAsElement(attribute, resourceModel, true, writer); + } + + @Override + public void marshallAsElement(final AttributeDefinition attribute, final ModelNode resourceModel, final boolean marshallDefault, final XMLStreamWriter writer) throws XMLStreamException { + if (isMarshallable(attribute, resourceModel, marshallDefault)) { + writer.writeStartElement(attribute.getXmlName()); + String content = resourceModel.get(attribute.getName()).asString(); + if (content.indexOf('\n') > -1) { + // Multiline content. Use the overloaded variant that staxmapper will format + writer.writeCharacters(content); + } else { + // Staxmapper will just output the chars without adding newlines if this is used + char[] chars = content.toCharArray(); + writer.writeCharacters(chars, 0, chars.length); + } + writer.writeEndElement(); + } + } +} From b69cc393d2fdbda328398ee5cce367bafee60777 Mon Sep 17 00:00:00 2001 From: "Aaron D. Fernandes" Date: Fri, 19 Feb 2016 16:11:24 -0500 Subject: [PATCH 5/8] Another simplifying assumption: always use DefaultAttributeMarshaller --- .../cassandra/PersistentResourceXMLDescription.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java b/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java index 79d9b04..31a20bb 100644 --- a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java +++ b/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java @@ -34,6 +34,8 @@ * @author Stuart Douglas */ public class PersistentResourceXMLDescription { + + protected static final AttributeMarshaller attributeMarshaller = new DefaultAttributeMarshaller(); protected final PersistentResourceDefinition resourceDefinition; protected final String xmlElementName; @@ -192,7 +194,7 @@ public void persist(XMLExtendedStreamWriter writer, ModelNode model, String name writer.writeAttribute(NAME, p.getName()); } for (Map.Entry def : attributes.entrySet()) { - def.getValue().getAttributeMarshaller().marshallAsAttribute(def.getValue(), p.getValue(), false, writer); + attributeMarshaller.marshallAsAttribute(def.getValue(), p.getValue(), false, writer); } persistChildren(writer, p.getValue()); writer.writeEndElement(); @@ -207,7 +209,7 @@ public void persist(XMLExtendedStreamWriter writer, ModelNode model, String name } for (Map.Entry def : attributes.entrySet()) { - def.getValue().getAttributeMarshaller().marshallAsAttribute(def.getValue(), model, true, writer); + attributeMarshaller.marshallAsAttribute(def.getValue(), model, true, writer); } persistChildren(writer, model); From edfc0d3c34d796dc006af024dab9b0b11665bb4f Mon Sep 17 00:00:00 2001 From: "Aaron D. Fernandes" Date: Fri, 19 Feb 2016 18:05:11 -0500 Subject: [PATCH 6/8] Implemented my own description provider so that the operation-name matches the operation --- .../cassandra/CassandraExtension.java | 4 +- .../CassandraModelDescriptionProvider.java | 51 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/wildfly/extension/cassandra/CassandraModelDescriptionProvider.java diff --git a/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java b/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java index d5a20c7..1896747 100644 --- a/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java +++ b/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java @@ -44,7 +44,7 @@ public class CassandraExtension implements Extension { * The name of our subsystem within the model. */ public static final String SUBSYSTEM_NAME = "cassandra"; - + protected static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME); protected static PathElement CLUSTER_PATH = PathElement.pathElement(CassandraModel.CLUSTER); @@ -69,7 +69,7 @@ public void initializeParsers(ExtensionParsingContext context) { public void initialize(ExtensionContext context) { final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, 1, 0); final ManagementResourceRegistration registration = subsystem.registerSubsystemModel(RootDefinition.INSTANCE); - registration.registerOperationHandler(ModelDescriptionConstants.DESCRIBE, GenericSubsystemDescribeHandler.INSTANCE, GenericSubsystemDescribeHandler.INSTANCE); + registration.registerOperationHandler(ModelDescriptionConstants.DESCRIBE, GenericSubsystemDescribeHandler.INSTANCE, CassandraModelDescriptionProvider.INSTANCE); subsystem.registerXMLElementWriter(SubsystemParser.INSTANCE); } diff --git a/src/main/java/org/wildfly/extension/cassandra/CassandraModelDescriptionProvider.java b/src/main/java/org/wildfly/extension/cassandra/CassandraModelDescriptionProvider.java new file mode 100644 index 0000000..0b3c88a --- /dev/null +++ b/src/main/java/org/wildfly/extension/cassandra/CassandraModelDescriptionProvider.java @@ -0,0 +1,51 @@ +package org.wildfly.extension.cassandra; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESCRIBE; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESCRIPTION; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OPERATION_NAME; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REPLY_PROPERTIES; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.TYPE; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE_TYPE; + +import java.util.Locale; +import java.util.ResourceBundle; +import org.jboss.as.controller.descriptions.DescriptionProvider; +import org.jboss.as.controller.descriptions.common.CommonDescriptions; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; + +/** + * A generic handler recursively creating add operations for a managed resource using it's + * attributes as the request-parameters. + * + * @author Emanuel Muckenhuber + */ +public class CassandraModelDescriptionProvider implements DescriptionProvider { + + public static final CassandraModelDescriptionProvider INSTANCE = new CassandraModelDescriptionProvider(); + + protected CassandraModelDescriptionProvider() { + // + } + + @Override + public ModelNode getModelDescription(Locale locale) { + final ResourceBundle bundle = getResourceBundle(locale); + final ModelNode root = new ModelNode(); + root.get(OPERATION_NAME).set(DESCRIBE); + root.get(DESCRIPTION).set(bundle.getString("subsystem.describe")); + root.get(REPLY_PROPERTIES, TYPE).set(ModelType.LIST); + root.get(REPLY_PROPERTIES, VALUE_TYPE).set(ModelType.OBJECT); + return root; + } + + private static final String RESOURCE_NAME = CommonDescriptions.class.getPackage().getName() + ".LocalDescriptions"; + + private static ResourceBundle getResourceBundle(Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } + return ResourceBundle.getBundle(RESOURCE_NAME, locale); + } + +} From fba171ac18f22a23a464d1842fdd2692a71ed3ba Mon Sep 17 00:00:00 2001 From: "Aaron D. Fernandes" Date: Mon, 22 Feb 2016 12:18:32 -0500 Subject: [PATCH 7/8] Refactoring and cleanup --- .../wildfly/extension/cassandra/CassandraExtension.java | 1 - .../wildfly/extension/cassandra/ClusterDefinition.java | 2 ++ .../org/wildfly/extension/cassandra/RootDefinition.java | 1 + .../org/wildfly/extension/cassandra/SubsystemParser.java | 6 ++++-- .../cassandra/{ => future}/AttributeMarshaller.java | 2 +- .../extension/cassandra/{ => future}/AttributeParser.java | 2 +- .../{ => future}/DefaultAttributeMarshaller.java | 2 +- .../{ => future}/PersistentResourceDefinition.java | 2 +- .../{ => future}/PersistentResourceXMLDescription.java | 8 ++++---- .../cassandra/{ => future}/ServiceRemoveStepHandler.java | 2 +- 10 files changed, 16 insertions(+), 12 deletions(-) rename src/main/java/org/wildfly/extension/cassandra/{ => future}/AttributeMarshaller.java (98%) rename src/main/java/org/wildfly/extension/cassandra/{ => future}/AttributeParser.java (99%) rename src/main/java/org/wildfly/extension/cassandra/{ => future}/DefaultAttributeMarshaller.java (98%) rename src/main/java/org/wildfly/extension/cassandra/{ => future}/PersistentResourceDefinition.java (98%) rename src/main/java/org/wildfly/extension/cassandra/{ => future}/PersistentResourceXMLDescription.java (97%) rename src/main/java/org/wildfly/extension/cassandra/{ => future}/ServiceRemoveStepHandler.java (98%) diff --git a/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java b/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java index 1896747..d8a5541 100644 --- a/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java +++ b/src/main/java/org/wildfly/extension/cassandra/CassandraExtension.java @@ -44,7 +44,6 @@ public class CassandraExtension implements Extension { * The name of our subsystem within the model. */ public static final String SUBSYSTEM_NAME = "cassandra"; - protected static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME); protected static PathElement CLUSTER_PATH = PathElement.pathElement(CassandraModel.CLUSTER); diff --git a/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java b/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java index faf8f98..5f8933b 100644 --- a/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java +++ b/src/main/java/org/wildfly/extension/cassandra/ClusterDefinition.java @@ -23,6 +23,8 @@ import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; +import org.wildfly.extension.cassandra.future.PersistentResourceDefinition; +import org.wildfly.extension.cassandra.future.ServiceRemoveStepHandler; import java.util.Arrays; import java.util.Collection; diff --git a/src/main/java/org/wildfly/extension/cassandra/RootDefinition.java b/src/main/java/org/wildfly/extension/cassandra/RootDefinition.java index b381b27..6e3e294 100644 --- a/src/main/java/org/wildfly/extension/cassandra/RootDefinition.java +++ b/src/main/java/org/wildfly/extension/cassandra/RootDefinition.java @@ -19,6 +19,7 @@ import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.wildfly.extension.cassandra.future.PersistentResourceDefinition; import java.util.Arrays; import java.util.Collection; diff --git a/src/main/java/org/wildfly/extension/cassandra/SubsystemParser.java b/src/main/java/org/wildfly/extension/cassandra/SubsystemParser.java index de379b9..af31faf 100644 --- a/src/main/java/org/wildfly/extension/cassandra/SubsystemParser.java +++ b/src/main/java/org/wildfly/extension/cassandra/SubsystemParser.java @@ -24,12 +24,14 @@ import org.jboss.staxmapper.XMLElementWriter; import org.jboss.staxmapper.XMLExtendedStreamReader; import org.jboss.staxmapper.XMLExtendedStreamWriter; +import org.wildfly.extension.cassandra.future.PersistentResourceXMLDescription; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; -import java.util.List; -import static org.wildfly.extension.cassandra.PersistentResourceXMLDescription.builder; +import static org.wildfly.extension.cassandra.future.PersistentResourceXMLDescription.builder; + +import java.util.List; /** diff --git a/src/main/java/org/wildfly/extension/cassandra/AttributeMarshaller.java b/src/main/java/org/wildfly/extension/cassandra/future/AttributeMarshaller.java similarity index 98% rename from src/main/java/org/wildfly/extension/cassandra/AttributeMarshaller.java rename to src/main/java/org/wildfly/extension/cassandra/future/AttributeMarshaller.java index dab977a..142fcc1 100644 --- a/src/main/java/org/wildfly/extension/cassandra/AttributeMarshaller.java +++ b/src/main/java/org/wildfly/extension/cassandra/future/AttributeMarshaller.java @@ -1,4 +1,4 @@ -package org.wildfly.extension.cassandra; +package org.wildfly.extension.cassandra.future; /* * JBoss, Home of Professional Open Source. diff --git a/src/main/java/org/wildfly/extension/cassandra/AttributeParser.java b/src/main/java/org/wildfly/extension/cassandra/future/AttributeParser.java similarity index 99% rename from src/main/java/org/wildfly/extension/cassandra/AttributeParser.java rename to src/main/java/org/wildfly/extension/cassandra/future/AttributeParser.java index 58ae4b6..56cb3ca 100644 --- a/src/main/java/org/wildfly/extension/cassandra/AttributeParser.java +++ b/src/main/java/org/wildfly/extension/cassandra/future/AttributeParser.java @@ -1,4 +1,4 @@ -package org.wildfly.extension.cassandra; +package org.wildfly.extension.cassandra.future; /* * diff --git a/src/main/java/org/wildfly/extension/cassandra/DefaultAttributeMarshaller.java b/src/main/java/org/wildfly/extension/cassandra/future/DefaultAttributeMarshaller.java similarity index 98% rename from src/main/java/org/wildfly/extension/cassandra/DefaultAttributeMarshaller.java rename to src/main/java/org/wildfly/extension/cassandra/future/DefaultAttributeMarshaller.java index 385e9c6..34c2e1a 100644 --- a/src/main/java/org/wildfly/extension/cassandra/DefaultAttributeMarshaller.java +++ b/src/main/java/org/wildfly/extension/cassandra/future/DefaultAttributeMarshaller.java @@ -1,4 +1,4 @@ -package org.wildfly.extension.cassandra; +package org.wildfly.extension.cassandra.future; /* * JBoss, Home of Professional Open Source. diff --git a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceDefinition.java b/src/main/java/org/wildfly/extension/cassandra/future/PersistentResourceDefinition.java similarity index 98% rename from src/main/java/org/wildfly/extension/cassandra/PersistentResourceDefinition.java rename to src/main/java/org/wildfly/extension/cassandra/future/PersistentResourceDefinition.java index 0cd7301..69d2831 100644 --- a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceDefinition.java +++ b/src/main/java/org/wildfly/extension/cassandra/future/PersistentResourceDefinition.java @@ -1,4 +1,4 @@ -package org.wildfly.extension.cassandra; +package org.wildfly.extension.cassandra.future; import java.util.Collection; import java.util.Collections; diff --git a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java b/src/main/java/org/wildfly/extension/cassandra/future/PersistentResourceXMLDescription.java similarity index 97% rename from src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java rename to src/main/java/org/wildfly/extension/cassandra/future/PersistentResourceXMLDescription.java index 31a20bb..ae3d855 100644 --- a/src/main/java/org/wildfly/extension/cassandra/PersistentResourceXMLDescription.java +++ b/src/main/java/org/wildfly/extension/cassandra/future/PersistentResourceXMLDescription.java @@ -1,4 +1,4 @@ -package org.wildfly.extension.cassandra; +package org.wildfly.extension.cassandra.future; import java.util.ArrayList; import java.util.Collection; @@ -35,7 +35,7 @@ */ public class PersistentResourceXMLDescription { - protected static final AttributeMarshaller attributeMarshaller = new DefaultAttributeMarshaller(); + protected static final AttributeMarshaller MARSHALLER = new DefaultAttributeMarshaller(); protected final PersistentResourceDefinition resourceDefinition; protected final String xmlElementName; @@ -194,7 +194,7 @@ public void persist(XMLExtendedStreamWriter writer, ModelNode model, String name writer.writeAttribute(NAME, p.getName()); } for (Map.Entry def : attributes.entrySet()) { - attributeMarshaller.marshallAsAttribute(def.getValue(), p.getValue(), false, writer); + MARSHALLER.marshallAsAttribute(def.getValue(), p.getValue(), false, writer); } persistChildren(writer, p.getValue()); writer.writeEndElement(); @@ -209,7 +209,7 @@ public void persist(XMLExtendedStreamWriter writer, ModelNode model, String name } for (Map.Entry def : attributes.entrySet()) { - attributeMarshaller.marshallAsAttribute(def.getValue(), model, true, writer); + MARSHALLER.marshallAsAttribute(def.getValue(), model, true, writer); } persistChildren(writer, model); diff --git a/src/main/java/org/wildfly/extension/cassandra/ServiceRemoveStepHandler.java b/src/main/java/org/wildfly/extension/cassandra/future/ServiceRemoveStepHandler.java similarity index 98% rename from src/main/java/org/wildfly/extension/cassandra/ServiceRemoveStepHandler.java rename to src/main/java/org/wildfly/extension/cassandra/future/ServiceRemoveStepHandler.java index 8aedbe8..301f4d5 100644 --- a/src/main/java/org/wildfly/extension/cassandra/ServiceRemoveStepHandler.java +++ b/src/main/java/org/wildfly/extension/cassandra/future/ServiceRemoveStepHandler.java @@ -1,4 +1,4 @@ -package org.wildfly.extension.cassandra; +package org.wildfly.extension.cassandra.future; import java.util.ArrayList; From 16dabedd6f922ed952099d55f01e9c3d9f6c2c3c Mon Sep 17 00:00:00 2001 From: "Aaron D. Fernandes" Date: Mon, 22 Feb 2016 12:51:23 -0500 Subject: [PATCH 8/8] Change namespace to 1.1 --- src/main/resources/module/main/module.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/module/main/module.xml b/src/main/resources/module/main/module.xml index b451251..5a10eeb 100644 --- a/src/main/resources/module/main/module.xml +++ b/src/main/resources/module/main/module.xml @@ -15,7 +15,7 @@ ~ limitations under the License. --> - +