/**
* 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.android.api.identity.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.societies.api.schema.identity.DataTypeDescription;
/**
* Utility method that helps manipulating data types and provides a hierarchy to SOCIETIES data
*
* @author Olivier Maridat (Trialog)
*/
public class DataTypeUtils {
private static Map<String, Set<String>> dataTypeHierarchy;
private static Map<String, String> dataTypeAntiHierarchy;
private static Map<String, DataTypeDescription> dataTypeDescription;
private static boolean loaded = false;
public DataTypeUtils() {
if (!loaded) {
dataTypeHierarchy = new HashMap<String, Set<String>>();
dataTypeAntiHierarchy = new HashMap<String, String>();
dataTypeDescription = new HashMap<String, DataTypeDescription>();
// -- Load hierarchy
loadDataHierarchy();
// -- Load type description
loadDataTypeDescription();
loaded = true;
}
}
/**
* To know if a data type is a leaf (external node) in the hierarchy or not
* E.g. true for NAME_FIRST (leaf) and ACTION (root without children), but false for NAME (root with children)
* @param dataType Data type name
* @return True if the data type is a leaf, false otherwise
*/
public boolean isLeaf(String dataType) {
// In the anti-hierarchy (i.e. children of someone)
// Or nor in the hierarchy, neither in the anti-hierarchy (i.e. not referenced type: root and leaf by default)
return (dataTypeAntiHierarchy.containsKey(dataType)
|| (!dataTypeHierarchy.containsKey(dataType) && !dataTypeAntiHierarchy.containsKey(dataType)));
}
/**
* To know if a data type is a root (internal node at the top level) in the hierarchy or not
* E.g. true for NAME (root with children) and ACTION (root without children), but false for NAME_FIRST (leaf)
* @param dataType Data type name
* @return True if the data type is a root, false otherwise
*/
public boolean isRoot(String dataType) {
// In the hierarchy (i.e. has got children)
// Or nor in the hierarchy, neither in the anti-hierarchy (i.e. not referenced type: root and leaf by default)
return (dataTypeHierarchy.containsKey(dataType)
|| (!dataTypeHierarchy.containsKey(dataType) && !dataTypeAntiHierarchy.containsKey(dataType)));
}
/**
* To retrieve the relevant lookable data types in the data hierarchy: itself or its children if any
* E.g. children of NAME (root with children) are: NAME_FIRST, NAME_LAST,
* E.g. children of ACTION (root) are: ACTION,
* E.g. children of NAME_FIRST (leaf) are: NAME_FIRST
* @param dataType Data type name
* @return The list of children data type if dataType is a root type with children, or a list containing only dataType if it is a leaf or a root without children
*/
public Set<String> getLookableDataTypes(String dataType) {
// Retrieve children
Set<String> children = getChildren(dataType);
// If no result: means no children, return at least the used dataType
if (null == children) {
children = new HashSet<String>();
children.add(dataType);
}
return children;
}
/**
* To retrieve the children data types of a data type in the data hierarchy
* E.g. children of NAME (root with children) are: NAME_FIRST, NAME_LAST,
* E.g. children of ACTION (root) are: null,
* E.g. children of NAME_FIRST (leaf) are: null
* @param dataType Data type name
* @return The list of children data type if dataType is a root type with children, or null if dataType is a leaf or a root without children
*/
public Set<String> getChildren(String dataType) {
// Leaf: no children
if (isLeaf(dataType)) {
return null;
}
// Otherwise: return the children
Set<String> children = dataTypeHierarchy.get(dataType);
// Robustness: return null if it is empty for some reason (but if data hiearchy is configured correctly, it should not)
return children.isEmpty() ? null : children;
}
/**
* To retrieve the parent data type of a data type in the data hierarchy
* E.g. parent of NAME (root with children) is: null,
* E.g. parent of ACTION (root) is: null,
* E.g. parent of NAME_FIRST (leaf) is: NAME
* @param dataType Data type name
* @return The parent data type if dataType is a leaf, or null if dataType is a root
*/
public String getParent(String dataType) {
// Not root: there is a parent
if (!isRoot(dataType)) {
return dataTypeAntiHierarchy.get(dataType);
}
// No parent
return null;
}
/**
* To retrieve the friendly description of a data type
* If no existing friendly description is retrieved, the data type is sanitized and returned
* @param dataType Data type name
* @return This data type friendly name and description
*/
public DataTypeDescription getFriendlyDescription(String dataType) {
DataTypeDescription description = null;
// Retrieve the stored description
if (dataTypeDescription.containsKey(dataType)) {
description = dataTypeDescription.get(dataType);
}
// No description available, or retrieved description null: compute one as good as possible
if (null == description) {
description = DataTypeDescriptionUtils.create(dataType);
}
return description;
}
/**
* To retrieve the friendly description of a data types
* @param dataTypeList List of data type logical name
* @return List of data type friendly names and descriptions
*/
public List<DataTypeDescription> getFriendlyDescription(List<String> dataTypeList) {
List<DataTypeDescription> friendlyNameList = new ArrayList<DataTypeDescription>();
for(String dataType : dataTypeList) {
friendlyNameList.add(getFriendlyDescription(dataType));
}
return friendlyNameList;
}
// -- Private methods
/**
* Load the whole Societies data hierarchy
* @return True if success
*/
private boolean loadDataHierarchy() {
// Set<String> postAddressHomeChildren = new HashSet<String>();
// postAddressHomeChildren.add(CtxAttributeTypes.ADDRESS_HOME_STREET_NUMBER);
// postAddressHomeChildren.add(CtxAttributeTypes.ADDRESS_HOME_STREET_NAME);
// postAddressHomeChildren.add(CtxAttributeTypes.ADDRESS_HOME_CITY);
// postAddressHomeChildren.add(CtxAttributeTypes.ADDRESS_HOME_COUNTRY);
// dataTypeHierarchy.put("ADDRESS_HOME", postAddressHomeChildren);
// dataTypeAntiHierarchy.put(CtxAttributeTypes.ADDRESS_HOME_STREET_NUMBER, "ADDRESS_HOME");
// dataTypeAntiHierarchy.put(CtxAttributeTypes.ADDRESS_HOME_STREET_NAME, "ADDRESS_HOME");
// dataTypeAntiHierarchy.put(CtxAttributeTypes.ADDRESS_HOME_CITY, "ADDRESS_HOME");
// dataTypeAntiHierarchy.put(CtxAttributeTypes.ADDRESS_HOME_COUNTRY, "ADDRESS_HOME");
//
// Set<String> postAddressWorkChildren = new HashSet<String>();
// postAddressWorkChildren.add(CtxAttributeTypes.ADDRESS_WORK_STREET_NUMBER);
// postAddressWorkChildren.add(CtxAttributeTypes.ADDRESS_WORK_STREET_NAME);
// postAddressWorkChildren.add(CtxAttributeTypes.ADDRESS_WORK_CITY);
// postAddressWorkChildren.add(CtxAttributeTypes.ADDRESS_WORK_COUNTRY);
// dataTypeHierarchy.put("ADDRESS_WORK", postAddressWorkChildren);
// dataTypeAntiHierarchy.put(CtxAttributeTypes.ADDRESS_WORK_STREET_NUMBER, "ADDRESS_WORK");
// dataTypeAntiHierarchy.put(CtxAttributeTypes.ADDRESS_WORK_STREET_NAME, "ADDRESS_WORK");
// dataTypeAntiHierarchy.put(CtxAttributeTypes.ADDRESS_WORK_CITY, "ADDRESS_WORK");
// dataTypeAntiHierarchy.put(CtxAttributeTypes.ADDRESS_WORK_COUNTRY, "ADDRESS_WORK");
//
// Set<String> nameChildren = new HashSet<String>();
// nameChildren.add(CtxAttributeTypes.NAME_FIRST);
// nameChildren.add(CtxAttributeTypes.NAME_LAST);
// dataTypeHierarchy.put(CtxAttributeTypes.NAME, nameChildren);
// dataTypeAntiHierarchy.put(CtxAttributeTypes.NAME_FIRST, CtxAttributeTypes.NAME);
// dataTypeAntiHierarchy.put(CtxAttributeTypes.NAME_LAST, CtxAttributeTypes.NAME);
return true;
}
/**
* Load friendly description for whole Societies data
* @return True if success
*/
private boolean loadDataTypeDescription() {
// addDataTypeDescription(CtxAttributeTypes.ABOUT, "Information about this entity");
// addDataTypeDescription(CtxAttributeTypes.ACTION, "Action done by this entity");
// addDataTypeDescription(CtxAttributeTypes.AGE, "Age of this entity");
// addDataTypeDescription(CtxAttributeTypes.BOOKS, "Favorite books", "Favorite books of this entity");
return true;
}
private void addDataTypeDescription(String dataTypeIdentifier, String dataTypeFriendlyName, String dataTypeFriendlyDescription) {
dataTypeDescription.put(dataTypeIdentifier, DataTypeDescriptionUtils.create(dataTypeIdentifier, dataTypeFriendlyName, dataTypeFriendlyDescription));
}
private void addDataTypeDescription(String dataTypeIdentifier, String dataTypeFriendlyDescription) {
dataTypeDescription.put(dataTypeIdentifier, DataTypeDescriptionUtils.create(dataTypeIdentifier, null, dataTypeFriendlyDescription));
}
}