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