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.nmr;
018
019 import java.util.ArrayList;
020 import java.util.List;
021
022 import javax.jbi.JBIException;
023 import javax.jbi.component.Component;
024 import javax.jbi.messaging.MessageExchange;
025 import javax.jbi.messaging.MessageExchange.Role;
026 import javax.jbi.messaging.MessagingException;
027 import javax.jbi.servicedesc.ServiceEndpoint;
028 import javax.management.JMException;
029 import javax.management.MBeanOperationInfo;
030 import javax.xml.namespace.QName;
031
032 import org.apache.commons.logging.Log;
033 import org.apache.commons.logging.LogFactory;
034 import org.apache.servicemix.jbi.api.EndpointResolver;
035 import org.apache.servicemix.jbi.container.ActivationSpec;
036 import org.apache.servicemix.jbi.container.JBIContainer;
037 import org.apache.servicemix.jbi.framework.ComponentContextImpl;
038 import org.apache.servicemix.jbi.framework.ComponentMBeanImpl;
039 import org.apache.servicemix.jbi.framework.ComponentNameSpace;
040 import org.apache.servicemix.jbi.framework.Registry;
041 import org.apache.servicemix.jbi.management.BaseSystemService;
042 import org.apache.servicemix.jbi.management.ManagementContext;
043 import org.apache.servicemix.jbi.management.OperationInfoHelper;
044 import org.apache.servicemix.jbi.messaging.MessageExchangeImpl;
045 import org.apache.servicemix.jbi.nmr.flow.DefaultFlowChooser;
046 import org.apache.servicemix.jbi.nmr.flow.Flow;
047 import org.apache.servicemix.jbi.nmr.flow.FlowChooser;
048 import org.apache.servicemix.jbi.nmr.flow.FlowProvider;
049 import org.apache.servicemix.jbi.resolver.ConsumerComponentEndpointFilter;
050 import org.apache.servicemix.jbi.resolver.EndpointChooser;
051 import org.apache.servicemix.jbi.resolver.EndpointFilter;
052 import org.apache.servicemix.jbi.resolver.FirstChoicePolicy;
053 import org.apache.servicemix.jbi.resolver.ProducerComponentEndpointFilter;
054 import org.apache.servicemix.jbi.servicedesc.AbstractServiceEndpoint;
055 import org.apache.servicemix.jbi.servicedesc.ExternalEndpoint;
056 import org.apache.servicemix.jbi.servicedesc.InternalEndpoint;
057 import org.apache.servicemix.jbi.servicedesc.LinkedEndpoint;
058
059 /**
060 * The Broker handles Nomalised Message Routing within ServiceMix
061 *
062 * @version $Revision: 384328 $
063 */
064 public class DefaultBroker extends BaseSystemService implements Broker {
065
066 private static final Log LOG = LogFactory.getLog(DefaultBroker.class);
067
068 private Registry registry;
069 private String flowNames = "seda";
070 private String subscriptionFlowName;
071 private Flow[] flows;
072 private EndpointChooser defaultServiceChooser = new FirstChoicePolicy();
073 private EndpointChooser defaultInterfaceChooser = new FirstChoicePolicy();
074 private SubscriptionManager subscriptionManager = new SubscriptionManager();
075 private FlowChooser defaultFlowChooser = new DefaultFlowChooser();
076
077 /**
078 * Constructor
079 */
080 public DefaultBroker() {
081 }
082
083 /**
084 * Get the description
085 *
086 * @return description
087 */
088 public String getDescription() {
089 return "Normalized Message Router";
090 }
091
092 public SubscriptionManager getSubscriptionManager() {
093 return subscriptionManager;
094 }
095
096 /**
097 * Sets the subscription manager
098 */
099 public void setSubscriptionManager(SubscriptionManager subscriptionManager) {
100 this.subscriptionManager = subscriptionManager;
101 }
102
103 /**
104 * initialize the broker
105 *
106 * @param container
107 * @throws JBIException
108 */
109 public void init(JBIContainer container) throws JBIException {
110 super.init(container);
111 this.registry = container.getRegistry();
112 // Create and initialize flows
113 if (this.flows == null) {
114 String[] names = flowNames.split(",");
115 flows = new Flow[names.length];
116 for (int i = 0; i < names.length; i++) {
117 flows[i] = FlowProvider.getFlow(names[i]);
118 flows[i].init(this);
119 }
120 } else {
121 for (int i = 0; i < flows.length; i++) {
122 flows[i].init(this);
123 }
124 }
125 subscriptionManager.init(this, registry);
126 }
127
128 protected Class<BrokerMBean> getServiceMBean() {
129 return BrokerMBean.class;
130 }
131
132 /**
133 * Get the name of the Container
134 *
135 * @return containerName
136 */
137 public String getContainerName() {
138 return container.getName();
139 }
140
141 /**
142 * Get the ManagementContext
143 *
144 * @return the managementContext
145 */
146 public ManagementContext getManagementContext() {
147 return container.getManagementContext();
148 }
149
150 /**
151 * Get the Registry
152 *
153 * @return the registry
154 */
155 public Registry getRegistry() {
156 return registry;
157 }
158
159 /**
160 * start brokering
161 *
162 * @throws JBIException
163 */
164 public void start() throws JBIException {
165 for (int i = 0; i < flows.length; i++) {
166 flows[i].start();
167 }
168 super.start();
169 }
170
171 /**
172 * stop brokering
173 *
174 * @throws JBIException
175 */
176 public void stop() throws JBIException {
177 for (int i = 0; i < flows.length; i++) {
178 flows[i].stop();
179 }
180 super.stop();
181 }
182
183 /**
184 * shutdown all Components
185 *
186 * @throws JBIException
187 */
188 public void shutDown() throws JBIException {
189 stop();
190 for (int i = 0; i < flows.length; i++) {
191 flows[i].shutDown();
192 }
193 container.deactivateComponent(SubscriptionManager.COMPONENT_NAME);
194 super.shutDown();
195 container.getManagementContext().unregisterMBean(this);
196 }
197
198 /**
199 * @return Returns the flow.
200 */
201 public String getFlowNames() {
202 return flowNames;
203 }
204
205 /**
206 * @param flowName
207 * The flow to set.
208 */
209 public void setFlowNames(String flowNames) {
210 this.flowNames = flowNames;
211 }
212
213 /**
214 * @return the subscriptionFlowName
215 */
216 public String getSubscriptionFlowName() {
217 return subscriptionFlowName;
218 }
219
220 /**
221 * Set the subscription flow name
222 *
223 * @param subscriptionFlowName
224 */
225 public void setSubscriptionFlowName(String subscriptionFlowName) {
226 this.subscriptionFlowName = subscriptionFlowName;
227 }
228
229 /**
230 * Set the flow
231 *
232 * @param flow
233 */
234 public void setFlows(Flow[] flows) {
235 this.flows = flows;
236 }
237
238 /**
239 * @return the Flow
240 */
241 public Flow[] getFlows() {
242 return this.flows;
243 }
244
245 /**
246 * suspend the flow to prevent any message exchanges
247 */
248 public void suspend() {
249 for (int i = 0; i < flows.length; i++) {
250 flows[i].suspend();
251 }
252 }
253
254 /**
255 * resume message exchange processing
256 */
257 public void resume() {
258 for (int i = 0; i < flows.length; i++) {
259 flows[i].resume();
260 }
261 }
262
263 /**
264 * Route an ExchangePacket to a destination
265 *
266 * @param exchange
267 * @throws JBIException
268 */
269 public void sendExchangePacket(MessageExchange me) throws JBIException {
270 MessageExchangeImpl exchange = (MessageExchangeImpl) me;
271 if (exchange.getRole() == Role.PROVIDER && exchange.getDestinationId() == null) {
272 resolveAddress(exchange);
273 }
274
275 boolean foundRoute = false;
276 // If we found a destination, or this is a reply
277 if (exchange.getEndpoint() != null || exchange.getRole() == Role.CONSUMER) {
278 foundRoute = true;
279 Flow flow = defaultFlowChooser.chooseFlow(flows, exchange);
280 if (flow == null) {
281 throw new MessagingException("Unable to choose a flow for exchange: " + exchange);
282 }
283 flow.send(exchange);
284 }
285
286 if (exchange.getRole() == Role.PROVIDER) {
287 getSubscriptionManager().dispatchToSubscribers(exchange);
288 }
289
290 if (!foundRoute) {
291 boolean throwException = true;
292 ActivationSpec activationSpec = exchange.getActivationSpec();
293 if (activationSpec != null) {
294 throwException = activationSpec.isFailIfNoDestinationEndpoint();
295 }
296 if (throwException) {
297 throw new MessagingException("Could not find route for exchange: " + exchange + " for service: " + exchange.getService()
298 + " and interface: " + exchange.getInterfaceName());
299 } else if (exchange.getMirror().getSyncState() == MessageExchangeImpl.SYNC_STATE_SYNC_SENT) {
300 exchange.handleAccept();
301 ComponentContextImpl ctx = (ComponentContextImpl) getSubscriptionManager().getContext();
302 exchange.setDestinationId(ctx.getComponentNameSpace());
303 // TODO: this will fail if exchange is InOut
304 getSubscriptionManager().done(exchange);
305 }
306 }
307 }
308
309 protected void resolveAddress(MessageExchangeImpl exchange) throws JBIException {
310 ServiceEndpoint theEndpoint = exchange.getEndpoint();
311 if (theEndpoint != null) {
312 if (theEndpoint instanceof ExternalEndpoint) {
313 throw new JBIException("External endpoints can not be used for routing: should be an internal or dynamic endpoint.");
314 }
315 if (!(theEndpoint instanceof AbstractServiceEndpoint)) {
316 throw new JBIException(
317 "Component-specific endpoints can not be used for routing: should be an internal or dynamic endpoint.");
318 }
319 }
320 // Resolve linked endpoints
321 if (theEndpoint instanceof LinkedEndpoint) {
322 QName svcName = ((LinkedEndpoint) theEndpoint).getToService();
323 String epName = ((LinkedEndpoint) theEndpoint).getToEndpoint();
324 ServiceEndpoint ep = registry.getInternalEndpoint(svcName, epName);
325 if (ep == null) {
326 throw new JBIException("Could not resolve linked endpoint: " + theEndpoint);
327 }
328 theEndpoint = ep;
329 }
330
331 // get the context which created the exchange
332 ComponentContextImpl context = exchange.getSourceContext();
333 if (theEndpoint == null) {
334 QName serviceName = exchange.getService();
335 QName interfaceName = exchange.getInterfaceName();
336
337 // check in order, ServiceName then InterfaceName
338 // check to see if there is a match on the serviceName
339 if (serviceName != null) {
340 ServiceEndpoint[] endpoints = registry.getEndpointsForService(serviceName);
341 endpoints = getMatchingEndpoints(endpoints, exchange);
342 theEndpoint = getServiceChooser(exchange).chooseEndpoint(endpoints, context, exchange);
343 if (theEndpoint == null) {
344 LOG.warn("ServiceName (" + serviceName + ") specified for routing, but can't find it registered");
345 }
346 }
347 if (theEndpoint == null && interfaceName != null) {
348 ServiceEndpoint[] endpoints = registry.getEndpointsForInterface(interfaceName);
349 endpoints = getMatchingEndpoints(endpoints, exchange);
350 theEndpoint = (InternalEndpoint) getInterfaceChooser(exchange).chooseEndpoint(endpoints, context, exchange);
351 if (theEndpoint == null) {
352 LOG.warn("InterfaceName (" + interfaceName + ") specified for routing, but can't find any matching components");
353 }
354 }
355 if (theEndpoint == null) {
356 // lets use the resolver on the activation spec if
357 // applicable
358 ActivationSpec activationSpec = exchange.getActivationSpec();
359 if (activationSpec != null) {
360 EndpointResolver destinationResolver = activationSpec.getDestinationResolver();
361 if (destinationResolver != null) {
362 try {
363 EndpointFilter filter = createEndpointFilter(context, exchange);
364 theEndpoint = (InternalEndpoint) destinationResolver.resolveEndpoint(context, exchange, filter);
365 } catch (JBIException e) {
366 throw new MessagingException("Failed to resolve endpoint: " + e, e);
367 }
368 }
369 }
370 }
371 }
372 if (theEndpoint != null) {
373 exchange.setEndpoint(theEndpoint);
374 }
375 if (LOG.isTraceEnabled()) {
376 LOG.trace("Routing exchange " + exchange + " to: " + theEndpoint);
377 }
378 }
379
380 /**
381 * Filter the given endpoints by asking to the provider and consumer if they
382 * are both ok to process the exchange.
383 *
384 * @param endpoints
385 * an array of internal endpoints to check
386 * @param exchange
387 * the exchange that will be serviced
388 * @return an array of endpoints on which both consumer and provider agrees
389 */
390 protected ServiceEndpoint[] getMatchingEndpoints(ServiceEndpoint[] endpoints, MessageExchangeImpl exchange) {
391 List<ServiceEndpoint> filtered = new ArrayList<ServiceEndpoint>();
392 ComponentMBeanImpl consumer = getRegistry().getComponent(exchange.getSourceId());
393
394 for (int i = 0; i < endpoints.length; i++) {
395 ComponentNameSpace id = ((InternalEndpoint) endpoints[i]).getComponentNameSpace();
396 if (id != null) {
397 ComponentMBeanImpl provider = getRegistry().getComponent(id);
398 if (provider != null
399 && (!consumer.getComponent().isExchangeWithProviderOkay(endpoints[i], exchange)
400 || !provider.getComponent().isExchangeWithConsumerOkay(endpoints[i], exchange))) {
401 continue;
402 }
403 }
404 filtered.add(endpoints[i]);
405 }
406 return filtered.toArray(new ServiceEndpoint[filtered.size()]);
407 }
408
409 /**
410 * @return the default EndpointChooser
411 */
412 public EndpointChooser getDefaultInterfaceChooser() {
413 return defaultInterfaceChooser;
414 }
415
416 /**
417 * Set the default EndpointChooser
418 *
419 * @param defaultInterfaceChooser
420 */
421 public void setDefaultInterfaceChooser(EndpointChooser defaultInterfaceChooser) {
422 this.defaultInterfaceChooser = defaultInterfaceChooser;
423 }
424
425 /**
426 * @return the default EndpointChooser
427 */
428 public EndpointChooser getDefaultServiceChooser() {
429 return defaultServiceChooser;
430 }
431
432 /**
433 * Set default EndpointChooser
434 *
435 * @param defaultServiceChooser
436 */
437 public void setDefaultServiceChooser(EndpointChooser defaultServiceChooser) {
438 this.defaultServiceChooser = defaultServiceChooser;
439 }
440
441 /**
442 * @return the defaultFlowChooser
443 */
444 public FlowChooser getDefaultFlowChooser() {
445 return defaultFlowChooser;
446 }
447
448 /**
449 * @param defaultFlowChooser
450 * the defaultFlowChooser to set
451 */
452 public void setDefaultFlowChooser(FlowChooser defaultFlowChooser) {
453 this.defaultFlowChooser = defaultFlowChooser;
454 }
455
456 /**
457 * Returns the endpoint chooser for endpoints found by service which will
458 * use the chooser on the exchange's activation spec if available otherwise
459 * will use the default
460 *
461 * @param exchange
462 * @return the EndpointChooser
463 */
464 protected EndpointChooser getServiceChooser(MessageExchangeImpl exchange) {
465 EndpointChooser chooser = null;
466 ActivationSpec activationSpec = exchange.getActivationSpec();
467 if (activationSpec != null) {
468 chooser = activationSpec.getServiceChooser();
469 }
470 if (chooser == null) {
471 chooser = defaultServiceChooser;
472 }
473 return chooser;
474 }
475
476 /**
477 * Returns the endpoint chooser for endpoints found by service which will
478 * use the chooser on the exchange's activation spec if available otherwise
479 * will use the default
480 *
481 * @param exchange
482 * @return the EndpointChooser
483 */
484 protected EndpointChooser getInterfaceChooser(MessageExchangeImpl exchange) {
485 EndpointChooser chooser = null;
486 ActivationSpec activationSpec = exchange.getActivationSpec();
487 if (activationSpec != null) {
488 chooser = activationSpec.getInterfaceChooser();
489 }
490 if (chooser == null) {
491 chooser = defaultInterfaceChooser;
492 }
493 return chooser;
494 }
495
496 /**
497 * Factory method to create an endpoint filter for the given component
498 * context and message exchange
499 *
500 * @param context
501 * @param exchange
502 * @return the EndpointFilter
503 */
504 protected EndpointFilter createEndpointFilter(ComponentContextImpl context, MessageExchangeImpl exchange) {
505 Component component = context.getComponent();
506 if (exchange.getRole() == Role.PROVIDER) {
507 return new ConsumerComponentEndpointFilter(component);
508 } else {
509 return new ProducerComponentEndpointFilter(component);
510 }
511 }
512
513 /**
514 * Get an array of MBeanOperationInfo
515 *
516 * @return array of OperationInfos
517 * @throws JMException
518 */
519 public MBeanOperationInfo[] getOperationInfos() throws JMException {
520 OperationInfoHelper helper = new OperationInfoHelper();
521 helper.addOperation(getObjectToManage(), "suspend", "suspend the NMR processing");
522 helper.addOperation(getObjectToManage(), "resume", "resume the NMR processing");
523
524 return OperationInfoHelper.join(super.getOperationInfos(), helper.getOperationInfos());
525 }
526
527 public JBIContainer getContainer() {
528 return container;
529 }
530
531 }