package org.jboss.seam.remoting.messaging; import static org.jboss.seam.annotations.Install.BUILT_IN; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import javax.jms.ExceptionListener; import javax.jms.JMSException; import javax.jms.TopicConnection; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; /** * * @author Shane Bryzak */ @Scope(ScopeType.APPLICATION) @BypassInterceptors @Name("org.jboss.seam.remoting.messaging.subscriptionRegistry") @Install(value = false, precedence=BUILT_IN) public class SubscriptionRegistry { private static final LogProvider log = Logging.getLogProvider(SubscriptionRegistry.class); private String connectionProvider; private volatile TopicConnection topicConnection; private Object monitor = new Object(); private Map<String,RemoteSubscriber> subscriptions = new ConcurrentHashMap<String,RemoteSubscriber>(); /** * Contains a list of all the topics that clients are allowed to subscribe to. */ private Set<String> allowedTopics = new HashSet<String>(); public static SubscriptionRegistry instance() { SubscriptionRegistry registry = (SubscriptionRegistry) Component.getInstance(SubscriptionRegistry.class); if (registry == null) { throw new IllegalStateException("No SubscriptionRegistry exists"); } return registry; } public Set<String> getAllowedTopics() { return allowedTopics; } public void setAllowedTopics(Set<String> allowedTopics) { this.allowedTopics = allowedTopics; } public String getConnectionProvider() { return connectionProvider; } public void setConnectionProvider(String connectionProvider) { this.connectionProvider = connectionProvider; } private TopicConnection getTopicConnection() throws Exception { if (topicConnection == null) { synchronized(monitor) { if (topicConnection == null) { topicConnection = org.jboss.seam.jms.TopicConnection.instance(); topicConnection.setExceptionListener(new ExceptionListener() { public void onException(JMSException ex) { // swallow the exception for now - do we need to try and reconnect??? } }); topicConnection.start(); } } } return topicConnection; } public RemoteSubscriber subscribe(String topicName) { if (!allowedTopics.isEmpty() && !allowedTopics.contains(topicName)) { throw new IllegalArgumentException(String.format( "Cannot subscribe to a topic that is not allowed. Topic [%s] is not an " + "allowed topic.", topicName)); } RemoteSubscriber sub = new RemoteSubscriber(UUID.randomUUID().toString(), topicName); try { subscribe(sub); subscriptions.put(sub.getToken(), sub); // Save the client's token in their session context getUserTokens().add(sub.getToken()); return sub; } catch (Exception ex) { log.error(ex); return null; } } private void subscribe(RemoteSubscriber sub) throws JMSException, Exception { try { sub.subscribe(getTopicConnection()); } catch (Exception e) { log.debug(e); // Clear the topic connection and try again. resetTopic(); sub.subscribe(getTopicConnection()); } } private void resetTopic() { TopicConnection savedTopic = null; synchronized(monitor) { if (topicConnection != null) { savedTopic = topicConnection; topicConnection = null; } } if (savedTopic != null) { try { savedTopic.close(); } catch (Exception ignored) { } } } public UserTokens getUserTokens() { return (UserTokens) Component.getInstance(UserTokens.class); } public RemoteSubscriber getSubscription(String token) { if (!getUserTokens().contains(token)) { throw new IllegalArgumentException("Invalid token argument - token not found in Session Context."); } return subscriptions.get(token); } public Set<String> getAllTokens() { return subscriptions.keySet(); } public void cleanupTokens(Set<String> tokens) { for (String token: tokens) { RemoteSubscriber subscriber = subscriptions.remove(token); if (subscriber!=null) { try { subscriber.unsubscribe(); } catch (Exception e) { log.debug("problem cleaning up subcription", e); } } } } }