/**
* Copyright 2014 Liverpool John Moores University <http://www.ljmu.ac.uk/cmp/>
* Aniketos Project FP7-ICT-257930 <http://www.aniketos.eu>
* David Llewellyn-Jones <D.Llewellyn-Jones@ljmu.ac.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package eu.aniketos.ncvm.impl;
import java.io.IOException;
import java.util.Iterator;
import org.eclipse.bpmn2.Definitions;
import org.eclipse.bpmn2.FlowElement;
import org.eclipse.bpmn2.RootElement;
import org.eclipse.bpmn2.ServiceTask;
import eu.aniketos.components.verification.compositionsecurityvalidation.CompositionSecurityValidationResult;
import eu.aniketos.data.SPState;
import eu.aniketos.marketplace.CompositionPlan;
import eu.aniketos.ncvm.IVerificationResult;
import eu.aniketos.ncvm.impl.NestedCompositionVerification.AniketosServices;
import eu.aniketos.ncvm.impl.NestedCompositionVerification.ServiceInfo;
/**
* Class for verifying composite services. This is particularly useful when verifying a service that
* has not already been registered in the Marketplace, but where a BPMN composition plan is available.
* @author LJMU/David Llewellyn-Jones
*
*/
public class VerifyComposite {
private String bpmn;
private String conspec;
private String propertyID;
private String serviceID;
private AniketosServices call;
private String serviceFilter;
/**
* Initialise the class.
* @param serviceID the ID of the service to check.
* @param propertyID the security property to check.
* @param conspec a ConSpec file for the property to be checked.
* @param call object for managing the external services.
* @param bpmn BPMN composition plan for the service.
* @param serviceFilter apply a filter in case only services with a given ID should be checked.
*/
public VerifyComposite(String serviceID, String propertyID, String conspec, AniketosServices call, String bpmn, String serviceFilter) {
this.serviceID = serviceID;
this.propertyID = propertyID;
this.conspec = conspec;
this.call = call;
this.bpmn = bpmn;
this.serviceFilter = serviceFilter;
}
private Definitions definitions = null;
/**
* Set the BPMN composition plan to be checked.
* @param bpmn the BPMN composition plan to be checked.
*/
public void setBpmn(String bpmn) {
this.bpmn = bpmn;
}
/**
* Set the ConSpec file of the security property to be checked.
* @param conspec the ConSpec file contents to set.
*/
public void setConspec(String conspec) {
this.conspec = conspec;
}
/**
* Set the property ID of the security property to be checked.
* @param propertyID the property ID to set.
*/
public void setPropertyID(String propertyID) {
this.propertyID = propertyID;
}
/**
* Set the ID of the service to be checked.
* @param serviceID the serviceID of the service to check.
*/
public void setServiceID(String serviceID) {
this.serviceID = serviceID;
}
/**
* Set the stored details of the external services to use.
* @param call object holding details of the external services to use.
*/
public void setCall(AniketosServices call) {
this.call = call;
}
/**
* Verify the composite service that is defined by the BPMN composition plan that has been set.
* The details for the verification should be set as class variables using the class setters.
* @return true if the verification process verifies that the property holds for the composition plan.
*/
public IVerificationResult verify () {
IVerificationResult result = new VerificationResult();
boolean filterMatches = (serviceFilter.isEmpty() || serviceFilter.equalsIgnoreCase(serviceID));
result.setResult(1);
SPState state = SPState.UnBind;
if ((serviceID != null) && (serviceID.length() > 0)) {
state = CacheSupport.CheckCachedProperty (call.spdm, serviceID, propertyID, result);
}
if (filterMatches && (state == SPState.Verified)) {
Activator.logLine("Property pre-cached and verified");
}
else {
// Check the property
// We need to different things depending on what the property is
if (filterMatches && (propertyID.equalsIgnoreCase("SoD") || propertyID.equalsIgnoreCase("BoD"))) {
// Simply pass the query on to the CSVM
CompositionPlan compositionPlan = new CompositionPlan();
compositionPlan.setBPMNXML(bpmn);
compositionPlan.setCompositionPlanID(serviceID);
CompositionSecurityValidationResult partial;
partial = call.csvm.VerifyCompositionCompliance(compositionPlan);
if (partial.getVerificationResult() == true) {
result.setResult(1);
Activator.logLine("CSVM verification passed: " + partial.getVerificationExplaination());
CacheSupport.SetCachedProperty (call.spdm, serviceID, propertyID, "1", SPState.Verified);
}
else {
result.setResult(0);
Activator.logLine("CSVM verification failed: " + partial.getVerificationExplaination());
// TODO: Set correct verification state
CacheSupport.SetCachedProperty (call.spdm, serviceID, propertyID, "0", SPState.Verified);
}
}
else {
// Parse the BPMN2 file
try {
definitions = BPMNSupport.parseBPMN(bpmn);
} catch (IOException e) {
Activator.logLine("Error reading BPMN2 data:" + e.toString());
}
// Cycle through all tasks in the composition
for (Iterator<RootElement> rootIter = definitions.getRootElements().iterator(); rootIter.hasNext();) {
RootElement rootElement = rootIter.next();
if (rootElement instanceof org.eclipse.bpmn2.Process) {
for (Iterator<FlowElement> flowIter = ((org.eclipse.bpmn2.Process) rootElement).getFlowElements().iterator(); flowIter.hasNext();) {
FlowElement flow = flowIter.next();
if (flow instanceof ServiceTask) {
// Service Tasks need to be handled
ServiceTask atomicService = (ServiceTask) flow;
String serviceId = BPMNSupport.getExtensionValue (atomicService, "id");
if (serviceId.isEmpty()) {
// If there's no ID extension element, we default to the service type
serviceId = atomicService.getId();
}
Activator.logLine("Marketplace, requesting service: " + serviceId);
ServiceInfo serviceInfo = ModuleSupport.FindServiceInfo(call.marketplace, serviceId);
switch (serviceInfo.type) {
case ATOMIC:
{
VerifyAtomic verify = new VerifyAtomic(serviceId, propertyID, conspec, call, serviceInfo.details, serviceFilter);
IVerificationResult partial = verify.verify();
if (partial.getResult() <= 0) {
// Verification fails completely
result.setResult(0);
}
}
break;
case COMPOSITE:
{
VerifyComposite verify = new VerifyComposite(serviceId, propertyID, conspec, call, serviceInfo.details, serviceFilter);
IVerificationResult partial = verify.verify();
if (partial.getResult() <= 0) {
// Verification fails completely
result.setResult(0);
}
}
break;
case ERROR:
result.setError(4, "Marketplace error");
break;
default:
result.setError(4, "Unknown service type");
break;
}
}
}
}
}
// Having checked all of the subservices, we now have a result for the composite service
if (result.getResult() >= 0) {
if ((serviceID != null) && (serviceID.length() > 0)) {
CacheSupport.SetCachedProperty (call.spdm, serviceID, propertyID, Integer.toString(result.getResult()), SPState.Verified);
}
Activator.logLine("Composite property verification successful");
}
else {
Activator.logLine("Composite property verification unsuccessful");
}
}
}
return result;
}
}