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.util.MissingResourceException;
020    import java.util.logging.Logger;
021    
022    import javax.jbi.JBIException;
023    import javax.jbi.component.Component;
024    import javax.jbi.component.ComponentContext;
025    import javax.jbi.management.MBeanNames;
026    import javax.jbi.messaging.DeliveryChannel;
027    import javax.jbi.servicedesc.ServiceEndpoint;
028    import javax.management.MBeanServer;
029    import javax.management.ObjectName;
030    import javax.naming.InitialContext;
031    import javax.xml.namespace.QName;
032    
033    import org.w3c.dom.Document;
034    import org.w3c.dom.DocumentFragment;
035    
036    import org.apache.commons.logging.Log;
037    import org.apache.commons.logging.LogFactory;
038    import org.apache.servicemix.jbi.container.ActivationSpec;
039    import org.apache.servicemix.jbi.container.ComponentEnvironment;
040    import org.apache.servicemix.jbi.container.JBIContainer;
041    import org.apache.servicemix.jbi.container.SubscriptionSpec;
042    import org.apache.servicemix.jbi.servicedesc.InternalEndpoint;
043    
044    /**
045     * This context provides access to data needed by all JBI components running in the JBI environment.
046     * 
047     * @version $Revision: 3095 $
048     */
049    public class ComponentContextImpl implements ComponentContext, MBeanNames {
050        
051        private static final Log LOG = LogFactory.getLog(ComponentContextImpl.class);
052        
053        private ComponentNameSpace componentName;
054        private ComponentEnvironment environment;
055        private JBIContainer container;
056        private Component component;
057        private DeliveryChannel deliveryChannel;
058        private ActivationSpec activationSpec;
059        private boolean activated;
060    
061        /**
062         * Constructor
063         * 
064         * @param container
065         * @param componentName
066         */
067        public ComponentContextImpl(JBIContainer container, ComponentNameSpace componentName) {
068            this.componentName = componentName;
069            this.container = container;
070        }
071    
072        /**
073         * Activate the ComponentContext
074         * 
075         * @param comp
076         * @param channel
077         * @param env
078         * @param spec
079         * @param installRoot
080         */
081        public void activate(Component comp, 
082                             ComponentEnvironment env,
083                             ActivationSpec spec) {
084            this.component = comp;
085            this.environment = env;
086            this.activationSpec = spec;
087            activated = true;
088            //activate and subscriptions
089            container.getRegistry().registerSubscriptions(this, spec);
090        }
091    
092        /**
093         * get the id of the ComponentConnector
094         * 
095         * @return the id
096         */
097        public ComponentNameSpace getComponentNameSpace() {
098            return componentName;
099        }
100    
101        /**
102         * @return the unique component name
103         */
104        public String getComponentName() {
105            return componentName.getName();
106        }
107    
108        /**
109         * @return this component instance
110         */
111        public Component getComponent() {
112            return component;
113        }
114    
115        /**
116         * @param serviceName
117         * @param endpointName
118         * @return EndPointReference
119         * @throws JBIException
120         */
121        public ServiceEndpoint activateEndpoint(QName serviceName, String endpointName) throws JBIException {
122            checkActivated();
123            if (LOG.isDebugEnabled()) {
124                LOG.debug("Component: " + componentName.getName() + " activated endpoint: " + serviceName + " : " + endpointName);
125            }
126            return container.getRegistry().activateEndpoint(this, serviceName, endpointName);
127        }
128    
129        /**
130         * @param serviceName
131         * @return endpoints registered against the service
132         * @throws JBIException
133         */
134        public ServiceEndpoint[] availableEndpoints(QName serviceName) throws JBIException {
135            checkActivated();
136            return container.getRegistry().getEndpointsForService(serviceName);
137        }
138    
139        /**
140         * Deregister the endpoint with the NMR
141         * 
142         * @param endpoint
143         * @throws JBIException
144         */
145        public void deactivateEndpoint(ServiceEndpoint endpoint) throws JBIException {
146            checkActivated();
147            container.getRegistry().deactivateEndpoint(this, (InternalEndpoint) endpoint);
148        }
149        
150        /**
151         * Register All subscriptions
152         * @param context 
153         * @param as 
154         */
155        public void registerSubscriptions(ComponentContextImpl context, ActivationSpec as) {
156            checkActivated();
157            container.getRegistry().registerSubscriptions(context, as);
158        }
159        
160        /**
161         * Deregister All subscriptions
162         * @param context
163         * @param as
164         */
165        public void deregisterSubscriptions(ComponentContextImpl context, ActivationSpec as) {
166            checkActivated();
167            container.getRegistry().deregisterSubscriptions(context, as);
168        }
169        
170        /**
171         * @param context 
172         * @param subscription
173         * @param endpoint
174         */
175        public void registerSubscription(ComponentContextImpl context, SubscriptionSpec subscription, ServiceEndpoint endpoint) {
176            checkActivated();
177            container.getRegistry().registerSubscription(context, subscription, endpoint);
178        }
179    
180        /**
181         * @param context 
182         * @param subscription
183         * @return the ServiceEndpoint
184         */
185        public InternalEndpoint deregisterSubscription(ComponentContextImpl context, SubscriptionSpec subscription) {
186            checkActivated();
187            return container.getRegistry().deregisterSubscription(context, subscription);
188        }
189        
190    
191        /**
192         * @return the Delivery Channel
193         * @throws MessagingException
194         */
195        public DeliveryChannel getDeliveryChannel() {
196            return deliveryChannel;
197        }
198    
199        /**
200         * Retrieve the default JMX Domain Name for MBeans registered in this instance of the JBI implementation.
201         * 
202         * @return the JMX domain name for this instance of the JBI implementation.
203         */
204        public String getJmxDomainName() {
205            return container.getManagementContext().getJmxDomainName();
206        }
207    
208        /**
209         * Formulate and return the MBean ObjectName of a custom control MBean for a JBI component.
210         * 
211         * @param customName the name of the custom control.
212         * @return the JMX ObjectName of the MBean, or <code>null</code> if <code>customName</code> is invalid.
213         */
214        public ObjectName createCustomComponentMBeanName(String customName) {
215            return container.getManagementContext().createCustomComponentMBeanName(customName, componentName.getName());
216        }
217    
218        /**
219         * @return the MBeanNames service
220         */
221        public MBeanNames getMBeanNames() {
222            return this;
223        }
224    
225        /**
226         * @return theMBean server assocated with the JBI
227         */
228        public MBeanServer getMBeanServer() {
229            return container.getMBeanServer();
230        }
231    
232        /**
233         * @return the naming context
234         */
235        public InitialContext getNamingContext() {
236            return container.getNamingContext();
237        }
238    
239        /**
240         * Get the TransactionManager for this implementation. The instance returned is an implementation of the standard
241         * JTA interface. If none is available, this method returns <code>null</code>.
242         * <p>
243         * The object returned by this method is untyped, to allow this interface to be compiled in environments that do not
244         * support JTA. If not null, the object returned must be of type <code>javax.transaction.TransactionManager</code>.
245         * <p>
246         * This downcast is necessary because JBI is used in environments that do not support JTA (i.e., J2SE). Explicit use
247         * of JTA types would cause compilation failures in such environments.
248         * 
249         * @return A TransactionManager instance, or <code>null</code> if none is available in the execution environment.
250         */
251        public Object getTransactionManager() {
252            return container.getTransactionManager();
253        }
254    
255        /**
256         * @return the root directory path
257         */
258        public String getWorkspaceRoot() {
259            if (environment.getWorkspaceRoot() != null) {
260                return environment.getWorkspaceRoot().getAbsolutePath();
261            }
262            return null;
263        }
264    
265        /**
266         * @return Returns the container.
267         */
268        public JBIContainer getContainer() {
269            return container;
270        }
271    
272        /**
273         * @return Returns the ComponentEnvironment
274         */
275        public ComponentEnvironment getEnvironment() {
276            return environment;
277        }
278        
279        /**
280         * Set the ComponentEnvironment
281         * @param ce
282         */
283        public void setEnvironment(ComponentEnvironment ce) {
284            this.environment = ce;
285        }
286    
287        /**
288         * @param container The container to set.
289         */
290        public void setContainer(JBIContainer container) {
291            this.container = container;
292        }
293    
294        /**
295         * @param deliveryChannel The deliveryChannel to set.
296         */
297        public void setDeliveryChannel(DeliveryChannel deliveryChannel) {
298            this.deliveryChannel = deliveryChannel;
299        }
300    
301        /**
302         * Registers the given external endpoint with the NMR. This indicates to the NMR that the given endpoint is used as
303         * a proxy for external service consumers to access an internal service of the same service name (but a different
304         * endpoint name).
305         * 
306         * @param externalEndpoint the external endpoint to be registered, must be non-null.
307         * @exception JBIException if an external endpoint with the same name is already registered, by this or another
308         * component.
309         */
310        public void registerExternalEndpoint(ServiceEndpoint externalEndpoint) throws JBIException {
311            checkActivated();
312            if (externalEndpoint == null) {
313                throw new IllegalArgumentException("externalEndpoint should be non null");
314            }
315            container.getRegistry().registerExternalEndpoint(getComponentNameSpace(), externalEndpoint);
316        }
317    
318        /**
319         * Deregisters the given external endpoint with the NMR. This indicates to the NMR that the given external endpoint
320         * can no longer be used as a proxy for external service consumers to access an internal service of the same service
321         * name.
322         * 
323         * @param externalEndpoint the external endpoint to be deregistered; must be non-null.
324         * @exception JBIException if the given external endpoint was not previously registered.
325         */
326        public void deregisterExternalEndpoint(ServiceEndpoint externalEndpoint) throws JBIException {
327            checkActivated();
328            container.getRegistry().deregisterExternalEndpoint(getComponentNameSpace(), externalEndpoint);
329        }
330    
331        /**
332         * Resolve the given endpoint reference into a service endpoint. This is called by the component when it has an EPR
333         * that it wants to resolve into a service endpoint.
334         * <p>
335         * Note that the service endpoint returned refers to a dynamic endpoint; the endpoint will exist only as long as
336         * this component retains a strong reference to the object returned by this method. The endpoint may not be included
337         * in the list of "activated" endpoints.
338         * 
339         * @param epr endpoint reference as an XML fragment; must be non-null.
340         * @return the service endpoint corresponding to the given endpoint reference; <code>null</code> if the reference
341         * cannot be resolved.
342         */
343        public ServiceEndpoint resolveEndpointReference(DocumentFragment epr) {
344            checkActivated();
345            return container.getRegistry().resolveEndpointReference(epr);
346        }
347    
348        /**
349         * Get the service endpoint for the named activated endpoint, if any.
350         * 
351         * @param service qualified-name of the endpoint's service; must be non-null.
352         * @param name name of the endpoint; must be non-null.
353         * @return the named endpoint, or <code>null</code> if the named endpoint is not activated.
354         */
355        public ServiceEndpoint getEndpoint(QName service, String name) {
356            checkActivated();
357            return container.getRegistry().getEndpoint(service, name);
358        }
359    
360        /**
361         * Retrieve the service description metadata for the specified endpoint.
362         * <p>
363         * Note that the result can use either the WSDL 1.1 or WSDL 2.0 description language.
364         * 
365         * @param endpoint endpoint reference; must be non-null.
366         * @return metadata describing endpoint, or <code>null</code> if metadata is unavailable.
367         * @exception JBIException invalid endpoint reference.
368         */
369        public Document getEndpointDescriptor(ServiceEndpoint endpoint) throws JBIException {
370            checkActivated();
371            return container.getRegistry().getEndpointDescriptor(endpoint);
372        }
373    
374        /**
375         * Queries the NMR for active endpoints that implement the given interface. This will return the endpoints for all
376         * services and endpoints that implement the named interface (portType in WSDL 1.1). This method does NOT include
377         * external endpoints (those registered using {@link #registerExternalEndpoint(ServiceEndpoint)}.
378         * 
379         * @param interfaceName qualified name of interface/portType that is implemented by the endpoint; if
380         * <code>null</code> then all activated endpoints in the JBI environment must be returned.
381         * @return an array of available endpoints for the specified interface name; must be non-null; may be empty.
382         */
383        public ServiceEndpoint[] getEndpoints(QName interfaceName) {
384            checkActivated();
385            return container.getRegistry().getEndpointsForInterface(interfaceName);
386        }
387    
388        /**
389         * Queries the NMR for active endpoints belonging to the given service. This method does NOT include external
390         * endpoints (those registered using {@link #registerExternalEndpoint(ServiceEndpoint)}.
391         * 
392         * @param serviceName qualified name of the service that the endpoints are part of; must be non-null.
393         * @return an array of available endpoints for the specified service name; must be non-null; may be empty.
394         */
395        public ServiceEndpoint[] getEndpointsForService(QName serviceName) {
396            checkActivated();
397            return container.getRegistry().getEndpointsForService(serviceName);
398        }
399    
400        /**
401         * Queries the NMR for external endpoints that implement the given interface name. This methods returns only
402         * registered external endpoints (see {@link #registerExternalEndpoint(ServiceEndpoint)}.
403         * 
404         * @param interfaceName qualified name of interface implemented by the endpoints; must be non-null.
405         * @return an array of available external endpoints for the specified interface name; must be non-null; may be
406         * empty.
407         */
408        public ServiceEndpoint[] getExternalEndpoints(QName interfaceName) {
409            checkActivated();
410            return container.getRegistry().getExternalEndpoints(interfaceName);
411        }
412    
413        /**
414         * Queries the NMR for external endpoints that are part of the given service.
415         * 
416         * @param serviceName qualified name of service that contains the endpoints; must be non-null.
417         * @return an array of available external endpoints for the specified service name; must be non-null; may be empty.
418         */
419        public ServiceEndpoint[] getExternalEndpointsForService(QName serviceName) {
420            checkActivated();
421            return container.getRegistry().getExternalEndpointsForService(serviceName);
422        }
423    
424        /**
425         * Get the installation root directory path for this component.
426         * <p>
427         * This method MUST return the file path formatted for the underlying platform.
428         * 
429         * @return the installation root directory path, in platform-specific form; must be non-null and non-empty.
430         */
431        public String getInstallRoot() {
432            if (environment.getInstallRoot() != null) {
433                return environment.getInstallRoot().getAbsolutePath();
434            }
435            return null;
436        }
437    
438        /**
439         * Get a logger instance from JBI. Loggers supplied by JBI are guaranteed to have unique names such that they avoid
440         * name collisions with loggers from other components created using this method. The suffix parameter allows for the
441         * creation of subloggers as needed. The JBI specification says nothing about the exact names to be used, only that
442         * they must be unique across components and the JBI implementation itself.
443         * 
444         * @param suffix for creating subloggers; use an empty string for the base component logger; must be non-null.
445         * @param resourceBundleName name of <code>ResourceBundle</code> to be used for localizing messages for the
446         * logger. May be <code>null</code> if none of the messages require localization. The resource, if non-null, must
447         * be loadable using the component's class loader as the initiating loader.
448         * @return a standard logger, named uniquely for this component (plus the given suffix, if applicable); must be
449         * non-null.
450         * @exception MissingResourceException if the ResourceBundleName is non-null and no corresponding resource can be
451         * found.
452         * @exception JBIException if the resourceBundleName has changed from a previous invocation by this component of
453         * this method with the same suffix.
454         */
455        public Logger getLogger(String suffix, String resourceBundleName) throws MissingResourceException, JBIException {
456            String name = suffix != null ? suffix : "";
457            name = componentName.getName() + name;
458            return container.getLogger(name, resourceBundleName);
459        }
460    
461        /**
462         * @return the ActivationSpec
463         */
464        public ActivationSpec getActivationSpec() {
465            return activationSpec;
466        }
467    
468        private void checkActivated() {
469            if (!activated) {
470                throw new IllegalStateException("ComponentContext not activated");
471            }
472        }
473    }