View Javadoc

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 }