| /** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.servicemix.common; |
| |
| import org.apache.servicemix.common.xbean.XBeanServiceUnit; |
| import org.apache.servicemix.common.xbean.BaseXBeanDeployer; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.DocumentFragment; |
| |
| import javax.jbi.component.ComponentContext; |
| import javax.jbi.component.ComponentLifeCycle; |
| import javax.jbi.component.ServiceUnitManager; |
| import javax.jbi.management.DeploymentException; |
| import javax.jbi.messaging.MessageExchange; |
| import javax.jbi.servicedesc.ServiceEndpoint; |
| import javax.xml.namespace.QName; |
| |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Iterator; |
| import java.util.Collections; |
| |
| /** |
| * <p> |
| * A useful base class for writing new JBI components which includes the {@link ComponentLifeCycle} interface methods so that |
| * you can write a new component in a single class with minimal overloading. |
| * </p> |
| * |
| * @version $Revision$ |
| */ |
| public class DefaultComponent extends AsyncBaseLifeCycle implements ServiceMixComponent { |
| |
| protected final transient Logger logger = LoggerFactory.getLogger(DefaultComponent.class); |
| |
| protected Registry registry; |
| protected BaseServiceUnitManager serviceUnitManager; |
| protected ServiceUnit serviceUnit; |
| protected ComponentLifeCycle lifeCycle; |
| |
| public DefaultComponent() { |
| setComponent(this); |
| logger.debug("Create the registry"); |
| registry = createRegistry(); |
| logger.debug("Create the SU manager"); |
| serviceUnitManager = createServiceUnitManager(); |
| logger.debug("Create the XBean SU"); |
| XBeanServiceUnit su = new XBeanServiceUnit(); |
| su.setName("#default#"); |
| su.setComponent(this); |
| serviceUnit = su; |
| registry.registerServiceUnit(serviceUnit); |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.jbi.component.Component#getLifeCycle() |
| */ |
| public ComponentLifeCycle getLifeCycle() { |
| if (lifeCycle == null) { |
| try { |
| // This should fail if not inside smx3 |
| lifeCycle = new SyncLifeCycleWrapper(this); |
| } catch (Throwable t) { |
| // In such a case, just not wrap the lifecycle |
| lifeCycle = this; |
| } |
| } |
| return lifeCycle; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.jbi.component.Component#getServiceUnitManager() |
| */ |
| public ServiceUnitManager getServiceUnitManager() { |
| return serviceUnitManager; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.jbi.component.Component#getServiceDescription(javax.jbi.servicedesc.ServiceEndpoint) |
| */ |
| public Document getServiceDescription(ServiceEndpoint endpoint) { |
| logger.debug("Querying service description for {}", endpoint); |
| String key = EndpointSupport.getKey(endpoint); |
| Endpoint ep = this.registry.getEndpoint(key); |
| if (ep != null) { |
| Document doc = ep.getDescription(); |
| if (doc == null) { |
| logger.debug("No description found for {}", key); |
| } |
| return doc; |
| } |
| else { |
| logger.debug("No endpoint found for {}", key); |
| return null; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.jbi.component.Component#isExchangeWithConsumerOkay(javax.jbi.servicedesc.ServiceEndpoint, javax.jbi.messaging.MessageExchange) |
| */ |
| public boolean isExchangeWithConsumerOkay(ServiceEndpoint endpoint, MessageExchange exchange) { |
| String key = EndpointSupport.getKey(endpoint); |
| Endpoint ep = this.registry.getEndpoint(key); |
| if (ep != null) { |
| if (ep.getRole() != MessageExchange.Role.PROVIDER) { |
| logger.debug("Endpoint {} is a consumer. Refusing exchange with consumer.", key); |
| return false; |
| } |
| else { |
| return ep.isExchangeOkay(exchange); |
| } |
| } |
| else { |
| logger.debug("No endpoint found for {}. Refusing exchange with consumer.", key); |
| return false; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.jbi.component.Component#isExchangeWithProviderOkay(javax.jbi.servicedesc.ServiceEndpoint, javax.jbi.messaging.MessageExchange) |
| */ |
| public boolean isExchangeWithProviderOkay(ServiceEndpoint endpoint, MessageExchange exchange) { |
| // TODO: check if the selected endpoint is good for us |
| return true; |
| } |
| |
| public QName getEPRServiceName() { |
| return new QName(getEPRUri(), getEPRComponentName()); |
| } |
| |
| public QName getEPRElementName() { |
| return new QName(getEPRUri(), "epr"); |
| } |
| |
| protected String[] getEPRProtocols() { |
| String protocol = getEPRStrippedComponentName().toLowerCase() + ":"; |
| return new String[] { protocol }; |
| } |
| |
| private String getEPRComponentName() { |
| String suffix = getClass().getName(); |
| suffix = suffix.substring(suffix.lastIndexOf('.') + 1); |
| if (suffix.lastIndexOf('$') > 0) { |
| suffix = suffix.substring(suffix.lastIndexOf('$') + 1); |
| } |
| return suffix; |
| } |
| |
| private String getEPRStrippedComponentName() { |
| String suffix = getEPRComponentName(); |
| if (suffix.endsWith("Component")) { |
| suffix = suffix.substring(0, suffix.length() - 9); |
| } |
| return suffix; |
| } |
| |
| private String getEPRUri() { |
| String uri = "urn:servicemix:" + getEPRStrippedComponentName().toLowerCase(); |
| return uri; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.jbi.component.Component#resolveEndpointReference(org.w3c.dom.DocumentFragment) |
| */ |
| public ServiceEndpoint resolveEndpointReference(DocumentFragment epr) { |
| String[] protocols = getEPRProtocols(); |
| QName elementName = getEPRElementName(); |
| QName serviceName = getEPRServiceName(); |
| for (int i = 0; i < protocols.length; i++) { |
| ServiceEndpoint ep = ResolvedEndpoint.resolveEndpoint(epr, elementName, serviceName, protocols[i]); |
| if (ep != null) { |
| return ep; |
| } |
| } |
| return null; |
| } |
| |
| |
| /** |
| * Create the service unit manager. |
| * Derived classes should override this method and return a |
| * BaseServiceUnitManager so that the component is able to |
| * handle service unit deployment. |
| * |
| * The default implementation will create a @{link BaseXBeanDeployer} instance |
| * using the value of @{link #getEndpointClasses()} if that method returns a non-null value |
| * otherwise it returns null. |
| * |
| * @return a newly created service unit manager |
| */ |
| protected BaseServiceUnitManager createServiceUnitManager() { |
| Class[] classes = getEndpointClasses(); |
| if (classes == null) { |
| return null; |
| } |
| Deployer[] deployers = new Deployer[] { new BaseXBeanDeployer(this, classes) }; |
| return new BaseServiceUnitManager(this, deployers); |
| } |
| |
| |
| protected Registry createRegistry() { |
| return new Registry(this); |
| } |
| |
| public ComponentContext getComponentContext() { |
| return getContext(); |
| } |
| |
| public String getComponentName() { |
| if (getComponentContext() == null) { |
| return "Component (" + getClass().getName() + ") not yet initialized"; |
| } |
| return getComponentContext().getComponentName(); |
| } |
| |
| /** |
| * @return Returns the logger. |
| */ |
| public Logger getLogger() { |
| return logger; |
| } |
| |
| /** |
| * @return Returns the registry. |
| */ |
| public Registry getRegistry() { |
| return registry; |
| } |
| |
| |
| /** |
| * Returns the service unit, lazily creating one on demand |
| * |
| * @return the service unit if one is being used. |
| */ |
| public ServiceUnit getServiceUnit() { |
| return serviceUnit; |
| } |
| |
| /** |
| * Returns an array of configured endpoints for the component or null if there are no configured endpoints |
| */ |
| protected List getConfiguredEndpoints() { |
| return null; |
| } |
| |
| /** |
| * Returns a list of valid endpoint classes or null if the component does not wish to programmatically |
| * restrict the list of possible endpoint classes |
| * |
| * @return the endpoint classes used to validate configuration or null to disable the validation |
| */ |
| protected Class[] getEndpointClasses() { |
| return null; |
| } |
| |
| /** |
| * A little helper method to turn a possibly null list of endpoints into a list of endpoints |
| */ |
| protected static List asList(Object[] endpoints) { |
| if (endpoints == null) { |
| return Collections.EMPTY_LIST; |
| } |
| return Arrays.asList(endpoints); |
| } |
| |
| /** |
| * Dynamically adds a new endpoint |
| */ |
| public synchronized void addEndpoint(Endpoint endpoint) throws Exception { |
| endpoint.setServiceUnit(serviceUnit); |
| validateEndpoint(endpoint); |
| endpoint.validate(); |
| registry.registerEndpoint(endpoint); |
| serviceUnit.addEndpoint(endpoint); |
| } |
| |
| public synchronized void removeEndpoint(Endpoint endpoint) throws Exception { |
| registry.unregisterEndpoint(endpoint); |
| endpoint.getServiceUnit().removeEndpoint(endpoint); |
| } |
| |
| |
| public boolean isKnownEndpoint(Endpoint endpoint) { |
| Class[] endpointClasses = getEndpointClasses(); |
| if (endpointClasses != null) { |
| for (int i = 0; i < endpointClasses.length; i++) { |
| Class endpointClass = endpointClasses[i]; |
| if (endpointClass.isInstance(endpoint)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Provides a hook to validate the statically configured endpoint |
| */ |
| protected void validateEndpoint(Endpoint endpoint) throws DeploymentException { |
| if (!isKnownEndpoint(endpoint)) { |
| throw new DeploymentException("The endpoint: " + endpoint |
| + " is not an instance of any of the allowable types: " + Arrays.asList(getEndpointClasses())); |
| } |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.apache.servicemix.common.AsyncBaseLifeCycle#doInit() |
| */ |
| @Override |
| protected void doInit() throws Exception { |
| super.doInit(); |
| List endpoints = getConfiguredEndpoints(); |
| if (endpoints != null && !endpoints.isEmpty()) { |
| Iterator iter = endpoints.iterator(); |
| while (iter.hasNext()) { |
| Endpoint endpoint = (Endpoint) iter.next(); |
| if (endpoint == null) { |
| logger.warn("Ignoring null endpoint in list: {}", endpoints); |
| continue; |
| } |
| addEndpoint(endpoint); |
| } |
| } |
| serviceUnit.init(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.servicemix.common.AsyncBaseLifeCycle#doStart() |
| */ |
| @Override |
| protected void doStart() throws Exception { |
| super.doStart(); |
| serviceUnit.start(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.servicemix.common.AsyncBaseLifeCycle#doStop() |
| */ |
| @Override |
| protected void doStop() throws Exception { |
| serviceUnit.stop(); |
| super.doStop(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.servicemix.common.AsyncBaseLifeCycle#doShutDown() |
| */ |
| @Override |
| protected void doShutDown() throws Exception { |
| serviceUnit.shutDown(); |
| super.doShutDown(); |
| } |
| |
| |
| } |