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.framework;
018    
019    import java.io.File;
020    import java.util.ArrayList;
021    import java.util.Collection;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.concurrent.ConcurrentHashMap;
025    import java.util.concurrent.CopyOnWriteArrayList;
026    
027    import javax.jbi.JBIException;
028    import javax.jbi.component.Component;
029    import javax.jbi.component.ComponentContext;
030    import javax.jbi.management.DeploymentException;
031    import javax.jbi.servicedesc.ServiceEndpoint;
032    import javax.management.JMException;
033    import javax.management.MBeanAttributeInfo;
034    import javax.management.ObjectName;
035    import javax.xml.namespace.QName;
036    
037    import org.w3c.dom.Document;
038    import org.w3c.dom.DocumentFragment;
039    import org.w3c.dom.Element;
040    import org.w3c.dom.Node;
041    import org.w3c.dom.NodeList;
042    
043    import org.apache.commons.logging.Log;
044    import org.apache.commons.logging.LogFactory;
045    import org.apache.servicemix.executors.Executor;
046    import org.apache.servicemix.jbi.container.ActivationSpec;
047    import org.apache.servicemix.jbi.container.EnvironmentContext;
048    import org.apache.servicemix.jbi.container.JBIContainer;
049    import org.apache.servicemix.jbi.container.ServiceAssemblyEnvironment;
050    import org.apache.servicemix.jbi.container.SubscriptionSpec;
051    import org.apache.servicemix.jbi.deployment.ServiceAssembly;
052    import org.apache.servicemix.jbi.deployment.ServiceUnit;
053    import org.apache.servicemix.jbi.management.AttributeInfoHelper;
054    import org.apache.servicemix.jbi.management.BaseSystemService;
055    import org.apache.servicemix.jbi.messaging.DeliveryChannelImpl;
056    import org.apache.servicemix.jbi.messaging.MessageExchangeImpl;
057    import org.apache.servicemix.jbi.resolver.URIResolver;
058    import org.apache.servicemix.jbi.servicedesc.AbstractServiceEndpoint;
059    import org.apache.servicemix.jbi.servicedesc.DynamicEndpoint;
060    import org.apache.servicemix.jbi.servicedesc.InternalEndpoint;
061    import org.apache.servicemix.jbi.util.DOMUtil;
062    import org.apache.servicemix.jbi.util.WSAddressingConstants;
063    
064    /**
065     * Registry - state infomation including running state, SA's deployed etc.
066     * 
067     * @version $Revision: 695373 $
068     */
069    public class Registry extends BaseSystemService implements RegistryMBean {
070        
071        private static final Log LOG = LogFactory.getLog(Registry.class);
072        
073        private ComponentRegistry componentRegistry;
074        private EndpointRegistry endpointRegistry;
075        private SubscriptionRegistry subscriptionRegistry;
076        private ServiceAssemblyRegistry serviceAssemblyRegistry;
077        private Map<String, SharedLibrary> sharedLibraries;
078        private Map<String, ServiceUnitLifeCycle> serviceUnits;
079        private List<ServiceAssemblyLifeCycle> pendingAssemblies;
080        private List<ComponentMBeanImpl> pendingComponents;
081        private Executor executor;
082    
083        /**
084         * Constructor
085         */
086        public Registry() {
087            this.componentRegistry = new ComponentRegistry(this);
088            this.endpointRegistry = new EndpointRegistry(this);
089            this.subscriptionRegistry = new SubscriptionRegistry(this);
090            this.serviceAssemblyRegistry = new ServiceAssemblyRegistry(this);
091            this.serviceUnits = new ConcurrentHashMap<String, ServiceUnitLifeCycle>();
092            this.pendingAssemblies = new CopyOnWriteArrayList<ServiceAssemblyLifeCycle>();
093            this.sharedLibraries = new ConcurrentHashMap<String, SharedLibrary>();
094            this.pendingComponents = new CopyOnWriteArrayList<ComponentMBeanImpl>();
095        }
096        
097        /**
098         * Get the description
099         * @return description
100         */
101        public String getDescription() {
102            return "Registry of Components/SU's and Endpoints";
103        }
104    
105        protected Class getServiceMBean() {
106            return RegistryMBean.class;
107        }
108    
109        
110        public ComponentRegistry getComponentRegistry() {
111            return componentRegistry;
112        }
113    
114        public EndpointRegistry getEndpointRegistry() {
115            return endpointRegistry;
116        }
117    
118        public void init(JBIContainer container) throws JBIException {
119            super.init(container);
120            executor = container.getExecutorFactory().createExecutor("services.registry");
121        }
122        
123        /**
124         * start brokering
125         * 
126         * @throws JBIException
127         */
128        public void start() throws JBIException {
129            componentRegistry.start();
130            serviceAssemblyRegistry.start();
131            super.start();
132        }
133    
134        /**
135         * stop brokering
136         * 
137         * @throws JBIException
138         */
139        public void stop() throws JBIException {
140            serviceAssemblyRegistry.stop();
141            componentRegistry.stop();
142            super.stop();
143        }
144    
145        /**
146         * shutdown all Components
147         * 
148         * @throws JBIException
149         */
150        public void shutDown() throws JBIException {
151            serviceAssemblyRegistry.shutDown();
152            componentRegistry.shutDown();
153            super.shutDown();
154            container.getManagementContext().unregisterMBean(this);
155            executor.shutdown();
156        }
157        
158        /**
159         * @return the EnvironmentContext
160         */
161        protected EnvironmentContext getEnvironmentContext() {
162            return container.getEnvironmentContext();
163        }
164        
165        /**
166         * @return true if the container is embedded
167         */
168        protected boolean isContainerEmbedded() {
169            return container.isEmbedded();
170        }
171    
172        protected InternalEndpoint matchEndpointByName(ServiceEndpoint[] endpoints, String endpointName) {
173            InternalEndpoint result = null;
174            if (endpoints != null && endpointName != null && endpointName.length() > 0) {
175                for (int i = 0; i < endpoints.length; i++) {
176                    if (endpoints[i].getEndpointName().equals(endpointName)) {
177                        result = (InternalEndpoint) endpoints[i];
178                        break;
179                    }
180                }
181            }
182            return result;
183        }
184    
185        /**
186         * @param context
187         * @param serviceName
188         * @param endpointName
189         * @return EndPointReference
190         * @throws JBIException
191         */
192        public ServiceEndpoint activateEndpoint(ComponentContextImpl context, 
193                                                QName serviceName,
194                                                String endpointName) throws JBIException {
195            return endpointRegistry.registerInternalEndpoint(context, serviceName, endpointName);
196        }
197    
198        public ServiceEndpoint[] getEndpointsForComponent(ComponentNameSpace cns) {
199            return endpointRegistry.getEndpointsForComponent(cns);
200        }
201        
202        /**
203         * @param interfaceName qualified name
204         * @return an array of available endpoints for the specified interface name;
205         */
206        public ServiceEndpoint[] getEndpointsForInterface(QName interfaceName) {
207            return endpointRegistry.getEndpointsForInterface(interfaceName);
208        }
209    
210        /**
211         * @param provider
212         * @param serviceEndpoint
213         */
214        public void deactivateEndpoint(ComponentContext provider, InternalEndpoint serviceEndpoint) {
215            endpointRegistry.unregisterInternalEndpoint(provider, serviceEndpoint);
216        }
217    
218        /**
219         * Retrieve the service description metadata for the specified endpoint.
220         * <p>
221         * Note that the result can use either the WSDL 1.1 or WSDL 2.0 description language.
222         * 
223         * @param endpoint endpoint reference; must be non-null.
224         * @return metadata describing endpoint, or <code>null</code> if metadata is unavailable.
225         * @throws JBIException invalid endpoint reference.
226         */
227        public Document getEndpointDescriptor(ServiceEndpoint endpoint) throws JBIException {
228            if (!(endpoint instanceof AbstractServiceEndpoint)) {
229                throw new JBIException("Descriptors can not be queried for external endpoints");
230            }
231            AbstractServiceEndpoint se = (AbstractServiceEndpoint) endpoint;
232            // TODO: what if the endpoint is linked or dynamic
233            ComponentMBeanImpl component = getComponent(se.getComponentNameSpace());
234            return component.getComponent().getServiceDescription(endpoint);
235        }
236    
237        /**
238         * Resolve the given endpoint reference into a service endpoint. This is called by the component when it has an EPR
239         * that it wants to resolve into a service endpoint.
240         * <p>
241         * Note that the service endpoint returned refers to a dynamic endpoint; the endpoint will exist only as long as
242         * this component retains a strong reference to the object returned by this method. The endpoint may not be included
243         * in the list of "activated" endpoints.
244         * 
245         * @param epr endpoint reference as an XML fragment; must be non-null.
246         * @return the service endpoint corresponding to the given endpoint reference; <code>null</code> if the reference
247         * cannot be resolved.
248         */
249        public ServiceEndpoint resolveEndpointReference(DocumentFragment epr) {
250            for (ComponentMBeanImpl connector : getComponents()) {
251                ServiceEndpoint se = connector.getComponent().resolveEndpointReference(epr);
252                if (se != null) {
253                    return new DynamicEndpoint(connector.getComponentNameSpace(), se, epr);  
254                }
255            }
256            ServiceEndpoint se = resolveInternalEPR(epr);
257            if (se != null) {
258                return se;
259            }
260            return resolveStandardEPR(epr);
261        }
262        
263        /**
264         * <p>
265         * Resolve an internal JBI EPR conforming to the format defined in the JBI specification.
266         * </p>
267         * 
268         * <p>The EPR would look like:
269         * <pre>
270         * <jbi:end-point-reference xmlns:jbi="http://java.sun.com/xml/ns/jbi/end-point-reference"
271         *      jbi:end-point-name="endpointName" 
272         *      jbi:service-name="foo:serviceName" 
273         *      xmlns:foo="urn:FooNamespace"/>
274         * </pre>
275         * </p>
276         * 
277         * @author Maciej Szefler m s z e f l e r @ g m a i l . c o m 
278         * @param epr EPR fragment
279         * @return internal service endpoint corresponding to the EPR, or <code>null</code>
280         *         if the EPR is not an internal EPR or if the EPR cannot be resolved
281         */
282        public ServiceEndpoint resolveInternalEPR(DocumentFragment epr) {
283            if (epr == null) {
284                throw new NullPointerException("resolveInternalEPR(epr) called with null epr.");
285            }
286            NodeList nl = epr.getChildNodes();
287            for (int i = 0; i < nl.getLength(); ++i) {
288                Node n = nl.item(i);
289                if (n.getNodeType() != Node.ELEMENT_NODE) {
290                    continue;
291                }
292                Element el = (Element) n;
293                // Namespace should be "http://java.sun.com/jbi/end-point-reference"
294                if (el.getNamespaceURI() == null 
295                        || !el.getNamespaceURI().equals("http://java.sun.com/jbi/end-point-reference")) 
296                {
297                    continue;
298                }
299                if (el.getLocalName() == null || !el.getLocalName().equals("end-point-reference")) {
300                    continue;
301                }
302                String serviceName = el.getAttributeNS(el.getNamespaceURI(), "service-name");
303                // Now the DOM pain-in-the-you-know-what: we need to come up with QName for this; 
304                // fortunately, there is only one place where the xmlns:xxx attribute could be, on 
305                // the end-point-reference element!
306                QName serviceQName = DOMUtil.createQName(el, serviceName);
307                String endpointName = el.getAttributeNS(el.getNamespaceURI(), "end-point-name");
308                return getInternalEndpoint(serviceQName, endpointName);
309            }
310            return null;
311        }
312        
313        /**
314         * Resolve a standard EPR understood by ServiceMix container.
315         * Currently, the supported syntax is the WSA one, the address uri
316         * being parsed with the following possiblities:
317         *    jbi:endpoint:service-namespace/service-name/endpoint
318         *    jbi:endpoint:service-namespace:service-name:endpoint
319         *    
320         * The full EPR will look like:
321         *   <epr xmlns:wsa="http://www.w3.org/2005/08/addressing">
322         *     <wsa:Address>jbi:endpoint:http://foo.bar.com/service/endpoint</wsa:Address>
323         *   </epr>
324         *   
325         * BCs should also be able to resolve such EPR but using their own URI parsing,
326         * for example:
327         *   <epr xmlns:wsa="http://www.w3.org/2005/08/addressing">
328         *     <wsa:Address>http://foo.bar.com/myService?http.soap=true</wsa:Address>
329         *   </epr>
330         * 
331         * or
332         *   <epr xmlns:wsa="http://www.w3.org/2005/08/addressing">
333         *     <wsa:Address>jms://activemq/queue/FOO.BAR?persistent=true</wsa:Address>
334         *   </epr>
335         *    
336         * Note that the separator should be same as the one used in the namespace
337         * depending on the namespace:
338         *     http://foo.bar.com  => '/'
339         *     urn:foo:bar         => ':' 
340         *    
341         * The syntax is the same as the one that can be used to specifiy a target
342         * for a JBI exchange with the restriction that it only allows the
343         * endpoint subprotocol to be used. 
344         * 
345         * @param epr
346         * @return
347         */
348        public ServiceEndpoint resolveStandardEPR(DocumentFragment epr) {
349            try {
350                NodeList children = epr.getChildNodes();
351                for (int i = 0; i < children.getLength(); ++i) {
352                    Node n = children.item(i);
353                    if (n.getNodeType() != Node.ELEMENT_NODE) {
354                        continue;
355                    }
356                    Element elem = (Element) n;
357                    String[] namespaces = new String[] {WSAddressingConstants.WSA_NAMESPACE_200508,
358                                                        WSAddressingConstants.WSA_NAMESPACE_200408,
359                                                        WSAddressingConstants.WSA_NAMESPACE_200403,
360                                                        WSAddressingConstants.WSA_NAMESPACE_200303 };
361                    NodeList nl = null;
362                    for (int ns = 0; ns < namespaces.length; ns++) {
363                        NodeList tnl = elem.getElementsByTagNameNS(namespaces[ns], WSAddressingConstants.EL_ADDRESS);
364                        if (tnl.getLength() == 1) {
365                            nl = tnl;
366                            break;
367                        }
368                    }
369                    if (nl != null) {
370                        Element address = (Element) nl.item(0);
371                        String uri = DOMUtil.getElementText(address);
372                        if (uri != null) {
373                            uri = uri.trim();
374                        }
375                        if (uri.startsWith("endpoint:")) {
376                            uri = uri.substring("endpoint:".length());
377                            String[] parts = URIResolver.split3(uri);
378                            return getInternalEndpoint(new QName(parts[0], parts[1]), parts[2]);
379                        } else if (uri.startsWith("service:")) {
380                            uri = uri.substring("service:".length());
381                            String[] parts = URIResolver.split2(uri);
382                            return getEndpoint(new QName(parts[0], parts[1]), parts[1]);
383                        }
384                        // TODO should we support interface: and operation: here?
385                    }
386                }
387            } catch (Exception e) {
388                LOG.debug("Unable to resolve EPR: " + e);
389            }
390            return null;
391        }
392    
393        /**
394         * @param provider
395         * @param externalEndpoint the external endpoint to be registered, must be non-null.
396         * @throws JBIException 
397         */
398        public void registerExternalEndpoint(ComponentNameSpace cns, ServiceEndpoint externalEndpoint) throws JBIException {
399            if (externalEndpoint != null) {
400                endpointRegistry.registerExternalEndpoint(cns, externalEndpoint);
401            }
402        }
403    
404        /**
405         * @param provider
406         * @param externalEndpoint the external endpoint to be deregistered; must be non-null.
407         */
408        public void deregisterExternalEndpoint(ComponentNameSpace cns, ServiceEndpoint externalEndpoint) {
409            endpointRegistry.unregisterExternalEndpoint(cns, externalEndpoint);
410        }
411    
412        /**
413         * @param service
414         * @param name
415         * @return endpoint
416         */
417        public ServiceEndpoint getEndpoint(QName service, String name) {
418            return endpointRegistry.getEndpoint(service, name);
419        }
420        
421        public ServiceEndpoint getInternalEndpoint(QName service, String name) {
422            return endpointRegistry.getInternalEndpoint(service, name);
423        }
424    
425        /**
426         * @param serviceName
427         * @return endpoints
428         */
429        public ServiceEndpoint[] getEndpointsForService(QName serviceName) {
430            return endpointRegistry.getEndpointsForService(serviceName);
431        }
432    
433        /**
434         * @param interfaceName
435         * @return endpoints
436         */
437        public ServiceEndpoint[] getExternalEndpoints(QName interfaceName) {
438            return endpointRegistry.getExternalEndpointsForInterface(interfaceName);
439        }
440    
441        /**
442         * @param serviceName
443         * @return endpoints
444         */
445        public ServiceEndpoint[] getExternalEndpointsForService(QName serviceName) {
446            return endpointRegistry.getExternalEndpointsForService(serviceName);
447        }
448    
449        /**
450         * REgister a local Component
451         * 
452         * @param name
453         * @param description
454         * @param component
455         * @param dc
456         * @param binding
457         * @param service
458         * @return ComponentConnector
459         * @throws JBIException
460         */
461        public ComponentMBeanImpl registerComponent(ComponentNameSpace name, 
462                                                    String description,
463                                                    Component component,
464                                                    boolean binding, 
465                                                    boolean service,
466                                                    String[] sharedLibs) throws JBIException {
467            return componentRegistry.registerComponent(name, description, component, binding, service, sharedLibs);
468        }
469    
470        /**
471         * @param component
472         * @return ComponentConnector
473         */
474        public void deregisterComponent(ComponentMBeanImpl component) {
475            componentRegistry.deregisterComponent(component);
476        }
477    
478        /**
479         * @return all local ComponentConnectors
480         */
481        public Collection<ComponentMBeanImpl> getComponents() {
482            return componentRegistry.getComponents();
483        }
484    
485        /**
486         * Get a Component
487         * @param cns
488         * @return the Component
489         */
490        public ComponentMBeanImpl getComponent(ComponentNameSpace cns) {
491            return componentRegistry.getComponent(cns);
492        }
493        
494        /**
495         * Get a Component
496         * @param name
497         * @return the Componment
498         */
499        public ComponentMBeanImpl getComponent(String name) {
500            ComponentNameSpace cns = new ComponentNameSpace(container.getName(), name);
501            return getComponent(cns);
502        }
503        
504        /**
505         * Get a list of all engines currently installed.
506         * @return array of JMX object names of all installed SEs.
507         */
508        public ObjectName[] getEngineComponents() {
509            ObjectName[] result = null;
510            List<ObjectName> tmpList = new ArrayList<ObjectName>();
511            for (ComponentMBeanImpl lcc : getComponents()) {
512                if (!lcc.isPojo() && lcc.isService() && lcc.getMBeanName() != null) {
513                    tmpList.add(lcc.getMBeanName());
514                }
515            }
516            result = new ObjectName[tmpList.size()];
517            tmpList.toArray(result);
518            return result;
519            
520        }
521        
522        /**
523         * Get a list of all binding components currently installed.
524         * @return array of JMX object names of all installed BCs.
525         */
526        public ObjectName[] getBindingComponents() {
527            ObjectName[] result = null;
528            List<ObjectName> tmpList = new ArrayList<ObjectName>();
529            for (ComponentMBeanImpl lcc : getComponents()) {
530                if (!lcc.isPojo() && lcc.isBinding() && lcc.getMBeanName() != null) {
531                    tmpList.add(lcc.getMBeanName());
532                }
533            }
534            result = new ObjectName[tmpList.size()];
535            tmpList.toArray(result);
536            return result;
537        }
538    
539        /**
540         * Get a list of all pojos currently installed.
541         * @return array of JMX object names of all installed PJOJO Conponents.
542         */
543        public ObjectName[] getPojoComponents() {
544            ObjectName[] result = null;
545            List<ObjectName> tmpList = new ArrayList<ObjectName>();
546            for (ComponentMBeanImpl lcc : getComponents()) {
547                if (lcc.isPojo() && lcc.getMBeanName() != null) {
548                    tmpList.add(lcc.getMBeanName());
549                }
550            }
551            result = new ObjectName[tmpList.size()];
552            tmpList.toArray(result);
553            return result;
554        }
555        
556        /**
557         * Register All subscriptions
558         * @param context 
559         * @param as 
560         */
561        public void registerSubscriptions(ComponentContextImpl context, ActivationSpec as) {
562            QName service = as.getService();
563            String endpointName = as.getEndpoint();
564            InternalEndpoint endpoint = new InternalEndpoint(context.getComponentNameSpace(), endpointName, service);
565            SubscriptionSpec[] specs = as.getSubscriptions();
566            if (specs != null) {
567                for (int i = 0; i < specs.length; i++) {
568                    registerSubscription(context, specs[i], endpoint);
569                }
570            }
571        }
572        
573        /**
574         * Deregister All subscriptions
575         * @param context
576         * @param as
577         */
578        public void deregisterSubscriptions(ComponentContextImpl context, ActivationSpec as) {
579            SubscriptionSpec[] specs = as.getSubscriptions();
580            if (specs != null) {
581                for (int i = 0; i < specs.length; i++) {
582                    deregisterSubscription(context, specs[i]);
583                }
584            }
585        }
586        
587        /**
588         * @param context 
589         * @param subscription
590         * @param endpoint
591         */
592        public void registerSubscription(ComponentContextImpl context, SubscriptionSpec subscription, ServiceEndpoint endpoint) {
593            InternalEndpoint sei = (InternalEndpoint)endpoint;
594            subscription.setName(context.getComponentNameSpace());
595            subscriptionRegistry.registerSubscription(subscription, sei);
596        }
597    
598        /**
599         * @param context 
600         * @param subscription
601         * @return the ServiceEndpoint
602         */
603        public InternalEndpoint deregisterSubscription(ComponentContextImpl context, SubscriptionSpec subscription) {
604            subscription.setName(context.getComponentNameSpace());
605            return subscriptionRegistry.deregisterSubscription(subscription);
606        }
607        
608        
609        /**
610         * @param exchange 
611         * @return a List of matching endpoints - can return null if no matches
612         */
613        public List<InternalEndpoint> getMatchingSubscriptionEndpoints(MessageExchangeImpl exchange) {
614            return subscriptionRegistry.getMatchingSubscriptionEndpoints(exchange);
615        }
616        
617        /**
618         * Register a service assembly
619         * @param sa
620         * @return true if not already registered
621         * @throws DeploymentException 
622         */
623        public ServiceAssemblyLifeCycle registerServiceAssembly(ServiceAssembly sa,
624                                                                ServiceAssemblyEnvironment env) throws DeploymentException {
625            return serviceAssemblyRegistry.register(sa, env);
626        }
627        
628        /**
629         * Register a service assembly
630         * @param sa
631         * @return true if not already registered
632         * @throws DeploymentException 
633         */
634        public ServiceAssemblyLifeCycle registerServiceAssembly(ServiceAssembly sa,
635                                                                String[] suKeys,
636                                                                ServiceAssemblyEnvironment env) throws DeploymentException {
637            return serviceAssemblyRegistry.register(sa, suKeys, env);
638        }
639        
640        /**
641         * Un-register a service assembly
642         * @param saName 
643         * @return true if successfully unregistered
644         */
645        public boolean unregisterServiceAssembly(String saName) {
646            return serviceAssemblyRegistry.unregister(saName);
647        }
648        
649        /**
650         * Get a named ServiceAssembly
651         * @param name
652         * @return the ServiceAssembly or null if it doesn't exist
653         */
654        public ServiceAssemblyLifeCycle getServiceAssembly(String saName) {
655            return serviceAssemblyRegistry.getServiceAssembly(saName);
656        }
657    
658        /**
659         * Returns a list of Service Units that are currently deployed to the given component.
660         * 
661         * @param componentName name of the component.
662         * @return List of deployed service units
663         */
664        public ServiceUnitLifeCycle[] getDeployedServiceUnits(String componentName)  {
665            List<ServiceUnitLifeCycle> tmpList = new ArrayList<ServiceUnitLifeCycle>();
666            for (ServiceUnitLifeCycle su : serviceUnits.values()) {
667                if (su.getComponentName().equals(componentName)) {
668                    tmpList.add(su);
669                }
670            }
671            ServiceUnitLifeCycle[] result = new ServiceUnitLifeCycle[tmpList.size()];
672            tmpList.toArray(result);
673            return result;
674        }
675    
676        /**
677         * Return a list of all service units.
678         * 
679         * @return list of all service units
680         */
681        public Collection<ServiceUnitLifeCycle> getServiceUnits() {
682            return serviceUnits.values();
683        }
684        
685        public Collection<ServiceAssemblyLifeCycle> getServiceAssemblies() {
686            return serviceAssemblyRegistry.getServiceAssemblies();
687        }
688        
689        /**
690         * Returns a list of Service Assemblies deployed to the JBI enviroment.
691         * 
692         * @return list of Service Assembly Name's.
693         */
694        public String[] getDeployedServiceAssemblies()  {
695            return serviceAssemblyRegistry.getDeployedServiceAssemblies();
696        }
697        
698        /**
699         * Returns a list of Service Assemblies that contain SUs for the given component.
700         * 
701         * @param componentName name of the component.
702         * @return list of Service Assembly names.
703         */
704        public String[] getDeployedServiceAssembliesForComponent(String componentName)  {
705            return serviceAssemblyRegistry.getDeployedServiceAssembliesForComponent(componentName);
706        }
707    
708        /**
709         * Returns a list of components(to which SUs are targeted for) in a Service Assembly.
710         * 
711         * @param saName name of the service assembly.
712         * @return list of component names.
713         */
714        public String[] getComponentsForDeployedServiceAssembly(String saName) {
715            return serviceAssemblyRegistry.getComponentsForDeployedServiceAssembly(saName);
716        }
717    
718        /**
719         * Returns a boolean value indicating whether the SU is currently deployed.
720         * 
721         * @param componentName - name of component.
722         * @param suName - name of the Service Unit.
723         * @return boolean value indicating whether the SU is currently deployed.
724         */
725        public boolean isSADeployedServiceUnit(String componentName, String suName)  {
726            return serviceAssemblyRegistry.isDeployedServiceUnit(componentName, suName);
727        }
728        
729        /**
730         * Get a ServiceUnit by its key.
731         * 
732         * @param suKey the key of the service unit
733         * @return the ServiceUnit or null of it doesn't exist
734         */
735        public ServiceUnitLifeCycle getServiceUnit(String suKey) {
736            return serviceUnits.get(suKey);
737        }
738        
739        /**
740         * Register a ServiceUnit.
741         * 
742         * @param su the service unit to register
743         * @param serviceAssembly the service assembly the service unit belongs to 
744         * @return the service unit key
745         */
746        public String registerServiceUnit(ServiceUnit su, String saName, File suDir) {
747            ServiceUnitLifeCycle sulc = new ServiceUnitLifeCycle(
748                    su, 
749                    saName, 
750                    this,
751                    suDir);
752            this.serviceUnits.put(sulc.getKey(), sulc);
753            try {
754                ObjectName objectName = getContainer().getManagementContext().createObjectName(sulc);
755                getContainer().getManagementContext().registerMBean(objectName, sulc, ServiceUnitMBean.class);
756            } catch (JMException e) {
757                LOG.error("Could not register MBean for service unit", e);
758            }
759            return sulc.getKey();
760        }
761        
762        /**
763         * Unregister a ServiceUnit by its key.
764         * 
765         * @param suKey the key of the service unit
766         */
767        public void unregisterServiceUnit(String suKey) {
768            ServiceUnitLifeCycle sulc = this.serviceUnits.remove(suKey);
769            if (sulc != null) {
770                try {
771                    getContainer().getManagementContext().unregisterMBean(sulc);
772                } catch (JBIException e) {
773                    LOG.error("Could not unregister MBean for service unit", e);
774                }
775            }
776        }
777        
778        public void registerSharedLibrary(org.apache.servicemix.jbi.deployment.SharedLibrary sl,
779                                          File installationDir) {
780            SharedLibrary library = new SharedLibrary(sl, installationDir);
781            this.sharedLibraries.put(library.getName(), library);
782            try {
783                ObjectName objectName = getContainer().getManagementContext().createObjectName(library);
784                getContainer().getManagementContext().registerMBean(objectName, library, SharedLibraryMBean.class);
785            } catch (JMException e) {
786                LOG.error("Could not register MBean for service unit", e);
787            }
788            checkPendingComponents();
789        }
790        
791        public void unregisterSharedLibrary(String name) {
792            // TODO: check for components depending on this library,
793            // shutdown them and add them to the list of pending components
794            SharedLibrary sl = this.sharedLibraries.remove(name);
795            if (sl != null) {
796                try {
797                    getContainer().getManagementContext().unregisterMBean(sl);
798                    sl.dispose();
799                } catch (JBIException e) {
800                    LOG.error("Could not unregister MBean for shared library", e);
801                }
802            }
803        }
804        
805        public SharedLibrary getSharedLibrary(String name) {
806            return sharedLibraries.get(name);
807        }
808        
809        public Collection<SharedLibrary> getSharedLibraries() {
810            return sharedLibraries.values();
811        }
812    
813        public void registerEndpointConnection(QName fromSvc, String fromEp, QName toSvc, String toEp, String link) throws JBIException {
814            endpointRegistry.registerEndpointConnection(fromSvc, fromEp, toSvc, toEp, link);
815        }
816    
817        public void unregisterEndpointConnection(QName fromSvc, String fromEp) {
818            endpointRegistry.unregisterEndpointConnection(fromSvc, fromEp);
819        }
820        
821        public void registerInterfaceConnection(QName fromItf, QName toSvc, String toEp) throws JBIException {
822            endpointRegistry.registerInterfaceConnection(fromItf, toSvc, toEp);
823        }
824    
825        public void unregisterInterfaceConnection(QName fromItf) {
826            endpointRegistry.unregisterInterfaceConnection(fromItf);
827        }
828    
829        public void registerRemoteEndpoint(ServiceEndpoint endpoint) {
830            endpointRegistry.registerRemoteEndpoint((InternalEndpoint) endpoint);
831        }
832    
833        public void unregisterRemoteEndpoint(ServiceEndpoint endpoint) {
834            endpointRegistry.unregisterRemoteEndpoint((InternalEndpoint) endpoint);
835        }
836    
837        public void checkPendingAssemblies() {
838            executor.execute(new Runnable() {
839                public void run() {
840                    startPendingAssemblies();
841                }
842            });
843        }
844    
845        public void addPendingAssembly(ServiceAssemblyLifeCycle sa) {
846            if (!pendingAssemblies.contains(sa)) {
847                pendingAssemblies.add(sa);
848            }
849        }
850        
851        protected synchronized void startPendingAssemblies() {
852            for (ServiceAssemblyLifeCycle sa : pendingAssemblies) {
853                ServiceUnitLifeCycle[] sus = sa.getDeployedSUs();
854                boolean ok = true;
855                for (int i = 0; i < sus.length; i++) {
856                    ComponentMBeanImpl c = getComponent(sus[i].getComponentName());
857                    if (c == null || !c.isStarted()) {
858                        ok = false;
859                        break;
860                    }
861                }
862                if (ok) {
863                    try {
864                        sa.restore();
865                        pendingAssemblies.remove(sa);
866                    } catch (Exception e) {
867                        LOG.error("Error trying to restore service assembly state", e);
868                    }
869                }
870            }
871        }
872    
873        public void checkPendingComponents() {
874            executor.execute(new Runnable() {
875                public void run() {
876                    startPendingComponents();
877                }
878            });
879        }
880    
881        public void addPendingComponent(ComponentMBeanImpl comp) {
882            if (!pendingComponents.contains(comp)) {
883                pendingComponents.add(comp);
884            }
885        }
886        
887        protected synchronized void startPendingComponents() {
888            for (ComponentMBeanImpl lcc : pendingComponents) {
889                // TODO: restore component state if 
890            }
891        }
892    
893        public ObjectName[] getComponentNames() {
894            List<ObjectName> tmpList = new ArrayList<ObjectName>();
895            for (ComponentMBeanImpl lcc : getComponents()) {
896                tmpList.add(container.getManagementContext().createObjectName(lcc));
897            }
898            return tmpList.toArray(new ObjectName[tmpList.size()]);
899        }
900        
901        public ObjectName[] getEndpointNames() {
902            List<ObjectName> tmpList = new ArrayList<ObjectName>();
903            for (Endpoint ep : container.getRegistry().getEndpointRegistry().getEndpointMBeans()) {
904                tmpList.add(container.getManagementContext().createObjectName(ep));
905            }
906            return tmpList.toArray(new ObjectName[tmpList.size()]);
907        }
908    
909        public ObjectName[] getServiceAssemblyNames() {
910            List<ObjectName> tmpList = new ArrayList<ObjectName>();
911            for (ServiceAssemblyLifeCycle sa : getServiceAssemblies()) {
912                tmpList.add(container.getManagementContext().createObjectName(sa));
913            }
914            return tmpList.toArray(new ObjectName[tmpList.size()]);
915        }
916    
917        public ObjectName[] getServiceUnitNames() {
918            List<ObjectName> tmpList = new ArrayList<ObjectName>();
919            for (ServiceUnitLifeCycle su : serviceUnits.values()) {
920                tmpList.add(container.getManagementContext().createObjectName(su));
921            }
922            return tmpList.toArray(new ObjectName[tmpList.size()]);
923        }
924    
925        public ObjectName[] getSharedLibraryNames() {
926            List<ObjectName> tmpList = new ArrayList<ObjectName>();
927            for (SharedLibrary sl : sharedLibraries.values()) {
928                tmpList.add(container.getManagementContext().createObjectName(sl));
929            }
930            return tmpList.toArray(new ObjectName[tmpList.size()]);
931        } 
932        
933        /**
934         * Get an array of MBeanAttributeInfo
935         * 
936         * @return array of AttributeInfos
937         * @throws JMException
938         */
939        public MBeanAttributeInfo[] getAttributeInfos() throws JMException {
940            AttributeInfoHelper helper = new AttributeInfoHelper();
941            helper.addAttribute(getObjectToManage(), "componentNames", "list of components");
942            helper.addAttribute(getObjectToManage(), "serviceUnitNames", "list of service units");
943            helper.addAttribute(getObjectToManage(), "serviceAssemblyNames", "list of service assemblies");
944            helper.addAttribute(getObjectToManage(), "endpointNames", "list of endpoints");
945            helper.addAttribute(getObjectToManage(), "sharedLibraryNames", "list of shared libraries");
946            return AttributeInfoHelper.join(super.getAttributeInfos(), helper.getAttributeInfos());
947        }
948    
949        /**
950         * Cancel pending exchanges in all components
951         */
952        public void cancelPendingExchanges() {
953            for (ComponentMBeanImpl mbean : componentRegistry.getComponents()) {
954                DeliveryChannelImpl channel = mbean.getDeliveryChannel();
955                if (channel != null) {
956                    channel.cancelPendingExchanges();
957                }
958            }
959            
960        }
961    
962    }