/** * 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.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.societies.personalisation.DIANNE.api.DianneNetwork.IDIANNE; import org.societies.personalisation.DIANNE.api.model.IDIANNEOutcome; import org.societies.personalisation.common.api.management.IInternalPersonalisationManager; import org.societies.personalisation.common.api.model.PersonalisationTypes; import org.societies.personalisation.dianne.model.IOutcomeListener; import org.societies.personalisation.dianne.model.Network; import org.societies.api.comm.xmpp.interfaces.ICommManager; import org.societies.api.context.CtxException; import org.societies.api.context.model.CtxAssociation; import org.societies.api.context.model.CtxAssociationIdentifier; import org.societies.api.context.model.CtxAttribute; import org.societies.api.context.model.CtxAttributeIdentifier; import org.societies.api.context.model.CtxEntity; import org.societies.api.context.model.CtxEntityIdentifier; import org.societies.api.context.model.CtxIdentifier; import org.societies.api.context.model.CtxModelType; import org.societies.api.context.model.IndividualCtxEntity; import org.societies.api.context.model.util.SerialisationHelper; import org.societies.api.identity.IIdentity; import org.societies.api.internal.context.broker.ICtxBroker; import org.societies.api.internal.context.model.CtxAssociationTypes; import org.societies.api.internal.context.model.CtxAttributeTypes; import org.societies.api.personalisation.model.IAction; import org.societies.api.schema.servicelifecycle.model.ServiceResourceIdentifier; import org.springframework.scheduling.annotation.AsyncResult; public class DIANNE implements IDIANNE, IOutcomeListener{ private Logger LOG = LoggerFactory.getLogger(DIANNE.class); private HashMap<IIdentity, Network> d_nets; //IIdentity - Network mappings private HashMap<String, NetworkRunner> runnerMappings; //IIdentity(bareJid) - runner mappings private List<IDIANNEOutcome> outcomes; private String[] defaultContext = { CtxAttributeTypes.LOCATION_SYMBOLIC, CtxAttributeTypes.STATUS, CtxAttributeTypes.TEMPERATURE }; private IInternalPersonalisationManager persoMgr; private ICtxBroker ctxBroker; private ICommManager commsMgr; private IIdentity cssID; private boolean activated; public DIANNE(){ d_nets = new HashMap<IIdentity, Network>(); runnerMappings = new HashMap<String, NetworkRunner>(); outcomes = null; activated = true; } @Override public Future<List<IDIANNEOutcome>> getOutcome(IIdentity ownerId, ServiceResourceIdentifier serviceId, String preferenceName) { LOG.debug("Request - getOutcome with values: "+ownerId.getBareJid()+", "+serviceId.getServiceInstanceIdentifier()+", "+preferenceName); //no updates received - just return current outcome List<IDIANNEOutcome> results = new ArrayList<IDIANNEOutcome>(); if(activated){ if(runnerMappings.containsKey(ownerId.getBareJid())){ LOG.debug("DIANNE already exists for this ownerId: "+ownerId.getBareJid()); NetworkRunner runner = runnerMappings.get(ownerId.getBareJid()); IDIANNEOutcome outcome = runner.getPrefOutcome(serviceId, preferenceName); if(outcome!=null){ results.add(outcome); }else{ LOG.debug("No outcomes to return from DIANNE"); } }else{ LOG.debug("No DIANNE exists for this ownerId: "+ownerId.getBareJid()+"...cannot return result"); } }else{ LOG.debug("DIANNE learning is not enabled - ignoring input and returning empty results list"); } return new AsyncResult<List<IDIANNEOutcome>>(results); } @Override public Future<List<IDIANNEOutcome>> getOutcome(IIdentity ownerId, CtxAttribute attribute) { LOG.debug("Context update - getOutcome with values: "+ownerId.getBareJid()+", "+attribute.getType()+"="+attribute.getStringValue()); List<IDIANNEOutcome> results = new ArrayList<IDIANNEOutcome>(); if(activated){ //process if context update is not null if(attribute.getType() != null && attribute.getStringValue()!=null){ // Context update received!!! if(runnerMappings.containsKey(ownerId.getBareJid())){ LOG.debug("DIANNE already exists for this ownerId: "+ownerId.getBareJid()); runnerMappings.get(ownerId.getBareJid()).contextUpdate(attribute); }else{ LOG.debug("DIANNE does not exist for this ownerId: "+ownerId.getBareJid()+"...creating"); Network newD_net = new Network(); NetworkRunner newRunner = new NetworkRunner(ownerId, newD_net, this); d_nets.put(ownerId, newD_net); runnerMappings.put(ownerId.getBareJid(), newRunner); newRunner.contextUpdate(attribute); } //wait for new outcomes int loopCount = 0; while(outcomes == null && loopCount < 10){ try { LOG.debug("waiting for output response..."+loopCount); Thread.sleep(500); loopCount++; } catch (InterruptedException e) { e.printStackTrace(); } } if(outcomes != null){ results = outcomes; outcomes = null; }else{ LOG.debug("Wait cycle exited - DIANNE did not return any new outcomes for this context update"); } }else{ LOG.debug("Not performing context update - context update contained null element: "+attribute.getType()+"="+attribute.getStringValue()); } }else{ LOG.debug("DIANNE learning is not enabled - ignoring input and returning empty results list"); } return new AsyncResult<List<IDIANNEOutcome>>(results); } @Override public Future<List<IDIANNEOutcome>> getOutcome(IIdentity ownerId, IAction action){ LOG.info("Action update with value: "+ownerId.getBareJid()+", "+action.getparameterName()+"="+action.getvalue()); // Action update received!!! if(activated){ if(runnerMappings.containsKey(ownerId.getBareJid())){ LOG.info("DIANNE already exists for this ownerId: "+ownerId.getBareJid()); runnerMappings.get(ownerId.getBareJid()).actionUpdate(action); }else{ LOG.info("DIANNE does not exist for this ownerId: "+ownerId.getBareJid()+"...creating"); Network newD_net = new Network(); NetworkRunner newRunner = new NetworkRunner(ownerId, newD_net, this); d_nets.put(ownerId, newD_net); runnerMappings.put(ownerId.getBareJid(), newRunner); newRunner.actionUpdate(action); } }else{ LOG.debug("DIANNE learning is not enabled - ignoring input and returning empty results list"); } //No new outcomes will be provided after action updates - return empty list return new AsyncResult<List<IDIANNEOutcome>>(new ArrayList<IDIANNEOutcome>()); } @Override public void enableDIANNELearning(IIdentity ownerId) { LOG.info("Enabling incremental learning for identity: "+ ownerId.getBareJid()); if(runnerMappings.containsKey(ownerId.getBareJid())){ NetworkRunner network = runnerMappings.get(ownerId.getBareJid()); network.play(); }else{ LOG.info("No networks exist for this identity"); } activated = true; } @Override public void disableDIANNELearning(IIdentity ownerId) { LOG.info("Disabling incremental learning for identity: "+ ownerId.getBareJid()); if(runnerMappings.containsKey(ownerId.getBareJid())){ NetworkRunner network = runnerMappings.get(ownerId.getBareJid()); network.pause(); }else{ LOG.info("No networks exist for this identity"); } activated = false; } @Override /* * Called by PersonalisationManager when initialised * (non-Javadoc) * @see org.societies.personalisation.DIANNE.api.DianneNetwork.IDIANNE#registerContext() */ public void registerContext(){ LOG.debug("DIANNE is registering for default context updates: symLoc, status and temperature"); for(int i=0; i<defaultContext.length; i++){ try { String nextType = defaultContext[i]; List<CtxIdentifier> attrIDs = ctxBroker.lookup(CtxModelType.ATTRIBUTE, nextType).get(); if(attrIDs.size() > 0){ LOG.debug("Registering for context update: "+defaultContext[i]); persoMgr.registerForContextUpdate(cssID, PersonalisationTypes.DIANNE, (CtxAttributeIdentifier)attrIDs.get(0)); }else{ LOG.debug("Ctx Attribute: "+defaultContext[i]+" does not yet exist - could not register for context updates"); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } catch (CtxException e) { e.printStackTrace(); } } } @Override public void receiveDIANNEFeedback(IIdentity ownerId, IAction action){ this.getOutcome(ownerId, action); } public void initialiseDIANNELearning(){ cssID = commsMgr.getIdManager().getThisNetworkNode(); retrieveNetworks(); //get Networks from context initialiseNetworks(); //start runners for each network //start DIANNE storage thread - store DIANNEs every 1?/5? minute(s) Thread persistThread = new Thread(new PersistenceManager(this, ctxBroker)); persistThread.setName("DIANNE Persistence Thread"); persistThread.start(); //TEMPORARY FIX FOR #751 - this.disableDIANNELearning(cssID); } private void retrieveNetworks(){ try { IndividualCtxEntity person = ctxBroker.retrieveIndividualEntity(cssID).get(); Set<CtxAssociationIdentifier> hasDianneAssocIDs = person.getAssociations(CtxAssociationTypes.HAS_DIANNE); if(hasDianneAssocIDs.size() > 0){// HAS_DIANNE association found in context CtxAssociation hasDianneAssoc = (CtxAssociation)ctxBroker.retrieve(hasDianneAssocIDs.iterator().next()).get(); Set<CtxEntityIdentifier> dianneEntityIDs = hasDianneAssoc.getChildEntities(); if(dianneEntityIDs.size() > 0){// DIANNEs found in context for(CtxEntityIdentifier nextDianneID: dianneEntityIDs){ CtxEntity nextDianne = (CtxEntity)ctxBroker.retrieve(nextDianneID).get(); Set<CtxAttribute> attributes = nextDianne.getAttributes(); if(attributes.size() > 0){// Network and ID found for this DIANNE entity IIdentity dNetID = null; Network dNet = null; for(CtxAttribute nextAttr: attributes){ if(nextAttr.getType().equals(CtxAttributeTypes.D_NET)){ dNet = (Network)SerialisationHelper.deserialise(nextAttr.getBinaryValue(), this.getClass().getClassLoader()); }else if(nextAttr.getType().equals(CtxAttributeTypes.ID)){ dNetID = (IIdentity)SerialisationHelper.deserialise(nextAttr.getBinaryValue(), this.getClass().getClassLoader()); } } d_nets.put(dNetID, dNet); } } } } } catch (CtxException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } private void initialiseNetworks(){ Iterator<IIdentity> e = d_nets.keySet().iterator(); while(e.hasNext()){ IIdentity nextIdentity = e.next(); Network nextNetwork = d_nets.get(nextIdentity); NetworkRunner nextRunner = new NetworkRunner(nextIdentity, nextNetwork, this); runnerMappings.put(nextIdentity.getBareJid(), nextRunner); } } /* * getter methods. Do not rename. The name of these methods are referenced in the spring osgi files */ public IInternalPersonalisationManager getPersoMgr() { return persoMgr; } public ICtxBroker getCtxBroker(){ return ctxBroker; } public ICommManager getCommsMgr(){ return commsMgr; } public HashMap<IIdentity, Network> getDNets(){ return this.d_nets; } /* * setter methods. Do not rename. The name of these methods are referenced in the spring osgi files */ public void setPersoMgr(IInternalPersonalisationManager persoMgr) { this.persoMgr = persoMgr; } public void setCtxBroker(ICtxBroker ctxBroker){ this.ctxBroker = ctxBroker; } public void setCommsMgr(ICommManager commsMgr){ this.commsMgr = commsMgr; } @Override public void handleOutcomes(List<IDIANNEOutcome> outcomes) { LOG.info("Received output response"); for(IDIANNEOutcome nextOutcome : outcomes){ LOG.info(nextOutcome.getServiceID().getServiceInstanceIdentifier()+": "+nextOutcome.getparameterName()+"="+nextOutcome.getvalue()); } this.outcomes = outcomes; } }