/** * 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.webapp.controller; import org.primefaces.model.DefaultTreeNode; import org.primefaces.model.TreeNode; import org.societies.api.context.model.CtxAttributeIdentifier; import org.societies.api.context.model.CtxAttributeTypes; import org.societies.api.context.model.CtxIdentifier; import org.societies.api.context.model.CtxModelType; import org.societies.api.internal.context.broker.ICtxBroker; import org.societies.api.internal.personalisation.model.PreferenceDetails; import org.societies.api.internal.servicelifecycle.IServiceDiscovery; import org.societies.api.personalisation.model.PersonalisablePreferenceIdentifier; import org.societies.api.schema.servicelifecycle.model.Service; import org.societies.personalisation.preference.api.IUserPreferenceManagement; import org.societies.personalisation.preference.api.UserPreferenceConditionMonitor.IUserPreferenceConditionMonitor; import org.societies.personalisation.preference.api.model.*; import org.societies.webapp.service.UserService; import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; import javax.faces.bean.SessionScoped; import java.util.*; import java.util.concurrent.Future; @ManagedBean(name = "profileSettings") // JSF @SessionScoped // JSF public class ProfileSettingsController extends BasePageController { private class PreferenceDetailsComparator implements Comparator<PreferenceDetails> { @Override public int compare(PreferenceDetails o1, PreferenceDetails o2) { if (o1 == null && o2 == null) return 0; if (o1 == null) return -1; if (o2 == null) return 1; if (o1.getPreferenceName() == null && o2.getPreferenceName() == null) return 0; if (o1.getPreferenceName() == null) return -1; if (o2.getPreferenceName() == null) return 1; return o1.getPreferenceName().compareTo(o2.getPreferenceName()); } } public static final String OUTCOME_NODE = "outcome"; public static final String CONDITION_NODE = "condition"; public static final String PREFERENCE_NODE = "preference"; @ManagedProperty(value = "#{userService}") private UserService userService; @ManagedProperty(value = "#{userPreferenceConditionMonitor}") private IUserPreferenceConditionMonitor userPreferenceConditionMonitor; @ManagedProperty(value = "#{internalCtxBroker}") private ICtxBroker internalCtxBroker; @ManagedProperty(value = "#{serviceDiscovery}") private IServiceDiscovery serviceDiscovery; // this is not a JSF managed property - it's contained within userPreferenceConditionMonitor private IUserPreferenceManagement userPreferenceManagement; private boolean treeChangesMade = false; private TreeNode preferencesRootNode; private TreeNode selectedTreeNode; private PreferenceDetails selectedPreference; private IPreferenceCondition selectedCondition; private IPreferenceOutcome selectedOutcome; private ContextPreferenceCondition conditionToAdd = new ContextPreferenceCondition(null, OperatorConstants.EQUALS, "", ""); private PreferenceOutcome outcomeToAdd = new PreferenceOutcome(null, "", "", ""); private String addConditionMode; private String newPreferenceName; /* The following are used for the edit/delete methods, to map a condition/outcome to the parent preference */ private final Map<IPreferenceCondition, PreferenceDetails> conditionToPDMap = new HashMap<IPreferenceCondition, PreferenceDetails>(); private final Map<IPreferenceOutcome, PreferenceDetails> outcomeToPDMap = new HashMap<IPreferenceOutcome, PreferenceDetails>(); private final Map<IPreferenceCondition, IPreference> conditionToPreferenceMap = new HashMap<IPreferenceCondition, IPreference>(); private final Map<IPreferenceOutcome, IPreference> outcomeToPreferenceMap = new HashMap<IPreferenceOutcome, IPreference>(); private final Map<PreferenceDetails, IPreference> pdToPreferenceMap = new HashMap<PreferenceDetails, IPreference>(); private final Map<PreferenceDetails, IPreferenceTreeModel> pdToPreferenceTreeModelMap = new HashMap<PreferenceDetails, IPreferenceTreeModel>(); private Service newPreferenceService; private List<Service> availableServices; private String[] availableCtxAttributeTypes; public ProfileSettingsController() { log.info("ProfileSettingsController ctor"); } /* Spring/JSF dependency Getters and Setters */ @SuppressWarnings("UnusedDeclaration") public UserService getUserService() { return userService; } @SuppressWarnings("UnusedDeclaration") public void setUserService(UserService userService) { this.userService = userService; } @SuppressWarnings("UnusedDeclaration") public IUserPreferenceConditionMonitor getUserPreferenceConditionMonitor() { return userPreferenceConditionMonitor; } @SuppressWarnings("UnusedDeclaration") public void setUserPreferenceConditionMonitor(IUserPreferenceConditionMonitor userPreferenceConditionMonitor) { if (userPreferenceConditionMonitor == null) log.error("setUserPreferenceConditionMonitor() = null"); else log.debug("setUserPreferenceConditionMonitor() = " + userPreferenceConditionMonitor.toString()); this.userPreferenceConditionMonitor = userPreferenceConditionMonitor; loadPreferenceTreeData(); } @SuppressWarnings("UnusedDeclaration") public IUserPreferenceManagement getUserPreferenceManagement() { return userPreferenceManagement; } @SuppressWarnings("UnusedDeclaration") public void setUserPreferenceManagement(IUserPreferenceManagement userPreferenceManagement) { this.userPreferenceManagement = userPreferenceManagement; } @SuppressWarnings("UnusedDeclaration") public ICtxBroker getInternalCtxBroker() { return internalCtxBroker; } @SuppressWarnings("UnusedDeclaration") public void setInternalCtxBroker(ICtxBroker internalCtxBroker) { this.internalCtxBroker = internalCtxBroker; } @SuppressWarnings("UnusedDeclaration") public IServiceDiscovery getServiceDiscovery() { return serviceDiscovery; } @SuppressWarnings("UnusedDeclaration") public void setServiceDiscovery(IServiceDiscovery serviceDiscovery) { this.serviceDiscovery = serviceDiscovery; } /* Web app Getters and Setters */ public TreeNode getPreferencesRootNode() { // log.debug("getPreferencesRootNode()"); if (preferencesRootNode == null) populatePreferencesRootNode(); return preferencesRootNode; } public void setSelectedTreeNode(TreeNode selectedTreeNode) { // log.debug("setSelectedTreeNode() = " + selectedTreeNode); this.selectedTreeNode = selectedTreeNode; } public TreeNode getSelectedTreeNode() { // log.debug("getSelectedTreeNode() = " + selectedTreeNode); return selectedTreeNode; } @SuppressWarnings("UnusedDeclaration") public PreferenceDetails getSelectedPreference() { return selectedPreference; } public IPreferenceCondition getSelectedCondition() { return selectedCondition; } public IPreferenceOutcome getSelectedOutcome() { return selectedOutcome; } public IPreferenceCondition getConditionToAdd() { return conditionToAdd; } public IPreferenceOutcome getOutcomeToAdd() { return outcomeToAdd; } public OperatorConstants[] getConditionOperators() { return OperatorConstants.values().clone(); } public String[] getAvailableCtxAttributeTypes() { if (availableCtxAttributeTypes == null) { String[] allTypes = CtxAttributeTypes.ALL_TYPES; ArrayList<String> availableTypes = new ArrayList<String>(); for (String ctxAttributeType : allTypes) { try { Future<List<CtxIdentifier>> idsFuture = this.internalCtxBroker.lookup(CtxModelType.ATTRIBUTE, ctxAttributeType); List<CtxIdentifier> ids = idsFuture.get(); for (CtxIdentifier id : ids) { availableTypes.add(id.getType()); } } catch (Exception e) { // } } availableCtxAttributeTypes = availableTypes.toArray(new String[availableTypes.size()]); } return availableCtxAttributeTypes; } private String[] availablePreferenceNames; public String[] getAvailablePreferenceNames() { if (availablePreferenceNames == null) { List<PersonalisablePreferenceIdentifier> knownPersonalisablePreferences = userPreferenceManagement.getKnownPersonalisablePreferences(); List<String> names = new ArrayList<String>(); for (PersonalisablePreferenceIdentifier pref : knownPersonalisablePreferences) { names.add(pref.getPreferenceName()); } availablePreferenceNames = names.toArray(new String[names.size()]); log.debug("Found " + availablePreferenceNames.length + " preference names: " + Arrays.toString(availablePreferenceNames)); } return availablePreferenceNames; } public void setNewPreferenceName(String newPreferenceName) { this.newPreferenceName = newPreferenceName; } public String getNewPreferenceName() { return newPreferenceName; } public void setNewPreferenceService(Service newPreferenceService) { this.newPreferenceService = newPreferenceService; } public Service getNewPreferenceService() { return newPreferenceService; } // this method may be called a few times in the same request public synchronized List<Service> getAvailableServices() { if (availableServices == null) { try { availableServices = serviceDiscovery.getServices(userService.getIdentity()).get(); } catch (Exception e) { addGlobalMessage("Error loading services list", e.getMessage(), FacesMessage.SEVERITY_ERROR); log.error("Error loading services list", e); // ensure we don't get the error again availableServices = new ArrayList<Service>(); } } return availableServices; } public boolean isShowAddCondition() { // ONLY time not to show "add condition" is when the root preference is selected, and it has no children if (selectedPreference != null) { IPreference preference = pdToPreferenceMap.get(selectedPreference); // only enable this if the preference has current children return hasConditionAsDirectChild(preference) || hasOutcomeAsDirectChild(preference); } return true; } public boolean isShowAddOutcome() { // DON'T show add outcome if: // - Adding a condition before anything return !"before".equals(addConditionMode); } public boolean isTreeChangesMade() { return treeChangesMade; } /* Public methods */ public void savePreferenceState() { log.debug("savePreferenceState()"); treeChangesMade = true; TreeNode node = getSelectedTreeNode(); if (node == null) { addGlobalMessage("Cannot edit", "No node selected", FacesMessage.SEVERITY_WARN); } else if (node.getData() == null) { addGlobalMessage("Cannot edit", "No data in selected node", FacesMessage.SEVERITY_WARN); } else if (node.getData() instanceof IPreferenceCondition) { IPreferenceCondition condition = (IPreferenceCondition) node.getData(); PreferenceDetails preferenceDetails = conditionToPDMap.get(condition); // IPreference preference = conditionToPreferenceMap.get(condition); if (condition.getoperator() == null) { addGlobalMessage("Condition NOT updated for " + preferenceDetails.getPreferenceName(), "Operator was null - something has gone wrong", FacesMessage.SEVERITY_ERROR); // log.debug("Operator was null - Condition NOT updated for " + preferenceDetails.getPreferenceName()); } else { // userPreferenceManagement.storePreference(userService.getIdentity(), preferenceDetails, preference); String fmt = "%s %s %s"; addGlobalMessage("Condition updated for " + preferenceDetails.getPreferenceName(), String.format(fmt, condition.getname(), condition.getoperator(), condition.getvalue()), FacesMessage.SEVERITY_INFO); // log.debug("Condition updated for " + preferenceDetails.getPreferenceName()); } } else if (node.getData() instanceof IPreferenceOutcome) { IPreferenceOutcome outcome = (IPreferenceOutcome) node.getData(); PreferenceDetails preferenceDetails = outcomeToPDMap.get(outcome); IPreference preference = outcomeToPreferenceMap.get(outcome); if (preferenceDetails == null) { addGlobalMessage("Cannot edit", "preferenceDetails was null", FacesMessage.SEVERITY_ERROR); } else if (preference == null) { addGlobalMessage("Cannot edit", "preference was null", FacesMessage.SEVERITY_ERROR); } else { // userPreferenceManagement.storePreference(userService.getIdentity(), preferenceDetails, preference); String fmt = "%s = %s (q=%s, p=%s)"; addGlobalMessage("Outcome updated for " + preferenceDetails.getPreferenceName(), String.format(fmt, outcome.getparameterName(), outcome.getvalue(), outcome.getQualityofPreference(), outcome.getConfidenceLevel()), FacesMessage.SEVERITY_INFO); // log.debug("Outcome updated for " + preferenceDetails.getPreferenceName()); } } else { addGlobalMessage("Cannot edit", "The node you selected cannot be edited", FacesMessage.SEVERITY_WARN); } // clears all stored data and forces it to be reloaded from the UserPrefManagement service // clearData(); preferencesRootNode = null; // force redraw of the tree } public void deleteSelectedNode() { log.debug("deleteSelectedNode()"); treeChangesMade = true; TreeNode node = getSelectedTreeNode(); if (node == null) { addGlobalMessage("Cannot delete", "No node selected", FacesMessage.SEVERITY_WARN); } else if (node.getData() == null) { addGlobalMessage("Cannot delete", "No data in selected node", FacesMessage.SEVERITY_WARN); } else if (node.getData() instanceof PreferenceDetails) { PreferenceDetails preferenceDetails = (PreferenceDetails) node.getData(); userPreferenceManagement.deletePreference(userService.getIdentity(), preferenceDetails); pdToPreferenceTreeModelMap.remove(preferenceDetails); pdToPreferenceMap.remove(preferenceDetails); addGlobalMessage("Preference " + preferenceDetails.getPreferenceName() + " removed", "The preference, including all conditions and outcomes, has been removed", FacesMessage.SEVERITY_INFO); } else if (node.getData() instanceof IPreferenceCondition) { IPreferenceCondition condition = (IPreferenceCondition) node.getData(); PreferenceDetails preferenceDetails = conditionToPDMap.get(condition); IPreference preference = conditionToPreferenceMap.get(condition); log.debug("Deleting condition..."); IPreference parent = (IPreference) preference.getParent(); // remove the preference from its parent parent.remove(preference); // userPreferenceManagement.storePreference(userService.getIdentity(), preferenceDetails, preference); String fmt = "%s %s %s"; addGlobalMessage("Condition removed for " + preferenceDetails.getPreferenceName(), String.format(fmt, condition.getname(), condition.getoperator(), condition.getvalue()), FacesMessage.SEVERITY_INFO); // log.debug("Condition removed for " + preferenceDetails.getPreferenceName()); } else if (node.getData() instanceof IPreferenceOutcome) { IPreferenceOutcome outcome = (IPreferenceOutcome) node.getData(); PreferenceDetails preferenceDetails = outcomeToPDMap.get(outcome); IPreference preference = outcomeToPreferenceMap.get(outcome); log.debug("Deleting outcome..."); IPreference parent = (IPreference) preference.getParent(); // remove the preference from its parent parent.remove(preference); // userPreferenceManagement.storePreference(userService.getIdentity(), preferenceDetails, preference); String fmt = "%s = %s (q=%s, p=%s)"; addGlobalMessage("Outcome removed for " + preferenceDetails.getPreferenceName(), String.format(fmt, outcome.getparameterName(), outcome.getvalue(), outcome.getQualityofPreference(), outcome.getConfidenceLevel()), FacesMessage.SEVERITY_INFO); // log.debug("Outcome removed for " + preferenceDetails.getPreferenceName()); } else { addGlobalMessage("Cannot delete", "The node you selected cannot be deleted", FacesMessage.SEVERITY_WARN); } // clears all stored data and forces it to be reloaded from the UserPrefManagement service // clearData(); preferencesRootNode = null; // force redraw of the tree } public void addPreference() { log.debug("addPreference()"); treeChangesMade = true; String prefName = getNewPreferenceName(); // set from the GUI Service prefService = getNewPreferenceService(); // set from the GUI setNewPreferenceName(""); setNewPreferenceService(null); // validation if (prefName == null || "".equals(prefName)) { addGlobalMessage("Preference NOT added", "The preference name cannot be empty", FacesMessage.SEVERITY_WARN); return; } PreferenceDetails preferenceDetails = new PreferenceDetails( prefService != null ? prefService.getServiceType().value() : "", prefService != null ? prefService.getServiceIdentifier() : null, prefName ); IPreference preferenceNode = new PreferenceTreeNode(); preferenceNode.setUserObject(preferenceDetails); PreferenceTreeModel model = new PreferenceTreeModel(preferenceDetails, preferenceNode); PreferenceOutcome outcome = new PreferenceOutcome( prefService != null ? prefService.getServiceIdentifier() : null, prefService != null ? prefService.getServiceType().value() : "", prefName, "default" ); PreferenceTreeNode outcomeNode = new PreferenceTreeNode(outcome); // store log.debug("Storing locally..."); pdToPreferenceTreeModelMap.put(preferenceDetails, model); pdToPreferenceMap.put(preferenceDetails, preferenceNode); // log.debug("Storing to UPM..."); // userPreferenceManagement.storePreference(userService.getIdentity(), preferenceDetails, outcomeNode); // notify user addGlobalMessage("Preference added", "The preference " + prefName + " was added", FacesMessage.SEVERITY_INFO); // clear down preferencesRootNode = null; // force redraw of the tree } public void addConditionOnly() { log.debug("addConditionOnly()"); treeChangesMade = true; ContextPreferenceCondition newCondition = conditionToAdd; conditionToAdd = new ContextPreferenceCondition(null, OperatorConstants.EQUALS, "", ""); PreferenceDetails preferenceDetails; IPreference parentObject; IPreference selectedObject; if (selectedOutcome != null) { preferenceDetails = outcomeToPDMap.get(selectedOutcome); selectedObject = outcomeToPreferenceMap.get(selectedOutcome); parentObject = (IPreference) selectedObject.getParent(); log.debug("Adding condition before outcome"); } else if (selectedCondition != null) { preferenceDetails = conditionToPDMap.get(selectedCondition); selectedObject = conditionToPreferenceMap.get(selectedCondition); parentObject = (IPreference) selectedObject.getParent(); log.debug("Adding condition before condition"); } else { addGlobalMessage("Add outcome failed", "PreferenceDetails was null - something has gone wrong", FacesMessage.SEVERITY_ERROR); log.error("PreferenceDetails was null, cannot save new condition"); return; } if (parentObject == null) { addGlobalMessage("Add condition for " + preferenceDetails.getPreferenceName(), "parentObject was null - something has gone wrong", FacesMessage.SEVERITY_ERROR); log.error("parentObject was null, cannot save new condition"); return; } log.debug("Creating objects..."); IPreference newConditionPreference = createCondition(preferenceDetails, newCondition); if (newConditionPreference == null) return; log.debug("Storing..."); if ("before".equals(addConditionMode)) { // This condition goes BEFORE the selected object, and AFTER the selected object's parent log.debug("Adding BEFORE"); // parentObject.remove(selectedObject); selectedObject.removeFromParent(); parentObject.add(newConditionPreference); newConditionPreference.add(selectedObject); } else if ("after".equals(addConditionMode)) { // this condition goes AFTER the selected object log.debug("Adding AFTER"); selectedObject.add(newConditionPreference); } String fmt = "%s %s %s"; addGlobalMessage("Condition added for " + preferenceDetails.getPreferenceName(), String.format(fmt, newCondition.getname(), newCondition.getoperator(), newCondition.getvalue()), FacesMessage.SEVERITY_INFO); preferencesRootNode = null; // force redraw of the tree } public void addConditionAndOutcome() { log.debug("addConditionAndOutcome()"); treeChangesMade = true; PreferenceDetails preferenceDetails; IPreference selectedPreferenceObject; ContextPreferenceCondition newCondition = conditionToAdd; PreferenceOutcome newOutcome = outcomeToAdd; conditionToAdd = new ContextPreferenceCondition(null, OperatorConstants.EQUALS, "", ""); outcomeToAdd = new PreferenceOutcome(null, "", "", ""); if (selectedCondition != null) { preferenceDetails = conditionToPDMap.get(selectedCondition); selectedPreferenceObject = conditionToPreferenceMap.get(selectedCondition); log.debug("Adding condition and outcome after condition"); } else if (selectedPreference != null) { preferenceDetails = (selectedPreference); selectedPreferenceObject = pdToPreferenceMap.get(selectedPreference); log.debug("Adding condition and outcome after preference"); } else { addGlobalMessage("Add condition and outcome failed", "PreferenceDetails was null - something has gone wrong", FacesMessage.SEVERITY_ERROR); log.error("PreferenceDetails was null, cannot save new condition"); return; } if (selectedPreferenceObject == null) { addGlobalMessage("Add outcome for " + preferenceDetails.getPreferenceName(), "selectedPreferenceObject was null - something has gone wrong", FacesMessage.SEVERITY_ERROR); log.error("selectedPreferenceObject was null, cannot save new outcome"); return; } log.debug("Creating objects..."); IPreference newConditionPreference = createCondition(preferenceDetails, newCondition); if (newConditionPreference == null) return; IPreference newOutcomePreference = createOutcome(preferenceDetails, newOutcome); if (newOutcomePreference == null) return; log.debug("Storing locally..."); // the outcome goes AFTER the new condition object newConditionPreference.add(newOutcomePreference); // this condition goes AFTER the selected object selectedPreferenceObject.add(newConditionPreference); String fmt = "%s %s %s => %s"; addGlobalMessage("Outcome and condition added for " + preferenceDetails.getPreferenceName(), String.format(fmt, newCondition.getname(), newCondition.getoperator(), newCondition.getvalue(), newOutcome.getvalue()), FacesMessage.SEVERITY_INFO); preferencesRootNode = null; // force redraw of the tree } public void addOutcomeOnly() { log.debug("addOutcomeOnly()"); treeChangesMade = true; PreferenceDetails preferenceDetails; IPreference parentPreferenceObject; PreferenceOutcome newOutcome = outcomeToAdd; outcomeToAdd = new PreferenceOutcome(null, "", "", ""); if (selectedCondition != null) { preferenceDetails = conditionToPDMap.get(selectedCondition); parentPreferenceObject = conditionToPreferenceMap.get(selectedCondition); log.debug("Adding outcome to condition"); } else if (selectedPreference != null) { preferenceDetails = selectedPreference; parentPreferenceObject = pdToPreferenceMap.get(selectedPreference); log.debug("Adding outcome to preference"); } else { addGlobalMessage("Add outcome failed", "PreferenceDetails was null - something has gone wrong", FacesMessage.SEVERITY_ERROR); log.error("PreferenceDetails was null, cannot save new outcome"); return; } if (preferenceDetails == null) { addGlobalMessage("Add outcome failed", "PreferenceDetails was null - something has gone wrong", FacesMessage.SEVERITY_ERROR); log.error("PreferenceDetails was null, cannot save new outcome"); return; } IPreference newOutcomePreference = createOutcome(preferenceDetails, newOutcome); if (newOutcomePreference == null) { addGlobalMessage("Add outcome failed", "newOutcomePreference was null - something has gone wrong", FacesMessage.SEVERITY_ERROR); log.error("newOutcomePreference was null, cannot save new outcome"); return; } newOutcomePreference.setUserObject(newOutcome); parentPreferenceObject.add(newOutcomePreference); String fmt = "%s = %s (q=%s, p=%s)"; String msg = String.format(fmt, newOutcome.getparameterName(), newOutcome.getvalue(), newOutcome.getQualityofPreference(), newOutcome.getConfidenceLevel()); addGlobalMessage("Outcome added for " + preferenceDetails.getPreferenceName(), msg, FacesMessage.SEVERITY_INFO); preferencesRootNode = null; // force redraw of the tree } private IPreference createCondition(PreferenceDetails preferenceDetails, ContextPreferenceCondition newCondition) { log.debug("createCondition()"); treeChangesMade = true; // validate if (newCondition.getname() == null || newCondition.getname().equals("") || newCondition.getoperator() == null || newCondition.getvalue() == null || newCondition.getvalue().equals("")) { addGlobalMessage("Add condition", "Value(s) null - something has gone wrong", FacesMessage.SEVERITY_ERROR); log.error("Value(s) null - something has gone wrong"); return null; } // Retrieve a context attribute with a string value String ctxAttributeType = newCondition.getname(); try { Future<List<CtxIdentifier>> idsFuture = this.internalCtxBroker.lookup(CtxModelType.ATTRIBUTE, ctxAttributeType); List<CtxIdentifier> ids = idsFuture.get(); if (ids.size() == 0) { addGlobalMessage("Crate condition failed", "no identifiers found for '" + ctxAttributeType + "'", FacesMessage.SEVERITY_ERROR); log.error("no identifiers found for '" + ctxAttributeType + "'"); return null; } else { log.debug("Identifiers for " + ctxAttributeType + ":..."); for (CtxIdentifier id : ids) { log.debug(id.toString()); } newCondition.setCtxIdentifier((CtxAttributeIdentifier) ids.get(0)); } } catch (Exception e) { log.error("ExecutionException", e); addGlobalMessage("Error saving condition", e.getMessage(), FacesMessage.SEVERITY_ERROR); return null; } log.debug("Creating objects..."); IPreference newConditionPreference = new PreferenceTreeNode(newCondition); log.debug("Storing locally..."); conditionToPDMap.put(newCondition, preferenceDetails); conditionToPreferenceMap.put(newCondition, newConditionPreference); return newConditionPreference; } private IPreference createOutcome(PreferenceDetails preferenceDetails, PreferenceOutcome newOutcome) { log.debug("createOutcome()"); treeChangesMade = true; IPreference parentPreferenceObject; // validate if (newOutcome.getvalue() == null || newOutcome.getvalue().equals("")) { addGlobalMessage("Add outcome for " + preferenceDetails.getPreferenceName(), "Operator was null - something has gone wrong", FacesMessage.SEVERITY_ERROR); log.error("Operator was null, cannot save new outcome"); return null; } log.debug("Creating objects..."); IPreference newOutcomePreference = new PreferenceTreeNode(newOutcome); log.debug("Storing locally..."); outcomeToPDMap.put(newOutcome, preferenceDetails); outcomeToPreferenceMap.put(newOutcome, newOutcomePreference); return newOutcomePreference; } public void saveTreeChanges() { log.debug("saveTreeChanges()"); Set<PreferenceDetails> preferenceDetailsSet = pdToPreferenceMap.keySet(); for (PreferenceDetails pd : preferenceDetailsSet) { log.debug("Storing preference: " + pd.getPreferenceName()); IPreferenceTreeModel model = pdToPreferenceTreeModelMap.get(pd); log.debug(model.toString()); userPreferenceManagement.storePreference(userService.getIdentity(), pd, pdToPreferenceMap.get(pd)); } loadPreferenceTreeData(); log.debug("end saveTreeChanges()"); } public void revertChanges() { log.debug("saveTreeChanges()"); loadPreferenceTreeData(); } public void updateTreeSelection() { this.selectedCondition = null; this.selectedOutcome = null; this.selectedPreference = null; if (getSelectedTreeNode() == null) return; if (PREFERENCE_NODE.equals(getSelectedTreeNode().getType())) { this.selectedPreference = (PreferenceDetails) getSelectedTreeNode().getData(); } else if (CONDITION_NODE.equals(getSelectedTreeNode().getType())) { this.selectedCondition = (IPreferenceCondition) getSelectedTreeNode().getData(); } else if (OUTCOME_NODE.equals(getSelectedTreeNode().getType())) { this.selectedOutcome = (IPreferenceOutcome) getSelectedTreeNode().getData(); } } public void selectAddConditionBefore() { this.addConditionMode = "before"; } public void selectAddConditionAfter() { this.addConditionMode = "after"; } /* Private helper methods */ private void clearData() { log.debug("clearData()"); preferencesRootNode = null; selectedTreeNode = null; selectedPreference = null; selectedCondition = null; selectedOutcome = null; conditionToAdd = new ContextPreferenceCondition(null, OperatorConstants.EQUALS, "", ""); outcomeToAdd = new PreferenceOutcome(null, "", "", ""); newPreferenceName = ""; conditionToPDMap.clear(); outcomeToPDMap.clear(); conditionToPreferenceMap.clear(); outcomeToPreferenceMap.clear(); pdToPreferenceMap.clear(); pdToPreferenceTreeModelMap.clear(); treeChangesMade = false; } private void loadPreferenceTreeData() { log.debug("loadPreferenceTreeData()"); clearData(); if (userPreferenceManagement == null) { if (userPreferenceConditionMonitor == null) { log.error("userPreferenceConditionMonitor is null - cannot populate preference root node"); return; } this.userPreferenceManagement = userPreferenceConditionMonitor.getPreferenceManager(); } if (userPreferenceManagement == null) { log.error("userPreferenceManagementService is null - cannot populate preference root node"); return; } List<PreferenceDetails> detailsList = userPreferenceManagement.getPreferenceDetailsForAllPreferences(); if (detailsList == null) { log.warn("userPreferenceManagement returned null preference details list"); return; } // sort the preferences by name Collections.sort(detailsList, new PreferenceDetailsComparator()); log.debug("Loaded " + detailsList.size() + " preferences"); for (PreferenceDetails preferenceDetails : detailsList) { try { IPreferenceTreeModel preferenceTreeModel = userPreferenceManagement.getModel(userService.getIdentity(), preferenceDetails); log.debug(" - Loaded preference " + preferenceDetails.getPreferenceName()); pdToPreferenceTreeModelMap.put(preferenceDetails, preferenceTreeModel); } catch (Exception ex) { log.error("Error loading preference tree model for " + preferenceDetails.getPreferenceName(), ex); } } } private void populatePreferencesRootNode() { log.debug("populatePreferencesRootNode()"); preferencesRootNode = new DefaultTreeNode("Preferences", null); preferencesRootNode.setExpanded(true); Set<PreferenceDetails> allPreferenceDetails = pdToPreferenceTreeModelMap.keySet(); for (PreferenceDetails preferenceDetails : allPreferenceDetails) { IPreferenceTreeModel preferenceTreeModel = pdToPreferenceTreeModelMap.get(preferenceDetails); populatePreferenceNode(preferenceDetails, preferenceTreeModel); } } private void populatePreferenceNode(PreferenceDetails preferenceDetails, IPreferenceTreeModel preferenceTreeModel) { if (preferenceTreeModel == null) { log.error("preferenceTreeModel was null in populatePreferenceNode for " + preferenceDetails.getPreferenceName()); return; } TreeNode preferenceNode = new DefaultTreeNode(PREFERENCE_NODE, preferenceDetails, preferencesRootNode); preferenceNode.setExpanded(true); log.debug("Creating preference node: " + preferenceDetails.getPreferenceName()); IPreference preference = preferenceTreeModel.getRootPreference(); pdToPreferenceMap.put(preferenceDetails, preference); processSubnodes(preference, preferenceNode, preferenceDetails); } private void populateConditionNode(IPreference preference, TreeNode preferenceNode, PreferenceDetails preferenceDetails) { IPreferenceCondition condition = preference.getCondition(); if (condition == null) { log.error("branch node " + preference.toString() + " contains null condition"); return; } TreeNode conditionNode = new DefaultTreeNode(CONDITION_NODE, condition, preferenceNode); conditionNode.setExpanded(true); log.debug("Creating condition node: " + condition.getname()); conditionToPDMap.put(condition, preferenceDetails); conditionToPreferenceMap.put(condition, preference); processSubnodes(preference, conditionNode, preferenceDetails); } private void populateOutcomeNode(IPreference preference, TreeNode conditionNode, PreferenceDetails preferenceDetails) { IPreferenceOutcome outcome = preference.getOutcome(); if (outcome == null) { log.error("leaf node " + preference.toString() + " contains null outcome"); return; } TreeNode outcomeNode = new DefaultTreeNode(OUTCOME_NODE, outcome, conditionNode); outcomeNode.setExpanded(true); log.debug("Creating outcome node: " + outcome.getparameterName()); outcomeToPDMap.put(outcome, preferenceDetails); outcomeToPreferenceMap.put(outcome, preference); } private void processSubnodes(IPreference preference, TreeNode node, PreferenceDetails preferenceDetails) { Enumeration<IPreference> e = preference.postorderEnumeration(); List<IPreference> conditions = new ArrayList<IPreference>(); List<IPreference> outcomes = new ArrayList<IPreference>(); while (e.hasMoreElements()) { IPreference ele = e.nextElement(); if (ele == preference) continue; if (preference.getLevel() != ele.getLevel() - 1) continue; if (ele.isBranch()) { // this is a CONDITION conditions.add(ele); // populateConditionNode(ele, node, preferenceDetails); } else if (ele.isLeaf()) { // this is an OUTCOME outcomes.add(ele); // populateOutcomeNode(ele, node, preferenceDetails); } } // process conditions if (conditions.size() > 0) { Collections.sort(conditions, new Comparator<IPreference>() { @Override public int compare(IPreference o1, IPreference o2) { int c; IPreferenceCondition c1 = o1.getCondition(); IPreferenceCondition c2 = o2.getCondition(); // compare by name c = c1.getname().compareTo(c2.getname()); if (c != 0) return c; // if same, compare by operator c = c1.getoperator().getDescription().compareTo(c2.getoperator().getDescription()); if (c != 0) return c; // if same, compare by value c = c1.getvalue().compareTo(c2.getvalue()); return c; } }); for (IPreference ele : conditions) { populateConditionNode(ele, node, preferenceDetails); } } // process outcomes only if no conditions found else if (outcomes.size() > 0) { Collections.sort(outcomes, new Comparator<IPreference>() { @Override public int compare(IPreference o1, IPreference o2) { int c; IPreferenceOutcome c1 = o1.getOutcome(); IPreferenceOutcome c2 = o2.getOutcome(); // compare by value c = c1.getvalue().compareTo(c2.getvalue()); return c; } }); for (IPreference ele : outcomes) { populateOutcomeNode(ele, node, preferenceDetails); } } } private boolean hasConditionAsDirectChild(IPreference parent) { Enumeration<IPreference> e = parent.breadthFirstEnumeration(); while (e.hasMoreElements()) { IPreference ele = e.nextElement(); if (ele == parent) continue; if (ele.isBranch()) { return true; } } return false; } private boolean hasOutcomeAsDirectChild(IPreference parent) { Enumeration<IPreference> e = parent.breadthFirstEnumeration(); boolean foundOutcome = false; while (e.hasMoreElements()) { IPreference ele = e.nextElement(); if (ele == parent) continue; if (ele.isBranch()) { return false; } if (ele.isLeaf()) { foundOutcome = true; } } return foundOutcome; } }