/***
* 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