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 */ 017package org.apache.activemq.osgi; 018 019import java.util.Collections; 020import java.util.Dictionary; 021import java.util.Enumeration; 022import java.util.HashMap; 023import java.util.Map; 024import java.util.Properties; 025 026import org.apache.activemq.broker.BrokerService; 027import org.apache.activemq.spring.SpringBrokerContext; 028import org.apache.activemq.spring.Utils; 029import org.apache.camel.blueprint.CamelContextFactoryBean; 030import org.osgi.framework.BundleContext; 031import org.osgi.framework.ServiceRegistration; 032import org.osgi.service.cm.ConfigurationException; 033import org.osgi.service.cm.ManagedServiceFactory; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036import org.springframework.beans.BeansException; 037import org.springframework.beans.factory.config.BeanFactoryPostProcessor; 038import org.springframework.beans.factory.config.BeanPostProcessor; 039import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 040import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; 041import org.springframework.context.support.ClassPathXmlApplicationContext; 042import org.springframework.core.io.Resource; 043 044public class ActiveMQServiceFactory implements ManagedServiceFactory { 045 046 private static final Logger LOG = LoggerFactory.getLogger(ActiveMQServiceFactory.class); 047 048 BundleContext bundleContext; 049 Map<String, BrokerService> brokers = new HashMap<>(); 050 Map<String, ServiceRegistration<BrokerService>> brokerRegs = new HashMap<>(); 051 052 @Override 053 public String getName() { 054 return "ActiveMQ Server Controller"; 055 } 056 057 public Map<String, BrokerService> getBrokersMap() { 058 return Collections.unmodifiableMap(brokers); 059 } 060 061 @Override 062 synchronized public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException { 063 064 // First stop currently running broker (if any) 065 deleted(pid); 066 067 String config = (String) properties.get("config"); 068 if (config == null) { 069 throw new ConfigurationException("config", "Property must be set"); 070 } 071 String name = (String) properties.get("broker-name"); 072 if (name == null) { 073 throw new ConfigurationException("broker-name", "Property must be set"); 074 } 075 076 LOG.info("Starting broker " + name); 077 078 try { 079 Thread.currentThread().setContextClassLoader(BrokerService.class.getClassLoader()); 080 Resource resource = Utils.resourceFromString(config); 081 082 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( 083 new String[]{resource.getURL().toExternalForm()}, false); 084 085 if (isCamelContextFactoryBeanExist()) { 086 087 ctx.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() { 088 089 @Override 090 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { 091 092 beanFactory.addBeanPostProcessor(new BeanPostProcessor() { 093 094 @Override 095 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 096 if (bean instanceof CamelContextFactoryBean) { 097 ((CamelContextFactoryBean) bean).setBundleContext(bundleContext); 098 } 099 return bean; 100 } 101 102 @Override 103 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 104 return bean; 105 } 106 }); 107 } 108 }); 109 } 110 111 // Handle properties in configuration 112 PropertyPlaceholderConfigurer configurator = new PropertyPlaceholderConfigurer(); 113 114 // convert dictionary to properties. Is there a better way? 115 Properties props = new Properties(); 116 Enumeration<?> elements = properties.keys(); 117 while (elements.hasMoreElements()) { 118 Object key = elements.nextElement(); 119 props.put(key, properties.get(key)); 120 } 121 122 configurator.setProperties(props); 123 configurator.setIgnoreUnresolvablePlaceholders(true); 124 125 ctx.addBeanFactoryPostProcessor(configurator); 126 127 ctx.refresh(); 128 129 // Start the broker 130 BrokerService broker = ctx.getBean(BrokerService.class); 131 if (broker == null) { 132 throw new ConfigurationException(null, "Broker not defined"); 133 } 134 // TODO deal with multiple brokers 135 136 SpringBrokerContext brokerContext = new SpringBrokerContext(); 137 brokerContext.setConfigurationUrl(resource.getURL().toExternalForm()); 138 brokerContext.setApplicationContext(ctx); 139 broker.setBrokerContext(brokerContext); 140 141 broker.setStartAsync(true); 142 broker.start(); 143 144 if (!broker.isSlave()) 145 broker.waitUntilStarted(); 146 brokers.put(pid, broker); 147 brokerRegs.put(pid, bundleContext.registerService(BrokerService.class, broker, properties)); 148 } catch (Exception e) { 149 throw new ConfigurationException(null, "Cannot start the broker", e); 150 } 151 } 152 153 private boolean isCamelContextFactoryBeanExist() { 154 try { 155 Class.forName("org.apache.camel.osgi.CamelContextFactoryBean"); 156 return true; 157 } catch (ClassNotFoundException e) { 158 return false; 159 } 160 } 161 162 @Override 163 synchronized public void deleted(String pid) { 164 ServiceRegistration<BrokerService> reg = brokerRegs.remove(pid); 165 if (reg != null) { 166 reg.unregister(); 167 } 168 BrokerService broker = brokers.remove(pid); 169 if (broker != null) { 170 stop(pid, broker); 171 } 172 } 173 174 private void stop(String pid, BrokerService broker) { 175 try { 176 LOG.info("Stopping broker " + pid); 177 broker.stop(); 178 broker.waitUntilStopped(); 179 } catch (Exception e) { 180 LOG.error("Exception on stopping broker", e); 181 } 182 } 183 184 synchronized public void destroy() { 185 for (String broker : brokers.keySet()) { 186 deleted(broker); 187 } 188 } 189 190 public BundleContext getBundleContext() { 191 return bundleContext; 192 } 193 194 public void setBundleContext(BundleContext bundleContext) { 195 this.bundleContext = bundleContext; 196 } 197}