Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 52dddc0c137c4be20ec71f40a263e2c31aabca0f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//
//  ========================================================================
//  Copyright (c) 1995-2015 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));
    }
}

Back to the top