/** * Copyright (c) 2011, SOCIETIES Consortium (WATERFORD INSTITUTE OF TECHNOLOGY (TSSG), HERIOT-WATT UNIVERSITY (HWU), SOLUTA.NET * (SN), GERMAN AEROSPACE CENTRE (Deutsches Zentrum fuer Luft- und Raumfahrt e.V.) (DLR), Zavod za varnostne tehnologije * informacijske družbe in elektronsko poslovanje (SETCCE), INSTITUTE OF COMMUNICATION AND COMPUTER SYSTEMS (ICCS), LAKE * COMMUNICATIONS (LAKE), INTEL PERFORMANCE LEARNING SOLUTIONS LTD (INTEL), PORTUGAL TELECOM INOVAÇÃO, SA (PTIN), IBM Corp., * INSTITUT TELECOM (ITSUD), AMITEC DIACHYTI EFYIA PLIROFORIKI KAI EPIKINONIES ETERIA PERIORISMENIS EFTHINIS (AMITEC), TELECOM * ITALIA S.p.a.(TI), TRIALOG (TRIALOG), Stiftelsen SINTEF (SINTEF), NEC EUROPE LTD (NEC)) * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.societies.personalisation.dianne; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.societies.personalisation.DIANNE.api.model.IDIANNEOutcome; import org.societies.personalisation.dianne.model.ContextNode; import org.societies.personalisation.dianne.model.DIANNEOutcome; import org.societies.personalisation.dianne.model.IOutcomeListener; import org.societies.personalisation.dianne.model.Network; import org.societies.personalisation.dianne.model.ContextGroup; import org.societies.personalisation.dianne.model.Node; import org.societies.personalisation.dianne.model.OutcomeGroup; import org.societies.personalisation.dianne.model.OutcomeNode; import org.societies.personalisation.dianne.model.Synapse; import org.societies.api.context.model.CtxAttribute; import org.societies.api.identity.IIdentity; import org.societies.api.personalisation.model.IAction; import org.societies.api.schema.servicelifecycle.model.ServiceResourceIdentifier; public class NetworkRunner implements Runnable{ public Network network; private Logger LOG = LoggerFactory.getLogger(NetworkRunner.class); private IOutcomeListener callback; private NetworkBuffer buffer; private int nur = 1000; //network update rate private int contextNodeCount; private int outcomeNodeCount; private int cycleNum; //for threads private Thread myThread; private Object pauseMonitor = new Object(); private boolean paused = false; private boolean getOutcomes = false; public NetworkRunner(IIdentity identity, Network network, IOutcomeListener callback){ this.network = network; this.callback = callback; buffer = new NetworkBuffer(); contextNodeCount = 0; outcomeNodeCount = 0; cycleNum = 1; //start thread myThread = new Thread(this); myThread.setName("Network runner ID: "+ identity.getBareJid()); myThread.start(); } public void contextUpdate(CtxAttribute attribute){ buffer.addContextUpdate(attribute); getOutcomes = true; } public void actionUpdate(IAction action){ buffer.addOutcomeUpdate(action); } public IDIANNEOutcome getPrefOutcome(ServiceResourceIdentifier serviceId, String preferenceName){ IDIANNEOutcome outcome = null; OutcomeGroup outcomeGroup = network.getOutcomeGroup(serviceId, preferenceName); if(outcomeGroup != null){ OutcomeNode activeNode = (OutcomeNode)outcomeGroup.getActiveNode(); outcome = new DIANNEOutcome( serviceId, outcomeGroup.getServiceType(), outcomeGroup.getGroupName(), activeNode.getNodeName()); } return outcome; } @Override public void run() { while(true) { updateNetwork(); synchronized (pauseMonitor){ //check for disable if(paused){ try{ pauseMonitor.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } } } } public void play(){ synchronized(pauseMonitor){ paused = false; pauseMonitor.notify(); } } public void pause(){ synchronized (pauseMonitor){ paused = true; } } private void updateNetwork(){ LOG.debug("Running next cycle "+cycleNum); LOG.debug(cycleNum+": getting buffers"); ArrayList[] snapshot = buffer.getSnapshot(); LOG.debug(cycleNum+": updating context layer"); updateContextLayer(snapshot[0]); //set network to reflect context updates, feed forward new context updates LOG.debug(cycleNum+": updating outcome layer"); updateOutcomeLayer(snapshot[1]); //set network to reflect outcome updates LOG.debug(cycleNum+": updating network output"); updateNetworkOutput(); //update synapses and outcomes LOG.debug(cycleNum+": checking for new outputs"); if(getOutcomes){ LOG.debug(cycleNum+": returning new outputs"); callback.handleOutcomes(retrieveNewOutcomes()); //get new outcomes - if any getOutcomes = false; } LOG.debug(cycleNum+": COMPLETE"); //network.printNetwork(); try { Thread.sleep(nur); } catch (InterruptedException e) { e.printStackTrace(); } cycleNum++; } /*********************************************************************************** * Update network methods ***********************************************************************************/ /* * Context layer update methods */ public void updateContextLayer(ArrayList<CtxAttribute> contextUpdates) { Iterator<CtxAttribute> contextUpdates_it = contextUpdates.iterator(); while(contextUpdates_it.hasNext()) { CtxAttribute nextUpdate = (CtxAttribute)contextUpdates_it.next(); String groupName = nextUpdate.getType(); String nodeName = nextUpdate.getStringValue(); //search for group ContextGroup contextGroup = network.getContextGroup(groupName); if(contextGroup != null) //group exists { //file.println("Group "+groupName+" already exists"); //search for node ContextNode contextNode = (ContextNode)contextGroup.getNode(nodeName); if(contextNode != null) //node exists in group { //file.println("Node "+nodeName+" already exists"); //activate node in group (deactivates all others) activateContextUpdate(contextGroup, contextNode); }else{ //no such node exsist in group //file.println("Node "+nodeName+" doesn't exist, creating new"); //create node, add it to group and activate createNewContextNode(contextGroup, nodeName); } }else{ //no such group exists //file.println("Group "+groupName+" doesn't exist, creating new with node "+nodeName); //create group including new node and activate createNewContextGroup(groupName, nodeName); } } } public void activateContextUpdate(ContextGroup contextGroup, ContextNode contextNode) { //activate context node contextGroup.activateNode(contextNode); //refresh network outcomes refreshActiveNodes(); } public void createNewContextNode(ContextGroup contextGroup, String nodeName) { //create new context node ContextNode newContextNode = new ContextNode(contextNodeCount, contextGroup.getGroupName(), nodeName); contextNodeCount++; //add new node to context group and activate contextGroup.addNode(newContextNode); //create synapses to outcome nodes connectOutcomes(newContextNode); //refresh network outcomes refreshActiveNodes(); } public void createNewContextGroup(String groupName, String nodeName) { //create new context group ContextGroup newContextGroup = new ContextGroup(groupName); //create new context node for group createNewContextNode(newContextGroup, nodeName); //add new group to list network.addContextGroup(newContextGroup); } private void refreshActiveNodes() { //update outcome node potentials //activate nodes with highest potentials Iterator<OutcomeGroup> outcomeGroups_it = network.getOutcomeGroups().iterator(); while(outcomeGroups_it.hasNext()) { OutcomeGroup nextGroup = (OutcomeGroup)outcomeGroups_it.next(); nextGroup.refreshOutcomes(); } } /* * Outcome layer update methods */ public void updateOutcomeLayer(ArrayList<IAction> outcomeUpdates) { Iterator<IAction> outcomeUpdates_it = outcomeUpdates.iterator(); while(outcomeUpdates_it.hasNext()) { IAction nextUpdate = (IAction)outcomeUpdates_it.next(); ServiceResourceIdentifier serviceId = nextUpdate.getServiceID(); String serviceType = nextUpdate.getServiceType(); String groupName = nextUpdate.getparameterName(); String nodeName = nextUpdate.getvalue(); //search for group OutcomeGroup outcomeGroup = network.getOutcomeGroup(serviceId, groupName); if(outcomeGroup != null) //group exists { LOG.debug("Group "+groupName+" already exists"); //search for node OutcomeNode outcomeNode = (OutcomeNode)outcomeGroup.getNode(nodeName); if(outcomeNode != null) //node exists in group { LOG.debug("Node "+nodeName+" already exists"); //activate node in group (deactivates all others) activateOutcomeUpdate(outcomeGroup, outcomeNode); }else{ //no such node exists in group LOG.debug("Node "+nodeName+" doesn't exist, creating new"); //create node, add it to group and activate createNewOutcomeNode(outcomeGroup, nodeName); } }else{ //no such group exists LOG.debug("Group "+groupName+" under serviceId "+serviceId.getServiceInstanceIdentifier()+" doesn't exist, creating new with node "+nodeName); //create group including new node and activate createNewOutcomeGroup(serviceId, serviceType, groupName, nodeName); } } } public void activateOutcomeUpdate(OutcomeGroup outcomeGroup, OutcomeNode outcomeNode) { //activate outcome node outcomeGroup.userActivateNode(outcomeNode); } public void createNewOutcomeNode(OutcomeGroup outcomeGroup, String nodeName) { OutcomeNode newOutcomeNode = new OutcomeNode(outcomeNodeCount, outcomeGroup.getGroupName(), nodeName); outcomeNodeCount++; //add new node to outcome group outcomeGroup.addNode(newOutcomeNode); //create synapses to context nodes connectContext(newOutcomeNode); //activate new node in group activateOutcomeUpdate(outcomeGroup, newOutcomeNode); } public void createNewOutcomeGroup(ServiceResourceIdentifier serviceId, String serviceType, String groupName, String nodeName) { //create new outcome group OutcomeGroup newOutcomeGroup = new OutcomeGroup(serviceId, serviceType, groupName); //create new outcome node for group createNewOutcomeNode(newOutcomeGroup, nodeName); //add new group to list network.addOutcomeGroup(newOutcomeGroup); LOG.debug("Number of outcome groups after adding new = "+network.getOutcomeGroups().size()); } private void connectOutcomes(ContextNode node){ int preNodeID = node.getID(); Iterator<OutcomeGroup> list_it = network.getOutcomeGroups().iterator(); while(list_it.hasNext()) { OutcomeGroup nextGroup = (OutcomeGroup)list_it.next(); ArrayList<Node> nodes = nextGroup.getGroupNodes(); Iterator<Node> nodes_it = nodes.iterator(); while(nodes_it.hasNext()) { Node nextNode = (Node)nodes_it.next(); int postNodeID = nextNode.getID(); String synapseID = postNodeID+"_"+preNodeID; //Create new Synapse with id, pre-node and post-node Synapse synapse = new Synapse(synapseID, (ContextNode)node, (OutcomeNode)nextNode); //node=context, nextnode=outcome //add synapse to pre and post nodes node.addSynapse(synapse); nextNode.addSynapse(synapse); network.addSynapse(synapse); } } } private void connectContext(OutcomeNode node){ int postNodeID = node.getID(); Iterator<ContextGroup> list_it = network.getContextGroups().iterator(); while(list_it.hasNext()) { ContextGroup nextGroup = (ContextGroup)list_it.next(); ArrayList<Node> nodes = nextGroup.getGroupNodes(); Iterator<Node> nodes_it = nodes.iterator(); while(nodes_it.hasNext()) { Node nextNode = (Node)nodes_it.next(); int preNodeID = nextNode.getID(); String synapseID = postNodeID+"_"+preNodeID; //Create new Synapse with id, pre-node and post-node Synapse synapse = new Synapse(synapseID, (ContextNode)nextNode, (OutcomeNode)node); //node=outcome, nextnode=context //add synapse to pre and post nodes node.addSynapse(synapse); nextNode.addSynapse(synapse); network.addSynapse(synapse); } } } /* * Network output update methods */ public void updateNetworkOutput() { //update synapses updateSynapses(); //calculate new winners and communicate Iterator<OutcomeGroup> outcomeGroups_it = network.getOutcomeGroups().iterator(); LOG.debug("Updating "+network.getOutcomeGroups().size()+" outcome groups"); while(outcomeGroups_it.hasNext()) { OutcomeGroup nextGroup = (OutcomeGroup)outcomeGroups_it.next(); LOG.debug("Updating: "+nextGroup.getServiceId().getServiceInstanceIdentifier()+nextGroup.getGroupName()); nextGroup.updateGroupOutput(); } } public void updateSynapses() { Iterator<Synapse> synapses_it = network.getSynapses().iterator(); while(synapses_it.hasNext()) { Synapse nextSynapse = (Synapse)synapses_it.next(); nextSynapse.updateWeight(); } } /* * Network output capture methods */ public List<IDIANNEOutcome> retrieveNewOutcomes(){ List<IDIANNEOutcome> results = new ArrayList<IDIANNEOutcome>(); Iterator<OutcomeGroup> outcomeGroups_it = network.getOutcomeGroups().iterator(); LOG.info("Retrieving new outputs from "+network.getOutcomeGroups().size()+" outcome groups"); while(outcomeGroups_it.hasNext()){ OutcomeGroup nextGroup = (OutcomeGroup)outcomeGroups_it.next(); if(nextGroup.newOutput){ LOG.info(nextGroup.getServiceId().getServiceInstanceIdentifier()+"->"+nextGroup.getGroupName()+" has new output"); OutcomeNode activeNode = (OutcomeNode)nextGroup.getNewOutput(); IDIANNEOutcome newOutcome = new DIANNEOutcome( nextGroup.getServiceId(), nextGroup.getServiceType(), nextGroup.getGroupName(), activeNode.getNodeName()); results.add(newOutcome); } } return results; } }