001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.activemq.osgi;
018    
019    import org.apache.activemq.broker.BrokerService;
020    import org.apache.activemq.spring.SpringBrokerContext;
021    import org.apache.activemq.spring.Utils;
022    import org.apache.xbean.spring.context.ResourceXmlApplicationContext;
023    import org.osgi.framework.BundleContext;
024    import org.osgi.service.cm.ConfigurationException;
025    import org.osgi.service.cm.ManagedServiceFactory;
026    import org.slf4j.Logger;
027    import org.slf4j.LoggerFactory;
028    import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
029    import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
030    import org.springframework.core.io.Resource;
031    
032    import java.util.*;
033    
034    public class ActiveMQServiceFactory implements ManagedServiceFactory {
035    
036        private static final Logger LOG = LoggerFactory.getLogger(ActiveMQServiceFactory.class);
037    
038        BundleContext bundleContext;
039        HashMap<String, BrokerService> brokers = new HashMap<String, BrokerService>();
040    
041        @Override
042        public String getName() {
043            return "ActiveMQ Server Controller";
044        }
045    
046        @Override
047        synchronized public void updated(String pid, Dictionary properties) throws ConfigurationException {
048    
049            // First stop currently running broker (if any)
050            deleted(pid);
051    
052            String config = (String)properties.get("config");
053            if (config == null) {
054                throw new ConfigurationException("config", "Property must be set");
055            }
056            String name = (String)properties.get("broker-name");
057            if (name == null) {
058                throw new ConfigurationException("broker-name", "Property must be set");
059            }
060    
061            LOG.info("Starting broker " + name);
062    
063            try {
064                Thread.currentThread().setContextClassLoader(BrokerService.class.getClassLoader());
065                Resource resource = Utils.resourceFromString(config);
066    
067                ResourceXmlApplicationContext ctx = new ResourceXmlApplicationContext(resource, Collections.EMPTY_LIST, null, Collections.EMPTY_LIST, false) {
068                    protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
069                        reader.setValidating(false);
070                    }
071                };
072    
073                // Handle properties in configuration
074                PropertyPlaceholderConfigurer configurator =
075                            new PropertyPlaceholderConfigurer();
076    
077                //convert dictionary to properties. Is there a better way?
078                Properties props = new Properties();
079                Enumeration elements = properties.keys();
080                while (elements.hasMoreElements()) {
081                    Object key = elements.nextElement();
082                    props.put(key, properties.get(key));
083                }
084    
085                configurator.setProperties(props);
086                configurator.setIgnoreUnresolvablePlaceholders(true);
087    
088                ctx.addBeanFactoryPostProcessor(configurator);
089    
090                ctx.refresh();
091    
092                // Start the broker
093                BrokerService broker = ctx.getBean(BrokerService.class);
094                if (broker == null) {
095                    throw new ConfigurationException(null, "Broker not defined");
096                }
097                //TODO deal with multiple brokers
098    
099                SpringBrokerContext brokerContext = new SpringBrokerContext();
100                brokerContext.setConfigurationUrl(resource.getURL().toExternalForm());
101                brokerContext.setApplicationContext(ctx);
102                broker.setBrokerContext(brokerContext);
103    
104                broker.start();
105                broker.waitUntilStarted();
106                brokers.put(pid, broker);
107    
108    
109            } catch (Exception e) {
110                throw new ConfigurationException(null, "Cannot start the broker", e);
111            }
112        }
113    
114        @Override
115        synchronized public void deleted(String pid) {
116            BrokerService broker = brokers.get(pid);
117            if (broker == null) {
118                return;
119            }
120            try {
121                LOG.info("Stopping broker " + pid);
122                broker.stop();
123                broker.waitUntilStopped();
124            } catch (Exception e) {
125                LOG.error("Exception on stopping broker", e);
126            }
127        }
128    
129        synchronized public void destroy() {
130            for (String broker: brokers.keySet()) {
131                deleted(broker);
132            }
133        }
134    
135        public BundleContext getBundleContext() {
136            return bundleContext;
137        }
138    
139        public void setBundleContext(BundleContext bundleContext) {
140            this.bundleContext = bundleContext;
141        }
142    }