/* * 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. */ package org.jboss.as.controller; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import org.jboss.as.controller.logging.ControllerLogger; import org.jboss.dmr.ModelNode; /** * @author <a href="mailto:tomaz.cerar@redhat.com">Tomaz Cerar</a> */ public abstract class AttributeMarshaller { /** * Gets whether the given {@code resourceModel} has a value for this attribute that should be marshalled to XML. * <p> * This is the same as {@code isMarshallable(resourceModel, true)}. * </p> * @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 ControllerLogger.ROOT_LOGGER.couldNotMarshalAttributeAsAttribute(attribute.getName()); } public void marshallAsElement(final AttributeDefinition attribute, final ModelNode resourceModel, final boolean marshallDefault, final XMLStreamWriter writer) throws XMLStreamException{ throw ControllerLogger.ROOT_LOGGER.couldNotMarshalAttributeAsElement(attribute.getName()); } public boolean isMarshallableAsElement(){ return false; } public void marshall(final AttributeDefinition attribute,final ModelNode resourceModel, final boolean marshallDefault, final XMLStreamWriter writer) throws XMLStreamException { if (isMarshallableAsElement()){ marshallAsElement(attribute,resourceModel, marshallDefault, writer); }else{ marshallAsAttribute(attribute, resourceModel, marshallDefault, writer); } } private static class ListMarshaller extends DefaultAttributeMarshaller { private final char delimiter; ListMarshaller(char delimiter) { this.delimiter = delimiter; } @Override protected String asString(ModelNode value) { StringBuilder builder = new StringBuilder(); Iterator<ModelNode> values = value.asList().iterator(); while (values.hasNext()) { builder.append(values.next().asString()); if (values.hasNext()) { builder.append(this.delimiter); } } return builder.toString(); } } private static class ObjectMarshaller extends DefaultAttributeMarshaller { private final boolean marshallSimpleTypeAsElement; private ObjectMarshaller(boolean marshallSimpleTypeAsAttribute) { this.marshallSimpleTypeAsElement = marshallSimpleTypeAsAttribute; } private static Set<AttributeDefinition> sortAttributes(AttributeDefinition[] attributes) { Set<AttributeDefinition> sortedAttrs = new LinkedHashSet<>(attributes.length); List<AttributeDefinition> elementAds = null; for (AttributeDefinition ad : attributes) { if (ad.getParser().isParseAsElement()) { if (elementAds == null) { elementAds = new ArrayList<>(); } elementAds.add(ad); } else { sortedAttrs.add(ad); } } if (elementAds != null) { sortedAttrs.addAll(elementAds); } return sortedAttrs; } @Override public void marshallAsElement(AttributeDefinition attribute, ModelNode resourceModel, boolean marshallDefault, XMLStreamWriter writer) throws XMLStreamException { assert attribute instanceof ObjectTypeAttributeDefinition; if (resourceModel.hasDefined(attribute.getName())) { AttributeDefinition[] valueTypes = ((ObjectTypeAttributeDefinition) attribute).getValueTypes(); Set<AttributeDefinition> sortedAttrs = sortAttributes(valueTypes); writer.writeStartElement(attribute.getXmlName()); for (AttributeDefinition valueType : sortedAttrs) { if(resourceModel.hasDefined(attribute.getName(), valueType.getName())) { ModelNode handler = resourceModel.get(attribute.getName()); if(marshallSimpleTypeAsElement) { valueType.marshallAsElement(handler, marshallDefault, writer); } else { valueType.getAttributeMarshaller().marshall(valueType, handler, marshallDefault, writer); } } } writer.writeEndElement(); } } @Override public boolean isMarshallableAsElement() { return !marshallSimpleTypeAsElement; } } private static class ObjectListMarshaller extends AttributeMarshaller { private ObjectListMarshaller() { } @Override public boolean isMarshallableAsElement() { return true; } ObjectTypeAttributeDefinition getObjectType(AttributeDefinition attribute) { assert attribute instanceof ObjectListAttributeDefinition; ObjectListAttributeDefinition list = ((ObjectListAttributeDefinition) attribute); return list.getValueType(); } private boolean isMarshallable(AttributeDefinition[] valueTypes, ModelNode element){ for (AttributeDefinition valueType : valueTypes) { if (valueType.getAttributeMarshaller().isMarshallable(valueType, element)){ return true; } } return false; } void writeElements(XMLStreamWriter writer, ObjectTypeAttributeDefinition objectType, AttributeDefinition[] valueTypes, List<ModelNode> elements) throws XMLStreamException { for (ModelNode element : elements) { if (isMarshallable(valueTypes, element)) { writer.writeStartElement(objectType.getXmlName()); for (AttributeDefinition valueType : valueTypes) { valueType.getAttributeMarshaller().marshall(valueType, element, false, writer); } writer.writeEndElement(); } } } @Override public void marshallAsElement(AttributeDefinition attribute, ModelNode resourceModel, boolean marshallDefault, XMLStreamWriter writer) throws XMLStreamException { ObjectTypeAttributeDefinition objectType = getObjectType(attribute); AttributeDefinition[] valueTypes = objectType.getValueTypes(); if (resourceModel.hasDefined(attribute.getName())) { List<ModelNode> elements = resourceModel.get(attribute.getName()).asList(); if (elements.isEmpty()) { writer.writeEmptyElement(attribute.getXmlName()); } else { writer.writeStartElement(attribute.getXmlName()); writeElements(writer, objectType, valueTypes, elements); writer.writeEndElement(); } } } } private static class UnwrappedObjectListMarshaller extends ObjectListMarshaller { private UnwrappedObjectListMarshaller() { } @Override public void marshallAsElement(AttributeDefinition attribute, ModelNode resourceModel, boolean marshallDefault, XMLStreamWriter writer) throws XMLStreamException { ObjectTypeAttributeDefinition objectType = getObjectType(attribute); AttributeDefinition[] valueTypes = objectType.getValueTypes(); if (resourceModel.hasDefined(attribute.getName())) { List<ModelNode> elements = resourceModel.get(attribute.getName()).asList(); writeElements(writer, objectType, valueTypes, elements); } } } /** * simple marshaller */ public static final AttributeMarshaller SIMPLE = new DefaultAttributeMarshaller(); /** * space delimited list marshaller */ public static final AttributeMarshaller STRING_LIST = new ListMarshaller(' '); /** * comma delimited list marshaller */ public static final AttributeMarshaller COMMA_STRING_LIST = new ListMarshaller(','); /** * Marshaller for ObjectTypeAttributeDefinition. The object and all its attributes will be marshalled as element only. */ public static final AttributeMarshaller ELEMENT_ONLY_OBJECT = new ObjectMarshaller(true); /** * Marshaller for ObjectTypeAttributeDefinition. The object and all its complex types descendants will get marshalled as elements whereas simple types will get marshalled as attributes. */ public static final AttributeMarshaller ATTRIBUTE_OBJECT = new ObjectMarshaller(false); public static final AttributeMarshaller WRAPPED_OBJECT_LIST_MARSHALLER = new ObjectListMarshaller(); public static final AttributeMarshaller UNWRAPPED_OBJECT_LIST_MARSHALLER = new UnwrappedObjectListMarshaller(); public static final AttributeMarshaller OBJECT_LIST_MARSHALLER = WRAPPED_OBJECT_LIST_MARSHALLER; public static final AttributeMarshaller OBJECT_MAP_MARSHALLER = new AttributeMarshallers.ObjectMapAttributeMarshaller(); public static final AttributeMarshaller PROPERTIES_MARSHALLER = new AttributeMarshallers.PropertiesAttributeMarshaller(); public static final AttributeMarshaller PROPERTIES_MARSHALLER_UNWRAPPED = new AttributeMarshallers.PropertiesAttributeMarshaller(null, false); }