Java tutorial
/** * Copyright (c) 2010 Alexandre Porcelli <alexandre.porcelli@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package br.com.porcelli.hornetq.integration.twitter.stream; import java.lang.management.ManagementFactory; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.management.MBeanServer; import javax.management.ObjectName; import org.hornetq.api.core.SimpleString; import org.hornetq.core.logging.Logger; import org.hornetq.core.persistence.StorageManager; import org.hornetq.core.postoffice.Binding; import org.hornetq.core.postoffice.PostOffice; import org.hornetq.core.server.ConnectorService; import org.hornetq.core.server.MessageReference; import org.hornetq.core.server.Queue; import org.hornetq.utils.ConfigurationHelper; import twitter4j.ResponseList; import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.TwitterFactory; import twitter4j.TwitterStream; import twitter4j.TwitterStreamFactory; import twitter4j.User; import twitter4j.conf.Configuration; import twitter4j.conf.ConfigurationBuilder; import br.com.porcelli.hornetq.integration.twitter.data.InternalTwitterConstants; import br.com.porcelli.hornetq.integration.twitter.data.TwitterStreamDTO; import br.com.porcelli.hornetq.integration.twitter.jmx.ExceptionNotifier; import br.com.porcelli.hornetq.integration.twitter.stream.impl.BaseStreamHandler; import br.com.porcelli.hornetq.integration.twitter.stream.impl.SiteStreamHandler; import br.com.porcelli.hornetq.integration.twitter.stream.impl.StatusStreamHandler; import br.com.porcelli.hornetq.integration.twitter.stream.impl.UserStreamHandler; import br.com.porcelli.hornetq.integration.twitter.stream.jmx.TwitterStreamManagement; import br.com.porcelli.hornetq.integration.twitter.stream.jmx.TwitterStreamManagementMBean; import br.com.porcelli.hornetq.integration.twitter.stream.listener.AbstractSiteBaseStreamListener; import br.com.porcelli.hornetq.integration.twitter.stream.listener.AbstractStatusBaseStreamListener; import br.com.porcelli.hornetq.integration.twitter.stream.listener.AbstractUserBaseStreamListener; import br.com.porcelli.hornetq.integration.twitter.support.ReflectionSupport; public final class StreamHandler implements ConnectorService { private static final Logger log = Logger.getLogger(StreamHandler.class); private final String connectorName; private final TwitterStreamDTO data; private final MessageQueuing message; private final Set<BaseStreamHandler> streamHandlers; private final Class<?>[] streamListenersConstructorArgs = new Class<?>[] { TwitterStreamDTO.class, MessageQueuing.class, ExceptionNotifier.class }; private final Object[] streamListenersInsanceArgs; private final TwitterStreamManagementMBean mbean; private boolean isStarted = false; public StreamHandler(final String connectorName, final Map<String, Object> configuration, final StorageManager storageManager, final PostOffice postOffice) { this.connectorName = connectorName; this.mbean = new TwitterStreamManagement(this); try { MBeanServer mbServer = ManagementFactory.getPlatformMBeanServer(); ObjectName mbeanName = new ObjectName("org.hornetq:module=ConnectorService,name=" + connectorName); mbServer.registerMBean(mbean, mbeanName); } catch (Exception e) { log.error("Error on registering JMX info.", e); } final Configuration conf = new ConfigurationBuilder() .setOAuthConsumerKey(ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_CONSUMER_KEY, null, configuration)) .setOAuthConsumerSecret(ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_CONSUMER_SECRET, null, configuration)) .setOAuthAccessToken(ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_ACCESS_TOKEN, null, configuration)) .setOAuthAccessTokenSecret(ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_ACCESS_TOKEN_SECRET, null, configuration)) .build(); final String queueName = ConfigurationHelper.getStringProperty(InternalTwitterConstants.PROP_QUEUE_NAME, null, configuration); final String userScreenName = ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_SCREEN_NAME, null, configuration); final String lastTweetQueueName = ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_LAST_TWEET_QUEUE_NAME, null, configuration); final String lastDMQueueName = ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_LAST_DM_QUEUE_NAME, null, configuration); Long lastTweetId = null; if (lastTweetQueueName != null && lastTweetQueueName.trim().length() > 0) { final Binding lastTweetBinding = postOffice.getBinding(new SimpleString(lastTweetQueueName)); if (lastTweetBinding != null) { final Queue lastTweetQueue = (Queue) lastTweetBinding.getBindable(); if (lastTweetQueue.getMessageCount() > 0) { long ltweetId = Long.MIN_VALUE; for (final Iterator<MessageReference> iterator = lastTweetQueue.iterator(); iterator .hasNext();) { final MessageReference msg = iterator.next(); lastTweetId = msg.getMessage().getBodyBuffer().readLong(); if (lastTweetId > ltweetId) { ltweetId = lastTweetId; } } lastTweetId = ltweetId + 1L; } } } Long lastDMId = null; if (lastDMQueueName != null && lastDMQueueName.trim().length() > 0) { final Binding lastTweetBinding = postOffice.getBinding(new SimpleString(lastDMQueueName)); if (lastTweetBinding != null) { final Queue lastDMQueue = (Queue) lastTweetBinding.getBindable(); if (lastDMQueue.getMessageCount() > 0) { long ldmId = Long.MIN_VALUE; for (final Iterator<MessageReference> iterator = lastDMQueue.iterator(); iterator.hasNext();) { final MessageReference msg = iterator.next(); lastDMId = msg.getMessage().getBodyBuffer().readLong(); if (lastDMId > ldmId) { ldmId = lastDMId; } } lastDMId = ldmId + 1L; } } } final String[] mentionedUsers = splitProperty(ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_MENTIONED_USERS, null, configuration)); final String[] hashTags = splitProperty( ConfigurationHelper.getStringProperty(InternalTwitterConstants.PROP_HASHTAGS, null, configuration)); int[] userIds = null; int userId = -1; Twitter twitter = null; if (mentionedUsers != null) { try { twitter = new TwitterFactory(conf).getInstance(); userId = twitter.getId(); userIds = userIds(twitter.lookupUsers(mentionedUsers)); } catch (final TwitterException e) { mbean.notifyException(e); } finally { if (twitter != null) { twitter.shutdown(); } } } data = new TwitterStreamDTO(queueName, userScreenName, userId, lastTweetQueueName, lastDMQueueName, lastTweetId, lastDMId, mentionedUsers, userIds, hashTags, conf, postOffice); final String reclaimers = ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_TWEET_RECLAIMERS, null, configuration); message = new MessageQueuing(data, this.mbean, splitProperty(reclaimers)); streamListenersInsanceArgs = new Object[] { data, message, mbean }; final String listenerList = ConfigurationHelper .getStringProperty(InternalTwitterConstants.PROP_STREAM_LISTENERS, null, configuration); final String[] listeners = splitProperty(listenerList); if (listeners != null) { final UserStreamHandler userHandler = buildUserStreamHandler(listeners); final SiteStreamHandler siteHandler = buildSiteStreamHandler(listeners); final StatusStreamHandler statusHandler = buildStatusStreamHandler(listeners); if (userHandler != null || siteHandler != null || statusHandler != null) { streamHandlers = new HashSet<BaseStreamHandler>(); if (userHandler != null) { streamHandlers.add(userHandler); } if (siteHandler != null) { streamHandlers.add(siteHandler); } if (statusHandler != null) { streamHandlers.add(statusHandler); } } else { streamHandlers = null; } } else { streamHandlers = null; } } private <U extends AbstractUserBaseStreamListener> UserStreamHandler buildUserStreamHandler( final String[] listeners) { final Set<U> result = new HashSet<U>(); for (final String listener : listeners) { try { final Class<?> clazz = Class.forName(listener); if (AbstractUserBaseStreamListener.class.isAssignableFrom(clazz)) { result.add(ReflectionSupport.buildInstance((Class<U>) clazz, streamListenersConstructorArgs, streamListenersInsanceArgs)); } } catch (final ClassNotFoundException e) { mbean.notifyException(e); log.error("Twitter Stream '" + listener + "' not found"); } } if (result.size() > 0) { final TwitterStream twitterStream = new TwitterStreamFactory(data.getConf()).getInstance(); for (final U activeUserListener : result) { twitterStream.addListener(activeUserListener); } return new UserStreamHandler(data, twitterStream); } return null; } private <S extends AbstractSiteBaseStreamListener> SiteStreamHandler buildSiteStreamHandler( final String[] listeners) { final Set<S> result = new HashSet<S>(); for (final String listener : listeners) { try { final Class<?> clazz = Class.forName(listener); if (AbstractSiteBaseStreamListener.class.isAssignableFrom(clazz)) { result.add(ReflectionSupport.buildInstance((Class<S>) clazz, streamListenersConstructorArgs, streamListenersInsanceArgs)); } } catch (final ClassNotFoundException e) { mbean.notifyException(e); log.error("Twitter Stream '" + listener + "' not found"); } } if (result.size() > 0) { final TwitterStream twitterStream = new TwitterStreamFactory(data.getConf()).getInstance(); for (final S activeUserListener : result) { twitterStream.addListener(activeUserListener); } return new SiteStreamHandler(data, twitterStream); } return null; } private <ST extends AbstractStatusBaseStreamListener> StatusStreamHandler buildStatusStreamHandler( final String[] listeners) { final Set<ST> result = new HashSet<ST>(); for (final String listener : listeners) { try { final Class<?> clazz = Class.forName(listener); if (AbstractStatusBaseStreamListener.class.isAssignableFrom(clazz)) { result.add(ReflectionSupport.buildInstance((Class<ST>) clazz, streamListenersConstructorArgs, streamListenersInsanceArgs)); } } catch (final ClassNotFoundException e) { mbean.notifyException(e); log.error("Twitter Stream '" + listener + "' not found"); } } if (result.size() > 0) { final TwitterStream twitterStream = new TwitterStreamFactory(data.getConf()).getInstance(); for (final ST activeUserListener : result) { twitterStream.addListener(activeUserListener); } return new StatusStreamHandler(data, twitterStream); } return null; } private int[] userIds(final ResponseList<User> users) { if (users == null || users.size() == 0) { return new int[0]; } final int[] ids = new int[users.size()]; for (int i = 0; i < users.size(); i++) { ids[i] = users.get(i).getId(); } return ids; } protected String[] splitProperty(final String propertyValue) { if (propertyValue == null || propertyValue.trim().length() == 0) { return null; } return propertyValue.replace(',', ';').replace(':', ';').split(";"); } @Override public String getName() { return connectorName; } @Override public void start() throws Exception { try { final Binding b = data.getPostOffice().getBinding(new SimpleString(data.getQueueName())); if (b == null) { throw new Exception(connectorName + ": queue " + data.getQueueName() + " not found"); } if (streamHandlers == null || streamHandlers.size() < 1) { log.error("There is no Listners, can't start the service."); return; } startStreaming(); isStarted = true; } catch (Exception e) { mbean.notifyException(e); } } protected void startStreaming() throws TwitterException { if (streamHandlers != null && streamHandlers.size() > 0) { for (final BaseStreamHandler activeHandler : streamHandlers) { activeHandler.start(); } } } @Override public void stop() throws Exception { try { if (!isStarted) { return; } if (streamHandlers != null && streamHandlers.size() > 0) { for (final BaseStreamHandler activeHandler : streamHandlers) { activeHandler.stop(); } } message.dispose(); isStarted = false; } catch (Exception e) { mbean.notifyException(e); } } @Override public boolean isStarted() { return isStarted; } public long getDMCount() { return message.getDMCount(); } public long getStatusCount() { return message.getStatusCount(); } public long getTweetCount() { return message.getTweetCount(); } public long getTotalCount() { return message.getTotalCount(); } }