/*** * Coalevo Project * http://www.coalevo.net * * (c) Verein zur Foerderung der Internetkommunikation, Austria * http://www.vfi.or.at * * 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 net.coalevo.bot.twitter.impl; import net.coalevo.bot.twitter.service.TwitterBotConfiguration; import net.coalevo.bot.twitter.service.TwitterBotService; import net.coalevo.bot.twitter.service.TwitterBotServiceException; import net.coalevo.foundation.model.*; import net.coalevo.foundation.util.CacheMapExpelHandler; import net.coalevo.foundation.util.ConfigurationUpdateHandler; import net.coalevo.foundation.util.LRUCacheMap; import net.coalevo.foundation.util.metatype.MetaTypeDictionary; import net.coalevo.foundation.util.metatype.MetaTypeDictionaryException; import net.coalevo.messaging.model.*; import net.coalevo.messaging.service.MessagingService; import net.coalevo.presence.model.AgentIdentifierList; import net.coalevo.presence.model.PresenceProxy; import net.coalevo.presence.model.PresenceServiceListenerAdapter; import net.coalevo.presence.model.ServicePresenceProxy; import net.coalevo.security.model.ServiceAgentProxy; import net.coalevo.system.service.ExecutionService; import net.coalevo.text.util.DateFormatter; import net.coalevo.text.util.MarkupLanguageFilter; import org.osgi.framework.BundleContext; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; import org.osgi.service.prefs.PreferencesService; import org.slf4j.Logger; import org.slf4j.Marker; import org.slf4j.MarkerFactory; import twitter4j.*; import java.util.*; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** * This class implements the Twitter Bot as a Service. *

* * @author Dieter Wimberger (wimpi) * @version @version@ (@date@) */ class TwitterBotServiceImpl extends BaseService implements TwitterBotService, ConfigurationUpdateHandler { private Marker m_LogMarker = MarkerFactory.getMarker(TwitterBotServiceImpl.class.getName()); private Messages m_BundleMessages; //Coalevo Services private ServiceMediator m_Services; //Security Context private ServiceAgentProxy m_ServiceAgentProxy; private ServicePresenceProxy m_ServicePresenceProxy; private ServiceMessagingProxy m_ServiceMessagingProxy; //Presence private Set m_PresentSubscribers; //private Set m_Registered; //Cache private LRUCacheMap m_TwitterCache; //Scan private Set m_Scanables; private ScheduledFuture m_Scheduled; TwitterBotServiceImpl() { super(TwitterBotService.class.getName(), ACTIONS); m_TwitterCache = new LRUCacheMap(10); m_Scanables = new HashSet(); }//constructor public boolean activate(BundleContext bc) { //1. Services and Messages m_Services = Activator.getServices(); m_BundleMessages = Activator.getBundleMessages(); //3. Authenticate ourself m_ServiceAgentProxy = new ServiceAgentProxy(this, Activator.log()); m_ServiceAgentProxy.activate(bc); //4. Presence Handling m_PresentSubscribers = new HashSet(); m_ServicePresenceProxy = new ServicePresenceProxy( new PresenceListenerImpl(), m_ServiceAgentProxy, Activator.log()); m_ServicePresenceProxy.activate(bc); //5. Messaging Handling m_ServiceMessagingProxy = new ServiceMessagingProxy( new MessagingServiceListenerImpl(), m_ServicePresenceProxy, Activator.log() ); //3. Run Presence Subscription task m_Services.getExecutionService(ServiceMediator.WAIT_UNLIMITED).execute(this.m_ServiceAgentProxy.getAuthenticPeer(), new Runnable() { public void run() { try { AgentIdentifierList requests = m_ServicePresenceProxy.getPresence().getRequestedSubscriptions(); for (Iterator iterator = requests.iterator(); iterator.hasNext();) { AgentIdentifier aid = iterator.next(); m_ServicePresenceProxy.getPresenceService().allowSubscription(m_ServicePresenceProxy.getPresence(), aid); m_ServicePresenceProxy.getPresenceService().requestSubscriptionTo(m_ServicePresenceProxy.getPresence(), aid); } } catch (Exception ex) { Activator.log().error(m_LogMarker, "activate()", ex); } }//run }); m_ServiceMessagingProxy.activate(bc); //2. Handle configuration update(m_Services.getConfigMediator().getConfiguration()); m_Services.getConfigMediator().addUpdateHandler(this); m_TwitterCache.setExpelHandler(new CacheMapExpelHandler() { public void expelled(Map.Entry entry) { //2. Add preferences data PreferencesService ps = m_Services.getPreferencesService(ServiceMediator.NO_WAIT); if (ps == null) { return; } String uid = entry.getKey().getIdentifier(); Preferences p = ps.getUserPreferences(uid); if (p == null) { return; } p.put(TWITTER_ACCOUNT_LASTFGET_KEY, Long.toString(entry.getValue().getLastFriends())); }//expelled }); return true; }//activate public boolean deactivate() { if (m_Scheduled != null) { try { m_Scheduled.cancel(false); } catch (Exception ex) { Activator.log().error(m_LogMarker, "deactivate()", ex); } } if (m_ServiceMessagingProxy != null) { m_ServiceMessagingProxy.deactivate(); m_ServiceMessagingProxy = null; } if (m_ServicePresenceProxy != null) { m_ServicePresenceProxy.deactivate(); m_ServicePresenceProxy = null; } if (m_ServiceAgentProxy != null) { m_ServiceAgentProxy.deactivate(); m_ServiceAgentProxy = null; } if (m_TwitterCache != null) { m_TwitterCache.clear(); m_TwitterCache = null; } m_Services = null; return true; }//deactivate public void update(MetaTypeDictionary mtd) { //1. Configure from persistent configuration int csize = 20; int scanperiod = 15; String sname = "Coalevo"; String curl = "http://www.coalevo.net"; //Retrieve config try { csize = mtd.getInteger(TwitterBotConfiguration.TWITTER_CACHESIZE_KEY).intValue(); } catch (MetaTypeDictionaryException ex) { Activator.log().error(m_LogMarker, m_BundleMessages.get("TwitterBotServiceImpl.activation.configexception", "attribute", TwitterBotConfiguration.TWITTER_CACHESIZE_KEY), ex ); } try { scanperiod = mtd.getInteger(TwitterBotConfiguration.TWITTER_SCANPERIOD_KEY).intValue(); } catch (MetaTypeDictionaryException ex) { Activator.log().error(m_LogMarker, m_BundleMessages.get("TwitterBotServiceImpl.activation.configexception", "attribute", TwitterBotConfiguration.TWITTER_SCANPERIOD_KEY), ex ); } try { sname = mtd.getString(TwitterBotConfiguration.TWITTER_SOURCENAME_KEY); } catch (MetaTypeDictionaryException ex) { Activator.log().error(m_LogMarker, m_BundleMessages.get("TwitterBotServiceImpl.activation.configexception", "attribute", TwitterBotConfiguration.TWITTER_SOURCENAME_KEY), ex ); } try { curl = mtd.getString(TwitterBotConfiguration.TWITTER_CLIENTURL_KEY); } catch (MetaTypeDictionaryException ex) { Activator.log().error(m_LogMarker, m_BundleMessages.get("TwitterBotServiceImpl.activation.configexception", "attribute", TwitterBotConfiguration.TWITTER_CLIENTURL_KEY), ex ); } //Update config Configuration.setSource(sname); Configuration.setClientURL(curl); //Update cache setting this.m_TwitterCache.setCeiling(csize); //Schedule scan scheduleScan(scanperiod); }//update protected boolean register(final AgentIdentifier aid, String user, String pass) { //System.out.println("==1==> register"); //1. verify credentials try { Twitter t = new Twitter("https://twitter.com/"); //System.out.println("==1.1==> register"); t.setUserId(user); //System.out.println("==1.2==> register"); t.setPassword(pass); //System.out.println("==1.3==> register"); t.setSource(Configuration.getSource()); t.setClientURL(Configuration.getClientURL()); //System.out.println("==2==> register"); if (t.verifyCredentials() == null) { //System.out.println("==3==> register"); return false; } else { //System.out.println("==4==> register"); m_TwitterCache.put(aid, t); } } catch (Exception e) { Activator.log().error(m_LogMarker, "register()", e); return false; } //2. Add preferences data PreferencesService ps = m_Services.getPreferencesService(ServiceMediator.NO_WAIT); if (ps == null) { return false; } String uid = aid.getIdentifier(); Preferences p = ps.getUserPreferences(uid); if (p == null) { return false; } if (!(p.get(TWITTER_ACCOUNT_USER_KEY, "").length() == 0)) { return false; } p.put(TWITTER_ACCOUNT_USER_KEY, user); p.put(TWITTER_ACCOUNT_PASS_KEY, pass); //3. Check subscriptions if (!m_ServicePresenceProxy.getPresence().getSubscriptionsTo().contains(aid)) { m_ServicePresenceProxy.getPresenceService().requestSubscriptionTo( m_ServicePresenceProxy.getPresence(), aid ); } return true; }//register public boolean unregister(final AgentIdentifier aid) { //1. remove from cache m_TwitterCache.remove(aid); //2. delete preferences data PreferencesService ps = m_Services.getPreferencesService(ServiceMediator.NO_WAIT); if (ps == null) { return false; } String uid = aid.getIdentifier(); Preferences p = ps.getUserPreferences(uid); if (p == null) { return false; } p.remove(TWITTER_ACCOUNT_USER_KEY); p.remove(TWITTER_ACCOUNT_PASS_KEY); try { p.flush(); } catch (BackingStoreException e) { Activator.log().error("unregister()", e); return false; } return true; }//unregister private Status update(AgentIdentifier aid, String msg) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.updateStatus(msg); } catch (TwitterException e) { Activator.log().error("update()", e); //TODO: i18n throw new TwitterBotServiceException("Update failed"); } }//update private List getPublicTimeline(AgentIdentifier aid) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.getPublicTimeline(); } catch (TwitterException e) { Activator.log().error("getPublicTimeLine()", e); //TODO: i18n throw new TwitterBotServiceException("getPublicTimeLine()", e); } }//getPublicTimeline private List getFriendsTimeline(AgentIdentifier aid, int page) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.getFriendsTimeline(new Paging(page)); } catch (TwitterException e) { Activator.log().error("getFriendsTimeLine()", e); //TODO: i18n throw new TwitterBotServiceException("getFriendsTimeLine()", e); } }//getFriendsTimeline private List getFriendsTimeline(AgentIdentifier aid) throws TwitterBotServiceException { //1. Twitter Twitter t = getTwitter(aid); try { List statii; if(t.getLastFriends() > 0) { statii = t.getFriendsTimeline(new Paging(t.getLastFriends())); } else { statii = t.getFriendsTimeline(); } if(!statii.isEmpty()) { Status st = statii.get(0); t.setLastFriends(st.getId()); } return statii; } catch (TwitterException e) { Activator.log().error("getFriendsTimeLine()", e); //TODO: i18n throw new TwitterBotServiceException("getFriendsTimeLine(ts)", e); } }//getFriendsTimeline private List getReplies(AgentIdentifier aid) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.getMentions(); } catch (TwitterException e) { Activator.log().error("getReplies()", e); //TODO: i18n throw new TwitterBotServiceException("getReplies()", e); } }//getReplies private Status getStatus(AgentIdentifier aid, long id) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.showStatus(id); } catch (TwitterException e) { Activator.log().error("getStatus()", e); //TODO: i18n throw new TwitterBotServiceException("getStatus()", e); } }//getStatus private User follow(AgentIdentifier aid, String who) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.createFriendship(who); } catch (TwitterException e) { Activator.log().error("follow()", e); //TODO: i18n throw new TwitterBotServiceException("follow()", e); } }//follow private void unfollow(AgentIdentifier aid, String whom) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { t.destroyFriendship(whom); } catch (TwitterException e) { Activator.log().error("unfollow()", e); //TODO: i18n throw new TwitterBotServiceException("unfollow()", e); } }//unfollow private List getFollowed(AgentIdentifier aid, String id) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { if (id == null || id.length() == 0) { return t.getFriends(); } else { return t.getFriends(id); } } catch (TwitterException e) { Activator.log().error("getFollowed()", e); //TODO: i18n throw new TwitterBotServiceException("getFollowed()", e); } }//getFollowed private List getFollowing(AgentIdentifier aid, String id) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { if (id == null || id.length() == 0) { return t.getFollowers(); } else { return t.getFollowers(id); } } catch (TwitterException e) { Activator.log().error("getFollowing()", e); //TODO: i18n throw new TwitterBotServiceException("getFollowing()", e); } }//getFollowing private Status removeStatus(AgentIdentifier aid, long id) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.destroyStatus(id); } catch (TwitterException e) { Activator.log().error("removeStatus()", e); //TODO: i18n throw new TwitterBotServiceException("removeStatus()", e); } }//removeStatus private List getUserTimeline(AgentIdentifier aid, String id) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.getUserTimeline(id); } catch (TwitterException e) { Activator.log().error("getUserTimeLine()", e); //TODO: i18n throw new TwitterBotServiceException("getUserTimeLine()", e); } }//getUserTimeline private User getUser(AgentIdentifier aid, String id) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.getUserDetail(id); } catch (TwitterException e) { Activator.log().error("getUser()", e); //TODO: i18n throw new TwitterBotServiceException("getUser()", e); } }//getUser private void fave(AgentIdentifier aid, long id) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { t.createFavorite(id); } catch (TwitterException e) { Activator.log().error("fave()", e); //TODO: i18n throw new TwitterBotServiceException("fave()", e); } }//fave private void unfave(AgentIdentifier aid, long id) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { t.destroyFavorite(id); } catch (TwitterException e) { Activator.log().error("unfave()", e); //TODO: i18n throw new TwitterBotServiceException("unfave()", e); } }//unfave private List getFavorites(AgentIdentifier aid) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.favorites(); } catch (TwitterException e) { Activator.log().error("getFavorites()", e); //TODO: i18n throw new TwitterBotServiceException("getFavorites()", e); } }//getUserFavorites private List getPrivates(AgentIdentifier aid) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { return t.getDirectMessages(); } catch (TwitterException e) { Activator.log().error("getPrivate()", e); //TODO: i18n throw new TwitterBotServiceException("getPrivate()", e); } }//getPrivate private void sendPrivate(AgentIdentifier aid, String id, String msg) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { t.sendDirectMessage(id, msg); } catch (TwitterException e) { Activator.log().error("getPrivate()", e); //TODO: i18n throw new TwitterBotServiceException("getPrivate()", e); } }//sendPrivate private void removePrivate(AgentIdentifier aid, Integer id) throws TwitterBotServiceException { Twitter t = getTwitter(aid); try { t.destroyDirectMessage(id); } catch (TwitterException e) { Activator.log().error("getPrivate()", e); //TODO: i18n throw new TwitterBotServiceException("getPrivate()", e); } }//removePrivate private Twitter getTwitter(AgentIdentifier aid) throws TwitterBotServiceException { Twitter t = m_TwitterCache.get(aid); if (t == null) { t = new Twitter("https://twitter.com/"); PreferencesService ps = m_Services.getPreferencesService(ServiceMediator.NO_WAIT); if (ps == null) { throw new TwitterBotServiceException("Prefservice unavailable."); } String uid = aid.getIdentifier(); Preferences p = ps.getUserPreferences(uid); if (p == null) { throw new TwitterBotServiceException("Preferences unavailable."); } String tmp = p.get(TWITTER_ACCOUNT_USER_KEY, ""); if (tmp.length() == 0) { throw new NotRegisteredException(); } t.setUserId(tmp); tmp = p.get(TWITTER_ACCOUNT_PASS_KEY, ""); if (tmp.length() == 0) { throw new NotRegisteredException(); } t.setPassword(tmp); tmp = p.get(TWITTER_ACCOUNT_LASTFGET_KEY, ""); long ts = System.currentTimeMillis(); if (tmp.length() > 0) { try { ts = Long.valueOf(tmp); } catch (NumberFormatException ex) { throw new TwitterBotServiceException("Invalid timestamp for last followed get."); } } t.setLastFriends(ts); t.setSource(Configuration.getSource()); t.setClientURL(Configuration.getClientURL()); m_TwitterCache.put(aid, t); } return t; }//getTwitter private void sendMessage(AgentIdentifier to, String content, String format) { try { MessagingService ms = m_ServiceMessagingProxy.getMessagingService(); EditableInteractiveMessage im = ms.create( m_ServicePresenceProxy.getPresence(), InteractiveMessageTypes.CHAT, m_Services.getUUIDGeneratorService(ServiceMediator.NO_WAIT).getUID() ); im.setTo(to); im.setBody(content); im.setConfirmationRequired(false); if (format != null && format.length() > 0) { im.setFormattingHint(format); } ms.send(m_ServicePresenceProxy.getPresence(), im); } catch (Exception mex) { Activator.log().error(m_LogMarker, "sendMessage()", mex); } }//sendMessage //** Command Implementations **// private void doHelp(AgentIdentifier aid) { sendMessage(aid, m_BundleMessages.get("TwitterBotServiceImpl.bot.help"), FORMAT_TML); }//doHelp public void doRegister(AgentIdentifier aid, String account) { String msg; if (account.length() > 0) { String[] acc = account.split(" "); if (acc == null || acc.length != 2) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.cmdsyntax", "cmd", "register"); } else { String uname = acc[0].trim(); String passw = acc[1].trim(); if (register(aid, uname, passw)) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.registered"); } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedregister"); } } } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.cmdsyntax", "cmd", "register"); } sendMessage(aid, msg, null); }//doRegister public void doUnregister(AgentIdentifier aid) { String msg; if (unregister(aid)) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.unregistered"); } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedunregister"); } sendMessage(aid, msg, null); }//doUnregister private void doUpdate(AgentIdentifier aid, String msg) { try { Status s = update(aid, msg.substring(0, Math.min(140, msg.length()))); MessageAttributes attr = m_BundleMessages.leaseAttributes(); attr.add("id", Long.toString(s.getId())); attr.add("msg", s.getText()); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.updated", attr); } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedupdate"); } sendMessage(aid, msg, FORMAT_TML); }//doUpdate private void doShow(AgentIdentifier aid, String msg) { try { if (msg.startsWith("@")) { doShowUser(aid, msg.substring(1)); return; } Status st = getStatus(aid, Long.parseLong(msg)); MessageAttributes attr = m_BundleMessages.leaseAttributes(); String[] items = new String[]{ Integer.toString(st.getUser().getId()), st.getUser().getScreenName(), Long.toString(st.getId()), st.getText(), DateFormatter.getISOInstance().format(st.getCreatedAt()), MarkupLanguageFilter.filterMLTags(st.getSource()) }; attr.add("status.{uid,uname,id,msg,date,source}", items); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.status", attr).replace("\\\\", "\\"); } catch (NumberFormatException nex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedstatusid"); } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedshow"); } catch (RuntimeException rex) { Activator.log().error(m_LogMarker, "doShow()", rex); } sendMessage(aid, msg, FORMAT_TML); }//doShow private void doShowUser(AgentIdentifier aid, String msg) { try { User uws = getUser(aid, msg); MessageAttributes attr = m_BundleMessages.leaseAttributes(); String[] items = new String[]{ Integer.toString(uws.getId()), uws.getScreenName(), uws.getName(), (uws.getDescription() != null && uws.getDescription().length() > 0) ? uws.getDescription() : null, (uws.getURL() != null) ? uws.getURL().toString() : null, (uws.getProfileImageURL() != null) ? uws.getProfileImageURL().toString() : null, (uws.getLocation() != null && uws.getLocation().length() > 0) ? uws.getLocation() : null, Integer.toString(uws.getFollowersCount()) }; attr.add("user.{id,name,rn,desc,url,avatar,location,followers}", items); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.user", attr).replace("\\\\", "\\"); attr = m_BundleMessages.leaseAttributes(); items = new String[]{ Integer.toString(uws.getId()), uws.getScreenName(), Long.toString(uws.getStatusId()), uws.getStatusText(), DateFormatter.getISOInstance().format(uws.getStatusCreatedAt()), MarkupLanguageFilter.filterMLTags(uws.getStatusSource()) }; attr.add("status.{uid,uname,id,msg,date,source}", items); msg += m_BundleMessages.get("TwitterBotServiceImpl.bot.status", attr).replace("\\\\", "\\"); } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedshowuser"); } catch (RuntimeException rex) { Activator.log().error(m_LogMarker, "doShowUser()", rex); } sendMessage(aid, msg, FORMAT_TML); }//doShowUser private void doDestroy(AgentIdentifier aid, String msg) { try { long sid = Long.parseLong(msg); removeStatus(aid, sid); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.statusdestroyed", "id", msg); } catch (NumberFormatException nex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedstatusid"); } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.faileddestroystatus"); } catch (RuntimeException rex) { Activator.log().error(m_LogMarker, "doDestroy()", rex); } sendMessage(aid, msg, FORMAT_TML); }//doDestroy private void doTimeline(AgentIdentifier aid, String msg, boolean silentempty) { try { List tl = null; if (TWITTER_SUBCMD_PUBLIC.equals(msg)) { tl = getPublicTimeline(aid); } else if (TWITTER_SUBCMD_FOLLOWED.equals(msg)) { tl = getFriendsTimeline(aid); } else if (msg.startsWith(TWITTER_SUBCMD_ID)) { tl = getUserTimeline(aid, msg.substring(1)); } else if (msg.startsWith(TWITTER_SUBCMD_FAVORITES)) { tl = getFavorites(aid); } else if (msg.startsWith(TWITTER_CMD_REPLIES)) { tl = getReplies(aid); } else { tl = getUserTimeline(aid, getTwitter(aid).getUserId()); } if (tl == null || tl.isEmpty()) { if (silentempty) { return; } msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.timelineempty"); } else if (tl.size() == 1) { Status st = tl.get(0); MessageAttributes attr = m_BundleMessages.leaseAttributes(); String[] items = new String[]{ Integer.toString(st.getUser().getId()), st.getUser().getScreenName(), Long.toString(st.getId()), st.getText(), DateFormatter.getISOInstance().format(st.getCreatedAt()), MarkupLanguageFilter.filterMLTags(st.getSource()) }; attr.add("status.{uid,uname,id,msg,date,source}", items); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.status", attr).replace("\\\\", "\\"); } else { Collections.sort(tl,STATUS_DATE_COMPARATOR); MessageAttributes attr = m_BundleMessages.leaseAttributes(); for (Status st : tl) { String[] items = new String[]{ Integer.toString(st.getUser().getId()), st.getUser().getScreenName(), Long.toString(st.getId()), st.getText(), DateFormatter.getISOInstance().format(st.getCreatedAt()), MarkupLanguageFilter.filterMLTags(st.getSource()) }; attr.add("items.{uid,uname,id,msg,date,source}", items); } msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.timeline", attr).replace("\\\\", "\\"); } } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedtimeline"); } catch (RuntimeException rex) { Activator.log().error(m_LogMarker, "doTimeline()", rex); } sendMessage(aid, msg, FORMAT_TML); }//doTimeline private void doFollow(AgentIdentifier aid, String msg) { try { char what = msg.charAt(0); String whom = msg.substring(1); if (what == '-') { //unfollow unfollow(aid, whom); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.unfollowed", "id", whom); } else if (what == '+') { //follow User u = follow(aid, whom); MessageAttributes attr = m_BundleMessages.leaseAttributes(); String[] items = new String[]{ Integer.toString(u.getId()), u.getScreenName(), u.getName(), (u.getDescription() != null && u.getDescription().length() > 0) ? u.getDescription() : null, (u.getURL() != null) ? u.getURL().toString() : null, (u.getProfileImageURL() != null) ? u.getProfileImageURL().toString() : null, u.getLocation(), Integer.toString(u.getFollowersCount()) }; attr.add("user.{id,name,rn,desc,url,avatar,location,followers}", items); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.followed") + m_BundleMessages.get("TwitterBotServiceImpl.bot.user", attr).replace("\\\\", "\\"); } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.cmdsyntax", "cmd", "follow"); } } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedfollow"); } catch (RuntimeException rex) { Activator.log().error(m_LogMarker, "doFollow()", rex); } sendMessage(aid, msg, FORMAT_TML); }//doFollow private void doFollowed(AgentIdentifier aid, String msg) { try { String id; //followed if (msg == null || msg.length() == 0) { id = getTwitter(aid).getUserId(); } else { id = msg; } List ul = getFollowed(aid, id); if (ul == null || ul.isEmpty()) { if (id == msg) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.nonefollowed", "id", id); } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.nonefollowed"); } } else { MessageAttributes attr = m_BundleMessages.leaseAttributes(); if (id == msg) { attr.add("id", id); } for (User u : ul) { String[] items = new String[]{ Integer.toString(u.getId()), u.getScreenName(), u.getName() }; attr.add("users.{id,name, rn}", items); } msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.followedlist", attr).replace("\\\\", "\\"); } } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedfollowed"); } catch (RuntimeException rex) { Activator.log().error(m_LogMarker, "doFollowed()", rex); } sendMessage(aid, msg, FORMAT_TML); }//doFollow private void doFollowing(AgentIdentifier aid, String msg) { try { String id; //followed if (msg == null || msg.length() == 0) { id = getTwitter(aid).getUserId(); } else { id = msg; } List ul = getFollowing(aid, id); if (ul == null || ul.isEmpty()) { if (id == msg) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.nonefollowing", "id", id); } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.nonefollowing"); } } else { MessageAttributes attr = m_BundleMessages.leaseAttributes(); if (id == msg) { attr.add("id", id); } for (User u : ul) { String[] items = new String[]{ Integer.toString(u.getId()), u.getScreenName(), u.getName() }; attr.add("users.{id,name, rn}", items); } msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.followinglist", attr).replace("\\\\", "\\"); } } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedfollowing"); } catch (RuntimeException rex) { Activator.log().error(m_LogMarker, "doFollowing()", rex); } sendMessage(aid, msg, FORMAT_TML); }//doFollowing private void doFave(AgentIdentifier aid, String msg) { try { char what = msg.charAt(0); long which = Long.parseLong(msg.substring(1)); if (what == '-') { unfave(aid, which); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.unfaved", "id", Long.toString(which)); } else if (what == '+') { fave(aid, which); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.faved", "id", Long.toString(which)); } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.cmdsyntax", "cmd", "fave"); } } catch (NumberFormatException nex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedstatusid"); } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedfave"); } catch (RuntimeException rex) { Activator.log().error(m_LogMarker, "doFave()", rex); } sendMessage(aid, msg, FORMAT_TML); }//doFave private void doAutoScan(AgentIdentifier aid, String msg) { try { if ("on".equals(msg)) { if (registerScan(aid)) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.autoscan"); } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedautoscan", "state", "on"); } } else if ("off".equals(msg)) { if (unregisterScan(aid)) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.noautoscan"); } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedautoscan", "state", "off"); } } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.cmdsyntax", "cmd", "autoscan"); } } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.errorautoscan"); } sendMessage(aid, msg, FORMAT_TML); }//doAutoScan private void doPrivate(AgentIdentifier aid, String msg) { try { if (msg.startsWith("-")) { int which = Integer.parseInt(msg.substring(1)); removePrivate(aid, which); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.privateremoved", "id", Long.toString(which)); } else if (msg.startsWith("@")) { int idx = msg.indexOf(" "); if (idx > 0) { String to = msg.substring(1, idx); msg = msg.substring(idx + 1, msg.length()); sendPrivate(aid, to, msg); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.privatesent", "id", to); } else { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.cmdsyntax", "cmd", "private"); } } else { List ls = getPrivates(aid); if (ls == null || ls.isEmpty()) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.privatesempty"); } else if (ls.size() == 1) { DirectMessage dm = ls.get(0); MessageAttributes attr = m_BundleMessages.leaseAttributes(); String[] items = new String[]{ Integer.toString(dm.getSenderId()), dm.getSenderScreenName(), Long.toString(dm.getId()), dm.getText(), DateFormatter.getISOInstance().format(dm.getCreatedAt()), }; attr.add("msg.{suid,suname,id,msg,date}", items); msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.message", attr).replace("\\\\", "\\"); } else { MessageAttributes attr = m_BundleMessages.leaseAttributes(); for (DirectMessage dm : ls) { String[] items = new String[]{ Integer.toString(dm.getSenderId()), dm.getSenderScreenName(), Long.toString(dm.getId()), dm.getText(), DateFormatter.getISOInstance().format(dm.getCreatedAt()), }; attr.add("items.{suid,suname,id,msg,date}", items); } msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.messages", attr).replace("\\\\", "\\"); } } } catch (NumberFormatException nex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedstatusid"); } catch (NotRegisteredException nrex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.notregistered"); } catch (TwitterBotServiceException ex) { msg = m_BundleMessages.get("TwitterBotServiceImpl.bot.failedprivate"); } catch (RuntimeException rex) { Activator.log().error(m_LogMarker, "doFave()", rex); } sendMessage(aid, msg, FORMAT_TML); }//doPrivate //*** Automatic scanning ***// private boolean registerScan(AgentIdentifier who) throws TwitterBotServiceException { getTwitter(who); String uid = who.getIdentifier(); PreferencesService ps = m_Services.getPreferencesService(ServiceMediator.NO_WAIT); if (ps != null) { Preferences p = ps.getUserPreferences(uid); if (p != null) { if (!Boolean.valueOf(p.get(TWITTER_ACCOUNT_AUTOSCAN_KEY, "false"))) { p.put(TWITTER_ACCOUNT_AUTOSCAN_KEY, "true"); m_Scanables.add(who); return true; } } } return false; }//registerScan private boolean unregisterScan(AgentIdentifier who) throws TwitterBotServiceException { getTwitter(who); String uid = who.getIdentifier(); PreferencesService ps = m_Services.getPreferencesService(ServiceMediator.NO_WAIT); if (ps != null) { Preferences p = ps.getUserPreferences(uid); if (p != null) { if (Boolean.valueOf(p.get(TWITTER_ACCOUNT_AUTOSCAN_KEY, "false"))) { p.put(TWITTER_ACCOUNT_AUTOSCAN_KEY, "false"); m_Scanables.remove(who); return true; } } } return false; }//unregisterScan private void scheduleScan(int period) { //1. Cancel old schedule if (m_Scheduled != null) { try { m_Scheduled.cancel(false); } catch (Exception ex) { Activator.log().error(m_LogMarker, "scheduleScan()", ex); } } //2. Schedule new ExecutionService es = Activator.getServices().getExecutionService(ServiceMediator.NO_WAIT); if (es == null) { Activator.log().error(m_LogMarker, "scheduleScan()::ExectionService unavailable."); return; } // Prepare runable: Runnable task = new Runnable() { private Logger log = Activator.log(); private Messages m_Messages = Activator.getBundleMessages(); private Marker lmk = MarkerFactory.getMarker("TWITTERBOT"); private ClassLoader cl = Activator.class.getClassLoader(); public void run() { ClassLoader tcl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(cl); log.info(lmk, m_Messages.get("TwitterBotServiceImpl.scan.start")); synchronized (m_Scanables) { for (Iterator iter = m_Scanables.iterator(); iter.hasNext();) { AgentIdentifier aid = iter.next(); log.info(lmk, m_Messages.get("TwitterBotServiceImpl.scan.run", "aid", aid.getIdentifier())); try { doTimeline(aid, TWITTER_SUBCMD_FOLLOWED, true); } catch (Exception ex) { log.error(lmk, "scheduleScan()", ex); } } } log.info(lmk, m_Messages.get("TwitterBotServiceImpl.scan.end")); } catch (Exception ex) { ex.printStackTrace(System.err); } finally { Thread.currentThread().setContextClassLoader(tcl); } } }; //Note: The period is assumed to be in minutes m_Scheduled = es.scheduleAtFixedRate( m_ServiceAgentProxy.getAuthenticPeer(), task, period, period, TimeUnit.MINUTES ); //log MessageAttributes attr = m_BundleMessages.leaseAttributes(); attr.add("period", Integer.toString(period)); // attr.add("futuredone", Boolean.toString(m_Scheduled.isDone())); // attr.add("futurecancelled", Boolean.toString(m_Scheduled.isCancelled())); Activator.log().debug( m_LogMarker, m_BundleMessages.get("TwitterBotServiceImpl.scan.scheduledfuture", attr) ); }//scheduleScan class PresenceListenerImpl extends PresenceServiceListenerAdapter { public void found(PresenceProxy p) { if (p.isAvailable()) { handlePresence(p.getAgentIdentifier()); } else { handleAbsence(p.getAgentIdentifier()); } }//found public void receivedPresence(PresenceProxy p) { if (p.isAvailable()) { handlePresence(p.getAgentIdentifier()); } else { handleAbsence(p.getAgentIdentifier()); } }//receivedPresence public void becamePresent(PresenceProxy p) { handlePresence(p.getAgentIdentifier()); }//becamePresent public void becameAbsent(PresenceProxy p) { handleAbsence(p.getAgentIdentifier()); }//becameAbsent public void statusUpdated(PresenceProxy p) { if (p.isAvailable()) { handlePresence(p.getAgentIdentifier()); } else { handleAbsence(p.getAgentIdentifier()); } }//statusUpdated public void subscriptionCanceled(final AgentIdentifier aid) { unregister(aid); }//subscriptionCanceled public void subscriptionAllowed(final AgentIdentifier aid) { m_Services.getExecutionService(ServiceMediator.NO_WAIT).execute(TwitterBotServiceImpl.this.m_ServiceAgentProxy.getAuthenticPeer(), new Runnable() { public void run() { m_ServicePresenceProxy.getPresenceService().requestSubscriptionTo( m_ServicePresenceProxy.getPresence(), aid ); }//run }//runnable );//execute }//subscriptionAllowed public void requestedSubscription(PresenceProxy p) { final AgentIdentifier aid = p.getAgentIdentifier(); m_Services.getExecutionService(ServiceMediator.NO_WAIT).execute(TwitterBotServiceImpl.this.m_ServiceAgentProxy.getAuthenticPeer(), new Runnable() { public void run() { m_ServicePresenceProxy.getPresenceService().allowSubscription( m_ServicePresenceProxy.getPresence(), aid ); m_ServicePresenceProxy.getPresenceService().requestSubscriptionTo( m_ServicePresenceProxy.getPresence(), aid ); }//run }//runnable );//execute }//requestedSubscription protected void handlePresence(final AgentIdentifier aid) { m_Services.getExecutionService(ServiceMediator.NO_WAIT).execute(TwitterBotServiceImpl.this.m_ServiceAgentProxy.getAuthenticPeer(), new Runnable() { public void run() { //subcriber logic if (m_PresentSubscribers.contains(aid)) { return; } else { m_PresentSubscribers.add(aid); //Scanning logic PreferencesService ps = m_Services.getPreferencesService(ServiceMediator.NO_WAIT); if (ps != null) { String uid = aid.getIdentifier(); Preferences p = ps.getUserPreferences(uid); if (p != null) { if (Boolean.valueOf(p.get(TWITTER_ACCOUNT_AUTOSCAN_KEY, "false"))) { m_Scanables.add(aid); } } } } }//run }//runnable );//execute }//handlePresence protected void handleAbsence(final AgentIdentifier aid) { m_Services.getExecutionService(ServiceMediator.NO_WAIT).execute(TwitterBotServiceImpl.this.m_ServiceAgentProxy.getAuthenticPeer(), new Runnable() { public void run() { if (!m_PresentSubscribers.remove(aid)) { return; } else { m_Scanables.remove(aid); } }//run }//runnable );//execute }//handleAbsence }//PresenceListenerImpl class MessagingServiceListenerImpl extends MessagingServiceListenerAdapter { public boolean received(final InteractiveMessage m) { m_Services.getExecutionService(ServiceMediator.NO_WAIT).execute(TwitterBotServiceImpl.this.m_ServiceAgentProxy.getAuthenticPeer(), new Runnable() { public void run() { EventInfo evinf = m.getEventInfo(); //1. Confirmation if (m.isConfirmationRequired()) { try { m_ServiceMessagingProxy.getMessagingService().confirm(m_ServicePresenceProxy.getPresence(), evinf ); } catch (MessagingException ex) { Activator.log().error(m_LogMarker, "MessagingServiceListener:received()", ex); } } //2. Skip Broadcasts if(m.isBroadcast()) { return; } //3. Interpret content String str = m.getBody(); if (str != null && str.length() > 0) { if (str.startsWith("help")) { doHelp(m.getFrom()); } else if (str.startsWith("register")) { doRegister(m.getFrom(), str.substring("register".length()).trim()); } else if (str.startsWith("unregister")) { doUnregister(m.getFrom()); } else if (str.startsWith(TWITTER_CMD_UPDATE)) { doUpdate(m.getFrom(), str.substring(TWITTER_CMD_UPDATE.length()).trim()); } else if (str.startsWith(TWITTER_CMD_GET)) { doTimeline(m.getFrom(), str.substring(TWITTER_CMD_GET.length()).trim(), false); } else if (str.startsWith(TWITTER_CMD_REPLIES)) { doTimeline(m.getFrom(), str.trim(), false); } else if (str.startsWith(TWITTER_CMD_SHOW)) { doShow(m.getFrom(), str.substring(TWITTER_CMD_SHOW.length()).trim()); } else if (str.startsWith(TWITTER_CMD_DESTROY)) { doDestroy(m.getFrom(), str.substring(TWITTER_CMD_DESTROY.length()).trim()); } else if (str.startsWith(TWITTER_SUBCMD_FOLLOWED)) { doFollowed(m.getFrom(), str.substring(TWITTER_SUBCMD_FOLLOWED.length()).trim()); } else if (str.startsWith(TWITTER_CMD_FOLLOWING)) { doFollowing(m.getFrom(), str.substring(TWITTER_CMD_FOLLOWING.length()).trim()); } else if (str.startsWith(TWITTER_CMD_FOLLOW)) { doFollow(m.getFrom(), str.substring(TWITTER_CMD_FOLLOW.length()).trim()); } else if (str.startsWith(TWITTER_SUBCMD_FAVORITES)) { doFave(m.getFrom(), str.substring(TWITTER_SUBCMD_FAVORITES.length()).trim()); } else if (str.startsWith(TWITTER_CMD_AUTOSCAN)) { doAutoScan(m.getFrom(), str.substring(TWITTER_CMD_AUTOSCAN.length()).trim()); } //else if (str.startsWith(TWITTER_CMD_PRIVATE)) { //doPrivate(m.getFrom(), str.substring(TWITTER_CMD_PRIVATE.length()).trim()); //} else { sendMessage(m.getFrom(), m_BundleMessages.get("TwitterBotServiceImpl.bot.nosuchcmd", "cmd", str.trim()), FORMAT_TML); } } }//run }//runnable );//execute return true; }//received }//MessagingServiceListenerImpl /* Defines a comparator for status date. The newest tweets are printed last. */ private static final Comparator STATUS_DATE_COMPARATOR = new Comparator(){ public int compare(Status status, Status status1) { return status.getCreatedAt().compareTo(status1.getCreatedAt()); }//compare }; private static Action[] ACTIONS = {}; private static final String TWITTER_ACCOUNT_USER_KEY = "twitter.account.user"; private static final String TWITTER_ACCOUNT_PASS_KEY = "twitter.account.pass"; private static final String TWITTER_ACCOUNT_AUTOSCAN_KEY = "twitter.account.autoscan"; private static final String TWITTER_ACCOUNT_LASTFGET_KEY = "twitter.account.lastfget"; private static final String TWITTER_CMD_UPDATE = "update"; private static final String TWITTER_CMD_GET = "get"; private static final String TWITTER_CMD_SHOW = "show"; private static final String TWITTER_CMD_DESTROY = "destroy"; private static final String TWITTER_CMD_REPLIES = "replies"; private static final String TWITTER_CMD_FOLLOW = "follow"; private static final String TWITTER_CMD_FOLLOWING = "following"; private static final String TWITTER_CMD_PRIVATE = "private"; private static final String TWITTER_CMD_AUTOSCAN = "autoscan"; private static final String TWITTER_SUBCMD_PUBLIC = "public"; private static final String TWITTER_SUBCMD_FOLLOWED = "followed"; private static final String TWITTER_SUBCMD_ID = "@"; private static final String TWITTER_SUBCMD_FAVORITES = "fave"; private static final String FORMAT_TML = "tml"; }//class TwitterBotServiceImpl