/*
* JBoss, Home of Professional Open Source
* Copyright 2015, Red Hat, Inc., and individual contributors as indicated
* by the @authors tag.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.as.controller;
import java.util.List;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.logging.ControllerLogger;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
/**
* @author Tomaz Cerar (c) 2015 Red Hat Inc.
*/
public interface AttributeMarshallers {
abstract static class MapAttributeMarshaller extends AttributeMarshaller {
protected final String wrapperElement;
protected final String elementName;
protected final boolean wrapElement;
public MapAttributeMarshaller(String wrapperElement, String elementName, boolean wrapElement) {
this.wrapperElement = wrapperElement;
this.elementName = elementName == null ? ModelDescriptionConstants.PROPERTY : elementName;
this.wrapElement = wrapElement;
}
@Override
public void marshallAsElement(AttributeDefinition attribute, ModelNode resourceModel, boolean marshallDefault, XMLStreamWriter writer) throws XMLStreamException {
resourceModel = resourceModel.get(attribute.getName());
if (!resourceModel.isDefined()) {
// nothing to do
return;
}
String wrapper = wrapperElement == null ? attribute.getName() : wrapperElement;
List<ModelNode> elementList = resourceModel.asList();
if (elementList.isEmpty()) {
if (wrapElement) {
writer.writeEmptyElement(wrapper);
} else {
// This is a subtle programming error, where the xml schema doesn't
// prevent ambiguity between the 'null' and 'empty collection' cases,
// or a defined but empty ModelNode isn't valid but there's no
// AttributeDefinition validation preventing that being accepted.
// TODO We can look into possibly throwing an exception here, but
// for now to be conservative and avoid regressions I'm just sticking
// with existing behavior and marshalling nothing. I'll log a DEBUG
// though in the off chance it's helpful if this happens.
ControllerLogger.MGMT_OP_LOGGER.debugf("%s found ambigous empty value for unwrapped property %s",
getClass().getSimpleName(), attribute.getName());
}
// No elements to marshal, so we're done
return;
}
if (wrapElement) {
writer.writeStartElement(wrapper);
}
for (ModelNode property : elementList) {
marshallSingleElement(attribute, property, marshallDefault, writer);
}
if (wrapElement) {
writer.writeEndElement();
}
}
@Override
public void marshallAsAttribute(AttributeDefinition attribute, ModelNode resourceModel, boolean marshallDefault, XMLStreamWriter writer) throws XMLStreamException {
marshallAsElement(attribute, resourceModel, marshallDefault, writer);
}
@Override
public boolean isMarshallableAsElement() {
return true;
}
public abstract void marshallSingleElement(AttributeDefinition attribute, ModelNode property, boolean marshallDefault, XMLStreamWriter writer) throws XMLStreamException;
}
static class PropertiesAttributeMarshaller extends MapAttributeMarshaller {
public PropertiesAttributeMarshaller(String wrapperElement, String elementName, boolean wrapElement) {
super(wrapperElement, elementName, wrapElement);
}
public PropertiesAttributeMarshaller(String wrapperElement, boolean wrapElement) {
this(wrapperElement, null, wrapElement);
}
public PropertiesAttributeMarshaller() {
this(null, null, true);
}
@Override
public void marshallSingleElement(AttributeDefinition attribute, ModelNode property, boolean marshallDefault, XMLStreamWriter writer) throws XMLStreamException {
writer.writeEmptyElement(elementName);
writer.writeAttribute(org.jboss.as.controller.parsing.Attribute.NAME.getLocalName(), property.asProperty().getName());
writer.writeAttribute(org.jboss.as.controller.parsing.Attribute.VALUE.getLocalName(), property.asProperty().getValue().asString());
}
}
static class ObjectMapAttributeMarshaller extends MapAttributeMarshaller {
protected final String keyAttributeName; //name of attribute to use for "key"
public ObjectMapAttributeMarshaller(String wrapperElement, String elementName, boolean wrapElement, String keyAttributeName) {
super(wrapperElement, elementName, wrapElement);
this.keyAttributeName = keyAttributeName == null ? "key" : keyAttributeName;
}
public ObjectMapAttributeMarshaller(String wrapperElement, String elementName, boolean wrapElement) {
this(wrapperElement, elementName, wrapElement, null);
}
public ObjectMapAttributeMarshaller(String wrapperElement, boolean wrapElement) {
this(wrapperElement, null, wrapElement);
}
public ObjectMapAttributeMarshaller(String keyAttributeName) {
this(null, null, true, keyAttributeName);
}
public ObjectMapAttributeMarshaller() {
this(null, null, true);
}
@Override
public void marshallSingleElement(AttributeDefinition attribute, ModelNode property, boolean marshallDefault, XMLStreamWriter writer) throws XMLStreamException {
ObjectMapAttributeDefinition map = ((ObjectMapAttributeDefinition) attribute);
AttributeDefinition[] valueTypes = map.getValueType().getValueTypes();
writer.writeEmptyElement(elementName);
Property p = property.asProperty();
writer.writeAttribute(keyAttributeName, p.getName());
for (AttributeDefinition valueType : valueTypes) {
valueType.getAttributeMarshaller().marshall(valueType, p.getValue(), false, writer);
}
}
}
class SimpleListAttributeMarshaller extends AttributeMarshaller {
private final boolean wrap;
SimpleListAttributeMarshaller(boolean wrap) {
this.wrap = wrap;
}
@Override
public void marshallAsElement(AttributeDefinition attribute, ModelNode resourceModel, boolean marshallDefault, XMLStreamWriter writer) throws XMLStreamException {
assert attribute instanceof SimpleListAttributeDefinition;
SimpleListAttributeDefinition attr = (SimpleListAttributeDefinition) attribute;
if (resourceModel.hasDefined(attribute.getName())) {
if (wrap) {
writer.writeStartElement(attribute.getXmlName());
}
for (ModelNode handler : resourceModel.get(attribute.getName()).asList()) {
attr.getValueType().marshallAsElement(handler, writer);
}
if (wrap) {
writer.writeEndElement();
}
}
}
}
static AttributeMarshaller getObjectMapAttributeMarshaller(String keyElementName) {
return new ObjectMapAttributeMarshaller(null, null, true, keyElementName);
}
static AttributeMarshaller getObjectMapAttributeMarshaller(String elementName, String keyElementName, boolean wrapElement) {
return new ObjectMapAttributeMarshaller(null, elementName, wrapElement, keyElementName);
}
static AttributeMarshaller getObjectMapAttributeMarshaller(String elementName, boolean wrapElement) {
return new ObjectMapAttributeMarshaller(null, elementName, wrapElement, null);
}
static AttributeMarshaller getObjectMapAttributeMarshaller(String wrapperElementName, boolean wrapElement, String elementName, String keyElementName) {
return new ObjectMapAttributeMarshaller(wrapperElementName, elementName, wrapElement, keyElementName);
}
static AttributeMarshaller getSimpleListMarshaller(boolean wrapper) {
return new SimpleListAttributeMarshaller(wrapper);
}
}