From ad2f94b4caabb7e222d136bc15b1cee528a73e31 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Mon, 28 Apr 2014 11:20:44 +0000 Subject: QPID-5721 : Allow interpolation to include the values of attributes of the object on which the value is being iterpolated git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1590603 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/model/AbstractConfiguredObject.java | 135 +++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java index 95bd2f582d..73fc59e057 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.model; +import java.io.IOException; +import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; @@ -49,6 +51,15 @@ import java.util.concurrent.atomic.AtomicBoolean; import javax.security.auth.Subject; +import org.codehaus.jackson.JsonGenerator; +import org.codehaus.jackson.JsonProcessingException; +import org.codehaus.jackson.Version; +import org.codehaus.jackson.map.JsonSerializer; +import org.codehaus.jackson.map.Module; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializerProvider; +import org.codehaus.jackson.map.module.SimpleModule; + import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.configuration.updater.Task; import org.apache.qpid.server.configuration.updater.TaskExecutor; @@ -156,6 +167,8 @@ public abstract class AbstractConfiguredObject> im @ManagedAttributeField private String _type; + private final OwnAttributeResolver _attributeResolver = new OwnAttributeResolver(this); + protected static Map, ConfiguredObject> parentsMap(ConfiguredObject... parents) { final Map, ConfiguredObject> parentsMap = @@ -1144,6 +1157,11 @@ public abstract class AbstractConfiguredObject> im return converter.convert("${"+propertyName+"}", this); } + private OwnAttributeResolver getOwnAttributeResolver() + { + return _attributeResolver; + } + //========================================================================================= static String interpolate(ConfiguredObject object, String value) @@ -1151,12 +1169,20 @@ public abstract class AbstractConfiguredObject> im Map inheritedContext = new HashMap(); generateInheritedContext(object.getModel(), object, inheritedContext); return Strings.expand(value, false, + getOwnAttributeResolver(object), new Strings.MapResolver(inheritedContext), Strings.JAVA_SYS_PROPS_RESOLVER, Strings.ENV_VARS_RESOLVER, new Strings.MapResolver(_defaultContext)); } + private static OwnAttributeResolver getOwnAttributeResolver(final ConfiguredObject object) + { + return object instanceof AbstractConfiguredObject + ? ((AbstractConfiguredObject)object).getOwnAttributeResolver() + : new OwnAttributeResolver(object); + } + static void generateInheritedContext(final Model model, final ConfiguredObject object, final Map inheritedContext) { @@ -1623,6 +1649,115 @@ public abstract class AbstractConfiguredObject> im return allDescendants.contains(descendantClass); } + private static class OwnAttributeResolver implements Strings.Resolver + { + private static final Module _module; + static + { + SimpleModule module= new SimpleModule("ConfiguredObjectSerializer", new Version(1,0,0,null)); + + final JsonSerializer serializer = new JsonSerializer() + { + @Override + public void serialize(final ConfiguredObject value, + final JsonGenerator jgen, + final SerializerProvider provider) + throws IOException, JsonProcessingException + { + jgen.writeString(value.getId().toString()); + } + }; + module.addSerializer(ConfiguredObject.class, serializer); + + _module = module; + } + + + public static final String PREFIX = "this:"; + private final ThreadLocal> _stack = new ThreadLocal<>(); + private final ConfiguredObject _object; + private final ObjectMapper _objectMapper; + + public OwnAttributeResolver(final ConfiguredObject object) + { + _object = object; + _objectMapper = new ObjectMapper(); + _objectMapper.registerModule(_module); + } + + @Override + public String resolve(final String variable) + { + boolean clearStack = false; + Set currentStack = _stack.get(); + if(currentStack == null) + { + currentStack = new HashSet<>(); + _stack.set(currentStack); + clearStack = true; + } + + try + { + if(variable.startsWith(PREFIX)) + { + String attrName = variable.substring(PREFIX.length()); + if(currentStack.contains(attrName)) + { + throw new IllegalArgumentException("The value of attribute " + attrName + " is defined recursively"); + } + else + { + currentStack.add(attrName); + Object returnVal = _object.getAttribute(attrName); + String returnString; + if(returnVal == null) + { + returnString = null; + } + else if(returnVal instanceof Map || returnVal instanceof Collection) + { + try + { + StringWriter writer = new StringWriter(); + + _objectMapper.writeValue(writer, returnVal); + + returnString = writer.toString(); + } + catch (IOException e) + { + throw new IllegalArgumentException(e); + } + } + else if(returnVal instanceof ConfiguredObject) + { + returnString = ((ConfiguredObject)returnVal).getId().toString(); + } + else + { + returnString = returnVal.toString(); + } + + return returnString; + } + } + else + { + return null; + } + } + finally + { + if(clearStack) + { + _stack.remove(); + } + + } + } + } + private class AttributeGettingHandler implements InvocationHandler { -- cgit v1.2.1