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