/* */ package org.jboss.ws.extensions.eventing.mgmt;
/* */
/* */ import java.io.PrintWriter;
/* */ import java.io.StringReader;
/* */ import java.io.StringWriter;
/* */ import java.net.InetAddress;
/* */ import java.net.URI;
/* */ import java.net.URISyntaxException;
/* */ import java.net.UnknownHostException;
/* */ import java.util.ArrayList;
/* */ import java.util.Collection;
/* */ import java.util.Date;
/* */ import java.util.Iterator;
/* */ import java.util.List;
/* */ import java.util.concurrent.BlockingQueue;
/* */ import java.util.concurrent.ConcurrentHashMap;
/* */ import java.util.concurrent.ConcurrentMap;
/* */ import java.util.concurrent.CopyOnWriteArrayList;
/* */ import java.util.concurrent.LinkedBlockingQueue;
/* */ import java.util.concurrent.ThreadPoolExecutor;
/* */ import java.util.concurrent.TimeUnit;
/* */ import javax.management.MBeanServer;
/* */ import javax.management.MBeanServerFactory;
/* */ import javax.naming.InitialContext;
/* */ import javax.naming.NamingException;
/* */ import javax.xml.bind.JAXBElement;
/* */ import javax.xml.namespace.QName;
/* */ import javax.xml.parsers.DocumentBuilder;
/* */ import javax.xml.parsers.DocumentBuilderFactory;
/* */ import org.apache.xml.utils.DefaultErrorHandler;
/* */ import org.jboss.logging.Logger;
/* */ import org.jboss.util.naming.Util;
/* */ import org.jboss.ws.WSException;
/* */ import org.jboss.ws.core.utils.UUIDGenerator;
/* */ import org.jboss.ws.extensions.eventing.deployment.EventingEndpointDeployment;
/* */ import org.jboss.ws.extensions.eventing.jaxws.AttributedURIType;
/* */ import org.jboss.ws.extensions.eventing.jaxws.EndpointReferenceType;
/* */ import org.jboss.ws.extensions.eventing.jaxws.ReferenceParametersType;
/* */ import org.jboss.wsf.common.DOMUtils;
/* */ import org.jboss.wsf.common.DOMWriter;
/* */ import org.w3c.dom.Element;
/* */ import org.xml.sax.InputSource;
/* */ import org.xml.sax.SAXException;
/* */ import org.xml.sax.SAXParseException;
/* */
/* */ public class SubscriptionManager
/* */ implements SubscriptionManagerMBean, EventDispatcher
/* */ {
/* 97 */ private static final Logger log = Logger.getLogger(SubscriptionManager.class);
/* */ private ConcurrentMap<URI, EventSource> eventSourceMapping;
/* */ private ConcurrentMap<URI, List<Subscription>> subscriptionMapping;
/* */ private BlockingQueue<Runnable> eventQueue;
/* */ private ThreadPoolExecutor threadPool;
/* */ private boolean validateNotifications;
/* */ private WatchDog watchDog;
/* */ private boolean isDispatcherBound;
/* */ private List<NotificationFailure> notificationFailures;
/* */ private String bindAddress;
/* 119 */ private static EventingBuilder builder = EventingBuilder.createEventingBuilder();
/* */
/* */ public SubscriptionManager()
/* */ {
/* 100 */ this.eventSourceMapping = new ConcurrentHashMap();
/* */
/* 102 */ this.subscriptionMapping = new ConcurrentHashMap();
/* */
/* 104 */ this.eventQueue = new LinkedBlockingQueue();
/* */
/* 108 */ this.validateNotifications = false;
/* */
/* 112 */ this.isDispatcherBound = false;
/* */
/* 115 */ this.notificationFailures = new ArrayList();
/* */ }
/* */
/* */ public String getBindAddress()
/* */ {
/* 123 */ if (this.bindAddress == null)
/* */ {
/* */ try
/* */ {
/* 127 */ InetAddress localHost = InetAddress.getLocalHost();
/* 128 */ log.debug("BindAddress not set, using host: " + localHost.getHostName());
/* 129 */ this.bindAddress = localHost.getHostName();
/* */ }
/* */ catch (UnknownHostException e)
/* */ {
/* 133 */ log.debug("BindAddress not set, using: 'localhost'");
/* 134 */ this.bindAddress = "localhost";
/* */ }
/* */ }
/* 137 */ return this.bindAddress;
/* */ }
/* */
/* */ public void setBindAddress(String bindAddress)
/* */ {
/* 142 */ this.bindAddress = bindAddress;
/* */ }
/* */
/* */ public void create() throws Exception
/* */ {
/* 147 */ MBeanServer server = getJMXServer();
/* 148 */ if (server != null)
/* */ {
/* 150 */ log.debug("Create subscription manager");
/* 151 */ server.registerMBean(this, OBJECT_NAME);
/* */ }
/* */ }
/* */
/* */ public void destroy() throws Exception
/* */ {
/* 157 */ MBeanServer server = getJMXServer();
/* 158 */ if (server != null)
/* */ {
/* 160 */ log.debug("Destroy subscription manager");
/* 161 */ server.unregisterMBean(OBJECT_NAME);
/* */ }
/* */ }
/* */
/* */ public void start() throws Exception
/* */ {
/* 167 */ log.debug("Start subscription manager");
/* */
/* 170 */ this.threadPool = new ThreadPoolExecutor(5, 15, 5000L, TimeUnit.MILLISECONDS, this.eventQueue);
/* */
/* 175 */ this.watchDog = new WatchDog(this.subscriptionMapping);
/* 176 */ this.watchDog.startup();
/* */ }
/* */
/* */ public void stop()
/* */ {
/* 181 */ log.debug("Stop subscription manager");
/* */ try
/* */ {
/* 185 */ Util.unbind(new InitialContext(), "EventDispatcher");
/* */
/* 188 */ this.threadPool.shutdown();
/* */
/* 191 */ this.watchDog.shutdown();
/* */
/* 193 */ for (URI eventSourceNS : this.eventSourceMapping.keySet())
/* */ {
/* 195 */ removeEventSource(eventSourceNS);
/* */ }
/* */ }
/* */ catch (NamingException e)
/* */ {
/* */ }
/* */ }
/* */
/* */ private static URI generateSubscriptionID()
/* */ {
/* */ try
/* */ {
/* 208 */ return new URI("urn:jbwse:" + UUIDGenerator.generateRandomUUIDString());
/* */ }
/* */ catch (URISyntaxException e) {
/* */ }
/* 212 */ throw new WSException(e.getMessage());
/* */ }
/* */
/* */ public void registerEventSource(EventingEndpointDeployment deploymentInfo)
/* */ {
/* 222 */ lazyBindEventDispatcher();
/* */
/* 224 */ EventSource eventSource = builder.newEventSource(deploymentInfo);
/* 225 */ if (!this.eventSourceMapping.containsKey(eventSource.getNameSpace()))
/* */ {
/* 227 */ this.eventSourceMapping.put(eventSource.getNameSpace(), eventSource);
/* 228 */ updateManagerAddress(deploymentInfo, eventSource);
/* */
/* 230 */ eventSource.setState(EventSource.State.CREATED);
/* 231 */ log.debug("Created: " + eventSource);
/* */ }
/* */ else
/* */ {
/* 235 */ eventSource = (EventSource)this.eventSourceMapping.get(eventSource.getNameSpace());
/* 236 */ updateManagerAddress(deploymentInfo, eventSource);
/* 237 */ this.subscriptionMapping.put(eventSource.getNameSpace(), new CopyOnWriteArrayList());
/* */
/* 239 */ eventSource.setState(EventSource.State.STARTED);
/* 240 */ log.debug("Started: " + eventSource);
/* */ }
/* */ }
/* */
/* */ private void lazyBindEventDispatcher()
/* */ {
/* 246 */ if (!this.isDispatcherBound)
/* */ {
/* */ try
/* */ {
/* 251 */ Util.rebind(new InitialContext(), "EventDispatcher", new DispatcherDelegate(getBindAddress()));
/* 252 */ log.info("Bound event dispatcher to java:/EventDispatcher");
/* 253 */ this.isDispatcherBound = true;
/* */ }
/* */ catch (NamingException e)
/* */ {
/* 257 */ throw new WSException("Unable to bind EventDispatcher ", e);
/* */ }
/* */ }
/* */ }
/* */
/* */ private static void updateManagerAddress(EventingEndpointDeployment deploymentInfo, EventSource eventSource)
/* */ {
/* 270 */ String addr = null;
/* 271 */ if (deploymentInfo.getPortName().getLocalPart().equals("SubscriptionManagerPort")) {
/* 272 */ addr = deploymentInfo.getEndpointAddress();
/* */ }
/* 274 */ if (addr != null)
/* 275 */ eventSource.setManagerAddress(addr);
/* */ }
/* */
/* */ public void removeEventSource(URI eventSourceNS)
/* */ {
/* 280 */ if (this.eventSourceMapping.containsKey(eventSourceNS))
/* */ {
/* 282 */ List subscriptions = (List)this.subscriptionMapping.get(eventSourceNS);
/* 283 */ for (Subscription s : subscriptions)
/* */ {
/* 285 */ s.end("http://schemas.xmlsoap.org/ws/2004/08/eventing/SourceShuttingDown");
/* */ }
/* */
/* 288 */ subscriptions.clear();
/* 289 */ this.eventSourceMapping.remove(eventSourceNS);
/* 290 */ log.debug("Event source " + eventSourceNS + " removed");
/* */ }
/* */ }
/* */
/* */ public SubscriptionTicket subscribe(URI eventSourceNS, EndpointReferenceType notifyTo, EndpointReferenceType endTo, Date expires, Filter filter)
/* */ throws SubscriptionError
/* */ {
/* 300 */ log.debug("Subscription request for " + eventSourceNS);
/* */
/* 302 */ EventSource eventSource = (EventSource)this.eventSourceMapping.get(eventSourceNS);
/* 303 */ if (null == eventSource) {
/* 304 */ throw new SubscriptionError("EventSourceUnableToProcess", "EventSource '" + eventSourceNS + "' not registered");
/* */ }
/* */
/* 307 */ if (expires != null)
/* */ {
/* 309 */ assertLeaseConstraints(expires);
/* */ }
/* */ else
/* */ {
/* 313 */ expires = new Date(System.currentTimeMillis() + 300000L);
/* */ }
/* */
/* 317 */ if (filter != null)
/* */ {
/* 319 */ if (eventSource.getSupportedFilterDialects().isEmpty()) {
/* 320 */ throw new SubscriptionError("FilteringNotSupported", "Filtering is not supported.");
/* */ }
/* */
/* 323 */ boolean filterAvailable = false;
/* 324 */ for (URI supportedDialect : eventSource.getSupportedFilterDialects())
/* */ {
/* 326 */ if (filter.getDialect().equals(supportedDialect))
/* */ {
/* 328 */ filterAvailable = true;
/* 329 */ break;
/* */ }
/* */ }
/* */
/* 333 */ if (!filterAvailable) {
/* 334 */ throw new SubscriptionError("FilteringRequestedUnavailable", "The requested filter dialect is not supported.");
/* */ }
/* */
/* */ }
/* */
/* 339 */ EndpointReferenceType epr = new EndpointReferenceType();
/* 340 */ AttributedURIType attrURI = new AttributedURIType();
/* 341 */ attrURI.setValue(eventSource.getManagerAddress().toString());
/* 342 */ epr.setAddress(attrURI);
/* 343 */ ReferenceParametersType refParam = new ReferenceParametersType();
/* 344 */ JAXBElement idqn = new JAXBElement(new QName("http://schemas.xmlsoap.org/ws/2004/08/eventing", "Identifier"), String.class, generateSubscriptionID().toString());
/* 345 */ refParam.getAny().add(idqn);
/* 346 */ epr.setReferenceParameters(refParam);
/* */
/* 348 */ Subscription subscription = new Subscription(eventSource.getNameSpace(), epr, notifyTo, endTo, expires, filter);
/* */
/* 350 */ ((List)this.subscriptionMapping.get(eventSourceNS)).add(subscription);
/* */
/* 352 */ log.debug("Registered subscription " + subscription.getIdentifier());
/* */
/* 354 */ return new SubscriptionTicket(epr, subscription.getExpires());
/* */ }
/* */
/* */ private void assertLeaseConstraints(Date expireDate) throws SubscriptionError
/* */ {
/* 359 */ long expires = expireDate.getTime() - System.currentTimeMillis();
/* 360 */ if ((expires < 0L) || (600000L < expires))
/* 361 */ throw new SubscriptionError("InvalidExpirationTime", "The expiration time requested is invalid: " + expires + "ms");
/* */ }
/* */
/* */ public Date renew(URI identifier, Date lease)
/* */ throws SubscriptionError
/* */ {
/* 374 */ Subscription subscription = subscriberForID(identifier);
/* 375 */ if (null == subscription) {
/* 376 */ throw new SubscriptionError("UnableToRenew", "Subscription " + identifier + " does not exist");
/* */ }
/* 378 */ if (lease != null)
/* 379 */ assertLeaseConstraints(lease);
/* 380 */ else lease = new Date(System.currentTimeMillis() + 300000L);
/* */
/* 382 */ subscription.setExpires(lease);
/* 383 */ return lease;
/* */ }
/* */
/* */ public final Date getStatus(URI identifier)
/* */ throws SubscriptionError
/* */ {
/* 395 */ Subscription subscription = subscriberForID(identifier);
/* 396 */ if (null == subscription) {
/* 397 */ throw new SubscriptionError("EventSourceUnableToProcess", "Subscription " + identifier + " does not exist");
/* */ }
/* 399 */ return subscription.getExpires();
/* */ }
/* */
/* */ public void unsubscribe(URI identifier)
/* */ throws SubscriptionError
/* */ {
/* 410 */ for (Iterator i$ = this.subscriptionMapping.values().iterator(); i$.hasNext(); ) { subscriptions = (List)i$.next();
/* */
/* 412 */ for (Subscription s : subscriptions)
/* */ {
/* 414 */ if (identifier.equals(s.getIdentifier()))
/* */ {
/* 416 */ subscriptions.remove(s);
/* 417 */ log.debug("Removed subscription " + s);
/* 418 */ break;
/* */ }
/* */ } }
/* */ List subscriptions;
/* */ }
/* */
/* */ public String showEventsourceTable()
/* */ {
/* 427 */ StringWriter sw = new StringWriter();
/* 428 */ PrintWriter pw = new PrintWriter(sw);
/* */
/* 430 */ pw.println("<h3>Deployed Eventsources</h3>");
/* */
/* 432 */ pw.println("<table>");
/* 433 */ pw.println("<tr><td>Name</td><td>NS</td></tr>");
/* */
/* 435 */ for (EventSource source : this.eventSourceMapping.values())
/* */ {
/* 437 */ pw.println("<tr><td>" + source.getName() + "</td><td>" + source.getNameSpace() + "</td></tr>");
/* */ }
/* */
/* 440 */ pw.println("</table>");
/* 441 */ pw.close();
/* */
/* 443 */ return sw.toString();
/* */ }
/* */
/* */ public String showSubscriptionTable()
/* */ {
/* 448 */ StringWriter sw = new StringWriter();
/* 449 */ PrintWriter pw = new PrintWriter(sw);
/* */
/* 451 */ pw.println("<h3>Registered Subscriptions</h3>");
/* */
/* 453 */ pw.println("<table>");
/* 454 */ pw.println("<tr><td>Identifier</td><td>Expires</td><td>Filter</td></tr>");
/* */
/* 456 */ for (List subscriptions : this.subscriptionMapping.values())
/* */ {
/* 458 */ for (Subscription s : subscriptions)
/* */ {
/* 460 */ pw.println("<tr><td>" + s.getIdentifier() + "</td><td>" + s.getExpires() + "</td><td>" + s.getFilter().getExpression() + "</td></tr>");
/* */ }
/* */ }
/* 463 */ pw.println("</table>");
/* 464 */ pw.close();
/* */
/* 466 */ return sw.toString();
/* */ }
/* */
/* */ private Subscription subscriberForID(URI id)
/* */ {
/* 471 */ Subscription subscription = null;
/* 472 */ for (List subscriptions : this.subscriptionMapping.values())
/* */ {
/* 474 */ for (Subscription s : subscriptions)
/* */ {
/* 476 */ if (id.equals(s.getIdentifier()))
/* */ {
/* 478 */ subscription = s;
/* 479 */ break;
/* */ }
/* */ }
/* */ }
/* 483 */ return subscription;
/* */ }
/* */
/* */ public void dispatch(URI eventSourceNS, Element payload)
/* */ {
/* 488 */ DispatchJob dispatchJob = new DispatchJob(eventSourceNS, payload, this.subscriptionMapping);
/* 489 */ if ((this.validateNotifications) && (!validateMessage(DOMWriter.printNode(payload, false), eventSourceNS)))
/* */ {
/* 491 */ throw new DispatchException("Notification message validation failed!");
/* */ }
/* 493 */ this.threadPool.execute(dispatchJob);
/* */ }
/* */
/* */ public void addNotificationFailure(NotificationFailure failure)
/* */ {
/* 498 */ this.notificationFailures.add(failure);
/* */ }
/* */
/* */ public List<NotificationFailure> showNotificationFailures()
/* */ {
/* 503 */ return this.notificationFailures;
/* */ }
/* */
/* */ private boolean validateMessage(String msg, URI eventSourceNS)
/* */ {
/* */ try
/* */ {
/* 510 */ EventSource es = (EventSource)this.eventSourceMapping.get(eventSourceNS);
/* 511 */ log.info("Validating message: \n\n" + msg + "\n\nagainst the following schema(s): \n");
/* 512 */ for (int i = 0; i < es.getNotificationSchema().length; i++)
/* */ {
/* 514 */ log.info(es.getNotificationSchema()[i]);
/* */ }
/* 516 */ Element rootElement = DOMUtils.parse(msg);
/* 517 */ if (!es.getNotificationRootElementNS().equalsIgnoreCase(rootElement.getNamespaceURI()))
/* */ {
/* 519 */ log.error("Root element expected namespace: " + es.getNotificationRootElementNS());
/* 520 */ return false;
/* */ }
/* 522 */ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
/* 523 */ factory.setNamespaceAware(true);
/* 524 */ factory.setValidating(true);
/* 525 */ factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
/* */
/* 527 */ String[] notificationSchemas = es.getNotificationSchema();
/* 528 */ InputSource[] is = new InputSource[notificationSchemas.length];
/* 529 */ for (int i = 0; i < notificationSchemas.length; i++)
/* */ {
/* 531 */ is[i] = new InputSource(new StringReader(notificationSchemas[(notificationSchemas.length - 1 - i)]));
/* */ }
/* */
/* 535 */ factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", is);
/* 536 */ DocumentBuilder docBuilder = factory.newDocumentBuilder();
/* 537 */ DefaultErrorHandler errorHandler = new Validator(null);
/* 538 */ docBuilder.setErrorHandler(errorHandler);
/* 539 */ docBuilder.parse(new InputSource(new StringReader(msg)));
/* 540 */ log.info("Document validated!");
/* 541 */ return true;
/* */ }
/* */ catch (Exception e)
/* */ {
/* 545 */ log.error(e);
/* 546 */ log.info("Cannot validate and/or parse the document!");
/* 547 */ }return false;
/* */ }
/* */
/* */ public int getCorePoolSize()
/* */ {
/* 557 */ return this.threadPool.getCorePoolSize();
/* */ }
/* */
/* */ public int getMaximumPoolSize()
/* */ {
/* 562 */ return this.threadPool.getMaximumPoolSize();
/* */ }
/* */
/* */ public int getLargestPoolSize()
/* */ {
/* 567 */ return this.threadPool.getLargestPoolSize();
/* */ }
/* */
/* */ public int getActiveCount()
/* */ {
/* 572 */ return this.threadPool.getActiveCount();
/* */ }
/* */
/* */ public long getCompletedTaskCount()
/* */ {
/* 577 */ return this.threadPool.getCompletedTaskCount();
/* */ }
/* */
/* */ public void setCorePoolSize(int corePoolSize)
/* */ {
/* 582 */ this.threadPool.setCorePoolSize(corePoolSize);
/* */ }
/* */
/* */ public void setMaxPoolSize(int maxPoolSize)
/* */ {
/* 587 */ this.threadPool.setMaximumPoolSize(maxPoolSize);
/* */ }
/* */
/* */ public void setEventKeepAlive(long millies)
/* */ {
/* 592 */ this.threadPool.setKeepAliveTime(millies, TimeUnit.MILLISECONDS);
/* */ }
/* */
/* */ public boolean isValidateNotifications()
/* */ {
/* 597 */ return this.validateNotifications;
/* */ }
/* */
/* */ public void setValidateNotifications(boolean validateNotifications)
/* */ {
/* 602 */ this.validateNotifications = validateNotifications;
/* */ }
/* */
/* */ private MBeanServer getJMXServer()
/* */ {
/* 607 */ MBeanServer server = null;
/* 608 */ ArrayList servers = MBeanServerFactory.findMBeanServer(null);
/* 609 */ if (servers.size() > 0)
/* */ {
/* 611 */ server = (MBeanServer)servers.get(0);
/* */ }
/* 613 */ return server;
/* */ }
/* */
/* */ private class Validator extends DefaultErrorHandler
/* */ {
/* */ private Validator()
/* */ {
/* */ }
/* */
/* */ public void error(SAXParseException exception)
/* */ throws SAXException
/* */ {
/* 676 */ throw new SAXException(exception);
/* */ }
/* */
/* */ public void fatalError(SAXParseException exception) throws SAXException
/* */ {
/* 681 */ throw new SAXException(exception);
/* */ }
/* */
/* */ public void warning(SAXParseException exception)
/* */ throws SAXException
/* */ {
/* */ }
/* */ }
/* */
/* */ private class WatchDog
/* */ implements Runnable
/* */ {
/* */ private ConcurrentMap<URI, List<Subscription>> subscriptions;
/* 623 */ private boolean active = true;
/* */ private Thread worker;
/* */
/* */ public WatchDog()
/* */ {
/* 628 */ this.subscriptions = subscriptions;
/* */ }
/* */
/* */ public void run()
/* */ {
/* 633 */ while (this.active)
/* */ {
/* 636 */ for (Iterator i$ = SubscriptionManager.this.subscriptionMapping.values().iterator(); i$.hasNext(); ) { subscriptions = (List)i$.next();
/* */
/* 638 */ for (Subscription s : subscriptions)
/* */ {
/* 640 */ if (s.isExpired())
/* */ {
/* 642 */ s.end("http://schemas.xmlsoap.org/ws/2004/08/eventing/SourceCanceling");
/* 643 */ subscriptions.remove(s);
/* */ }
/* */ }
/* */ }
/* */ try
/* */ {
/* */ List subscriptions;
/* 650 */ Thread.sleep(60000L);
/* */ }
/* */ catch (InterruptedException e)
/* */ {
/* 654 */ SubscriptionManager.log.error(e);
/* */ }
/* */ }
/* */ }
/* */
/* */ public void startup()
/* */ {
/* 661 */ this.worker = new Thread(this, "SubscriptionWatchDog");
/* 662 */ this.worker.start();
/* */ }
/* */
/* */ public void shutdown()
/* */ {
/* 667 */ this.active = false;
/* */ }
/* */ }
/* */ }
/* Location: /home/mnovotny/projects/EMBEDDED_JBOSS_BETA3_COMMUNITY/embedded/output/lib/embedded-jboss/lib/jboss-embedded-all.jar
* Qualified Name: org.jboss.ws.extensions.eventing.mgmt.SubscriptionManager
* JD-Core Version: 0.6.0
*/