/**
* 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.datamanagement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.societies.api.identity.util.DataIdentifierUtils;
import org.societies.api.identity.util.RequestorUtils;
import org.societies.api.privacytrust.privacy.model.PrivacyException;
import org.societies.api.privacytrust.privacy.util.privacypolicy.ActionUtils;
import org.societies.api.schema.identity.DataIdentifier;
import org.societies.api.schema.identity.RequestorBean;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.Action;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.Decision;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.ResponseItem;
import org.societies.privacytrust.privacyprotection.api.IPrivacyDataManagerInternal;
import org.societies.privacytrust.privacyprotection.datamanagement.util.PrivacyDataManagerInternalUtility;
import org.societies.privacytrust.privacyprotection.model.PrivacyPermission;
/**
* @author Olivier Maridat (Trialog)
*/
public class PrivacyDataManagerInternal extends PrivacyDataManagerInternalUtility implements IPrivacyDataManagerInternal {
private static final Logger LOG = LoggerFactory.getLogger(PrivacyDataManagerInternal.class);
private SessionFactory sessionFactory;
@Override
public List<ResponseItem> getPermissions(RequestorBean requestor, List<DataIdentifier> dataIds, List<Action> actions) throws PrivacyException {
// Verifications
if (null == requestor) {
throw new PrivacyException("[Parameters] RequestorId is missing");
}
if (null == dataIds || dataIds.size() <= 0) {
LOG.debug("[Parameters] Data id list is missing, return null");
return null;
}
List<ResponseItem> permissions = null;
Session session = null;
try {
session = sessionFactory.openSession();
// Search all matching permissions
List<PrivacyPermission> privacyPermissions = findPrivacyPermissions(session, requestor, dataIds, actions, false);
LOG.info("Get: "+(null == privacyPermissions ? "0" : privacyPermissions.size())+" permissions retrieved");
if (null == privacyPermissions) {
return null;
}
int i = 1;
for(PrivacyPermission perm : privacyPermissions) {
LOG.info((i++)+": "+perm);
}
// Keep the most relevants for these actions
permissions = new ArrayList<ResponseItem>();
if (actions != null && actions.size() > 0) {
for(DataIdentifier dataId : dataIds) {
PrivacyPermission permission = selectRelevantPermission(dataId, privacyPermissions);
if (null != permission) {
LOG.info("Get: on of the retrieved and selected permission. "+permission);
permissions.add(permission.createResponseItem());
}
}
}
else {
LOG.info("Get: don't check actions and keep them all");
permissions.addAll(PrivacyPermission.createResponseItems(privacyPermissions));
}
// Robustness
if (permissions.size() <= 0) {
permissions = null;
}
} catch (Exception e) {
throw new PrivacyException("Error during the persistance of the privacy permission", e);
} finally {
if (null != session) {
session.close();
}
}
return permissions;
}
@Override
public boolean updatePermission(RequestorBean requestor, DataIdentifier dataId, List<Action> actions, Decision decision) throws PrivacyException {
// Verifications
if (null == requestor) {
throw new PrivacyException("[Parameters] RequestorId is missing");
}
if (null == dataId) {
throw new PrivacyException("[Parameters] DataId is missing");
}
if (null == actions || actions.size() <= 0) {
throw new PrivacyException("[Parameters] Actions are missing");
}
if (null == decision) {
throw new PrivacyException("[Parameters] Decision is missing");
}
Session session = null;
Transaction t = null;
boolean result = false;
try {
session = sessionFactory.openSession();
t = session.beginTransaction();
// -- Retrieve the privacy permission (that matches all actions)
PrivacyPermission privacyPermission = findPrivacyPermissions(session, requestor, dataId, actions);
// -- Update this privacy permission
// - Privacy Permission doesn't exist: create a new one
if (null == privacyPermission) {
LOG.info("Update: no permission retrieved, create a new one");
privacyPermission = new PrivacyPermission(requestor, dataId, actions, decision);
}
// - Privacy permission already exists: update it
else {
LOG.info("Update: permission retrieved, update it. "+privacyPermission);
privacyPermission.setRequestor(requestor);
privacyPermission.setDataId(dataId);
privacyPermission.setActionsToData(actions);
privacyPermission.setPermission(decision);
}
// - Update
session.saveOrUpdate(privacyPermission);
LOG.info("Update: updated permission is "+privacyPermission);
t.commit();
result = true;
} catch (Exception e) {
if (null != t) {
t.rollback();
}
throw new PrivacyException("Error during the persistance of the privacy permission", e);
} finally {
if (null != session) {
session.close();
}
}
return result;
}
@Override
public boolean deletePermissions(RequestorBean requestor, DataIdentifier dataId, List<Action> actions) throws PrivacyException {
// Verifications
if (null == requestor) {
throw new PrivacyException("[Parameters] RequestorId is missing");
}
if (null == dataId) {
throw new PrivacyException("[Parameters] DataId is missing");
}
Session session = null;
Transaction t = null;
boolean result = false;
try {
session = sessionFactory.openSession();
t = session.beginTransaction();
// -- Retrieve the privacy permissions
List<DataIdentifier> dataIds = new ArrayList<DataIdentifier>();
dataIds.add(dataId);
List<PrivacyPermission> privacyPermissions = findPrivacyPermissions(session, requestor, dataIds, actions, false);
// -- Delete the privacy permission
// - Privacy permission retrieved: delete it
if (null != privacyPermissions && privacyPermissions.size() > 0) {
for(Iterator<PrivacyPermission> it = privacyPermissions.iterator(); it.hasNext();) {
session.delete(it.next());
}
t.commit();
}
result = true;
} catch (Exception e) {
if (null != t) {
t.rollback();
}
result = false;
throw new PrivacyException("Error during the removal of the privacy permission", e);
} finally {
if (session != null) {
session.close();
}
}
return result;
}
/* --- Private methods --- */
/**
* Retrieve a list of privacy permission
*
* @param session
* @param requestor
* @param dataId
* @param actions
* @param mustMatchAllActions True to retrieve only if it matches all actions
* @return If all actions are mandatory: only one result
* @return If some actions are optional: several results, ordered by relevance
* @throws PrivacyException
*/
private List<PrivacyPermission> findPrivacyPermissions(Session session, RequestorBean requestor, List<DataIdentifier> dataIds, List<Action> actions, boolean mustMatchAllActions) throws PrivacyException {
List<PrivacyPermission> privacyPermissions = null;
try {
// Retrieve the privacy permissions
Criteria criteria = createPrivacyPermissionsCriteria(session, requestor, dataIds, actions, mustMatchAllActions);
privacyPermissions = (List<PrivacyPermission>) criteria.list();
if (null == privacyPermissions || privacyPermissions.size() <= 0) {
privacyPermissions = null;
}
}
catch (Exception e) {
throw new PrivacyException("Error during the retrieving of the privacy permissions", e);
}
return privacyPermissions;
}
/**
* Duplication of {@link #findPrivacyPermissions(RequestorBean, List, List, boolean)} for one data id
* All actions must match
*/
private PrivacyPermission findPrivacyPermissions(Session session, RequestorBean requestor, DataIdentifier dataId, List<Action> actions) throws PrivacyException {
List<DataIdentifier> dataIds = new ArrayList<DataIdentifier>();
dataIds.add(dataId);
List<PrivacyPermission> privacyPermissions = findPrivacyPermissions(session, requestor, dataIds, actions, true);
if (null == privacyPermissions || privacyPermissions.size() <= 0) {
return null;
}
return privacyPermissions.get(0);
}
private Criteria createPrivacyPermissionsCriteria(Session session, RequestorBean requestor, List<DataIdentifier> dataIds, List<Action> actions, boolean mustMatchAllActions) {
Criteria criteria = session.createCriteria(PrivacyPermission.class);
// -- Criteria about data id
criteria = criteria.add(Restrictions.in("dataId", DataIdentifierUtils.toUriString(dataIds).toArray()));
// -- Criteria about requestor
criteria.add(Restrictions.like("requestorId", RequestorUtils.toUriString(requestor)));
// -- Criteria about action list
if (null != actions && actions.size() > 0) {
// - Create strings
Criterion criterionAllActions = null;
Criterion criterionMandatoryActions = null;
StringBuilder strAllActions = new StringBuilder();
StringBuilder strMandatoryActions = new StringBuilder();
Collections.sort(actions, new ActionUtils.ActionComparator());
for(Action action : actions) {
strAllActions.append(action.getActionConstant().value()+"/");
if (!action.isOptional()) {
strMandatoryActions.append(action.getActionConstant().value()+"/");
}
}
// - Create the query
criterionAllActions = Restrictions.like("actions", strAllActions.toString());
// If mode: match only mandatory actions OR no optional actions requested
if (mustMatchAllActions || strAllActions.toString().equals(strMandatoryActions.toString())) {
criteria.add(criterionAllActions);
}
// Otherwise: match all actions OR only mandatory actions
else {
criterionMandatoryActions = Restrictions.like("actions", strMandatoryActions.toString());
criteria.add(Restrictions.or(criterionAllActions, criterionMandatoryActions));
}
}
// - Order by data id, then the number of mandatory actions, and then by decision
criteria.addOrder(Order.desc("dataId"));
criteria.addOrder(Order.desc("nbOfActions"));
criteria.addOrder(Order.desc("permission"));
return criteria;
}
/**
* Select the most relevant permission for this data id
* @pre The list of permissions is order by the number of actions available and their decisions. For a faster algorithm.
* @param dataId
* @param privacyPermissions
* @return The most relevant permission
*/
private PrivacyPermission selectRelevantPermission(DataIdentifier dataId, List<PrivacyPermission> privacyPermissions) {
if (null == privacyPermissions || privacyPermissions.size() <= 0) {
return null;
}
PrivacyPermission mostRelevantPrivacyPermission = null;
PrivacyPermission aPrivacyPermission = null;
// Find the most relevant PERMIT (even if we need to avoid some optional actions)
boolean found = false;
for(PrivacyPermission privacyPermission : privacyPermissions) {
// Interesting permission
if (DataIdentifierUtils.toUriString(dataId).equals(privacyPermission.getDataId())) {
// Store one matching privacy permission
aPrivacyPermission = privacyPermission;
// If it matches to PERMIT, this is the most relevant
if(privacyPermission.getPermission().equals(Decision.PERMIT)) {
mostRelevantPrivacyPermission = privacyPermission;
privacyPermissions.remove(privacyPermission);
found = true;
break;
}
}
}
// If no PERMIT has been found: take a matching permission (if any)
if (!found) {
mostRelevantPrivacyPermission = aPrivacyPermission;
}
// - Return the most relevant privacy permission
if (null == mostRelevantPrivacyPermission) {
return null;
}
return mostRelevantPrivacyPermission;
}
/* --- Dependency Injection --- */
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}