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.framework;
018
019 import java.util.ArrayList;
020 import java.util.Collection;
021 import java.util.HashSet;
022 import java.util.Iterator;
023 import java.util.List;
024 import java.util.Map;
025 import java.util.Set;
026 import java.util.concurrent.ConcurrentHashMap;
027
028 import javax.jbi.JBIException;
029 import javax.jbi.component.ComponentContext;
030 import javax.jbi.servicedesc.ServiceEndpoint;
031 import javax.management.JMException;
032 import javax.management.ObjectName;
033 import javax.xml.namespace.QName;
034
035 import org.apache.commons.logging.Log;
036 import org.apache.commons.logging.LogFactory;
037 import org.apache.servicemix.jbi.event.EndpointEvent;
038 import org.apache.servicemix.jbi.event.EndpointListener;
039 import org.apache.servicemix.jbi.framework.support.EndpointProcessor;
040 import org.apache.servicemix.jbi.servicedesc.AbstractServiceEndpoint;
041 import org.apache.servicemix.jbi.servicedesc.ExternalEndpoint;
042 import org.apache.servicemix.jbi.servicedesc.InternalEndpoint;
043 import org.apache.servicemix.jbi.servicedesc.LinkedEndpoint;
044
045 /**
046 * Registry for Components
047 *
048 * @version $Revision: 564900 $
049 */
050 public class EndpointRegistry {
051
052 private static final Log LOG = LogFactory.getLog(EndpointRegistry.class);
053
054 private Registry registry;
055
056 private Map<AbstractServiceEndpoint, Endpoint> endpointMBeans;
057
058 private Map<String, ServiceEndpoint> internalEndpoints;
059
060 private Map<String, ServiceEndpoint> externalEndpoints;
061
062 private Map<String, ServiceEndpoint> linkedEndpoints;
063
064 private Map<QName, InterfaceConnection> interfaceConnections;
065
066 private List<EndpointProcessor> endpointProcessors;
067
068 /**
069 * Constructor
070 *
071 * @param cr
072 */
073 public EndpointRegistry(Registry registry) {
074 this.registry = registry;
075 this.endpointMBeans = new ConcurrentHashMap<AbstractServiceEndpoint, Endpoint>();
076 this.internalEndpoints = new ConcurrentHashMap<String, ServiceEndpoint>();
077 this.externalEndpoints = new ConcurrentHashMap<String, ServiceEndpoint>();
078 this.linkedEndpoints = new ConcurrentHashMap<String, ServiceEndpoint>();
079 this.interfaceConnections = new ConcurrentHashMap<QName, InterfaceConnection>();
080 this.endpointProcessors = getEndpointProcessors();
081 }
082
083 private List<EndpointProcessor> getEndpointProcessors() {
084 List<EndpointProcessor> l = new ArrayList<EndpointProcessor>();
085 String[] classes = {"org.apache.servicemix.jbi.framework.support.SUDescriptorProcessor",
086 "org.apache.servicemix.jbi.framework.support.WSDL1Processor",
087 "org.apache.servicemix.jbi.framework.support.WSDL2Processor" };
088 for (int i = 0; i < classes.length; i++) {
089 try {
090 EndpointProcessor p = (EndpointProcessor) Class.forName(classes[i]).newInstance();
091 p.init(registry);
092 l.add(p);
093 } catch (Throwable e) {
094 LOG.warn("Disabled endpoint processor '" + classes[i] + "': " + e);
095 }
096 }
097 return l;
098 }
099
100 public ServiceEndpoint[] getEndpointsForComponent(ComponentNameSpace cns) {
101 Collection<ServiceEndpoint> endpoints = new ArrayList<ServiceEndpoint>();
102 for (Iterator<ServiceEndpoint> iter = getInternalEndpoints().iterator(); iter.hasNext();) {
103 InternalEndpoint endpoint = (InternalEndpoint) iter.next();
104 if (cns.equals(endpoint.getComponentNameSpace())) {
105 endpoints.add(endpoint);
106 }
107 }
108 return asEndpointArray(endpoints);
109 }
110
111 public ServiceEndpoint[] getAllEndpointsForComponent(ComponentNameSpace cns) {
112 Collection<ServiceEndpoint> endpoints = new ArrayList<ServiceEndpoint>();
113 for (Iterator<ServiceEndpoint> iter = getInternalEndpoints().iterator(); iter.hasNext();) {
114 InternalEndpoint endpoint = (InternalEndpoint) iter.next();
115 if (cns.equals(endpoint.getComponentNameSpace())) {
116 endpoints.add(endpoint);
117 }
118 }
119 for (Iterator<ServiceEndpoint> iter = getExternalEndpoints().iterator(); iter.hasNext();) {
120 ExternalEndpoint endpoint = (ExternalEndpoint) iter.next();
121 if (cns.equals(endpoint.getComponentNameSpace())) {
122 endpoints.add(endpoint);
123 }
124 }
125 return asEndpointArray(endpoints);
126 }
127
128 /**
129 * Returns a collection of Endpoint objects
130 */
131 public Collection<Endpoint> getEndpointMBeans() {
132 return endpointMBeans.values();
133 }
134
135 /**
136 * Get all endpoints for a given service
137 *
138 * @param serviceName
139 * @return array of endpoints
140 */
141 public ServiceEndpoint[] getEndpointsForService(QName serviceName) {
142 Collection<ServiceEndpoint> collection = getEndpointsByService(serviceName, getInternalEndpoints());
143 return asEndpointArray(collection);
144 }
145
146 /**
147 * This will return the endpoints for all services and endpoints that implement the named interface (portType in
148 * WSDL 1.1). This method does NOT include external endpoints.
149 *
150 * @param interfaceName qualified name of interface/portType that is implemented by the endpoint; if
151 * <code>null</code> then all activated endpoints in the JBI environment must be returned.
152 * @return an array of available endpoints for the specified interface name; must be non-null; may be empty.
153 */
154 public ServiceEndpoint[] getEndpointsForInterface(QName interfaceName) {
155 if (interfaceName == null) {
156 return asEndpointArray(internalEndpoints.values());
157 }
158 InterfaceConnection conn = interfaceConnections.get(interfaceName);
159 if (conn != null) {
160 String key = getKey(conn.service, conn.endpoint);
161 ServiceEndpoint ep = internalEndpoints.get(key);
162 if (ep == null) {
163 LOG.warn("Connection for interface " + interfaceName + " could not find target for service "
164 + conn.service + " and endpoint " + conn.endpoint);
165 return new ServiceEndpoint[0];
166 } else {
167 return new ServiceEndpoint[] {ep };
168 }
169 }
170 Collection<ServiceEndpoint> result = getEndpointsByInterface(interfaceName, getInternalEndpoints());
171 return asEndpointArray(result);
172 }
173
174 /**
175 * Activate an endpoint
176 *
177 * @param provider
178 * @param serviceName
179 * @param endpointName
180 * @return the endpoint
181 * @throws JBIException
182 */
183 public InternalEndpoint registerInternalEndpoint(ComponentContextImpl provider,
184 QName serviceName,
185 String endpointName) throws JBIException {
186 // Create endpoint
187 String key = getKey(serviceName, endpointName);
188 InternalEndpoint registered = (InternalEndpoint) internalEndpoints.get(key);
189 // Check if the endpoint has already been activated by another component
190 if (registered != null && registered.isLocal()) {
191 throw new JBIException("An internal endpoint for service " + serviceName
192 + " and endpoint " + endpointName + " is already registered");
193 }
194 // Create a new endpoint
195 InternalEndpoint serviceEndpoint = new InternalEndpoint(provider.getComponentNameSpace(), endpointName, serviceName);
196 // Get interface from activationSpec
197 if (provider.getActivationSpec().getInterfaceName() != null) {
198 serviceEndpoint.addInterface(provider.getActivationSpec().getInterfaceName());
199 }
200 // Get interfaces
201 for (Iterator<EndpointProcessor> it = endpointProcessors.iterator(); it.hasNext();) {
202 EndpointProcessor p = it.next();
203 p.process(serviceEndpoint);
204 }
205 // Set remote namespaces
206 if (registered != null) {
207 InternalEndpoint[] remote = registered.getRemoteEndpoints();
208 for (int i = 0; i < remote.length; i++) {
209 serviceEndpoint.addRemoteEndpoint(remote[i]);
210 }
211 }
212 // Register endpoint
213 internalEndpoints.put(key, serviceEndpoint);
214 registerEndpoint(serviceEndpoint);
215 fireEvent(serviceEndpoint, EndpointEvent.INTERNAL_ENDPOINT_REGISTERED);
216 return serviceEndpoint;
217 }
218
219 /**
220 * Called by component context when endpoints are being deactivated.
221 *
222 * @param provider
223 * @param serviceEndpoint
224 */
225 public void unregisterInternalEndpoint(ComponentContext provider, InternalEndpoint serviceEndpoint) {
226 if (serviceEndpoint.isClustered()) {
227 fireEvent(serviceEndpoint, EndpointEvent.INTERNAL_ENDPOINT_UNREGISTERED);
228 // set endpoint to be no more local
229 serviceEndpoint.setComponentName(null);
230 } else {
231 String key = getKey(serviceEndpoint);
232 internalEndpoints.remove(key);
233 unregisterEndpoint(serviceEndpoint);
234 fireEvent(serviceEndpoint, EndpointEvent.INTERNAL_ENDPOINT_UNREGISTERED);
235 }
236 }
237
238 /**
239 * Registers a remote endpoint
240 *
241 * @param remote
242 */
243 public void registerRemoteEndpoint(InternalEndpoint remote) {
244 InternalEndpoint endpoint = (InternalEndpoint) internalEndpoints.get(getKey(remote));
245 // Create endpoint if not already existing
246 if (endpoint == null) {
247 endpoint = new InternalEndpoint(null, remote.getEndpointName(), remote.getServiceName());
248 internalEndpoints.put(getKey(endpoint), endpoint);
249 }
250 // Add remote endpoint
251 endpoint.addRemoteEndpoint(remote);
252 fireEvent(remote, EndpointEvent.REMOTE_ENDPOINT_REGISTERED);
253 }
254
255 /**
256 * Unregisters a remote endpoint
257 *
258 * @param remote
259 */
260 public void unregisterRemoteEndpoint(InternalEndpoint remote) {
261 String key = getKey(remote);
262 InternalEndpoint endpoint = (InternalEndpoint) internalEndpoints.get(key);
263 if (endpoint != null) {
264 endpoint.removeRemoteEndpoint(remote);
265 if (!endpoint.isClustered() && !endpoint.isLocal()) {
266 internalEndpoints.remove(key);
267 unregisterEndpoint(endpoint);
268 }
269 fireEvent(remote, EndpointEvent.REMOTE_ENDPOINT_UNREGISTERED);
270 }
271 }
272
273 /**
274 * Get the named ServiceEndpoint, if activated
275 *
276 * @param service
277 * @param name
278 * @return the activated ServiceEndpoint or null
279 */
280 public ServiceEndpoint getEndpoint(QName service, String name) {
281 String key = getKey(service, name);
282 ServiceEndpoint ep = linkedEndpoints.get(key);
283 if (ep == null) {
284 ep = internalEndpoints.get(key);
285 }
286 return ep;
287 }
288
289 public ServiceEndpoint getInternalEndpoint(QName service, String name) {
290 return internalEndpoints.get(getKey(service, name));
291 }
292
293 /**
294 * Registers the given external endpoint with the NMR. This indicates to the NMR that the given endpoint is used as
295 * a proxy for external service consumers to access an internal service of the same service name (but a different
296 * endpoint name).
297 *
298 * @param provider
299 * @param externalEndpoint the external endpoint to be registered, must be non-null.
300 * @throws JBIException
301 */
302 public void registerExternalEndpoint(ComponentNameSpace cns, ServiceEndpoint externalEndpoint) throws JBIException {
303 ExternalEndpoint serviceEndpoint = new ExternalEndpoint(cns, externalEndpoint);
304 if (externalEndpoints.get(getKey(serviceEndpoint)) != null) {
305 throw new JBIException("An external endpoint for service " + externalEndpoint.getServiceName()
306 + " and endpoint " + externalEndpoint.getEndpointName() + " is already registered");
307 }
308 registerEndpoint(serviceEndpoint);
309 externalEndpoints.put(getKey(serviceEndpoint), serviceEndpoint);
310 fireEvent(serviceEndpoint, EndpointEvent.EXTERNAL_ENDPOINT_REGISTERED);
311 }
312
313 /**
314 * Deregisters the given external endpoint with the NMR. This indicates to the NMR that the given external endpoint
315 * can no longer be used as a proxy for external service consumers to access an internal service of the same service
316 * name.
317 *
318 * @param provider
319 * @param externalEndpoint the external endpoint to be deregistered; must be non-null.
320 */
321 public void unregisterExternalEndpoint(ComponentNameSpace cns, ServiceEndpoint externalEndpoint) {
322 ExternalEndpoint ep = (ExternalEndpoint) externalEndpoints.remove(getKey(externalEndpoint));
323 unregisterEndpoint(ep);
324 fireEvent(ep, EndpointEvent.EXTERNAL_ENDPOINT_UNREGISTERED);
325 }
326
327 /**
328 * This methods returns only registered external endpoints
329 *
330 * @param interfaceName qualified name of interface implemented by the endpoints; must be non-null.
331 * @return an array of available external endpoints for the specified interface name; must be non-null; may be
332 * empty.
333 */
334 public ServiceEndpoint[] getExternalEndpointsForInterface(QName interfaceName) {
335 Collection<ServiceEndpoint> endpoints = getEndpointsByInterface(interfaceName, getExternalEndpoints());
336 return asEndpointArray(endpoints);
337 }
338
339 /**
340 * Get external endpoints for the service
341 *
342 * @param serviceName qualified name of service that contains the endpoints; must be non-null.
343 * @return an array of available external endpoints for the specified service name; must be non-null; may be empty.
344 */
345 public ServiceEndpoint[] getExternalEndpointsForService(QName serviceName) {
346 Collection<ServiceEndpoint> endpoints = getEndpointsByService(serviceName, getExternalEndpoints());
347 return asEndpointArray(endpoints);
348 }
349
350 /**
351 * Helper method to convert the given collection into an array of endpoints
352 *
353 * @param collection
354 * @return array of endpoints
355 */
356 protected ServiceEndpoint[] asEndpointArray(Collection<ServiceEndpoint> collection) {
357 if (collection == null) {
358 return new ServiceEndpoint[0];
359 }
360 ServiceEndpoint[] answer = new ServiceEndpoint[collection.size()];
361 answer = collection.toArray(answer);
362 return answer;
363 }
364
365 /**
366 * return a collection of endpoints
367 *
368 * @param serviceName
369 * @param endpoints
370 * @return collection of endpoints
371 */
372 protected Collection<ServiceEndpoint> getEndpointsByService(QName serviceName, Collection<ServiceEndpoint> endpoints) {
373 Collection<ServiceEndpoint> answer = new ArrayList<ServiceEndpoint>();
374 for (Iterator<ServiceEndpoint> i = endpoints.iterator(); i.hasNext();) {
375 ServiceEndpoint endpoint = i.next();
376 if (endpoint.getServiceName().equals(serviceName)) {
377 answer.add(endpoint);
378 }
379 }
380 return answer;
381 }
382
383 /**
384 * Filters the given endpoints and returns those implementing the
385 * given interface name. If interfaceName is null, then no filter
386 * is applied.
387 *
388 */
389 protected Collection<ServiceEndpoint> getEndpointsByInterface(QName interfaceName, Collection<ServiceEndpoint> endpoints) {
390 if (interfaceName == null) {
391 return endpoints;
392 }
393 Set<ServiceEndpoint> answer = new HashSet<ServiceEndpoint>();
394 for (Iterator<ServiceEndpoint> i = endpoints.iterator(); i.hasNext();) {
395 ServiceEndpoint endpoint = i.next();
396 QName[] interfaces = endpoint.getInterfaces();
397 if (interfaces != null) {
398 for (int k = 0; k < interfaces.length; k++) {
399 QName qn = interfaces[k];
400 if (qn != null && qn.equals(interfaceName)) {
401 answer.add(endpoint);
402 break;
403 }
404 }
405 }
406 }
407 return answer;
408 }
409
410 /**
411 * @return all default endpoints
412 */
413 protected Collection<ServiceEndpoint> getInternalEndpoints() {
414 return internalEndpoints.values();
415 }
416
417 /**
418 * @return all external endpoints
419 */
420 protected Collection<ServiceEndpoint> getExternalEndpoints() {
421 return externalEndpoints.values();
422 }
423
424 /**
425 * Registers an endpoint connection.
426 *
427 * @param fromSvc
428 * @param fromEp
429 * @param toSvc
430 * @param toEp
431 * @param link
432 * @throws JBIException
433 */
434 public void registerEndpointConnection(QName fromSvc, String fromEp,
435 QName toSvc, String toEp, String link) throws JBIException {
436 LinkedEndpoint ep = new LinkedEndpoint(fromSvc, fromEp, toSvc, toEp, link);
437 if (linkedEndpoints.get(getKey(ep)) != null) {
438 throw new JBIException("An endpoint connection for service " + ep.getServiceName() + " and name "
439 + ep.getEndpointName() + " is already registered");
440 }
441 linkedEndpoints.put(getKey(ep), ep);
442 registerEndpoint(ep);
443 fireEvent(ep, EndpointEvent.LINKED_ENDPOINT_REGISTERED);
444 }
445
446 /**
447 * Unregister an endpoint connection.
448 *
449 * @param fromSvc
450 * @param fromEp
451 */
452 public void unregisterEndpointConnection(QName fromSvc, String fromEp) {
453 LinkedEndpoint ep = (LinkedEndpoint) linkedEndpoints.remove(getKey(fromSvc, fromEp));
454 unregisterEndpoint(ep);
455 fireEvent(ep, EndpointEvent.LINKED_ENDPOINT_UNREGISTERED);
456 }
457
458 /**
459 * Registers an interface connection.
460 *
461 * @param fromItf
462 * @param toSvc
463 * @param toEp
464 * @throws JBIException
465 */
466 public void registerInterfaceConnection(QName fromItf, QName toSvc, String toEp) throws JBIException {
467 if (interfaceConnections.get(fromItf) != null) {
468 throw new JBIException("An interface connection for " + fromItf + " is already registered");
469 }
470 interfaceConnections.put(fromItf, new InterfaceConnection(toSvc, toEp));
471 }
472
473 /**
474 * Unregisters an interface connection.
475 *
476 * @param fromItf
477 */
478 public void unregisterInterfaceConnection(QName fromItf) {
479 interfaceConnections.remove(fromItf);
480
481 }
482
483 private void registerEndpoint(AbstractServiceEndpoint serviceEndpoint) {
484 try {
485 Endpoint endpoint = new Endpoint(serviceEndpoint, registry);
486 ObjectName objectName = registry.getContainer().getManagementContext().createObjectName(endpoint);
487 registry.getContainer().getManagementContext().registerMBean(objectName, endpoint, EndpointMBean.class);
488 endpointMBeans.put(serviceEndpoint, endpoint);
489 } catch (JMException e) {
490 LOG.error("Could not register MBean for endpoint", e);
491 }
492 }
493
494 private void unregisterEndpoint(AbstractServiceEndpoint se) {
495 Endpoint ep = endpointMBeans.remove(se);
496 try {
497 registry.getContainer().getManagementContext().unregisterMBean(ep);
498 } catch (JBIException e) {
499 LOG.error("Could not unregister MBean for endpoint", e);
500 }
501 }
502
503 private String getKey(ServiceEndpoint ep) {
504 return getKey(ep.getServiceName(), ep.getEndpointName());
505 }
506
507 private String getKey(QName svcName, String epName) {
508 return svcName + epName;
509 }
510
511 private static class InterfaceConnection {
512 QName service;
513 String endpoint;
514 InterfaceConnection(QName service, String endpoint) {
515 this.service = service;
516 this.endpoint = endpoint;
517 }
518 }
519
520 protected void fireEvent(ServiceEndpoint ep, int type) {
521 EndpointEvent event = new EndpointEvent(ep, type);
522 EndpointListener[] listeners = (EndpointListener[]) registry.getContainer().getListeners(EndpointListener.class);
523 for (int i = 0; i < listeners.length; i++) {
524 switch (type) {
525 case EndpointEvent.INTERNAL_ENDPOINT_REGISTERED:
526 listeners[i].internalEndpointRegistered(event);
527 break;
528 case EndpointEvent.INTERNAL_ENDPOINT_UNREGISTERED:
529 listeners[i].internalEndpointUnregistered(event);
530 break;
531 case EndpointEvent.EXTERNAL_ENDPOINT_REGISTERED:
532 listeners[i].externalEndpointRegistered(event);
533 break;
534 case EndpointEvent.EXTERNAL_ENDPOINT_UNREGISTERED:
535 listeners[i].externalEndpointUnregistered(event);
536 break;
537 case EndpointEvent.LINKED_ENDPOINT_REGISTERED:
538 listeners[i].linkedEndpointRegistered(event);
539 break;
540 case EndpointEvent.LINKED_ENDPOINT_UNREGISTERED:
541 listeners[i].linkedEndpointUnregistered(event);
542 break;
543 case EndpointEvent.REMOTE_ENDPOINT_REGISTERED:
544 listeners[i].remoteEndpointRegistered(event);
545 break;
546 case EndpointEvent.REMOTE_ENDPOINT_UNREGISTERED:
547 listeners[i].remoteEndpointUnregistered(event);
548 break;
549 default:
550 break;
551 }
552 }
553
554 }
555
556 }