/* * 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.bot.context.ParticipantCoordinatorBotContextWrapper; import won.bot.framework.eventbot.EventListenerContext; import won.bot.framework.eventbot.action.impl.wonmessage.ConnectFromListToListAction; import won.bot.framework.eventbot.action.impl.needlifecycle.CreateNeedWithFacetsAction; import won.bot.framework.eventbot.action.impl.needlifecycle.DeactivateAllNeedsOfListAction; import won.bot.framework.eventbot.action.impl.lifecycle.SignalWorkDoneAction; import won.bot.framework.eventbot.bus.EventBus; import won.bot.framework.eventbot.event.impl.lifecycle.ActEvent; import won.bot.framework.eventbot.event.impl.listener.FinishedEvent; import won.bot.framework.eventbot.event.impl.needlifecycle.NeedCreatedEvent; import won.bot.framework.eventbot.event.impl.wonmessage.CloseFromOtherNeedEvent; import won.bot.framework.eventbot.event.impl.wonmessage.ConnectFromOtherNeedEvent; import won.bot.framework.eventbot.event.impl.wonmessage.MessageFromOtherNeedEvent; import won.bot.framework.eventbot.event.impl.wonmessage.OpenFromOtherNeedEvent; import won.bot.framework.eventbot.filter.impl.AcceptOnceFilter; import won.bot.framework.eventbot.filter.impl.FinishedEventFilter; import won.bot.framework.eventbot.filter.impl.OrFilter; import won.bot.framework.eventbot.listener.BaseEventListener; import won.bot.framework.eventbot.listener.baStateBots.BATestBotScript; import won.bot.framework.eventbot.listener.baStateBots.BATestScriptListener; import won.bot.framework.eventbot.listener.impl.ActionOnEventListener; import won.bot.framework.eventbot.listener.impl.ActionOnceAfterNEventsListener; import won.protocol.model.FacetType; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * Created with IntelliJ IDEA. * User: Danijel * Date: 26.2.14. * Time: 15.15 * To change this template use File | Settings | File Templates. */ public abstract class BABaseBot extends EventBot { protected final int noOfNeeds; protected final List<BATestBotScript> scripts; private static final long MILLIS_BETWEEN_MESSAGES = 10; //we use protected members so we can extend the class and //access the listeners for unit test assertions and stats // //we use BaseEventListener as their types so we can access the generic //functionality offered by that class protected BaseEventListener participantNeedCreator; protected BaseEventListener coordinatorNeedCreator; protected BaseEventListener needConnector; protected BaseEventListener scriptsDoneListener; protected BaseEventListener workDoneSignaller; protected final List<BATestScriptListener> testScriptListeners; protected BABaseBot() { this.scripts= getScripts(); this.noOfNeeds = scripts.size()+1; this.testScriptListeners = Collections.synchronizedList(new ArrayList(noOfNeeds-1)); } protected abstract FacetType getParticipantFacetType(); protected abstract FacetType getCoordinatorFacetType(); @Override protected void initializeEventListeners() { final EventListenerContext ctx = getEventListenerContext(); final EventBus bus = getEventBus(); ParticipantCoordinatorBotContextWrapper botContextWrapper = (ParticipantCoordinatorBotContextWrapper) getBotContextWrapper(); //create needs every trigger execution until noOfNeeds are created this.participantNeedCreator = new ActionOnEventListener( ctx, "participantCreator", new CreateNeedWithFacetsAction(ctx, botContextWrapper.getParticipantListName(), getParticipantFacetType().getURI()), noOfNeeds - 1 ); bus.subscribe(ActEvent.class, this.participantNeedCreator); //when done, create one coordinator need this.coordinatorNeedCreator = new ActionOnEventListener( ctx, "coordinatorCreator", new FinishedEventFilter(participantNeedCreator), new CreateNeedWithFacetsAction(ctx, botContextWrapper.getCoordinatorListName(), getCoordinatorFacetType().getURI()), 1 ); bus.subscribe(FinishedEvent.class, this.coordinatorNeedCreator); final Iterator<BATestBotScript> scriptIterator = scripts.iterator(); //make a composite filter, with one filter for each testScriptListener that wait // for the FinishedEvents the they emit. That filter will be used to shut // down all needs after all the scriptListeners have finished. final OrFilter mainScriptListenerFilter = new OrFilter(); //create a callback that gets called immediately before the connection is established ConnectFromListToListAction.ConnectHook scriptConnectHook = new ConnectFromListToListAction.ConnectHook() { @Override public void onConnect(final URI fromNeedURI, final URI toNeedURI) { //create the listener that will execute the script actions BATestScriptListener testScriptListener = new BATestScriptListener(ctx, scriptIterator.next(), fromNeedURI, toNeedURI, MILLIS_BETWEEN_MESSAGES); //remember it so we can check its state later testScriptListeners.add(testScriptListener); //subscribe it to the relevant events. bus.subscribe(ConnectFromOtherNeedEvent.class, testScriptListener); bus.subscribe(OpenFromOtherNeedEvent.class, testScriptListener); bus.subscribe(MessageFromOtherNeedEvent.class, testScriptListener); //add a filter that will wait for the FinishedEvent emitted by that listener //wrap it in an acceptance filter to make extra sure we count each listener only once. mainScriptListenerFilter.addFilter( new AcceptOnceFilter( new FinishedEventFilter(testScriptListener))); } }; //when done, connect the participants to the coordinator this.needConnector = new ActionOnceAfterNEventsListener( ctx, "needConnector", noOfNeeds, new ConnectFromListToListAction(ctx, botContextWrapper.getCoordinatorListName(), botContextWrapper.getParticipantListName(), getCoordinatorFacetType().getURI(), getParticipantFacetType().getURI(), MILLIS_BETWEEN_MESSAGES, scriptConnectHook,"Hi!")); bus.subscribe(NeedCreatedEvent.class, this.needConnector); //for each group member, there are 2 listeners waiting for messages. when they are all finished, we're done. this.scriptsDoneListener = new ActionOnceAfterNEventsListener( ctx, "scriptsDoneListener", mainScriptListenerFilter, noOfNeeds - 1, new DeactivateAllNeedsOfListAction(ctx, botContextWrapper.getParticipantListName())); bus.subscribe(FinishedEvent.class, this.scriptsDoneListener); //When the needs are deactivated, all connections are closed. wait for the close events and signal work done. this.workDoneSignaller = new ActionOnceAfterNEventsListener( ctx, "workDoneSignaller", noOfNeeds - 1, new SignalWorkDoneAction(ctx) ); bus.subscribe(CloseFromOtherNeedEvent.class, this.workDoneSignaller); } protected abstract List<BATestBotScript> getScripts(); }