View Javadoc

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