/*** * 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.knsu.impl; import net.coalevo.bot.knsu.service.KnsuBotConfiguration; import net.coalevo.bot.knsu.service.KnsuBotService; import net.coalevo.foundation.model.*; 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 org.osgi.framework.BundleContext; import org.slf4j.Marker; import org.slf4j.MarkerFactory; import java.io.IOException; import java.net.MalformedURLException; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * This class implements the Knsu Bot as a Service. *

* * @author Dieter Wimberger (wimpi) * @version @version@ (@date@) */ class KnsuBotServiceImpl extends BaseService implements KnsuBotService, ConfigurationUpdateHandler { private Marker m_LogMarker = MarkerFactory.getMarker(KnsuBotServiceImpl.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; //Cache private LRUCacheMap m_URLCache; private LRUCacheMap m_InfoCache; //Client private KnsuClient m_KnsuClient; KnsuBotServiceImpl() { super(KnsuBotService.class.getName(), ACTIONS); m_URLCache = new LRUCacheMap(20); m_InfoCache = new LRUCacheMap(20); m_KnsuClient = new KnsuClient(); }//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); return true; }//activate public boolean deactivate() { 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_URLCache != null) { m_URLCache.clear(); } if (m_InfoCache != null) { m_InfoCache.clear(); } m_Services = null; return true; }//deactivate public void update(MetaTypeDictionary mtd) { //1. Configure from persistent configuration int urlcsize = 20; int infocsize = 20; String login = ""; String apikey = ""; //Retrieve config try { login = mtd.getString(KnsuBotConfiguration.KNSU_LOGIN_KEY); } catch (MetaTypeDictionaryException ex) { Activator.log().error(m_LogMarker, m_BundleMessages.get("KnsuBotServiceImpl.activation.configexception", "attribute", KnsuBotConfiguration.KNSU_LOGIN_KEY), ex ); } try { apikey = mtd.getString(KnsuBotConfiguration.KNSU_APIKEY_KEY); } catch (MetaTypeDictionaryException ex) { Activator.log().error(m_LogMarker, m_BundleMessages.get("KnsuBotServiceImpl.activation.configexception", "attribute", KnsuBotConfiguration.KNSU_APIKEY_KEY), ex ); } try { urlcsize = mtd.getInteger(KnsuBotConfiguration.KNSU_URLCACHESIZE_KEY).intValue(); } catch (MetaTypeDictionaryException ex) { Activator.log().error(m_LogMarker, m_BundleMessages.get("KnsuBotServiceImpl.activation.configexception", "attribute", KnsuBotConfiguration.KNSU_URLCACHESIZE_KEY), ex ); } try { infocsize = mtd.getInteger(KnsuBotConfiguration.KNSU_URLCACHESIZE_KEY).intValue(); } catch (MetaTypeDictionaryException ex) { Activator.log().error(m_LogMarker, m_BundleMessages.get("KnsuBotServiceImpl.activation.configexception", "attribute", KnsuBotConfiguration.KNSU_URLCACHESIZE_KEY), ex ); } //Update config m_KnsuClient.setAuthentication(login, apikey); //Update cache setting m_URLCache.setCeiling(urlcsize); m_InfoCache.setCeiling(infocsize); }//update 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("KnsuBotServiceImpl.bot.help"), FORMAT_TML); }//doHelp private void doShorten(AgentIdentifier aid, String url) { String msg; try { KnsuURL bu = m_KnsuClient.shorten(url); if (bu.notError()) { msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.shortened", "long", bu.getLong(), "short", bu.getShort()); } else { msg = m_BundleMessages.get( "KnsuBotServiceImpl.bot.knsuerror", "code", Integer.toString(bu.getError()), "msg", bu.getErrorMessage() ); } } catch (MalformedURLException muex) { msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.malformedurl"); } catch (IOException ex) { msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.iofailed"); } sendMessage(aid, msg, FORMAT_TML); }//doShorten private void doExpand(AgentIdentifier aid, String str) { String msg; KnsuURL bu = null; try { //check cache if (str.startsWith("http://")) { String hash = str.substring(str.lastIndexOf('/') + 1); bu = m_URLCache.get(hash); } if (bu == null) { bu = m_KnsuClient.expand(str); } if (bu.notError()) { m_URLCache.put(bu.getTag(),bu); msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.expanded", "long", bu.getLong(), "short", bu.getShort()); } else { msg = m_BundleMessages.get( "KnsuBotServiceImpl.bot.knsuerror", "code", Integer.toString(bu.getError()), "msg", bu.getErrorMessage() ); } } catch (MalformedURLException muex) { msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.malformedurl"); } catch (IOException ex) { msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.iofailed"); } sendMessage(aid, msg, FORMAT_TML); }//doExpand private void doInfo(AgentIdentifier aid, String str) { String msg; KnsuInfo bi = null; try { //check cache if (str.startsWith("http://")) { String hash = str.substring(str.lastIndexOf('/') + 1); bi = m_InfoCache.get(hash); } if (bi == null) { bi = m_KnsuClient.info(str); //System.out.println(bi.toString()); } if (bi.notError()) { m_InfoCache.put(bi.getTag(), bi); MessageAttributes attr = m_BundleMessages.leaseAttributes(); attr.add("tag", bi.getTag()); attr.add("short", bi.getShort()); attr.add("long", bi.getLong()); attr.add("longenc", KnsuClient.encodeURL(bi.getLong())); addIf(attr, "title", bi.getTitle()); addIf(attr, "desc", bi.getDescription()); addIf(attr, "keywords", bi.getKeywordsAsString()); addIf(attr, "shortenuser", bi.getShortenUser()); addIf(attr, "when", bi.getWhen()); msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.urlinfo", attr); //System.out.println("Got message " + msg); } else { msg = m_BundleMessages.get( "KnsuBotServiceImpl.bot.knsuerror", "code", Integer.toString(bi.getError()), "msg", bi.getErrorMessage() ); } } catch (MalformedURLException muex) { msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.malformedurl"); } catch (IOException ex) { msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.iofailed"); } sendMessage(aid, msg, FORMAT_TML); }//doInfo private void addIf(MessageAttributes attr, String key, String val) { if(val != null && val.trim().length() > 0) { attr.add(key, val); } }//addIf private void doStats(AgentIdentifier aid, String str) { String msg; KnsuStats bs = null; try { bs = m_KnsuClient.stats(str); if (bs.notError()) { MessageAttributes attr = m_BundleMessages.leaseAttributes(); attr.add("tag", bs.getTag()); attr.add("short", bs.getShort()); attr.add("clicks", Long.toString(bs.getClicks())); msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.urlstats", attr); } else { msg = m_BundleMessages.get( "KnsuBotServiceImpl.bot.knsuerror", "code", Integer.toString(bs.getError()), "msg", bs.getErrorMessage() ); } } catch (MalformedURLException muex) { msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.malformedurl"); } catch (IOException ex) { msg = m_BundleMessages.get("KnsuBotServiceImpl.bot.iofailed"); } sendMessage(aid, msg, FORMAT_TML); }//doStats 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(KnsuBotServiceImpl.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(KnsuBotServiceImpl.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(KnsuBotServiceImpl.this.m_ServiceAgentProxy.getAuthenticPeer(), new Runnable() { public void run() { //subcriber logic if (m_PresentSubscribers.contains(aid)) { return; } else { m_PresentSubscribers.add(aid); } }//run }//runnable );//execute }//handlePresence protected void handleAbsence(final AgentIdentifier aid) { m_Services.getExecutionService(ServiceMediator.NO_WAIT).execute(KnsuBotServiceImpl.this.m_ServiceAgentProxy.getAuthenticPeer(), new Runnable() { public void run() { if (!m_PresentSubscribers.remove(aid)) { return; } }//run }//runnable );//execute }//handleAbsence }//PresenceListenerImpl class MessagingServiceListenerImpl extends MessagingServiceListenerAdapter { public boolean received(final InteractiveMessage m) { m_Services.getExecutionService(ServiceMediator.NO_WAIT).execute(KnsuBotServiceImpl.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(KNSU_CMD_HELP)) { doHelp(m.getFrom()); } else if (str.startsWith(KNSU_CMD_SHORTEN)) { doShorten(m.getFrom(), str.substring(KNSU_CMD_SHORTEN.length()).trim()); } else if (str.startsWith(KNSU_CMD_EXPAND)) { doExpand(m.getFrom(), str.substring(KNSU_CMD_EXPAND.length()).trim()); } else if (str.startsWith(KNSU_URL)) { doInfo(m.getFrom(),str.trim()); } else if (str.startsWith(ANY_URL)) { doShorten(m.getFrom(), str.trim()); } else if (str.startsWith(KNSU_CMD_INFO)) { doInfo(m.getFrom(), str.substring(KNSU_CMD_INFO.length()).trim()); } else if (str.startsWith(KNSU_CMD_STATS)) { doStats(m.getFrom(), str.substring(KNSU_CMD_STATS.length()).trim()); } else { sendMessage(m.getFrom(), m_BundleMessages.get("KnsuBotServiceImpl.bot.nosuchcmd", "cmd", str.trim()), FORMAT_TML); } } }//run }//runnable );//execute return true; }//received }//MessagingServiceListenerImpl private static Action[] ACTIONS = {}; private static final String KNSU_CMD_HELP = "help"; private static final String KNSU_CMD_SHORTEN = "shorten"; private static final String KNSU_CMD_EXPAND = "expand"; private static final String KNSU_CMD_INFO = "info"; private static final String KNSU_CMD_STATS = "stats"; private static final String KNSU_URL = "http://karanet.at/r"; private static final String ANY_URL = "http://"; private static final String FORMAT_TML = "tml"; }//class KnsuBotServiceImpl