/**
* 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.privacytrust.privacyprotection.privacypreferencemanager.merging;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.societies.api.context.CtxException;
import org.societies.api.context.model.CtxAttribute;
import org.societies.api.context.model.CtxIdentifier;
import org.societies.api.context.model.CtxModelType;
import org.societies.api.identity.IIdentity;
import org.societies.api.identity.IIdentityManager;
import org.societies.api.identity.InvalidFormatException;
import org.societies.api.internal.context.broker.ICtxBroker;
import org.societies.api.internal.schema.privacytrust.privacyprotection.preferences.AccessControlPreferenceDetailsBean;
import org.societies.api.internal.schema.privacytrust.privacyprotection.preferences.IDSPreferenceDetailsBean;
import org.societies.api.schema.identity.RequestorBean;
import org.societies.privacytrust.privacyprotection.api.model.privacypreference.ContextPreferenceCondition;
import org.societies.privacytrust.privacyprotection.api.model.privacypreference.IPrivacyOutcome;
import org.societies.privacytrust.privacyprotection.api.model.privacypreference.IPrivacyPreference;
import org.societies.privacytrust.privacyprotection.api.model.privacypreference.IPrivacyPreferenceCondition;
import org.societies.privacytrust.privacyprotection.api.model.privacypreference.IPrivacyPreferenceTreeModel;
import org.societies.privacytrust.privacyprotection.api.model.privacypreference.PrivacyPreference;
import org.societies.privacytrust.privacyprotection.api.model.privacypreference.constants.OperatorConstants;
import org.societies.privacytrust.privacyprotection.api.model.privacypreference.ids.IDSPrivacyPreferenceTreeModel;
import org.societies.privacytrust.privacyprotection.api.model.privacypreference.ids.IdentitySelectionPreferenceOutcome;
import org.societies.privacytrust.privacyprotection.privacypreferencemanager.CtxTypes;
import org.societies.privacytrust.privacyprotection.privacypreferencemanager.PrivacyPreferenceManager;
public class PrivacyPreferenceMerger {
private ICtxBroker broker;
private PrivacyPreferenceManager ppMgr;
private IIdentityManager idMgr;
private Logger logging = LoggerFactory.getLogger(this.getClass());
public PrivacyPreferenceMerger(ICtxBroker broker, PrivacyPreferenceManager ppMgr){
this.broker = broker;
this.ppMgr = ppMgr;
this.idMgr = ppMgr.getIdm();
}
public void addIDSDecision(IIdentity selectedDPI, RequestorBean requestor){
ContextSnapshot snapshot = this.takeSnapshot();
IDSPreferenceDetailsBean details = new IDSPreferenceDetailsBean();
details.setAffectedIdentity(selectedDPI.getJid());
details.setRequestor(requestor);
IPrivacyPreferenceTreeModel existingModel = ppMgr.getIDSPreference(details);
if (existingModel==null){
IDSPrivacyPreferenceTreeModel model;
try {
model = new IDSPrivacyPreferenceTreeModel(details, this.createIDSPreference(snapshot, details));
this.ppMgr.storeIDSPreference(details, model);
} catch (InvalidFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
IPrivacyPreference mergedPreference;
try {
mergedPreference = this.mergeIDSPreference(details, existingModel.getRootPreference(), snapshot);
if (mergedPreference!=null){
IDSPrivacyPreferenceTreeModel model = new IDSPrivacyPreferenceTreeModel(details, mergedPreference);
this.ppMgr.storeIDSPreference(details, model);
}
} catch (InvalidFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public IPrivacyPreference mergeIDSPreference(IDSPreferenceDetailsBean d, IPrivacyPreference node, ContextSnapshot snapshot) throws InvalidFormatException{
if (node.isLeaf()){
this.logging.debug("existing node does not contain context condition. merging as leaf");
IPrivacyPreference p = new PrivacyPreference();
p.add(this.createIDSPreference(snapshot, d));
p = p.getRoot();
p.add(node);
return p;
}
ArrayList<SingleRule> singleRules = this.convertToSingleRules(snapshot);
IPrivacyPreference mergedTree = node;
for (int i = 0; i< singleRules.size(); i++){
SingleRule sr = singleRules.get(i);
//logging.debug("Merging new Single Rule: "+sr.toString());
//logging.debug("\twith: "+mergedTree.toTreeString());
IPrivacyPreference temp = merge(mergedTree, sr);
if (temp==null){
return null;
}
mergedTree = temp; //in the MergingManager if this method returns null, it means we have to request a full learning cycle
}
return mergedTree;
}
public IPrivacyPreference mergeAccCtrlPreference(AccessControlPreferenceDetailsBean d, IPrivacyPreference existingPreference, IPrivacyPreference newPreference){
if (existingPreference.isLeaf()){
this.logging.debug("existing node does not contain context condition. merging as leaf");
newPreference = newPreference.getRoot();
IPrivacyPreference p = new PrivacyPreference();
p.add(newPreference);
p.add(existingPreference);
return p;
}
ArrayList<SingleRule> newSingleRules = this.convertToSingleRules(newPreference);
IPrivacyPreference mergedTree = existingPreference;
for (SingleRule sr : newSingleRules){
IPrivacyPreference temp = merge(mergedTree, sr);
if (temp==null){
return null;
}
mergedTree = temp;
}
return mergedTree;
}
private IPrivacyPreference merge(IPrivacyPreference oldTree, SingleRule sr){
//IPreference newTree = null;
ArrayList<SingleRule> oldRules = this.convertToSingleRules(oldTree);
//check if we're in Situation 1 (same conditions different outcomes)
ArrayList<SingleRule> temp = this.checkConflicts(oldRules, sr);
if (temp.size()>0){
return null;
}
this.logging.debug("Not in situation 1");
//check if we're in Situation 2 (100% match)
temp = this.checkMatches(oldRules, sr);
if (temp.size()>0){
//return createTree(temp);
return oldTree;
}
this.logging.debug("Not in Situation 2");
//we're going to find a branch that has the most common conditions with this rule.
IPrivacyPreference commonNode = this.findCommonNode(oldTree, sr);
if (null==commonNode){
IPrivacyPreference root = (IPrivacyPreference) oldTree.getRoot();
if (null==root.getUserObject()){
return this.addToNode((IPrivacyPreference) oldTree.getRoot(),sr);
}
IPrivacyPreference newRoot = new PrivacyPreference();
newRoot.add(root);
return this.addToNode(newRoot, sr);
}
return this.addToNode(commonNode, sr);
//ArrayList<SingleRule> sortedRules = sortTree(oldRules);
//newTree = createTree(sortedRules);
//return newTree;
}
private ArrayList<SingleRule> checkMatches(ArrayList<SingleRule> oldRules, SingleRule newRule){
for (int i=0; i< oldRules.size(); i++){
SingleRule sr = oldRules.get(i);
if (sr.equals(newRule)){
oldRules.set(i, this.increaseConfidenceLevel(sr));
return oldRules;
}
}
return new ArrayList<SingleRule>();
}
private SingleRule increaseConfidenceLevel(SingleRule sr){
//need to increase the confidence level by running the algorithm
return sr;
}
private IPrivacyPreference findCommonNode(IPrivacyPreference ptn, SingleRule sr){
CommonNodeCounter cnc = new CommonNodeCounter();
//if it's an empty root, we have to repeat with all its children
if (ptn.getUserObject() == null){
this.logging.debug("current node is empty root");
Enumeration<IPrivacyPreference> e = ptn.children();
while (e.hasMoreElements()){
IPrivacyPreference p = e.nextElement();
this.logging.debug("processing child :"+p.toString()+" which is child of: "+ptn.toString());
cnc = findCommonNode(p,sr, cnc);
}
}else{
cnc = findCommonNode(ptn,sr,cnc);
}
return cnc.getMostCommonNode();
}
private CommonNodeCounter findCommonNode(IPrivacyPreference ptn, SingleRule sr, CommonNodeCounter cnc){
//unlikely
if (ptn.isLeaf()){
this.logging.debug("current node is leaf. returning common node counter");
return cnc;
}
IPrivacyPreferenceCondition pc = (IPrivacyPreferenceCondition) ptn.getUserObject();
//if they have a common condition, go to the children, otherwise, return and continue with siblings
if (sr.hasCondition(pc)){
this.logging.debug("Single rule: "+sr.toString()+" has common node: "+pc.toString());
cnc.add(ptn, ptn.getLevel());
Enumeration<IPrivacyPreference> e = ptn.children();
while (e.hasMoreElements()){
cnc = findCommonNode(e.nextElement(),sr,cnc);
}
}
return cnc;
}
private ArrayList<SingleRule> checkConflicts(ArrayList<SingleRule> oldRules, SingleRule newRule){
for (int i=0; i< oldRules.size(); i++){
SingleRule sr = oldRules.get(i);
if (sr.conflicts(newRule)){
oldRules.set(i, this.resolveConflict(sr, newRule));
return oldRules;
}
}
return new ArrayList<SingleRule>();
}
private SingleRule resolveConflict(SingleRule oldRule, SingleRule newRule){
//resolve
return oldRule;
}
public ArrayList<SingleRule> convertToSingleRules(IPrivacyPreference ptn){
ArrayList<SingleRule> singleRules = new ArrayList<SingleRule>();
//Enumeration<IPreference> newNodeEnum = ptn.depthFirstEnumeration();
Enumeration<IPrivacyPreference> newNodeEnum = ptn.preorderEnumeration();
//we're going to construct SingleRule objects from the new tree to use as input to merge with the old tree
while (newNodeEnum.hasMoreElements()){
IPrivacyPreference temp = (IPrivacyPreference) newNodeEnum.nextElement();
if (temp.isLeaf()){
Object[] userObjs = temp.getUserObjectPath();
SingleRule sr = new SingleRule();
for (int i=0; i<userObjs.length; i++){
if (userObjs!=null){
if (userObjs[i] instanceof IPrivacyPreferenceCondition){
sr.addConditions((IPrivacyPreferenceCondition) userObjs[i]);
}else {
sr.setOutcome((IPrivacyOutcome) userObjs[i]);
}
}
}
singleRules.add(sr);
}
}
for (int i=0; i<singleRules.size(); i++){
logging.debug("::"+singleRules.get(i).toString());
}
return singleRules;
}
public ArrayList<SingleRule> convertToSingleRules(ContextSnapshot snapshot){
ArrayList<SingleRule> srlist = new ArrayList<SingleRule>();
List<SingleContextAttributeSnapshot> slist = snapshot.getList();
SingleRule sr = new SingleRule();
for (SingleContextAttributeSnapshot s : slist){
IPrivacyPreferenceCondition con = this.getContextConditionPreference(s);
sr.addConditions(con);
}
srlist.add(sr);
return srlist;
}
private IPrivacyPreference createIDSPreference(ContextSnapshot snapshot, IDSPreferenceDetailsBean details) throws InvalidFormatException{
IdentitySelectionPreferenceOutcome outcome = new IdentitySelectionPreferenceOutcome(this.idMgr.fromJid(details.getAffectedIdentity()));
IPrivacyPreference p = new PrivacyPreference(outcome);
List<SingleContextAttributeSnapshot> list = snapshot.getList();
for (SingleContextAttributeSnapshot s : list){
IPrivacyPreference temp = new PrivacyPreference(this.getContextConditionPreference(s));
temp.add(p);
p = temp;
}
return p;
}
private IPrivacyPreferenceCondition getContextConditionPreference(SingleContextAttributeSnapshot attrSnapshot){
ContextPreferenceCondition condition = new ContextPreferenceCondition(attrSnapshot.getId(),OperatorConstants.EQUALS, attrSnapshot.getValue());
//IPrivacyPreference pref = new PrivacyPreference(condition);
return condition;
}
private ContextSnapshot takeSnapshot(){
ContextSnapshot snapshot = new ContextSnapshot();
SingleContextAttributeSnapshot attrSnapshot = this.takeAttributeSnapshot(CtxTypes.SYMBOLIC_LOCATION);
if (attrSnapshot!=null){
snapshot.addSnapshot(attrSnapshot);
}
attrSnapshot = this.takeAttributeSnapshot(CtxTypes.STATUS);
if (attrSnapshot!=null){
snapshot.addSnapshot(attrSnapshot);
}
attrSnapshot = this.takeAttributeSnapshot(CtxTypes.ACTIVITY);
if (attrSnapshot!=null){
snapshot.addSnapshot(attrSnapshot);
}
return snapshot;
}
private SingleContextAttributeSnapshot takeAttributeSnapshot(String type){
CtxIdentifier id;
try {
List<CtxIdentifier> l = this.broker.lookup(CtxModelType.ATTRIBUTE, type).get();
if (l.size()==0){
return null;
}
id = l.get(0);
CtxAttribute attr = (CtxAttribute) this.broker.retrieve(id);
SingleContextAttributeSnapshot attrSnapshot = new SingleContextAttributeSnapshot(attr);
return attrSnapshot;
} catch (CtxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private IPrivacyPreference addToNode(IPrivacyPreference ptn, SingleRule sr){
logging.debug("BEFORE REMOVAL: "+sr.toString());
if (null!=ptn.getUserObject()){
logging.debug(" found common node: "+ptn.getUserObject().toString());
//IPreferenceCondition[] cons = new IPreferenceCondition[ptn.getLevel()];
Object[] objs = ptn.getUserObjectPath();
for (int i = 0; i< objs.length; i++){
if (objs[i] instanceof ContextPreferenceCondition){
ContextPreferenceCondition con = (ContextPreferenceCondition) objs[i];
logging.debug(" removing conditions");
if (sr.hasCondition(con)){
sr.removeCondition(con);
logging.debug(" REMOVED "+con.toString());
}
}
}
if (ptn.getUserObject() instanceof ContextPreferenceCondition){
if (sr.hasCondition((ContextPreferenceCondition) ptn.getUserObject())){
sr.removeCondition((ContextPreferenceCondition) ptn.getUserObject());
}
}
}else{
logging.debug(" not found common node");
}
logging.debug("AFTER REMOVAL: "+sr.toString());
IPrivacyPreference leaf = new PrivacyPreference(sr.getOutcome());
for (int i = 0; i< sr.getConditions().size(); i++){
ContextPreferenceCondition pc = (ContextPreferenceCondition) ptn.getUserObject();
if (null==pc){
logging.debug("weird");
}
if (sr.getConditions().get(i) == null){
logging.debug("even weirder");
}
//log("pc: "+pc.toString());
logging.debug("sr con: "+sr.getConditions().get(i).toString());
IPrivacyPreference temp = new PrivacyPreference(sr.getConditions().get(i));
ptn.add(temp);
ptn = temp;
}
ptn.add(leaf);
return (IPrivacyPreference) ptn.getRoot();
}
}