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