| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| |
| package org.eclipse.jetty.spring; |
| |
| import java.net.URL; |
| import java.nio.charset.StandardCharsets; |
| import java.util.Arrays; |
| import java.util.Map; |
| import java.util.ServiceLoader; |
| |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| 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.support.DefaultListableBeanFactory; |
| import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; |
| import org.springframework.beans.factory.xml.XmlBeanFactory; |
| import org.springframework.core.io.ByteArrayResource; |
| import org.springframework.core.io.Resource; |
| import org.springframework.core.io.UrlResource; |
| |
| /** |
| * Spring ConfigurationProcessor |
| * <p/> |
| * A {@link ConfigurationProcessor} that uses a spring XML file to emulate the {@link XmlConfiguration} format. |
| * <p/> |
| * {@link XmlConfiguration} expects a primary object that is either passed in to a call to {@link #configure(Object)} |
| * or that is constructed by a call to {@link #configure()}. This processor looks for a bean definition |
| * with an id, name or alias of "Main" as uses that as the primary bean. |
| * <p/> |
| * The objects mapped by {@link XmlConfiguration#getIdMap()} are set as singletons before any configuration calls |
| * and if the spring configuration file contains a definition for the singleton id, the the singleton is updated |
| * with a call to {@link XmlBeanFactory#configureBean(Object, String)}. |
| * <p/> |
| * The property map obtained via {@link XmlConfiguration#getProperties()} is set as a singleton called "properties" |
| * and values can be accessed by somewhat verbose |
| * usage of {@link org.springframework.beans.factory.config.MethodInvokingFactoryBean}. |
| * <p/> |
| * This processor is returned by the {@link SpringConfigurationProcessorFactory} for any XML document whos first |
| * element is "beans". The factory is discovered by a {@link ServiceLoader} for {@link ConfigurationProcessorFactory}. |
| */ |
| public class SpringConfigurationProcessor implements ConfigurationProcessor |
| { |
| private static final Logger LOG = Log.getLogger(SpringConfigurationProcessor.class); |
| |
| private XmlConfiguration _configuration; |
| private DefaultListableBeanFactory _beanFactory; |
| private String _main; |
| |
| @Override |
| public void init(URL url, XmlParser.Node config, XmlConfiguration configuration) |
| { |
| try |
| { |
| _configuration = configuration; |
| |
| Resource resource = url != null |
| ? new UrlResource(url) |
| : 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(StandardCharsets.UTF_8)); |
| |
| _beanFactory = new DefaultListableBeanFactory() |
| { |
| @Override |
| protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) |
| { |
| _configuration.initializeDefaults(bw.getWrappedInstance()); |
| super.applyPropertyValues(beanName, mbd, bw, pvs); |
| } |
| }; |
| |
| new XmlBeanDefinitionReader(_beanFactory).loadBeanDefinitions(resource); |
| } |
| catch (Exception e) |
| { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Override |
| public Object configure(Object obj) throws Exception |
| { |
| doConfigure(); |
| return _beanFactory.configureBean(obj, _main); |
| } |
| |
| /** |
| * 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. |
| * |
| * @see org.eclipse.jetty.xml.ConfigurationProcessor#configure() |
| */ |
| @Override |
| public Object configure() throws Exception |
| { |
| doConfigure(); |
| return _beanFactory.getBean(_main); |
| } |
| |
| private void doConfigure() |
| { |
| _beanFactory.registerSingleton("properties", _configuration.getProperties()); |
| |
| // Look for the main bean; |
| for (String bean : _beanFactory.getBeanDefinitionNames()) |
| { |
| LOG.debug("{} - {}", bean, Arrays.asList(_beanFactory.getAliases(bean))); |
| String[] aliases = _beanFactory.getAliases(bean); |
| if ("Main".equals(bean) || aliases != null && Arrays.asList(aliases).contains("Main")) |
| { |
| _main = bean; |
| break; |
| } |
| } |
| if (_main == null) |
| _main = _beanFactory.getBeanDefinitionNames()[0]; |
| |
| // Register id beans as singletons |
| Map<String, Object> idMap = _configuration.getIdMap(); |
| LOG.debug("idMap {}", idMap); |
| for (String id : idMap.keySet()) |
| { |
| LOG.debug("register {}", id); |
| _beanFactory.registerSingleton(id, idMap.get(id)); |
| } |
| |
| // Apply configuration to existing singletons |
| for (String id : idMap.keySet()) |
| { |
| if (_beanFactory.containsBeanDefinition(id)) |
| { |
| LOG.debug("reconfigure {}", id); |
| _beanFactory.configureBean(idMap.get(id), id); |
| } |
| } |
| |
| // Extract id's for next time. |
| for (String id : _beanFactory.getSingletonNames()) |
| idMap.put(id, _beanFactory.getBean(id)); |
| } |
| } |