/* Copyright 2012-2015 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package eu.aniketos.securebpmn.export.aslan.export;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.securebpmn2.ActivityAction;
import org.eclipse.securebpmn2.Permission;
import org.eclipse.securebpmn2.SeparationOfDuty;
/**
* Creates the ASLan representation of a SecureBPMN SeparationOfDuty element.
*
*
*/
public class SeparationOfDutyExport {
/**
* Generates the ASLan representation of the provided SeparationOfDuty element
* and sends the output to the provided AslanFileBuilder.
*
* @param sod
* The SeparationOfDuty element for which the representation should
* be generated.
* @param afb
* The AslanFileBuilder the output is sent to.
*/
public static void createSeparationOfDutyElements(SeparationOfDuty sod, AslanFileBuilder afb) {
if (sod.isDynamicEnforcement()) return;
List<String> assignTasks = new ArrayList<String>();
List<String> claimTasks = new ArrayList<String>();
List<String> completeTasks = new ArrayList<String>();
for (Permission p : sod.getPermissions()) {
if (p.getActions().size() == 0) {
System.err.println("[WARNING] The permission with name=\"" + p.getPName() + "\" and id=\"" + p.getId() + "\" has no action. This should never happen! Check your .activiti diagram file.");
continue;
}
// Permissions only have one Action
if (p.getActions().get(0) instanceof ActivityAction) {
ActivityAction a = (ActivityAction) p.getActions().get(0);
if (a.getActionName().equals("Complete")) {
completeTasks.add(a.getActivity().getId());
} else if (a.getActionName().equals("Claim")) {
claimTasks.add(a.getActivity().getId());
} else if (a.getActionName().equals("Assign")) {
assignTasks.add(a.getActivity().getId());
} else if (a.getActionName().equals("Full Access")) {
assignTasks.add(a.getActivity().getId());
claimTasks.add(a.getActivity().getId());
completeTasks.add(a.getActivity().getId());
}
}
}
if (assignTasks.size() > 1) {
// TODO what to check? only executed() is persistent...
}
if (claimTasks.size() > 1) {
// TODO what to check? only executed() is persistent...
}
if (completeTasks.size() > 1) {
// safe default assumptions
int minUsers = completeTasks.size();
int maxActions = 1;
if (sod.getMinimumUsers() == null) {
System.out.println("[SCVM-EXPORT-ASLAN] minimum users for SoD \"" + sod.getId() + "\" not set, using " + minUsers + ".");
} else {
if (sod.getMinimumUsers() > completeTasks.size() || sod.getMinimumUsers() < 1) {
System.err.println("[SCVM-EXPORT-ASLAN] invalid input for minimum users at SoD \"" + sod.getId() + "\", using " + minUsers + ".");
} else {
minUsers = sod.getMinimumUsers();
}
}
if (sod.getMaxUserActionsPermitted() == null) {
System.out.println("[SCVM-EXPORT-ASLAN] maximum permitted actions for SoD \"" + sod.getId() + "\" not set, using " + maxActions + ".");
} else {
if (sod.getMaxUserActionsPermitted() < 1) {
System.err.println("[SCVM-EXPORT-ASLAN] invalid input for maximum permitted actions at SoD \"" + sod.getId() + "\", using " + maxActions + ".");
} else {
maxActions = sod.getMaxUserActionsPermitted();
}
}
// calculate numeric partitions
final List<int[]> allPartitions = ExportUtil.generateIntegerPartitions(completeTasks.size());
// select invalid partitions
List<int[]> selectedPartitions = new ArrayList<int[]>();
for (int[] part : allPartitions) {
if (part.length > 0 && (part.length < minUsers
|| part[0] > maxActions)) {
selectedPartitions.add(part);
}
}
// create goals for partitions
String[] tasks = new String[completeTasks.size()];
for (int i = 0; i < completeTasks.size(); i++) {
tasks[i] = completeTasks.get(i);
}
List<int[]> permList = ExportUtil.generateLocationPermutations(tasks.length);
for (int[] part : selectedPartitions) {
// we assume that tasks.lengh equals the sum of each partition
List<List<Set<String>>> sets = new ArrayList<List<Set<String>>>();
// loop over index permutations
for (int[] perm : permList) {
int indexStart = 0;
// list of sets (parts of the partition) for the current permutation
List<Set<String>> setList = new ArrayList<Set<String>>();
// create the sets
for (int partLength : part) {
Set<String> partTasks = new HashSet<String>();
// get the tasks and add them to the set
for (int i = 0; i < partLength; i++) {
partTasks.add(tasks[perm[indexStart + i]-1]);
}
indexStart += partLength;
setList.add(partTasks);
}
// check if partition config already exists
boolean newSet = true;
for (List<Set<String>> presentSetList : sets) {
if (presentSetList.equals(setList)) {
newSet = false;
break;
}
}
// add partition config if new
if (newSet) {
sets.add(setList);
}
}
// create goals for this partition
for (List<Set<String>> setArray : sets) {
// generate goal
int numUsers = setArray.size();
int numTasks = tasks.length;
List<String> natVars = new ArrayList<String>();
StringBuilder goalString = new StringBuilder();
goalString.append("(");
// generate user variables
for (int i = 0; i < numUsers; i++) {
afb.addType("user", "U" + i);
if (i > 0) goalString.append(",");
goalString.append("U" + i);
}
// generate task nat variables
for (int i = 0; i < numTasks; i++) {
String currentVar = afb.addNatVar();
natVars.add(currentVar);
goalString.append("," + currentVar);
}
goalString.append("):=");
// generate facts
int natVarPos = 0;
for (int i = 0; i < numUsers; i++) {
for (String currentTask : setArray.get(i)) {
goalString.append(" executed(U" + i + ",task(" + currentTask + "," + natVars.get(natVarPos) + ")).");
natVarPos++;
}
}
// add goal
String finalGoalString = goalString.toString();
afb.addGoal("sod_" + sod.getId() + "_", finalGoalString.substring(0, finalGoalString.length()-1));
}
}
}
}
}