diff --git a/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessor.java b/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessor.java index b95da72300c..89108bc73d6 100644 --- a/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessor.java +++ b/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessor.java @@ -30,6 +30,9 @@ import org.eclipse.jetty.xml.ConfigurationProcessor; import org.eclipse.jetty.xml.ConfigurationProcessorFactory; import org.eclipse.jetty.xml.XmlConfiguration; import org.eclipse.jetty.xml.XmlParser; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; @@ -59,17 +62,15 @@ public class SpringConfigurationProcessor implements ConfigurationProcessor { private static final Logger LOG = Log.getLogger(SpringConfigurationProcessor.class); - private Map _idMap; - private Map _propertyMap; + private XmlConfiguration _configuration; private XmlBeanFactory _beanFactory; private String _main; - public void init(URL url, XmlParser.Node config, Map idMap, Map properties) + public void init(URL url, XmlParser.Node config, XmlConfiguration configuration) { try { - _idMap = idMap; - _propertyMap = properties; + _configuration = configuration; Resource resource = url != null ? new UrlResource(url) @@ -78,7 +79,14 @@ public class SpringConfigurationProcessor implements ConfigurationProcessor "" + config).getBytes("UTF-8")); - _beanFactory = new XmlBeanFactory(resource); + _beanFactory = new XmlBeanFactory(resource){ + @Override + protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) + { + _configuration.initializeDefaults(bw.getWrappedInstance()); + super.applyPropertyValues(beanName, mbd, bw, pvs); + } + }; } catch (Exception e) { @@ -105,7 +113,7 @@ public class SpringConfigurationProcessor implements ConfigurationProcessor private void doConfigure() { - _beanFactory.registerSingleton("properties", _propertyMap); + _beanFactory.registerSingleton("properties", _configuration.getProperties()); // Look for the main bean; for (String bean : _beanFactory.getBeanDefinitionNames()) @@ -122,25 +130,26 @@ public class SpringConfigurationProcessor implements ConfigurationProcessor _main = _beanFactory.getBeanDefinitionNames()[0]; // Register id beans as singletons - LOG.debug("idMap {}", _idMap); - for (String id : _idMap.keySet()) + Map idMap = _configuration.getIdMap(); + LOG.debug("idMap {}", idMap); + for (String id : idMap.keySet()) { LOG.debug("register {}", id); - _beanFactory.registerSingleton(id, _idMap.get(id)); + _beanFactory.registerSingleton(id, idMap.get(id)); } // Apply configuration to existing singletons - for (String id : _idMap.keySet()) + for (String id : idMap.keySet()) { if (_beanFactory.containsBeanDefinition(id)) { LOG.debug("reconfigure {}", id); - _beanFactory.configureBean(_idMap.get(id), id); + _beanFactory.configureBean(idMap.get(id), id); } } // Extract id's for next time. for (String id : _beanFactory.getSingletonNames()) - _idMap.put(id, _beanFactory.getBean(id)); + idMap.put(id, _beanFactory.getBean(id)); } } diff --git a/jetty-spring/src/test/java/org/eclipse/jetty/spring/SpringXmlConfigurationTest.java b/jetty-spring/src/test/java/org/eclipse/jetty/spring/SpringXmlConfigurationTest.java index 7c712ccb011..13a333d2eb5 100644 --- a/jetty-spring/src/test/java/org/eclipse/jetty/spring/SpringXmlConfigurationTest.java +++ b/jetty-spring/src/test/java/org/eclipse/jetty/spring/SpringXmlConfigurationTest.java @@ -21,16 +21,18 @@ package org.eclipse.jetty.spring; import java.net.URL; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.xml.XmlConfiguration; -import org.junit.Assert; -import org.junit.Assume; import org.junit.Before; import org.junit.Test; +import static junit.framework.Assert.assertEquals; +import static org.junit.Assume.assumeTrue; + public class SpringXmlConfigurationTest { protected String _configure="org/eclipse/jetty/spring/configure.xml"; @@ -48,7 +50,7 @@ public class SpringXmlConfigurationTest if (matcher.matches()) { String minor = matcher.group(1); - Assume.assumeTrue(Integer.parseInt(minor) > 5); + assumeTrue(Integer.parseInt(minor) > 5); } } @@ -74,54 +76,71 @@ public class SpringXmlConfigurationTest tc=(TestConfiguration)configuration.configure(tc); - Assert.assertEquals("preconfig", tc.getTestString0()); - Assert.assertEquals(42, tc.getTestInt0()); - Assert.assertEquals("SetValue", tc.getTestString1()); - Assert.assertEquals(1, tc.getTestInt1()); + assertEquals("preconfig", tc.getTestString0()); + assertEquals(42, tc.getTestInt0()); + assertEquals("SetValue", tc.getTestString1()); + assertEquals(1, tc.getTestInt1()); - Assert.assertEquals("nested", tc.getNested().getTestString0()); - Assert.assertEquals("nested", tc.getNested().getTestString1()); - Assert.assertEquals("default", tc.getNested().getNested().getTestString0()); - Assert.assertEquals("deep", tc.getNested().getNested().getTestString1()); + assertEquals("nested", tc.getNested().getTestString0()); + assertEquals("nested", tc.getNested().getTestString1()); + assertEquals("default", tc.getNested().getNested().getTestString0()); + assertEquals("deep", tc.getNested().getNested().getTestString1()); - Assert.assertEquals("deep", ((TestConfiguration)configuration.getIdMap().get("nestedDeep")).getTestString1()); - Assert.assertEquals(2, ((TestConfiguration)configuration.getIdMap().get("nestedDeep")).getTestInt2()); + assertEquals("deep", ((TestConfiguration)configuration.getIdMap().get("nestedDeep")).getTestString1()); + assertEquals(2, ((TestConfiguration)configuration.getIdMap().get("nestedDeep")).getTestInt2()); - Assert.assertEquals("xxx", tc.getTestString2()); + assertEquals("xxx", tc.getTestString2()); } @Test public void testNewObject() throws Exception { + final String newDefaultValue = "NEW DEFAULT"; TestConfiguration.VALUE=71; URL url = SpringXmlConfigurationTest.class.getClassLoader().getResource(_configure); - XmlConfiguration configuration = new XmlConfiguration(url); + final AtomicInteger count = new AtomicInteger(0); + XmlConfiguration configuration = new XmlConfiguration(url) + { + @Override + public void initializeDefaults(Object object) + { + super.initializeDefaults(object); + if (object instanceof TestConfiguration) + { + count.incrementAndGet(); + ((TestConfiguration)object).setTestString0(newDefaultValue); + ((TestConfiguration)object).setTestString1("WILL BE OVERRIDDEN"); + } + } + }; - Map properties = new HashMap<>(); + Map properties = new HashMap(); properties.put("test", "xxx"); TestConfiguration nested = new TestConfiguration(); nested.setTestString0("nested"); - configuration.getIdMap().put("nested",nested); + configuration.getIdMap().put("nested", nested); configuration.getProperties().putAll(properties); TestConfiguration tc = (TestConfiguration)configuration.configure(); - Assert.assertEquals("default", tc.getTestString0()); - Assert.assertEquals(-1, tc.getTestInt0()); - Assert.assertEquals("SetValue", tc.getTestString1()); - Assert.assertEquals(1, tc.getTestInt1()); + assertEquals(3,count.get()); - Assert.assertEquals("nested", tc.getNested().getTestString0()); - Assert.assertEquals("nested", tc.getNested().getTestString1()); - Assert.assertEquals("default", tc.getNested().getNested().getTestString0()); - Assert.assertEquals("deep", tc.getNested().getNested().getTestString1()); + assertEquals(newDefaultValue, tc.getTestString0()); + assertEquals(-1, tc.getTestInt0()); + assertEquals("SetValue", tc.getTestString1()); + assertEquals(1, tc.getTestInt1()); - Assert.assertEquals("deep", ((TestConfiguration)configuration.getIdMap().get("nestedDeep")).getTestString1()); - Assert.assertEquals(2, ((TestConfiguration)configuration.getIdMap().get("nestedDeep")).getTestInt2()); + assertEquals(newDefaultValue, tc.getNested().getTestString0()); + assertEquals("nested", tc.getNested().getTestString1()); + assertEquals(newDefaultValue, tc.getNested().getNested().getTestString0()); + assertEquals("deep", tc.getNested().getNested().getTestString1()); - Assert.assertEquals("xxx", tc.getTestString2()); + assertEquals("deep", ((TestConfiguration)configuration.getIdMap().get("nestedDeep")).getTestString1()); + assertEquals(2, ((TestConfiguration)configuration.getIdMap().get("nestedDeep")).getTestInt2()); + + assertEquals("xxx", tc.getTestString2()); } @Test diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/ConfigurationProcessor.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/ConfigurationProcessor.java index b179da4a2e2..c6f91510304 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/ConfigurationProcessor.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/ConfigurationProcessor.java @@ -19,7 +19,6 @@ package org.eclipse.jetty.xml; import java.net.URL; -import java.util.Map; /** * A ConfigurationProcessor for non XmlConfiguration format files. @@ -32,7 +31,7 @@ import java.util.Map; */ public interface ConfigurationProcessor { - public void init(URL url, XmlParser.Node config, Map idMap, Map properties); + public void init(URL url, XmlParser.Node root, XmlConfiguration configuration); public Object configure( Object obj) throws Exception; public Object configure() throws Exception; diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index f68a308b3ae..a6b93fd5dd0 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -201,7 +201,7 @@ public class XmlConfiguration { throw new IllegalArgumentException("Unknown XML tag:"+config.getTag()); } - _processor.init(_url,config,_idMap, _propertyMap); + _processor.init(_url,config,this); } /* ------------------------------------------------------------ */ @@ -261,52 +261,61 @@ public class XmlConfiguration { return _processor.configure(); } + + /* ------------------------------------------------------------ */ + /** Initialize a new Object defaults. + *

This method must be called by any {@link ConfigurationProcessor} when it + * creates a new instance of an object before configuring it, so that a derived + * XmlConfiguration class may inject default values. + * @param object the object to initialize defaults on + */ + public void initializeDefaults(Object object) + { + } private static class JettyXmlConfiguration implements ConfigurationProcessor { private String _url; - private XmlParser.Node _config; - private Map _idMap; - private Map _propertyMap; + XmlParser.Node _root; + XmlConfiguration _configuration; - public void init(URL url, XmlParser.Node config, Map idMap, Map properties) + public void init(URL url, XmlParser.Node root, XmlConfiguration configuration) { _url=url==null?null:url.toString(); - _config=config; - _idMap=idMap; - _propertyMap=properties; + _root=root; + _configuration=configuration; } public Object configure(Object obj) throws Exception { // Check the class of the object - Class oClass = nodeClass(_config); + Class oClass = nodeClass(_root); if (oClass != null && !oClass.isInstance(obj)) { String loaders = (oClass.getClassLoader()==obj.getClass().getClassLoader())?"":"Object Class and type Class are from different loaders."; throw new IllegalArgumentException("Object of class '"+obj.getClass().getCanonicalName()+"' is not of type '" + oClass.getCanonicalName()+"'. "+loaders+" in "+_url); } - configure(obj,_config,0); + configure(obj,_root,0); return obj; } public Object configure() throws Exception { - Class oClass = nodeClass(_config); + Class oClass = nodeClass(_root); - String id = _config.getAttribute("id"); - Object obj = id == null ? null : _idMap.get(id); + String id = _root.getAttribute("id"); + Object obj = id == null?null:_configuration.getIdMap().get(id); int index = 0; if (obj == null && oClass != null) { - index = _config.size(); + index = _root.size(); Map namedArgMap = new HashMap<>(); List arguments = new LinkedList<>(); - for (int i = 0; i < _config.size(); i++) + for (int i = 0; i < _root.size(); i++) { - Object o = _config.get(i); + Object o = _root.get(i); if (o instanceof String) { continue; @@ -340,8 +349,9 @@ public class XmlConfiguration throw new IllegalStateException("No suitable constructor on " + oClass, x); } } + _configuration.initializeDefaults(obj); - configure(obj, _config, index); + configure(obj, _root, index); return obj; } @@ -367,7 +377,7 @@ public class XmlConfiguration { String id = cfg.getAttribute("id"); if (id != null) - _idMap.put(id,obj); + _configuration.getIdMap().put(id,obj); // Object already constructed so skip any arguments for (; i < cfg.size(); i++) @@ -558,6 +568,7 @@ public class XmlConfiguration } Constructor cons = sClass.getConstructor(vClass); arg[0] = cons.newInstance(arg); + _configuration.initializeDefaults(arg[0]); set.invoke(obj,arg); return; } @@ -664,7 +675,7 @@ public class XmlConfiguration } } if (id != null) - _idMap.put(id,obj); + _configuration.getIdMap().put(id,obj); return obj; } @@ -718,7 +729,7 @@ public class XmlConfiguration { Object n= TypeUtil.call(oClass,method,obj,arg); if (id != null) - _idMap.put(id,n); + _configuration.getIdMap().put(id,n); configure(n,node,argIndex); return n; } @@ -799,7 +810,8 @@ public class XmlConfiguration { throw new IllegalStateException("No suitable constructor: " + node + " on " + obj); } - + + _configuration.initializeDefaults(n); configure(n,node,argIndex); return n; } @@ -814,7 +826,7 @@ public class XmlConfiguration String refid = node.getAttribute("refid"); if (refid==null) refid = node.getAttribute("id"); - obj = _idMap.get(refid); + obj = _configuration.getIdMap().get(refid); if (obj == null && node.size()>0) throw new IllegalStateException("No object for refid=" + refid); configure(obj,node,0); @@ -862,12 +874,12 @@ public class XmlConfiguration Object v = value(obj,item); al = LazyList.add(al,(v == null && aClass.isPrimitive())?0:v); if (nid != null) - _idMap.put(nid,v); + _configuration.getIdMap().put(nid,v); } Object array = LazyList.toArray(al,aClass); if (id != null) - _idMap.put(id,array); + _configuration.getIdMap().put(id,array); return array; } @@ -880,7 +892,7 @@ public class XmlConfiguration Map map = new HashMap<>(); if (id != null) - _idMap.put(id,map); + _configuration.getIdMap().put(id,map); for (Object o : node) { @@ -916,9 +928,9 @@ public class XmlConfiguration map.put(k,v); if (kid != null) - _idMap.put(kid,k); + _configuration.getIdMap().put(kid,k); if (vid != null) - _idMap.put(vid,v); + _configuration.getIdMap().put(vid,v); } return map; @@ -937,12 +949,13 @@ public class XmlConfiguration String name = node.getAttribute("name"); String defaultValue = node.getAttribute("default"); Object prop; - if (_propertyMap != null && _propertyMap.containsKey(name)) - prop = _propertyMap.get(name); + Map property_map=_configuration.getProperties(); + if (property_map != null && property_map.containsKey(name)) + prop = property_map.get(name); else prop = defaultValue; if (id != null) - _idMap.put(id,prop); + _configuration.getIdMap().put(id,prop); if (prop != null) configure(prop,node,0); return prop; @@ -963,7 +976,7 @@ public class XmlConfiguration String ref = node.getAttribute("ref"); if (ref != null) { - value = _idMap.get(ref); + value = _configuration.getIdMap().get(ref); } else { @@ -1197,10 +1210,10 @@ public class XmlConfiguration } // For all arguments, load properties - for (int i = 0; i < args.length; i++) + for (String arg : args) { - if (args[i].toLowerCase(Locale.ENGLISH).endsWith(".properties")) - properties.load(Resource.newResource(args[i]).getInputStream()); + if (arg.toLowerCase(Locale.ENGLISH).endsWith(".properties")) + properties.load(Resource.newResource(arg).getInputStream()); } // For all arguments, parse XMLs diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/TestConfiguration.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/TestConfiguration.java index 3fa46db0fa8..37fa1785ae7 100644 --- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/TestConfiguration.java +++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/TestConfiguration.java @@ -34,8 +34,11 @@ public class TestConfiguration extends HashMap { public static int VALUE=77; + public final Object ID = new Object(); + public final String name; public TestConfiguration nested; + public String testString="default"; public Object testObject; public int testInt; public URL url; @@ -79,6 +82,25 @@ public class TestConfiguration extends HashMap propValue=value; } + public TestConfiguration getNested() + { + return nested; + } + + public void setNested(TestConfiguration nested) + { + this.nested = nested; + } + + public String getTestString() + { + return testString; + } + + public void setTestString(String testString) + { + this.testString = testString; + } public void call() { @@ -87,7 +109,6 @@ public class TestConfiguration extends HashMap public TestConfiguration call(Boolean b) { - nested=new TestConfiguration("called-"+name); nested.put("Arg",b); return nested; } @@ -167,4 +188,5 @@ public class TestConfiguration extends HashMap { this.map = map; } + } diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java index f4b76f1fca2..929a980e37c 100644 --- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java +++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java @@ -29,6 +29,7 @@ import java.io.ByteArrayInputStream; import java.net.URL; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Assert; import org.junit.Test; @@ -128,10 +129,29 @@ public class XmlConfigurationTest properties.put("whatever", "xxx"); URL url = XmlConfigurationTest.class.getClassLoader().getResource(_configure); - XmlConfiguration configuration = new XmlConfiguration(url); + final AtomicInteger count = new AtomicInteger(0); + XmlConfiguration configuration = new XmlConfiguration(url) + { + @Override + public void initializeDefaults(Object object) + { + if (object instanceof TestConfiguration) + { + count.incrementAndGet(); + ((TestConfiguration)object).setNested(null); + ((TestConfiguration)object).setTestString("NEW DEFAULT"); + } + } + }; configuration.getProperties().putAll(properties); TestConfiguration tc = (TestConfiguration)configuration.configure(); + assertEquals(3,count.get()); + + assertEquals("NEW DEFAULT",tc.getTestString()); + assertEquals("nested",tc.getNested().getTestString()); + assertEquals("NEW DEFAULT",tc.getNested().getNested().getTestString()); + assertEquals("Set String","SetValue",tc.testObject); assertEquals("Set Type",2,tc.testInt); diff --git a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml index 709bd0d6112..7fcccd23700 100644 --- a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml +++ b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml @@ -84,6 +84,16 @@ 2.3 + + + nested + + + + + + +