/**
* 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.integration.performance.test.upper_tester.trust;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.societies.api.comm.xmpp.interfaces.ICommManager;
import org.societies.api.internal.privacytrust.trust.ITrustBroker;
import org.societies.api.internal.privacytrust.trust.evidence.ITrustEvidenceCollector;
import org.societies.api.internal.privacytrust.trust.model.ExtTrustRelationship;
import org.societies.api.privacytrust.trust.TrustException;
import org.societies.api.privacytrust.trust.TrustQuery;
import org.societies.api.privacytrust.trust.event.ITrustUpdateEventListener;
import org.societies.api.privacytrust.trust.event.TrustUpdateEvent;
import org.societies.api.privacytrust.trust.evidence.TrustEvidenceType;
import org.societies.api.privacytrust.trust.model.TrustEvidence;
import org.societies.api.privacytrust.trust.model.TrustRelationship;
import org.societies.api.privacytrust.trust.model.TrustValueType;
import org.societies.api.privacytrust.trust.model.TrustedEntityId;
import org.societies.api.privacytrust.trust.model.TrustedEntityType;
import org.societies.integration.performance.test.lower_tester.PerformanceLowerTester;
import org.societies.integration.performance.test.lower_tester.PerformanceTestMgmtInfo;
import org.societies.integration.performance.test.lower_tester.PerformanceTestResult;
import org.societies.integration.performance.test.upper_tester.trust.direct.ITestDirectTrustPerformance;
import org.societies.integration.performance.test.upper_tester.trust.indirect.ITestIndirectTrustPerformance;
/**
* Implementation of the {@link ITestDirectTrustPerformance} interface.
*
* @author <a href="mailto:nicolas.liampotis@cn.ntua.gr">Nicolas Liampotis</a> (ICCS)
* @since 1.2
*/
public class TestIndirectTrustPerformance implements ITestIndirectTrustPerformance {
private static Logger LOG = LoggerFactory.getLogger(TestIndirectTrustPerformance.class);
/** The time to wait for DIRECT trust update events. */
private static final long DIRECT_EVAL_TIMEOUT = 2000l;
/** The time to wait for INDIRECT trust update events. */
private static final long INDIRECT_EVAL_TIMEOUT = 60000l;
private PerformanceLowerTester performanceLowerTester;
private PerformanceTestResult performanceTestResult;
/** The Comms Manager service reference. */
private ICommManager commManager;
/** The internal Trust Evidence Collector service reference. */
private ITrustEvidenceCollector internalTrustEvidenceCollector;
/** The internal Trust Broker service reference. */
private ITrustBroker internalTrustBroker;
/** The count-down latch to use for verifying trust update events. */
private CountDownLatch cdLatch;
public TestIndirectTrustPerformance() {
LOG.info("{} instantiated", this.getClass().getName());
}
/*
* @see org.societies.integration.performance.test.upper_tester.trust.indirect.ITestIndirectTrustPerformance#testEvaluateIndirectTrust(org.societies.integration.performance.test.lower_tester.PerformanceTestMgmtInfo, org.societies.integration.performance.test.upper_tester.trust.TrustEvidenceParams)
*/
@Override
public void testEvaluateIndirectTrust(
PerformanceTestMgmtInfo performanceTestMgmtInfo,
TrustEvidenceParams trustEvidenceParams) {
// The following 2 lines are mandatory for the beginning of each test
this.performanceLowerTester = new PerformanceLowerTester(performanceTestMgmtInfo);
this.performanceLowerTester.testStart(this.getClass().getName(), this.getCommManager());
final Date testStart = new Date();
// Extract the Map<cssId, Set<TrustEvidence> contained in the test params.
Map<String, Set<TrustEvidence>> trustEvidenceMap = null;
try {
trustEvidenceMap = TrustEvidenceParamParser.toTrustEvidence(trustEvidenceParams);
} catch (Exception e) {
this.fail("Could not parse TrustEvidenceParams JSON String: "
+ e.getLocalizedMessage());
return;
}
try {
// Retrieve the IIdentity of my CSS.
final String myCssId = this.commManager.getIdManager().getCloudNode().getBareJid();
final TrustedEntityId myTeid = new TrustedEntityId(TrustedEntityType.CSS, myCssId);
// Extract TrustSimilarity Map based on the test params.
final Map<TrustedEntityId, TrustSimilarity> trustSimilarityMap =
this.extractTrustSimilarity(myTeid, trustEvidenceMap);
// The set of trust evidence to evaluate
final Set<TrustEvidence> trustEvidenceSet = (trustEvidenceMap.get(myCssId) != null)
? trustEvidenceMap.get(myCssId) : Collections.<TrustEvidence>emptySet();
// Start test
LOG.info("START testEvaluateDirectTrust: trustEvidenceSet={}, trustSimilarityMap={}",
trustEvidenceSet, trustSimilarityMap);
final Set<TrustRelationship> result = new LinkedHashSet<TrustRelationship>();
for (final TrustEvidence trustEvidence : trustEvidenceSet) {
LOG.info("Evaluating evidence '{}'", trustEvidence);
// Create a DIRECT trust query for the entity specified in this piece of evidence
final TrustQuery trustQuery = new TrustQuery(myTeid).setTrusteeId(
trustEvidence.getObjectId()).setTrustValueType(TrustValueType.DIRECT);
// Initialise count-down latch to use for verifying trust update event.
this.cdLatch = new CountDownLatch(1);
final TrustUpdateEventListener trustListener = new TrustUpdateEventListener();
// Register for trust value updates of this entity
this.internalTrustBroker.registerTrustUpdateListener(trustListener, trustQuery);
// Add evidence
this.internalTrustEvidenceCollector.addDirectEvidence(
trustEvidence.getSubjectId(), trustEvidence.getObjectId(),
trustEvidence.getType(), trustEvidence.getTimestamp(),
trustEvidence.getInfo());
final boolean isTrustUpdated = this.cdLatch.await(DIRECT_EVAL_TIMEOUT, TimeUnit.MILLISECONDS);
// Unregister from trust value updates of this entity
this.internalTrustBroker.unregisterTrustUpdateListener(trustListener, trustQuery);
if (!isTrustUpdated) {
LOG.warn("Did not receive TrustUpdateEvent for evidence '"
+ trustEvidence + "' in the specified timeout: " + DIRECT_EVAL_TIMEOUT + "ms");
} else {
final TrustRelationship updatedTrustRelationship =
trustListener.getUpdatedTrustRelationship();
LOG.info("Updated trust relationship '{}'", updatedTrustRelationship);
// Verify Trust Relationships properties
if (!myTeid.equals(updatedTrustRelationship.getTrustorId())) {
this.fail("Expected trustorId '" + myTeid + "' but was '"
+ updatedTrustRelationship.getTrustorId() + "'");
return;
}
if (!trustEvidence.getObjectId().equals(updatedTrustRelationship.getTrusteeId())) {
this.fail("Expected trusteeId '" + myTeid + "' but was '"
+ updatedTrustRelationship.getTrusteeId() + "'");
return;
}
if (TrustValueType.DIRECT != updatedTrustRelationship.getTrustValueType()) {
this.fail("Expected trustValueType '" + TrustValueType.DIRECT + "' but was '"
+ updatedTrustRelationship.getTrustValueType() + "'");
return;
}
}
}
final Set<TrustedEntityId> connectionTeids = trustSimilarityMap.keySet();
for (final TrustedEntityId connectionTeid : connectionTeids) {
LOG.info("Establishing DIRECT trust relationship with connection '{}'",
connectionTeid);
// Create a DIRECT trust query for the new connection
final TrustQuery trustQuery = new TrustQuery(myTeid).setTrusteeId(
connectionTeid).setTrustValueType(TrustValueType.DIRECT);
// Initialise count-down latch to use for verifying trust update event.
this.cdLatch = new CountDownLatch(1);
final TrustUpdateEventListener trustListener = new TrustUpdateEventListener();
// Register for trust value updates of this entity
this.internalTrustBroker.registerTrustUpdateListener(trustListener, trustQuery);
// Add fake evidence to establish DIRECT trust connection with connection
this.internalTrustEvidenceCollector.addDirectEvidence(
myTeid, connectionTeid, TrustEvidenceType.FRIENDED_USER,
new Date(), null);
final boolean isTrustUpdated = this.cdLatch.await(DIRECT_EVAL_TIMEOUT, TimeUnit.MILLISECONDS);
// Unregister from trust value updates of this entity
this.internalTrustBroker.unregisterTrustUpdateListener(trustListener, trustQuery);
if (!isTrustUpdated) {
LOG.warn("Did not receive TrustUpdateEvent for connection '"
+ connectionTeid + "' in the specified timeout: " + DIRECT_EVAL_TIMEOUT + "ms");
} else {
final TrustRelationship updatedTrustRelationship =
trustListener.getUpdatedTrustRelationship();
LOG.info("Updated trust relationship '{}'", updatedTrustRelationship);
// Verify Trust Relationships properties
if (!myTeid.equals(updatedTrustRelationship.getTrustorId())) {
this.fail("Expected trustorId '" + myTeid + "' but was '"
+ updatedTrustRelationship.getTrustorId() + "'");
return;
}
if (!connectionTeid.equals(updatedTrustRelationship.getTrusteeId())) {
this.fail("Expected trusteeId '" + connectionTeid + "' but was '"
+ updatedTrustRelationship.getTrusteeId() + "'");
return;
}
if (TrustValueType.DIRECT != updatedTrustRelationship.getTrustValueType()) {
this.fail("Expected trustValueType '" + TrustValueType.DIRECT + "' but was '"
+ updatedTrustRelationship.getTrustValueType() + "'");
return;
}
}
}
LOG.info("Sleeping for {}ms to allow INDIRECT trust evaluation", INDIRECT_EVAL_TIMEOUT);
Thread.sleep(INDIRECT_EVAL_TIMEOUT);
for (final Map.Entry<TrustedEntityId, TrustSimilarity> trustSimilarity : trustSimilarityMap.entrySet()) {
for (final TrustedEntityId trusteeId : trustSimilarity.getValue().getUnsharedTrustees()) {
final ExtTrustRelationship extTrustRelationship =
this.internalTrustBroker.retrieveExtTrustRelationship(new TrustQuery(myTeid)
.setTrusteeId(trusteeId).setTrustValueType(TrustValueType.INDIRECT)).get();
LOG.info("INDIRECT trust relationship '{}'", extTrustRelationship);
if (extTrustRelationship == null) {
this.fail("INDIRECT trust relationship with '" + trusteeId + "' not found");
return;
}
if (extTrustRelationship.getTimestamp().compareTo(testStart) < 0) {
this.fail("INDIRECT trust relationship with '" + trusteeId + "' is out-of-date");
return;
}
if (extTrustRelationship.getTrustEvidence().isEmpty()) {
this.fail("INDIRECT trust relationship with '" + trusteeId + "' contains no evidence");
return;
}
boolean foundConnection = false;
for (final TrustEvidence evidence : extTrustRelationship.getTrustEvidence()) {
if (TrustEvidenceType.DIRECTLY_TRUSTED == evidence.getType()
&& trustSimilarity.getKey().equals(evidence.getSubjectId())) {
foundConnection = true;
break;
}
}
if (!foundConnection) {
this.fail("INDIRECT trust relationship with '"
+ trusteeId + "' not associated with connection '"
+ trustSimilarity.getKey() + "'");
return;
}
result.add(extTrustRelationship);
}
}
// End test
LOG.info("END testEvaluateDirectTrust for params: {}", trustEvidenceSet);
this.performanceTestResult = new PerformanceTestResult(this.getClass().getName(),
"Updated trust relationships: " + result,
PerformanceTestResult.SUCCESS_STATUS);
this.performanceLowerTester.testFinish(this.performanceTestResult);
} catch (TrustException te) {
this.fail(te.getLocalizedMessage());
} catch (InterruptedException ie) {
this.fail("Interrupted while executing test: " + ie.getLocalizedMessage());
} catch (Exception e) {
this.fail(e.getLocalizedMessage());
}
}
public ICommManager getCommManager() {
return this.commManager;
}
public void setCommManager(ICommManager commManager) {
this.commManager = commManager;
}
public ITrustEvidenceCollector getInternalTrustEvidenceCollector() {
return this.internalTrustEvidenceCollector;
}
public void setInternalTrustEvidenceCollector(ITrustEvidenceCollector internalTrustEvidenceCollector) {
this.internalTrustEvidenceCollector = internalTrustEvidenceCollector;
}
public ITrustBroker getInternalTrustBroker() {
return this.internalTrustBroker;
}
public void setInternalTrustBroker(ITrustBroker internalTrustBroker) {
this.internalTrustBroker = internalTrustBroker;
}
private Map<TrustedEntityId,TrustSimilarity> extractTrustSimilarity(
final TrustedEntityId myTeid, final Map<String,Set<TrustEvidence>> trustEvidenceMap)
throws TrustException {
final Map<TrustedEntityId,TrustSimilarity> trustSimilarityMap =
new LinkedHashMap<TrustedEntityId, TrustSimilarity>();
final Map<TrustedEntityId,Set<TrustedEntityId>> trustPrefsMap =
this.extractTrustPrefs(trustEvidenceMap);
LOG.info("extractTrustSimilarity: trustPrefsMap={}", trustPrefsMap);
final Set<TrustedEntityId> myTrustees = (trustPrefsMap.get(myTeid) != null)
? trustPrefsMap.get(myTeid) : Collections.<TrustedEntityId>emptySet();
for (final Map.Entry<TrustedEntityId, Set<TrustedEntityId>> trustPrefs : trustPrefsMap.entrySet()) {
if (trustPrefs.getKey().equals(myTeid)) {
continue;
}
final Set<TrustedEntityId> sharedTrustees = new LinkedHashSet<TrustedEntityId>(trustPrefs.getValue());
sharedTrustees.retainAll(myTrustees);
final Set<TrustedEntityId> unsharedTrustees = new LinkedHashSet<TrustedEntityId>(trustPrefs.getValue());
unsharedTrustees.removeAll(myTrustees);
trustSimilarityMap.put(trustPrefs.getKey(),
new TrustSimilarity(sharedTrustees, unsharedTrustees));
}
return trustSimilarityMap;
}
/**
* Map<TEID,Set<TEID>> = {
* userTeidX = { teid1, teid2 }
* userTeidY = { teid2 }
* userTeidZ = { teid1, teid2, teid3, teid4 }
* }
* @param trustEvidenceMap
* @return
*/
private Map<TrustedEntityId,Set<TrustedEntityId>> extractTrustPrefs(
final Map<String,Set<TrustEvidence>> trustEvidenceMap)
throws TrustException {
final Map<TrustedEntityId,Set<TrustedEntityId>> trustPrefsMap =
new LinkedHashMap<TrustedEntityId, Set<TrustedEntityId>>(trustEvidenceMap.size());
for (final Map.Entry<String, Set<TrustEvidence>> trustorEntry : trustEvidenceMap.entrySet()) {
final TrustedEntityId trustorId = new TrustedEntityId(TrustedEntityType.CSS, trustorEntry.getKey());
final Set<TrustedEntityId> trustPrefs = new LinkedHashSet<TrustedEntityId>();
for (final TrustEvidence evidence : trustEvidenceMap.get(trustorEntry.getKey())) {
trustPrefs.add(evidence.getObjectId());
}
trustPrefsMap.put(trustorId, trustPrefs);
}
return trustPrefsMap;
}
private void fail(String errorMesg) {
this.performanceTestResult = new PerformanceTestResult(
this.getClass().getName(), errorMesg,
PerformanceTestResult.ERROR_STATUS);
this.performanceLowerTester.testFinish(this.performanceTestResult);
}
private class TrustSimilarity {
private final Set<TrustedEntityId> sharedTrustees;
private final Set<TrustedEntityId> unsharedTrustees;
private TrustSimilarity(final Set<TrustedEntityId> sharedTrustees,
final Set<TrustedEntityId> unsharedTrustees) {
this.sharedTrustees = sharedTrustees;
this.unsharedTrustees = unsharedTrustees;
}
@SuppressWarnings("unused")
private Set<TrustedEntityId> getSharedTrustees() {
return this.sharedTrustees;
}
private Set<TrustedEntityId> getUnsharedTrustees() {
return this.unsharedTrustees;
}
/*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("TrustSimilarity [sharedTrustees=");
sb.append(this.sharedTrustees);
sb.append(", unsharedTrustees=");
sb.append(this.unsharedTrustees);
sb.append("]");
return sb.toString();
}
}
private class TrustUpdateEventListener implements ITrustUpdateEventListener {
private TrustRelationship updatedTrustRelationship;
/*
* @see org.societies.api.privacytrust.trust.event.ITrustUpdateEventListener#onUpdate(org.societies.api.privacytrust.trust.event.TrustUpdateEvent)
*/
@Override
public void onUpdate(TrustUpdateEvent event) {
this.updatedTrustRelationship = event.getTrustRelationship();
// Signal event has been received
TestIndirectTrustPerformance.this.cdLatch.countDown();
}
private TrustRelationship getUpdatedTrustRelationship() {
return this.updatedTrustRelationship;
}
}
}