/** * 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.UserPreferenceManagement.impl.evaluation; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import javax.swing.JOptionPane; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.societies.api.context.model.CtxIdentifier; import org.societies.api.internal.personalisation.model.IOutcome; import org.societies.personalisation.preference.api.model.ContextPreferenceCondition; import org.societies.personalisation.preference.api.model.IPreference; import org.societies.personalisation.preference.api.model.IPreferenceCondition; import org.societies.personalisation.preference.api.model.IPreferenceOutcome; import org.societies.personalisation.preference.api.model.OperatorConstants; public class PreferenceEvaluator { private PrivateContextCache contextCache; private Logger logging = LoggerFactory.getLogger(this.getClass()); public PreferenceEvaluator(PrivateContextCache cache){ this.contextCache = cache; } public Hashtable<IPreferenceOutcome,List<CtxIdentifier>> evaluatePreference(IPreference ptn){ Hashtable<IPreferenceOutcome,List<CtxIdentifier>> temp = new Hashtable<IPreferenceOutcome,List<CtxIdentifier>>(); IPreference p = this.evaluatePreferenceInternal(ptn); if (p!=null){ ArrayList<CtxIdentifier> ctxIds = new ArrayList<CtxIdentifier>(); Object[] objs = p.getUserObjectPath(); for (Object obj : objs){ if (obj instanceof IPreferenceCondition){ ctxIds.add( ((IPreferenceCondition) obj).getCtxIdentifier()); } } /*IPreference[] prefs = (IPreference[]) p.getUserObjectPath(); for (int i = 0; i<prefs.length; i++){ if (null!=prefs[i].getUserObject()){ if (prefs[i].isBranch()){ IPreferenceCondition condition = prefs[i].getCondition(); ctxIds.add(condition.getCtxIdentifier()); } } }*/ temp.put(p.getOutcome(), ctxIds); return temp; }else{ return new Hashtable<IPreferenceOutcome,List<CtxIdentifier>>(); } } private IPreference evaluatePreferenceInternal(IPreference ptn){ logging.debug("evaluating preference"); //a non-context aware preference if (ptn.isLeaf()){ logging.debug("preference is not context-dependent. returning IAction object"+ptn.getOutcome().toString()); return ptn; } //if the root object is null then the tree is split so we have to evaluate more than one tree if (ptn.getUserObject()==null){ logging.debug("preference tree is split. we might have a conflict"); Enumeration<IPreference> e = ptn.children(); ArrayList<IPreference> prefList = new ArrayList<IPreference>(); while (e.hasMoreElements()){ IPreference p = e.nextElement(); IPreference outcomePreference = this.evaluatePreferenceInternal(p); if (outcomePreference!=null){ prefList.add(outcomePreference); } } //if only one IOutcome is applicable with the current context return that if (prefList.size()==1){ logging.debug("PrefEvaluator> Returning: "+ prefList.get(0).toString()); return prefList.get(0); } //if no IOutcome is applicable, return a null object else if (prefList.size()==0){ logging.debug("PrefEvaluator> No preference applicable"); return null; } //if more than one IOutcome objs is applicable, use conflict resolution and return the most applicable else{ ConflictResolver cr = new ConflictResolver(); IPreference io = cr.resolveConflicts(prefList); logging.debug("PrefEvaluator> Returning: "+io.toString()); return io; } } //if the root node is not empty else{ logging.debug("preference tree is not split. no conflicts here"); //and it's a condition if (ptn.isBranch()){ //evaluate the condition IPreferenceCondition con = ptn.getCondition(); try { if (evaluatesToTrue(con)){ logging.debug(con.toString()+" is true - descending tree levels"); //traverse the tree in preorder traversal to evaluate all the conditions under this branch and find an Action Enumeration<IPreference> e = ptn.children(); while (e.hasMoreElements()){ IPreference p = e.nextElement(); IPreference outcomePreference = this.evaluatePreferenceInternal(p); if(null != outcomePreference){ return outcomePreference; } } }else{ logging.debug(con.toString()+" is false - returning"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }//and it's not a condition but an Outcome (i.e. not a branch but a leaf) else{ logging.debug("PrefEvaluator> Returning: "+ptn.getOutcome()); return ptn; } } return null; } public boolean evaluatesToTrue(IPreferenceCondition cond){ if (cond instanceof ContextPreferenceCondition){ String currentContextValue = this.getValueFromContext(cond.getCtxIdentifier()); OperatorConstants operator = cond.getoperator(); logging.debug("evaluating cond: "+cond.toString()+" against current value: "+currentContextValue); if (operator.equals(OperatorConstants.EQUALS)){ //JOptionPane.showMessageDialog(null, "Comparing: "+cond.getvalue()+" with current context value: "+currentContextValue); return currentContextValue.equalsIgnoreCase(cond.getvalue()); } else return this.evaluateInt(parseString(cond.getvalue()), parseString(currentContextValue), operator); }else{ this.logging.error("Catastrophic failure. Request to evaluate a node that is not a conditional node"); return false; } } public boolean evaluateInt(int valueInPreference, int valueInContext, OperatorConstants operator){ boolean result = false; switch (operator){ case GREATER_OR_EQUAL_THAN: result = valueInContext >= valueInPreference; break; case GREATER_THAN: result = valueInContext > valueInPreference; break; case LESS_OR_EQUAL_THAN: result = valueInContext <= valueInPreference; break; case LESS_THAN: result = valueInContext < valueInPreference; break; default: logging.debug("Invalid Operator"); } return result; } public String getValueFromContext(CtxIdentifier id){ if (id==null){ this.logging.debug("can't get context value from null id"); } if (this.contextCache==null){ this.logging.debug("ContextCache is null. PrefEvaluator not initialised properly"); } return this.contextCache.getContextValue(id); } public int parseString(String str){ try{ return Integer.parseInt(str); }catch (NumberFormatException nbe){ logging.debug("Could not parse String to int"); return 0; } } /* public static void main(String[] args){ ICtxBroker sbroker = new StubCtxBroker(); try { ICtxEntity entity = sbroker.createEntity("Person"); if (entity==null){ System.out.println("entity is null"); } ICtxEntityIdentifier entityID = entity.getCtxIdentifier(); ICtxAttribute symlocAttr = sbroker.createAttribute(entityID, CtxAttributeTypes.SYMBOLIC_LOCATION); //ICtxEntityIdentifier entityID = new StubCtxEntityIdentifier("AliceSecret1234%5Bbe94bf83-1264-4f36-b339-53894b0a376f%5D,","ac3fdc679c58235326","person",1L); //ICtxAttributeIdentifier symlocAttrID = new StubCtxAttributeIdentifier(entityID, CtxAttributeTypes.SYMBOLIC_LOCATION, 62L); //ICtxAttribute symlocAttr = new StubCtxAttribute(symlocAttrID, entityID); symlocAttr.setStringValue("home"); sbroker.update(symlocAttr); IPreference condition1 = new PreferenceTreeNode( new ContextPreferenceCondition(symlocAttr.getCtxIdentifier(), OperatorConstants.EQUALS, "home", CtxAttributeTypes.SYMBOLIC_LOCATION)); IPreference condition2 = new PreferenceTreeNode( new ContextPreferenceCondition(symlocAttr.getCtxIdentifier(), OperatorConstants.EQUALS, "work", CtxAttributeTypes.SYMBOLIC_LOCATION)); //define outcomes IPreference outcome1 = new PreferenceTreeNode(new PreferenceOutcome("volume", "100")); IPreference outcome2 = new PreferenceTreeNode(new PreferenceOutcome("volume", "0")); //build tree IPreference preference = new PreferenceTreeNode(); preference.add(condition1); //branch 1 condition1.add(outcome1); preference.add(condition2); //branch 2 condition2.add(outcome2); PrivateContextCache cc = new PrivateContextCache(sbroker); PreferenceEvaluator ev = new PreferenceEvaluator(cc); Hashtable<IOutcome,List<CtxIdentifier>> result = ev.evaluatePreference(preference); if (result!=null && (!result.isEmpty())){ System.out.println("got result. size: "+result.size()); Enumeration<IOutcome> outcomes = result.keys(); while (outcomes.hasMoreElements()){ IOutcome o = outcomes.nextElement(); System.out.println(o.toString()); } } } catch (ContextException e) { // TODO Auto-generated catch block e.printStackTrace(); } }*/ }