1 //
2 // ========================================================================
3 // Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19
20 package org.eclipse.jetty.spring;
21
22 import java.net.URL;
23 import java.util.Arrays;
24 import java.util.Map;
25
26 import org.eclipse.jetty.util.log.Logger;
27 import org.eclipse.jetty.xml.ConfigurationProcessor;
28 import org.eclipse.jetty.xml.ConfigurationProcessorFactory;
29 import org.eclipse.jetty.xml.XmlConfiguration;
30 import org.eclipse.jetty.xml.XmlParser;
31 import org.springframework.beans.factory.xml.XmlBeanFactory;
32 import org.springframework.core.io.ByteArrayResource;
33 import org.springframework.core.io.Resource;
34 import org.springframework.core.io.UrlResource;
35
36 /**
37 * Spring ConfigurationProcessor
38 * <p>
39 * A {@link ConfigurationProcessor} that uses a spring XML file to emulate the {@link XmlConfiguration} format.
40 * <p>
41 * {@link XmlConfiguration} expects a primary object that is either passed in to a call to {@link #configure(Object)}
42 * or that is constructed by a call to {@link #configure()}. This processor looks for a bean definition
43 * with an id, name or alias of "Main" as uses that as the primary bean.
44 * <p>
45 * The objects mapped by {@link XmlConfiguration#getIdMap()} are set as singletons before any configuration calls
46 * and if the spring configuration file contains a definition for the singleton id, the the singleton is updated
47 * with a call to {@link XmlBeanFactory#configureBean(Object, String)}.
48 * <p>
49 * The property map obtained via {@link XmlConfiguration#getProperties()} is set as a singleton called "properties"
50 * and values can be accessed by somewhat verbose
51 * usage of {@link org.springframework.beans.factory.config.MethodInvokingFactoryBean}.
52 * <p>
53 * This processor is returned by the {@link SpringConfigurationProcessorFactory} for any XML document whos first
54 * element is "beans". The factory is discovered by a {@link ServiceLoader} for {@link ConfigurationProcessorFactory}.
55 */
56 public class SpringConfigurationProcessor implements ConfigurationProcessor
57 {
58 static final Logger __log = org.eclipse.jetty.util.log.Log.getLogger(SpringConfigurationProcessor.class.getName());
59
60 Map<String, Object> _idMap;
61 Map<String, String> _propertyMap;
62 XmlBeanFactory _beanFactory;
63 String _main;
64
65 public void init(URL url, XmlParser.Node config, Map<String, Object> idMap, Map<String, String> properties)
66 {
67 try
68 {
69 _idMap=idMap;
70 _propertyMap=properties;
71
72 Resource resource = (url!=null)
73 ?new UrlResource(url)
74 :new ByteArrayResource(("<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN//EN\" \"http://www.springframework.org/dtd/spring-beans.dtd\">"+config).getBytes("UTF-8"));
75
76 _beanFactory=new XmlBeanFactory(resource);
77
78 }
79 catch(Exception e)
80 {
81 throw new RuntimeException(e);
82 }
83 }
84
85 public Object configure(Object obj) throws Exception
86 {
87 doConfigure();
88 return _beanFactory.configureBean(obj,_main);
89 }
90
91 /**
92 * Return a configured bean. If a bean has the id or alias of "Main", then it is returned, otherwise the first bean in the file is returned.
93 * @see org.eclipse.jetty.xml.ConfigurationProcessor#configure()
94 */
95 public Object configure() throws Exception
96 {
97 doConfigure();
98 return _beanFactory.getBean(_main);
99 }
100
101 private void doConfigure()
102 {
103 _beanFactory.registerSingleton("properties",_propertyMap);
104
105 // Look for the main bean;
106 for (String bean : _beanFactory.getBeanDefinitionNames())
107 {
108 __log.debug("{} - {}",bean,Arrays.asList(_beanFactory.getAliases(bean)));
109 String[] aliases = _beanFactory.getAliases(bean);
110 if ("Main".equals(bean) || aliases!=null && Arrays.asList(aliases).contains("Main"))
111 {
112 _main=bean;
113 break;
114 }
115 }
116 if (_main==null)
117 _main=_beanFactory.getBeanDefinitionNames()[0];
118
119 // Register id beans as singletons
120 __log.debug("idMap {}",_idMap);
121 for (String id : _idMap.keySet())
122 {
123 __log.debug("register {}",id);
124 _beanFactory.registerSingleton(id,_idMap.get(id));
125 }
126
127 // Apply configuration to existing singletons
128 for (String id : _idMap.keySet())
129 {
130 if (_beanFactory.containsBeanDefinition(id))
131 {
132 __log.debug("reconfigure {}",id);
133 _beanFactory.configureBean(_idMap.get(id),id);
134 }
135 }
136
137 // Extract id's for next time.
138 for (String id : _beanFactory.getSingletonNames())
139 _idMap.put(id,_beanFactory.getBean(id));
140 }
141 }