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.lwcontainer;
018    
019    import java.lang.reflect.Method;
020    import java.util.EventListener;
021    import java.util.IdentityHashMap;
022    import java.util.Iterator;
023    import java.util.LinkedHashMap;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.Properties;
027    
028    import javax.jbi.JBIException;
029    import javax.jbi.component.Component;
030    import javax.jbi.component.ComponentContext;
031    import javax.jbi.messaging.MessageExchange;
032    import javax.xml.namespace.QName;
033    
034    import org.apache.servicemix.common.DefaultComponent;
035    import org.apache.servicemix.common.Endpoint;
036    import org.apache.servicemix.common.ExchangeProcessor;
037    import org.apache.servicemix.id.IdGenerator;
038    import org.apache.servicemix.jbi.container.JBIContainer;
039    import org.apache.servicemix.jbi.framework.ComponentContextImpl;
040    import org.apache.servicemix.jbi.management.BaseSystemService;
041    import org.apache.xbean.spring.context.impl.NamespaceHelper;
042    import org.springframework.beans.BeanUtils;
043    import org.springframework.core.io.support.PropertiesLoaderUtils;
044    import org.springframework.util.ClassUtils;
045    
046    /**
047     * Fake endpoint that hold components, endpoints, listeners and services.
048     */
049    public class LwContainerExtra extends Endpoint {
050    
051        private Map components;
052        private Map endpoints;
053        private EventListener[] listeners;
054        private BaseSystemService[] services;
055        private IdGenerator idGenerator = new IdGenerator();
056        private Map<Object, Component> endpointToComponent = new IdentityHashMap<Object, Component>();
057    
058        public LwContainerExtra(Map components, Map endpoints, EventListener[] listeners, BaseSystemService[] services) {
059            this.service = new QName("http://servicemix.apache.org/lwcontainer", "extra");
060            this.endpoint = idGenerator.generateSanitizedId();
061            this.components = components;
062            this.endpoints = endpoints;
063            this.listeners = listeners;
064            this.services = services;
065        }
066    
067        public void activate() throws Exception {
068            if (components != null) {
069                for (Iterator it = components.entrySet().iterator(); it.hasNext();) {
070                    Map.Entry e = (Map.Entry) it.next();
071                    if (!(e.getKey() instanceof String)) {
072                        throw new JBIException("Component must have a non null string name");
073                    }
074                    if (!(e.getValue() instanceof Component)) {
075                        throw new JBIException("Component is not a known component");
076                    }
077                    String name = (String) e.getKey();
078                    getContainer().activateComponent((Component) e.getValue(), name);
079                    getContainer().getComponent(name).init();
080                }
081            }
082    
083            if (endpoints != null) {
084                initEndpoints();
085            }
086            if (listeners != null) {
087                for (int i = 0; i < listeners.length; i++) {
088                    getContainer().addListener(listeners[i]);
089                }
090            }
091            if (services != null) {
092                for (int i = 0; i < services.length; i++) {
093                    services[i].init(getContainer());
094                    services[i].start();
095                }
096            }
097        }
098    
099        public void deactivate() throws Exception {
100            // Remove endpoints
101            if (endpoints != null) {
102                for (Iterator it = endpoints.entrySet().iterator(); it.hasNext();) {
103                    Map.Entry e = (Map.Entry) it.next();
104                    List l = (List) e.getValue();
105                    for (Iterator itEp = l.iterator(); itEp.hasNext();) {
106                        Object endpoint = itEp.next();
107                        Component c = endpointToComponent.remove(endpoint);
108                        ((DefaultComponent) c).removeEndpoint((Endpoint) endpoint);
109                    }
110                }
111            }
112            // Deactivate components
113            if (components != null) {
114                for (Iterator it = components.entrySet().iterator(); it.hasNext();) {
115                    Map.Entry e = (Map.Entry) it.next();
116                    String name = (String) e.getKey();
117                    getContainer().deactivateComponent(name);
118                }
119            }
120            // Remove listeners
121            if (listeners != null) {
122                for (int i = 0; i < listeners.length; i++) {
123                    getContainer().removeListener(listeners[i]);
124                }
125            }
126            // Remove services
127            if (services != null) {
128                for (int i = 0; i < services.length; i++) {
129                    services[i].stop();
130                    services[i].shutDown();
131                }
132            }
133        }
134    
135        public ExchangeProcessor getProcessor() {
136            return null;
137        }
138    
139        public MessageExchange.Role getRole() {
140            return null;
141        }
142    
143        private void initEndpoints() throws Exception {
144            if (components == null) {
145                components = new LinkedHashMap();
146            }
147            Method getEndpointClassesMethod = DefaultComponent.class.getDeclaredMethod("getEndpointClasses", null);
148            getEndpointClassesMethod.setAccessible(true);
149            for (Iterator it = endpoints.entrySet().iterator(); it.hasNext();) {
150                Map.Entry e = (Map.Entry) it.next();
151                String key = (String) e.getKey();
152                List l = (List) e.getValue();
153                for (Iterator itEp = l.iterator(); itEp.hasNext();) {
154                    Object endpoint = itEp.next();
155                    Component c = null;
156                    if (key.length() > 0) {
157                        Component comp = (Component) components.get(key);
158                        if (comp == null) {
159                            throw new JBIException("Could not find component '" + key + "' specified for endpoint");
160                        }
161                        c = comp;
162                    } else {
163                        for (Iterator itCmp = components.values().iterator(); itCmp.hasNext();) {
164                            Component comp = (Component) itCmp.next();
165                            Class[] endpointClasses = (Class[]) getEndpointClassesMethod.invoke(comp, null);
166                            if (isKnownEndpoint(endpoint, endpointClasses)) {
167                                c = comp;
168                                break;
169                            }
170                        }
171                        if (c == null) {
172                            c = getComponentForEndpoint(getEndpointClassesMethod, endpoint);
173                            if (c == null) {
174                                throw new JBIException("Unable to find a component for endpoint class: " + endpoint.getClass());
175                            }
176                        }
177                    }
178                    ((DefaultComponent) c).addEndpoint((Endpoint) endpoint);
179                    endpointToComponent.put(endpoint, c);
180                }
181            }
182        }
183    
184        private Component getComponentForEndpoint(Method getEndpointClassesMethod, Object endpoint) throws Exception {
185            Properties namespaces = PropertiesLoaderUtils.loadAllProperties("META-INF/spring.handlers");
186            for (Iterator itNs = namespaces.keySet().iterator(); itNs.hasNext();) {
187                String namespaceURI = (String) itNs.next();
188                String uri = NamespaceHelper.createDiscoveryPathName(namespaceURI);
189                Properties props = PropertiesLoaderUtils.loadAllProperties(uri);
190                String compClassName = props.getProperty("component");
191                if (compClassName != null) {
192                    Class compClass = ClassUtils.forName(compClassName);
193                    Component comp = (Component) BeanUtils.instantiateClass(compClass);
194                    Class[] endpointClasses = (Class[]) getEndpointClassesMethod.invoke(comp, null);
195                    if (isKnownEndpoint(endpoint, endpointClasses)) {
196                        String name = chooseComponentName(comp);
197                        getContainer().activateComponent(comp, name);
198                        components.put(name, comp);
199                        return comp;
200                    }
201                }
202            }
203            return null;
204        }
205    
206        private String chooseComponentName(Object c) {
207            String className = c.getClass().getName();
208            if (className.startsWith("org.apache.servicemix.")) {
209                int idx1 = className.lastIndexOf('.');
210                int idx0 = className.lastIndexOf('.', idx1 - 1);
211                String name = "servicemix-" + className.substring(idx0 + 1, idx1);
212                return name + "-" + createComponentID();
213            }
214            return createComponentID();
215        }
216    
217        private boolean isKnownEndpoint(Object endpoint, Class[] knownClasses) {
218            if (knownClasses != null) {
219                for (int i = 0; i < knownClasses.length; i++) {
220                    if (knownClasses[i].isInstance(endpoint)) {
221                        return true;
222                    }
223                }
224            }
225            return false;
226        }
227    
228        private JBIContainer getContainer() {
229            ComponentContext context = getServiceUnit().getComponent().getComponentContext();
230            if (context instanceof ComponentContextImpl) {
231                return ((ComponentContextImpl) context).getContainer();
232            }
233            throw new IllegalStateException("LwContainer component can only be deployed in ServiceMix");
234        }
235    
236        protected String createComponentID() {
237            return idGenerator.generateId();
238        }
239    
240    }