/* * Copyright 2012 Research Studios Austria Forschungsges.m.b.H. * * 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 won.bot.impl; import won.bot.framework.bot.base.EventBot; import won.bot.framework.eventbot.EventListenerContext; import won.bot.framework.eventbot.action.impl.MultipleActions; import won.bot.framework.eventbot.action.impl.RandomDelayedAction; import won.bot.framework.eventbot.action.impl.debugbot.*; import won.bot.framework.eventbot.action.impl.matcher.RegisterMatcherAction; import won.bot.framework.eventbot.action.impl.needlifecycle.DeactivateNeedAction; import won.bot.framework.eventbot.action.impl.wonmessage.*; import won.bot.framework.eventbot.bus.EventBus; import won.bot.framework.eventbot.event.impl.command.SendTextMessageOnConnectionEvent; import won.bot.framework.eventbot.event.impl.debugbot.*; import won.bot.framework.eventbot.event.impl.lifecycle.ActEvent; import won.bot.framework.eventbot.event.impl.matcher.MatcherRegisterFailedEvent; import won.bot.framework.eventbot.event.impl.matcher.NeedCreatedEventForMatcher; import won.bot.framework.eventbot.event.impl.wonmessage.*; import won.bot.framework.eventbot.filter.impl.NeedUriInNamedListFilter; import won.bot.framework.eventbot.filter.impl.NotFilter; import won.bot.framework.eventbot.listener.BaseEventListener; import won.bot.framework.eventbot.listener.impl.ActionOnEventListener; import won.protocol.model.FacetType; import java.net.URI; /** * Bot that reacts to each new need that is created in the system by creating two needs, it sends a connect message from * one of these needs, and a hint message for original need offering match to another of these needs. Additionally, * it reacts to certain commands send via text messages on the connections with the created by the bot needs. */ public class DebugBot extends EventBot { private static final long CONNECT_DELAY_MILLIS = 0; private static final long DELAY_BETWEEN_N_MESSAGES = 1000; private static final double CHATTY_MESSAGE_PROBABILITY = 0.1; private BaseEventListener matcherRegistrator; protected BaseEventListener needCreator; protected BaseEventListener needConnector; protected BaseEventListener needHinter; protected BaseEventListener autoOpener; protected BaseEventListener needCloser; protected BaseEventListener needDeactivator; protected BaseEventListener messageFromOtherNeedListener; protected BaseEventListener usageMessageSender; private int registrationMatcherRetryInterval; public void setRegistrationMatcherRetryInterval(final int registrationMatcherRetryInterval) { this.registrationMatcherRetryInterval = registrationMatcherRetryInterval; } private URI matcherUri; public void setMatcherUri(final URI matcherUri) { this.matcherUri = matcherUri; } @Override protected void initializeEventListeners() { String welcomeMessage = "Greetings! \nI am the DebugBot. I " + "can simulate multiple other users so you can test things. I understand a few commands. \nTo see which ones, " + "type \n\n'usage'\n\n (without the quotes)."; EventListenerContext ctx = getEventListenerContext(); EventBus bus = getEventBus(); //register with WoN nodes, be notified when new needs are created RegisterMatcherAction registerMatcherAction = new RegisterMatcherAction(ctx); this.matcherRegistrator = new ActionOnEventListener(ctx, registerMatcherAction, 1); bus.subscribe(ActEvent.class, this.matcherRegistrator); RandomDelayedAction delayedRegistration = new RandomDelayedAction(ctx, registrationMatcherRetryInterval, registrationMatcherRetryInterval, 0, registerMatcherAction); ActionOnEventListener matcherRetryRegistrator = new ActionOnEventListener(ctx, delayedRegistration); bus.subscribe(MatcherRegisterFailedEvent.class, matcherRetryRegistrator); //create the echo need for debug initial connect - if we're not reacting to the creation of our own echo need. CreateDebugNeedWithFacetsAction needForInitialConnectAction = new CreateDebugNeedWithFacetsAction(ctx,true,true); needForInitialConnectAction.setIsInitialForConnect(true); ActionOnEventListener initialConnector = new ActionOnEventListener( ctx, new NotFilter(new NeedUriInNamedListFilter(ctx, ctx.getBotContextWrapper().getNeedCreateListName())), needForInitialConnectAction ); bus.subscribe(NeedCreatedEventForMatcher.class, initialConnector); //create the echo need for debug initial hint - if we're not reacting to the creation of our own echo need. CreateDebugNeedWithFacetsAction initialHinter = new CreateDebugNeedWithFacetsAction(ctx, true, true); initialHinter.setIsInitialForHint(true); ActionOnEventListener needForInitialHintListener = new ActionOnEventListener(ctx, new NotFilter( new NeedUriInNamedListFilter(ctx, ctx.getBotContextWrapper().getNeedCreateListName() ) ), initialHinter); bus.subscribe(NeedCreatedEventForMatcher.class, needForInitialHintListener); //as soon as the echo need triggered by debug connect created, connect to original this.needConnector = new ActionOnEventListener( ctx, "needConnector", new RandomDelayedAction(ctx, CONNECT_DELAY_MILLIS,CONNECT_DELAY_MILLIS,1, new ConnectWithAssociatedNeedAction(ctx, FacetType.OwnerFacet.getURI(), FacetType.OwnerFacet.getURI(), welcomeMessage))); bus.subscribe(NeedCreatedEventForDebugConnect.class, this.needConnector); //as soon as the echo need triggered by debug hint command created, hint to original this.needHinter = new ActionOnEventListener( ctx, "needHinter", new RandomDelayedAction(ctx, CONNECT_DELAY_MILLIS,CONNECT_DELAY_MILLIS,1, new HintAssociatedNeedAction(ctx, FacetType.OwnerFacet.getURI(), FacetType.OwnerFacet.getURI(), matcherUri) )); bus.subscribe(NeedCreatedEventForDebugHint.class, this.needHinter); //if the original need wants to connect - always open this.autoOpener = new ActionOnEventListener(ctx, new MultipleActions(ctx, new OpenConnectionAction(ctx, welcomeMessage ), new PublishSetChattinessEventAction(ctx, true))); bus.subscribe(ConnectFromOtherNeedEvent.class, this.autoOpener); //if the remote side opens, send a greeting and set to chatty. bus.subscribe(OpenFromOtherNeedEvent.class, new ActionOnEventListener(ctx, new MultipleActions(ctx, new RespondToMessageAction(ctx, "Hi there!"), new PublishSetChattinessEventAction(ctx, true)))); //if the bot receives a text message - try to map the command of the text message to a DebugEvent messageFromOtherNeedListener = new ActionOnEventListener(ctx, new DebugBotIncomingMessageToEventMappingAction(ctx)); bus.subscribe(MessageFromOtherNeedEvent.class, messageFromOtherNeedListener); //react to usage command event this.usageMessageSender = new ActionOnEventListener(ctx, new SendMultipleMessagesAction( ctx,DebugBotIncomingMessageToEventMappingAction.USAGE_MESSAGES)); bus.subscribe(UsageDebugCommandEvent.class, usageMessageSender); //react to the debug close command (close the connection) this.needCloser = new ActionOnEventListener(ctx, new MultipleActions(ctx, new CloseConnectionAction(ctx, "As per your" + " request, this " + "connection is being closed."), new PublishSetChattinessEventAction(ctx, false))); bus.subscribe(CloseDebugCommandEvent.class, this.needCloser); //react to the debug deactivate command (deactivate my need) this.needDeactivator = new ActionOnEventListener(ctx,new DeactivateNeedAction(ctx)); bus.subscribe(DeactivateDebugCommandEvent.class, this.needDeactivator); //react to close event: set connection to not chatty bus.subscribe(CloseFromOtherNeedEvent.class, new ActionOnEventListener(ctx, new PublishSetChattinessEventAction(ctx, false))); // react to the hint and connect commands by creating a need (it will fire correct need created for connect/hint // events) needCreator = new ActionOnEventListener(ctx, new CreateDebugNeedWithFacetsAction(ctx, true, true)); bus.subscribe(HintDebugCommandEvent.class, needCreator); bus.subscribe(ConnectDebugCommandEvent.class, needCreator); //react to a message that was not identified as a debug command bus.subscribe(SendTextMessageOnConnectionEvent.class, new ActionOnEventListener(ctx, new SendMessageOnConnectionAction(ctx))); bus.subscribe(SendNDebugCommandEvent.class, new ActionOnEventListener(ctx, new SendNDebugMessagesAction(ctx, DELAY_BETWEEN_N_MESSAGES, DebugBotIncomingMessageToEventMappingAction.N_MESSAGES))); MessageTimingManager timingManager = new MessageTimingManager(ctx, 20); //on every actEvent there is a chance we send a chatty message bus.subscribe(ActEvent.class, new ActionOnEventListener(ctx, new SendChattyMessageAction(ctx, CHATTY_MESSAGE_PROBABILITY, timingManager, DebugBotIncomingMessageToEventMappingAction.RANDOM_MESSAGES, DebugBotIncomingMessageToEventMappingAction.LAST_MESSAGES) )); //set the chattiness of the connection bus.subscribe(SetChattinessDebugCommandEvent.class, new ActionOnEventListener(ctx, new SetChattinessAction(ctx))); //process eliza messages with eliza bus.subscribe(MessageToElizaEvent.class, new ActionOnEventListener(ctx, new AnswerWithElizaAction(ctx,20))); //remember when we sent the last message bus.subscribe(WonMessageSentOnConnectionEvent.class, new ActionOnEventListener(ctx, new RecordMessageSentTimeAction(ctx, timingManager))); //remember when we got the last message bus.subscribe(WonMessageReceivedOnConnectionEvent.class, new ActionOnEventListener(ctx, new RecordMessageReceivedTimeAction(ctx, timingManager))); //initialize the sent timestamp when the open message is received bus.subscribe(OpenFromOtherNeedEvent.class, new ActionOnEventListener(ctx, new RecordMessageSentTimeAction(ctx, timingManager))); //initialize the sent timestamp when the connect message is received bus.subscribe(ConnectFromOtherNeedEvent.class, new ActionOnEventListener(ctx, new RecordMessageSentTimeAction(ctx, timingManager))); } }