Java tutorial
/******************************************************************************* * Copyright (c) 2015-2017 University of Stuttgart. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and the Apache License 2.0 which both accompany this distribution, * and are available at http://www.eclipse.org/legal/epl-v10.html * and http://www.apache.org/licenses/LICENSE-2.0 * * Contributors: * Sebastian Wagner - initial API and implementation *******************************************************************************/ package org.eclipse.winery.bpmn2bpel.parser; import java.net.URI; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.namespace.QName; import org.eclipse.winery.bpmn2bpel.model.EndTask; import org.eclipse.winery.bpmn2bpel.model.ManagementFlow; import org.eclipse.winery.bpmn2bpel.model.ManagementTask; import org.eclipse.winery.bpmn2bpel.model.Node; import org.eclipse.winery.bpmn2bpel.model.StartTask; import org.eclipse.winery.bpmn2bpel.model.Task; import org.eclipse.winery.bpmn2bpel.model.param.ConcatParameter; import org.eclipse.winery.bpmn2bpel.model.param.DeploymentArtefactParameter; import org.eclipse.winery.bpmn2bpel.model.param.ImplementationArtefactParameter; import org.eclipse.winery.bpmn2bpel.model.param.Parameter; import org.eclipse.winery.bpmn2bpel.model.param.PlanParameter; import org.eclipse.winery.bpmn2bpel.model.param.StringParameter; import org.eclipse.winery.bpmn2bpel.model.param.TopologyParameter; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * TODO describe expected JSON format here */ public class Bpmn4JsonParser extends Parser { private static Logger log = LoggerFactory.getLogger(Bpmn4JsonParser.class); @Override public ManagementFlow parse(URI jsonFileUrl) throws ParseException { try { // general method, same as with data binding ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); // (note: can also use more specific type, like ArrayNode or // ObjectNode!) JsonNode rootNode = mapper.readValue(jsonFileUrl.toURL(), JsonNode.class); String prettyPrintedJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode); log.debug("Creating management flow from following Json model:" + prettyPrintedJson); ManagementFlow managementFlow = new ManagementFlow(); /* Contains the ids (values) of the target nodes of a certain node * (key is node id of this node) */ Map<String, Set<String>> nodeWithTargetsMap = new HashMap<String, Set<String>>(); /* Create model objects from Json nodes */ log.debug("Creating node models..."); Iterator<JsonNode> iter = rootNode.iterator(); while (iter.hasNext()) { JsonNode jsonNode = (JsonNode) iter.next(); /* * As top level elements just start events, end events and * management tasks expected which are transformed to tasks in * our management model */ Task task = createTaskFromJson(jsonNode); /* * Task may be null if it could not be created due to missing or * incorrect fields/values in the Json node */ if (task != null) { managementFlow.addVertex(task); // TODO GATEWAAAAYYYYSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS // !!!!!!!!!!!!!!!!!! /* * To create the links later, relate the id of the created * node with its direct successor nodes */ nodeWithTargetsMap.put(task.getId(), extractNodeTargetIds(jsonNode)); } else { String ignoredJsonNode = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode); log.warn( "No model element could be created from following node due to missing or invalid keys/values :" + ignoredJsonNode); } } /* * Now since all node models are created they can be linked with each other in the management flow */ log.debug("Building management flow by relating node models..."); Iterator<Map.Entry<String, Set<String>>> nodeWithTargetsMapIter = nodeWithTargetsMap.entrySet() .iterator(); while (nodeWithTargetsMapIter.hasNext()) { Map.Entry<String, Set<String>> inputParamEntry = (Map.Entry<String, Set<String>>) nodeWithTargetsMapIter .next(); String srcNodeId = inputParamEntry.getKey(); Node srcNode = managementFlow.getNode(srcNodeId); if (srcNode == null) { throw new Exception( "Node with id '" + srcNodeId + "' could not be found in the management flow."); } /* Relate the source node with its link targets */ Iterator<String> nodeTargetIdsIter = inputParamEntry.getValue().iterator(); while (nodeTargetIdsIter.hasNext()) { String targetNodeId = (String) nodeTargetIdsIter.next(); Node targetNode = managementFlow.getNode(targetNodeId); if (targetNode == null) { throw new Exception( "Node with id '" + targetNodeId + "' could not be found in the management flow."); } log.debug("Creating link between node with id '" + srcNodeId + "' and target node with id '" + targetNodeId + "'"); managementFlow.addEdge(srcNode, targetNode); } } return managementFlow; } catch (Exception e) { log.error("Error while creating management flow : " + e.getMessage()); throw new ParseException(e); } } protected Task createTaskFromJson(JsonNode jsonNode) { // TODO check if type attributes are set and are correct if (!hasRequiredFields(jsonNode, Arrays.asList(JsonKeys.TYPE, JsonKeys.NAME, JsonKeys.ID))) { log.warn("Ignoring task/event node: One of the fields '" + JsonKeys.TYPE + "', '" + JsonKeys.NAME + "' or '" + JsonKeys.ID + "' is missing"); return null; } Task task = null; String taskType = jsonNode.get(JsonKeys.TYPE).asText(); String taskName = jsonNode.get(JsonKeys.NAME).asText(); String taskId = jsonNode.get(JsonKeys.ID).asText(); log.debug("Parsing JSON task or event node with id '" + taskId + "', name '" + taskName + "', type '" + taskType + "'"); switch (taskType) { case JsonKeys.TASK_TYPE_START_EVENT: task = createStartTaskFromJson(jsonNode); break; case JsonKeys.TASK_TYPE_MGMT_TASK: task = createManagementTaskFromJson(jsonNode); break; case JsonKeys.TASK_TYPE_END_EVENT: task = createEndTaskFromJson(jsonNode); break; default: log.warn("Ignoring node: type '" + taskType + "' is unkown"); return null; } /* Set generic task attributes */ task.setId(taskId); task.setName(taskName); /* Add input parameters to task */ JsonNode inputParams = jsonNode.get(JsonKeys.INPUT); if (inputParams != null) { /* * Iterator map required to retrieve the name of the parameter node * * @see * http://stackoverflow.com/questions/7653813/jackson-json-get-node- * name-from-json-tree */ Iterator<Map.Entry<String, JsonNode>> inputParamIter = inputParams.fields(); while (inputParamIter.hasNext()) { Map.Entry<String, JsonNode> inputParamEntry = (Map.Entry<String, JsonNode>) inputParamIter.next(); Parameter inputParam = createParameterFromJson(inputParamEntry.getKey(), inputParamEntry.getValue()); task.addInputParameter(inputParam); } } else { log.debug("No input parameters found for node with id '" + taskId + "'"); } /* Add output Parameters to task */ JsonNode outputParams = jsonNode.get(JsonKeys.OUTPUT); if (outputParams != null) { Iterator<Map.Entry<String, JsonNode>> outputParamIter = outputParams.fields(); while (outputParamIter.hasNext()) { Map.Entry<String, JsonNode> outputParamEntry = (Map.Entry<String, JsonNode>) outputParamIter.next(); Parameter outputParam = createParameterFromJson(outputParamEntry.getKey(), outputParamEntry.getValue()); task.addOutputParameter(outputParam); } } else { log.debug("No output parameters found for node with id '" + taskId + "'"); } return task; } protected StartTask createStartTaskFromJson(JsonNode startTaskNode) { return new StartTask(); } protected EndTask createEndTaskFromJson(JsonNode endTaskNode) { return new EndTask(); } protected ManagementTask createManagementTaskFromJson(JsonNode managementTaskNode) { if (!hasRequiredFields(managementTaskNode, Arrays.asList(JsonKeys.NODE_TEMPLATE, JsonKeys.NODE_OPERATION))) { log.warn("Ignoring mangement node: One of the fields '" + JsonKeys.NODE_TEMPLATE + "' or '" + JsonKeys.NODE_OPERATION + "' is missing"); return null; } String nodeTemplate = managementTaskNode.get(JsonKeys.NODE_TEMPLATE).asText(); String nodeInterfaceName = managementTaskNode.get(JsonKeys.NODE_INTERFACE_NAME).asText(); String nodeOperation = managementTaskNode.get(JsonKeys.NODE_OPERATION).asText(); log.debug("Creating management task with id '" + managementTaskNode.get(JsonKeys.ID) + "', name '" + managementTaskNode.get(JsonKeys.NAME) + "', node template '" + nodeTemplate + "', node operation '" + "', node operation '" + nodeOperation + "'"); ManagementTask task = new ManagementTask(); task.setNodeTemplateId(QName.valueOf(nodeTemplate)); task.setNodeOperation(nodeOperation); task.setInterfaceName(nodeInterfaceName); return task; } protected Parameter createParameterFromJson(String paramName, JsonNode paramNode) { if (!hasRequiredFields(paramNode, Arrays.asList(JsonKeys.TYPE, JsonKeys.VALUE))) { log.warn("Ignoring parameter node: One of the fields '" + JsonKeys.TYPE + "' or '" + JsonKeys.VALUE + "' is missing"); return null; } String paramType = paramNode.get(JsonKeys.TYPE).asText(); String paramValue = paramNode.get(JsonKeys.VALUE).asText(); log.debug("Parsing JSON parameter node with name '" + paramName + "', type '" + paramType + "' and value '" + paramValue + "'"); Parameter param = null; switch (paramType) { case JsonKeys.PARAM_TYPE_VALUE_CONCAT: param = new ConcatParameter(); // TODO add concat operands break; case JsonKeys.PARAM_TYPE_VALUE_DA: param = new DeploymentArtefactParameter(); break; case JsonKeys.PARAM_TYPE_VALUE_IA: param = new ImplementationArtefactParameter(); break; case JsonKeys.PARAM_TYPE_VALUE_PLAN: param = new PlanParameter(); // TODO add task name break; case JsonKeys.PARAM_TYPE_VALUE_STRING: param = new StringParameter(); break; case JsonKeys.PARAM_TYPE_VALUE_TOPOLOGY: param = new TopologyParameter(); break; default: log.warn("JSON parameter type '" + paramType + "' unknown"); return null; } /* Set generic parameter attributes */ param.setName(paramName); param.setValue(paramValue); return param; } protected Set<String> extractNodeTargetIds(JsonNode node) { Set<String> linkTargetIds = new HashSet<String>(); /* Look for the 'connections' element within the node or its children */ JsonNode connectionsNode = node.findValue(JsonKeys.CONNECTIONS); /* * The connection node hosts an array of all outgoing connections to * other nodes */ if (connectionsNode != null && connectionsNode.isArray()) { Iterator<JsonNode> iter = connectionsNode.iterator(); while (iter.hasNext()) { JsonNode connectionEntry = (JsonNode) iter.next(); /* * Should always be true as the connection entry is the id of * the target node */ if (connectionEntry.isTextual()) { linkTargetIds.add(connectionEntry.asText()); } else { // TODO warn } } } else { log.debug("Node with id '" + node.get(JsonKeys.ID) + "' has no connections to other nodes"); return null; } return linkTargetIds; } protected boolean hasRequiredFields(JsonNode jsonNode, List<String> reqFieldNames) { Iterator<String> fieldNAmeIter = reqFieldNames.iterator(); /* Returns false if one of the field names is missing */ while (fieldNAmeIter.hasNext()) { String reqField = (String) fieldNAmeIter.next(); if (jsonNode.get(reqField) == null) { return false; } } return true; } }