001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.servicemix.common;
018:
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021: import org.apache.servicemix.common.xbean.XBeanServiceUnit;
022: import org.apache.servicemix.common.xbean.BaseXBeanDeployer;
023: import org.w3c.dom.Document;
024: import org.w3c.dom.DocumentFragment;
025:
026: import javax.jbi.component.ComponentContext;
027: import javax.jbi.component.ComponentLifeCycle;
028: import javax.jbi.component.ServiceUnitManager;
029: import javax.jbi.management.DeploymentException;
030: import javax.jbi.messaging.MessageExchange;
031: import javax.jbi.servicedesc.ServiceEndpoint;
032: import javax.xml.namespace.QName;
033:
034: import java.util.Arrays;
035: import java.util.List;
036: import java.util.Iterator;
037: import java.util.Collections;
038:
039: /**
040: * A useful base class for writing new JBI components which includes the {@link ComponentLifeCycle} interface methods so that
041: * you can write a new component in a single class with minimal overloading.
042: *
043: * @version $Revision: 584990 $
044: */
045: public abstract class DefaultComponent extends BaseLifeCycle implements
046: ServiceMixComponent {
047:
048: protected final transient Log logger = LogFactory
049: .getLog(getClass());
050:
051: protected Registry registry;
052: protected BaseServiceUnitManager serviceUnitManager;
053: protected ServiceUnit serviceUnit;
054:
055: public DefaultComponent() {
056: setComponent(this );
057: registry = createRegistry();
058: serviceUnitManager = createServiceUnitManager();
059: }
060:
061: /* (non-Javadoc)
062: * @see javax.jbi.component.Component#getLifeCycle()
063: */
064: public ComponentLifeCycle getLifeCycle() {
065: return this ;
066: }
067:
068: /* (non-Javadoc)
069: * @see javax.jbi.component.Component#getServiceUnitManager()
070: */
071: public ServiceUnitManager getServiceUnitManager() {
072: return serviceUnitManager;
073: }
074:
075: /* (non-Javadoc)
076: * @see javax.jbi.component.Component#getServiceDescription(javax.jbi.servicedesc.ServiceEndpoint)
077: */
078: public Document getServiceDescription(ServiceEndpoint endpoint) {
079: if (logger.isDebugEnabled()) {
080: logger
081: .debug("Querying service description for "
082: + endpoint);
083: }
084: String key = EndpointSupport.getKey(endpoint);
085: Endpoint ep = this .registry.getEndpoint(key);
086: if (ep != null) {
087: Document doc = ep.getDescription();
088: if (doc == null) {
089: if (logger.isDebugEnabled()) {
090: logger.debug("No description found for " + key);
091: }
092: }
093: return doc;
094: } else {
095: if (logger.isDebugEnabled()) {
096: logger.debug("No endpoint found for " + key);
097: }
098: return null;
099: }
100: }
101:
102: /* (non-Javadoc)
103: * @see javax.jbi.component.Component#isExchangeWithConsumerOkay(javax.jbi.servicedesc.ServiceEndpoint, javax.jbi.messaging.MessageExchange)
104: */
105: public boolean isExchangeWithConsumerOkay(ServiceEndpoint endpoint,
106: MessageExchange exchange) {
107: String key = EndpointSupport.getKey(endpoint);
108: Endpoint ep = this .registry.getEndpoint(key);
109: if (ep != null) {
110: if (ep.getRole() != MessageExchange.Role.PROVIDER) {
111: if (logger.isDebugEnabled()) {
112: logger
113: .debug("Endpoint "
114: + key
115: + " is a consumer. Refusing exchange with consumer.");
116: }
117: return false;
118: } else {
119: return ep.isExchangeOkay(exchange);
120: }
121: } else {
122: if (logger.isDebugEnabled()) {
123: logger.debug("No endpoint found for " + key
124: + ". Refusing exchange with consumer.");
125: }
126: return false;
127: }
128: }
129:
130: /* (non-Javadoc)
131: * @see javax.jbi.component.Component#isExchangeWithProviderOkay(javax.jbi.servicedesc.ServiceEndpoint, javax.jbi.messaging.MessageExchange)
132: */
133: public boolean isExchangeWithProviderOkay(ServiceEndpoint endpoint,
134: MessageExchange exchange) {
135: // TODO: check if the selected endpoint is good for us
136: return true;
137: }
138:
139: public QName getEPRServiceName() {
140: return new QName(getEPRUri(), getEPRComponentName());
141: }
142:
143: public QName getEPRElementName() {
144: return new QName(getEPRUri(), "epr");
145: }
146:
147: protected String[] getEPRProtocols() {
148: String protocol = getEPRStrippedComponentName().toLowerCase()
149: + ":";
150: return new String[] { protocol };
151: }
152:
153: private String getEPRComponentName() {
154: String suffix = getClass().getName();
155: suffix = suffix.substring(suffix.lastIndexOf('.') + 1);
156: if (suffix.lastIndexOf('$') > 0) {
157: suffix = suffix.substring(suffix.lastIndexOf('$') + 1);
158: }
159: return suffix;
160: }
161:
162: private String getEPRStrippedComponentName() {
163: String suffix = getEPRComponentName();
164: if (suffix.endsWith("Component")) {
165: suffix = suffix.substring(0, suffix.length() - 9);
166: }
167: return suffix;
168: }
169:
170: private String getEPRUri() {
171: String uri = "urn:servicemix:"
172: + getEPRStrippedComponentName().toLowerCase();
173: return uri;
174: }
175:
176: /* (non-Javadoc)
177: * @see javax.jbi.component.Component#resolveEndpointReference(org.w3c.dom.DocumentFragment)
178: */
179: public ServiceEndpoint resolveEndpointReference(DocumentFragment epr) {
180: String[] protocols = getEPRProtocols();
181: QName elementName = getEPRElementName();
182: QName serviceName = getEPRServiceName();
183: for (int i = 0; i < protocols.length; i++) {
184: ServiceEndpoint ep = ResolvedEndpoint.resolveEndpoint(epr,
185: elementName, serviceName, protocols[i]);
186: if (ep != null) {
187: return ep;
188: }
189: }
190: return null;
191: }
192:
193: /**
194: * Create the service unit manager.
195: * Derived classes should override this method and return a
196: * BaseServiceUnitManager so that the component is able to
197: * handle service unit deployment.
198: *
199: * The default implementation will create a @{link BaseXBeanDeployer} instance
200: * using the value of @{link #getEndpointClasses()} if that method returns a non-null value
201: * otherwise it returns null.
202: *
203: * @return a newly created service unit manager
204: */
205: protected BaseServiceUnitManager createServiceUnitManager() {
206: Class[] classes = getEndpointClasses();
207: if (classes == null) {
208: return null;
209: }
210: Deployer[] deployers = new Deployer[] { new BaseXBeanDeployer(
211: this , classes) };
212: return new BaseServiceUnitManager(this , deployers);
213: }
214:
215: protected Registry createRegistry() {
216: return new Registry(this );
217: }
218:
219: public ComponentContext getComponentContext() {
220: return getContext();
221: }
222:
223: public String getComponentName() {
224: if (getComponentContext() == null) {
225: return "Component (" + getClass().getName()
226: + ") not yet initialized";
227: }
228: return getComponentContext().getComponentName();
229: }
230:
231: /**
232: * @return Returns the logger.
233: */
234: public Log getLogger() {
235: return logger;
236: }
237:
238: /**
239: * @return Returns the registry.
240: */
241: public Registry getRegistry() {
242: return registry;
243: }
244:
245: /**
246: * Returns the service unit, lazily creating one on demand
247: *
248: * @return the service unit if one is being used.
249: */
250: public ServiceUnit getServiceUnit() {
251: if (serviceUnit == null) {
252: serviceUnit = new XBeanServiceUnit();
253: serviceUnit.setName("#default#");
254: serviceUnit.setComponent(this );
255: }
256: return serviceUnit;
257: }
258:
259: /**
260: * Returns an array of configured endpoints for the component or null if there are no configured endpoints
261: */
262: protected abstract List getConfiguredEndpoints();
263:
264: /**
265: * Returns a list of valid endpoint classes or null if the component does not wish to programmatically
266: * restrict the list of possible endpoint classes
267: *
268: * @return the endpoint classes used to validate configuration or null to disable the validation
269: */
270: protected abstract Class[] getEndpointClasses();
271:
272: /**
273: * A little helper method to turn a possibly null list of endpoints into a list of endpoints
274: */
275: protected static List asList(Object[] endpoints) {
276: if (endpoints == null) {
277: return Collections.EMPTY_LIST;
278: }
279: return Arrays.asList(endpoints);
280: }
281:
282: /* (non-Javadoc)
283: * @see org.servicemix.common.BaseLifeCycle#doInit()
284: */
285: protected void doInit() throws Exception {
286: super .doInit();
287: List endpoints = getConfiguredEndpoints();
288: if (endpoints != null && !endpoints.isEmpty()) {
289: Iterator iter = endpoints.iterator();
290: while (iter.hasNext()) {
291: Endpoint endpoint = (Endpoint) iter.next();
292: if (endpoint == null) {
293: logger.warn("Ignoring null endpoint in list: "
294: + endpoints);
295: continue;
296: }
297: addEndpoint(endpoint);
298: }
299: }
300: }
301:
302: /**
303: * Dynamically adds a new endpoint
304: */
305: public void addEndpoint(Endpoint endpoint) throws Exception {
306: ServiceUnit su = getServiceUnit();
307: endpoint.setServiceUnit(su);
308: validateEndpoint(endpoint);
309: endpoint.validate();
310: su.addEndpoint(endpoint);
311: if (registry.isRegistered(su)) {
312: registry.registerEndpoint(endpoint);
313: } else {
314: registry.registerServiceUnit(su);
315: if (isStarted()) {
316: su.start();
317: }
318: }
319: }
320:
321: public void removeEndpoint(Endpoint endpoint) throws Exception {
322: ServiceUnit su = endpoint.getServiceUnit();
323: su.removeEndpoint(endpoint);
324: }
325:
326: /**
327: * Provides a hook to validate the statically configured endpoint
328: */
329: protected void validateEndpoint(Endpoint endpoint)
330: throws DeploymentException {
331: Class[] endpointClasses = getEndpointClasses();
332: if (endpointClasses != null) {
333: boolean valid = false;
334: for (int i = 0; i < endpointClasses.length; i++) {
335: Class endpointClass = endpointClasses[i];
336: if (endpointClass.isInstance(endpoint)) {
337: valid = true;
338: }
339: }
340: if (!valid) {
341: throw new DeploymentException(
342: "The endpoint: "
343: + endpoint
344: + " is not an instance of any of the allowable types: "
345: + Arrays.asList(endpointClasses));
346: }
347: }
348: }
349:
350: /* (non-Javadoc)
351: * @see org.servicemix.common.BaseLifeCycle#doStart()
352: */
353: protected void doStart() throws Exception {
354: super .doStart();
355: if (serviceUnit != null) {
356: if (!registry.isRegistered(serviceUnit)) {
357: registry.registerServiceUnit(serviceUnit);
358: }
359: serviceUnit.start();
360: }
361: }
362:
363: /* (non-Javadoc)
364: * @see org.servicemix.common.BaseLifeCycle#doStop()
365: */
366: protected void doStop() throws Exception {
367: if (serviceUnit != null) {
368: serviceUnit.stop();
369: }
370: super .doStop();
371: }
372:
373: /* (non-Javadoc)
374: * @see org.servicemix.common.BaseLifeCycle#doShutDown()
375: */
376: protected void doShutDown() throws Exception {
377: if (serviceUnit != null) {
378: serviceUnit.shutDown();
379: }
380: super.doShutDown();
381: }
382:
383: }
|