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