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.servicemix.jbi.container;
018
019 import java.lang.reflect.Method;
020 import java.util.Iterator;
021 import java.util.LinkedHashMap;
022 import java.util.List;
023 import java.util.Map;
024 import java.util.Properties;
025
026 import javax.jbi.JBIException;
027 import javax.jbi.component.Component;
028
029 import org.apache.servicemix.components.util.ComponentAdaptor;
030 import org.apache.servicemix.jbi.framework.ComponentMBeanImpl;
031 import org.apache.xbean.spring.context.impl.NamespaceHelper;
032 import org.springframework.beans.BeanUtils;
033 import org.springframework.beans.BeansException;
034 import org.springframework.beans.factory.BeanFactory;
035 import org.springframework.beans.factory.BeanFactoryAware;
036 import org.springframework.beans.factory.DisposableBean;
037 import org.springframework.beans.factory.InitializingBean;
038 import org.springframework.context.ApplicationContext;
039 import org.springframework.context.ApplicationContextAware;
040 import org.springframework.core.io.support.PropertiesLoaderUtils;
041 import org.springframework.util.ClassUtils;
042
043 /**
044 * An enhanced JBI container which adds some Spring helper methods for
045 * easier configuration through spring's XML configuration file.
046 *
047 * @org.apache.xbean.XBean element="container" rootElement="true"
048 * description="The ServiceMix JBI Container"
049 *
050 * @version $Revision: 594535 $
051 */
052 public class SpringJBIContainer extends JBIContainer implements InitializingBean, DisposableBean,
053 BeanFactoryAware, ApplicationContextAware {
054
055 private String[] componentNames;
056 private ActivationSpec[] activationSpecs;
057 private BeanFactory beanFactory;
058 private ApplicationContext applicationContext;
059 private String[] deployArchives;
060 private DeploySupport[] deployments;
061 private Map components;
062 private Map endpoints;
063 private Runnable onShutDown;
064
065 public void afterPropertiesSet() throws Exception {
066 init();
067
068 // lets iterate through all the component names and register them
069 if (componentNames != null) {
070 for (int i = 0; i < componentNames.length; i++) {
071 String componentName = componentNames[i];
072 activateComponent(new ActivationSpec(componentName, lookupBean(componentName)));
073 }
074 }
075
076 if (activationSpecs != null) {
077 for (int i = 0; i < activationSpecs.length; i++) {
078 ActivationSpec activationSpec = activationSpecs[i];
079 activateComponent(activationSpec);
080 }
081 }
082
083 if (deployArchives != null) {
084 for (int i = 0; i < deployArchives.length; i++) {
085 String archive = deployArchives[i];
086 installArchive(archive);
087 }
088 }
089
090 if (components != null) {
091 for (Iterator it = components.entrySet().iterator(); it.hasNext();) {
092 Map.Entry e = (Map.Entry) it.next();
093 if (!(e.getKey() instanceof String)) {
094 throw new JBIException("Component must have a non null string name");
095 }
096 if (!(e.getValue() instanceof Component)) {
097 throw new JBIException("Component is not a known component");
098 }
099 String name = (String) e.getKey();
100 activateComponent((Component) e.getValue(), name);
101 getComponent(name).init();
102 }
103 }
104
105 if (endpoints != null) {
106 initEndpoints();
107 }
108
109 if (deployments != null) {
110 for (DeploySupport deployment : deployments) {
111 deployment.deploy(this);
112 }
113 }
114
115 start();
116 }
117
118 private void initEndpoints() throws Exception {
119 if (components == null) {
120 components = new LinkedHashMap();
121 }
122 Class componentClass = Class.forName("org.apache.servicemix.common.DefaultComponent");
123 Class endpointClass = Class.forName("org.apache.servicemix.common.Endpoint");
124 Method addEndpointMethod = componentClass.getDeclaredMethod("addEndpoint", new Class[] {endpointClass });
125 addEndpointMethod.setAccessible(true);
126 Method getEndpointClassesMethod = componentClass.getDeclaredMethod("getEndpointClasses", null);
127 getEndpointClassesMethod.setAccessible(true);
128 for (Iterator it = endpoints.entrySet().iterator(); it.hasNext();) {
129 Map.Entry e = (Map.Entry) it.next();
130 String key = (String) e.getKey();
131 List l = (List) e.getValue();
132 for (Iterator itEp = l.iterator(); itEp.hasNext();) {
133 Object endpoint = itEp.next();
134 Component c = null;
135 if (key.length() > 0) {
136 Component comp = (Component) components.get(key);
137 if (comp == null) {
138 throw new JBIException("Could not find component '" + key + "' specified for endpoint");
139 }
140 c = comp;
141 } else {
142 for (Iterator itCmp = components.values().iterator(); itCmp.hasNext();) {
143 Component comp = (Component) itCmp.next();
144 Class[] endpointClasses = (Class[]) getEndpointClassesMethod.invoke(comp, null);
145 if (isKnownEndpoint(endpoint, endpointClasses)) {
146 c = comp;
147 break;
148 }
149 }
150 if (c == null) {
151 c = getComponentForEndpoint(getEndpointClassesMethod, endpoint);
152 if (c == null) {
153 throw new JBIException("Unable to find a component for endpoint class: " + endpoint.getClass());
154 }
155 }
156 }
157 addEndpointMethod.invoke(c, new Object[] {endpoint });
158 }
159 }
160 }
161
162 private Component getComponentForEndpoint(Method getEndpointClassesMethod, Object endpoint) throws Exception {
163 Properties namespaces = PropertiesLoaderUtils.loadAllProperties("META-INF/spring.handlers");
164 for (Iterator itNs = namespaces.keySet().iterator(); itNs.hasNext();) {
165 String namespaceURI = (String) itNs.next();
166 String uri = NamespaceHelper.createDiscoveryPathName(namespaceURI);
167 Properties props = PropertiesLoaderUtils.loadAllProperties(uri);
168 String compClassName = props.getProperty("component");
169 if (compClassName != null) {
170 Class compClass = ClassUtils.forName(compClassName);
171 Component comp = (Component) BeanUtils.instantiateClass(compClass);
172 Class[] endpointClasses = (Class[]) getEndpointClassesMethod.invoke(comp, null);
173 if (isKnownEndpoint(endpoint, endpointClasses)) {
174 String name = chooseComponentName(comp);
175 activateComponent(comp, name);
176 components.put(name, comp);
177 return comp;
178 }
179 }
180 }
181 return null;
182 }
183
184 private String chooseComponentName(Object c) {
185 String className = c.getClass().getName();
186 if (className.startsWith("org.apache.servicemix.")) {
187 int idx1 = className.lastIndexOf('.');
188 int idx0 = className.lastIndexOf('.', idx1 - 1);
189 String name = "servicemix-" + className.substring(idx0 + 1, idx1);
190 if (registry.getComponent(name) == null) {
191 return name;
192 }
193 }
194 return createComponentID();
195 }
196
197 private boolean isKnownEndpoint(Object endpoint, Class[] knownClasses) {
198 if (knownClasses != null) {
199 for (int i = 0; i < knownClasses.length; i++) {
200 if (knownClasses[i].isInstance(endpoint)) {
201 return true;
202 }
203 }
204 }
205 return false;
206 }
207
208 public void stop() throws JBIException {
209 if (beanFactory instanceof DisposableBean) {
210 DisposableBean disposable = (DisposableBean) beanFactory;
211 try {
212 disposable.destroy();
213 } catch (Exception e) {
214 throw new JBIException("Failed to dispose of the Spring BeanFactory due to: " + e, e);
215 }
216 }
217 super.stop();
218 }
219
220 /**
221 * Returns the compoment or POJO registered with the given component ID.
222 *
223 * @param id
224 * @return the Component
225 */
226 public Object getBean(String id) {
227 ComponentMBeanImpl component = getComponent(id);
228 Object bean = component != null ? component.getComponent() : null;
229 if (bean instanceof ComponentAdaptor) {
230 bean = ((ComponentAdaptor) bean).getLifeCycle();
231 }
232 return bean;
233 }
234
235 // Properties
236 //-------------------------------------------------------------------------
237 /**
238 * @org.apache.xbean.Property hidden="true"
239 */
240 public BeanFactory getBeanFactory() {
241 return beanFactory;
242 }
243
244 public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
245 this.beanFactory = beanFactory;
246 }
247
248 public String[] getComponentNames() {
249 return componentNames;
250 }
251
252 public void setComponentNames(String[] componentNames) {
253 this.componentNames = componentNames;
254 }
255
256 public ActivationSpec[] getActivationSpecs() {
257 return activationSpecs;
258 }
259
260 public void setActivationSpecs(ActivationSpec[] activationSpecs) throws JBIException {
261 this.activationSpecs = activationSpecs;
262 }
263
264 public String[] getDeployArchives() {
265 return deployArchives;
266 }
267
268 public void setDeployArchives(String[] deployArchives) {
269 this.deployArchives = deployArchives;
270 }
271
272 public DeploySupport[] getDeployments() {
273 return deployments;
274 }
275
276 public void setDeployments(DeploySupport[] deployments) {
277 this.deployments = deployments;
278 }
279
280 // Implementation methods
281 //-------------------------------------------------------------------------
282 protected Object lookupBean(String componentName) {
283 Object bean = beanFactory.getBean(componentName);
284 if (bean == null) {
285 throw new IllegalArgumentException("Component name: " + componentName + " is not found in the Spring BeanFactory");
286 }
287 return bean;
288 }
289
290 /**
291 * @return
292 * @org.apache.xbean.Property hidden="true"
293 */
294 public ApplicationContext getApplicationContext() {
295 return applicationContext;
296 }
297
298 public void setApplicationContext(ApplicationContext applicationContext) {
299 this.applicationContext = applicationContext;
300 }
301
302 public void destroy() throws Exception {
303 super.shutDown();
304 }
305
306 public void shutDown() throws JBIException {
307 if (onShutDown != null) {
308 onShutDown.run();
309 } else {
310 //no shutdown handler has been set
311 //shutting down the container ourselves
312 super.shutDown();
313 }
314 }
315
316 /**
317 * Set a {@link Runnable} which can handle the shutdown of the container
318 *
319 * @param runnable the shutdown handler
320 */
321 public void onShutDown(Runnable runnable) {
322 this.onShutDown = runnable;
323 }
324
325 /**
326 * @org.apache.xbean.Map flat="true" keyName="name"
327 */
328 public Map getComponents() {
329 return components;
330 }
331
332 public void setComponents(Map components) {
333 this.components = components;
334 }
335
336 /**
337 * @org.apache.xbean.Map flat="true" dups="always" keyName="component" defaultKey=""
338 */
339 public Map getEndpoints() {
340 return endpoints;
341 }
342
343 public void setEndpoints(Map endpoints) {
344 this.endpoints = endpoints;
345 }
346
347 }