
org.ow2.petals.ant.task.monit.BuildFlowTreesTask Maven / Gradle / Ivy
/**
* Copyright (c) 2016 Linagora
*
* This program/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 2.1 of the License, or (at your
* option) any later version.
*
* This program/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 program/library; If not, see http://www.gnu.org/licenses/
* for the GNU Lesser General Public License version 2.1.
*/
package org.ow2.petals.ant.task.monit;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.tools.ant.BuildException;
import org.ow2.petals.ant.task.monit.exception.BuildIdEmptyException;
import org.ow2.petals.ant.task.monit.exception.BuildIdMissingException;
import org.ow2.petals.commons.log.FlowLogData;
import org.ow2.petals.commons.log.TraceCode;
import org.ow2.petals.log.parser.api.model.Flow;
import org.ow2.petals.log.parser.api.model.FlowStep;
/**
* The Ant task to build the flow tree from MONIT traces previously loaded. All flow instances correlated are grouped on
* the same flow tree.
*
* @author Christophe DENEUX - Linagora
*
*/
public class BuildFlowTreesTask extends AbstractMonitFlowsAntTaskRequiringRefId {
private static final String ATTR_CORRELATED_FLOW_INSTANCE_ID = "correlatedFlowInstanceId";
private static final String ATTR_CORRELATED_FLOW_STEP_ID = "correlatedFlowStepId";
/**
* Name of the object reference in which flow trees will be put
*/
private String id;
/**
* @param id
*/
public void setId(final String id) {
this.id = id;
}
@Override
public void doTaskWithFlows(final Set flows) throws Exception {
this.validateIdParameter();
// All flow trees available in MONIT traces read. We use a Map to retrieve easily a flow tree according to a
// flow instance id.
final Map flowTrees = new HashMap<>();
for (final Flow flow : flows) {
this.processFlow(flow, flowTrees, flows);
}
this.log(String.format("%d flow tree(s) found from %d flow(s).", flowTrees.size(), flows.size()));
this.getProject().addReference(this.id, Collections.unmodifiableCollection(flowTrees.values()));
}
/**
* Retrieve all flow instance correlated to the given one.
*
* @param currentFlow
*/
private void processFlow(final Flow currentFlow, final Map flowTrees, final Set flows) {
// For each flow instance, we create a flow tree. Parents and children will be completed parsing all flow
// instances.
// Caution, the current flow tree can have been created previously when required by a correlated child.
final FlowTreeNode currentFlowTree;
final FlowTreeNode existingFlowTreeNode = flowTrees.get(currentFlow.getFlowId());
if (existingFlowTreeNode != null) {
// The flow tree was previously added. We complete its content.
existingFlowTreeNode.setFlow(currentFlow);
currentFlowTree = existingFlowTreeNode;
} else {
currentFlowTree = new FlowTreeNode(currentFlow, null);
flowTrees.put(currentFlow.getFlowId(), currentFlowTree);
}
// A flow instance matching these criterias is a flow instance correlated to the current one if:
// -1- the current flow instance starts by a step 'ConsumeExtBegin' having attributes 'correlatedFlowInstanceId'
// and 'correlatedFlowStepId' pointing to an existing step in all flow instances,
// -2- the current flow instance contains flow step 'ProvideEnd'/'ProvideFailure" having attributes
// 'correlatedFlowInstanceId' and 'correlatedFlowStepId' pointing to an existing step in all flow instances.
// -1- correlation on 'ConsumeExtBegin'
this.processFlowRootStepAsConsumeExtBegin(currentFlow.getRoot(), currentFlowTree, flowTrees, flows);
// -2- other correlations
this.processFlowStep(currentFlow.getRoot(), currentFlowTree, flowTrees, flows);
for (final FlowStep flowStep : currentFlow.getRoot().getChildren()) {
this.processFlowStep(flowStep, currentFlowTree, flowTrees, flows);
}
}
private void processFlowRootStepAsConsumeExtBegin(final FlowStep currentFlowStep,
final FlowTreeNode currentFlowTree, final Map flowTrees, final Set flows) {
final String traceCode = currentFlowStep.getBeginProperties().get(FlowLogData.FLOW_STEP_TRACE_CODE);
if (traceCode.equals(TraceCode.CONSUME_EXT_FLOW_STEP_BEGIN.toString())) {
final Map flowProperties = currentFlowStep.getBeginProperties();
final String correlatedFlowInstanceId = flowProperties == null ? null
: flowProperties.get(ATTR_CORRELATED_FLOW_INSTANCE_ID);
final String correlatedFlowStepId = flowProperties == null ? null
: flowProperties.get(ATTR_CORRELATED_FLOW_STEP_ID);
// As owner of the container hosting the component emiting this MONIT traces, it is possible that we
// can't access MONIT traces on the other size, and so, we can't get the parent flow.
this.processFlowStepWithItsParent(currentFlowTree, flowTrees, flows, correlatedFlowInstanceId,
correlatedFlowStepId);
}
}
private void processFlowStep(final FlowStep currentFlowStep, final FlowTreeNode currentFlowTree,
final Map flowTrees, final Set flows) {
final String traceCode = currentFlowStep.getBeginProperties().get(FlowLogData.FLOW_STEP_TRACE_CODE);
if (traceCode.equals(TraceCode.PROVIDE_FLOW_STEP_BEGIN.toString())) {
final String correlatedFlowInstanceId = currentFlowStep.getBeginProperties()
.get(ATTR_CORRELATED_FLOW_INSTANCE_ID) == null
? currentFlowStep.getOutcomeProperties().get(ATTR_CORRELATED_FLOW_INSTANCE_ID)
: currentFlowStep.getBeginProperties().get(ATTR_CORRELATED_FLOW_INSTANCE_ID);
final String correlatedFlowStepId = currentFlowStep.getBeginProperties()
.get(ATTR_CORRELATED_FLOW_STEP_ID) == null
? currentFlowStep.getOutcomeProperties().get(ATTR_CORRELATED_FLOW_STEP_ID)
: currentFlowStep.getBeginProperties().get(ATTR_CORRELATED_FLOW_STEP_ID);
if (correlatedFlowInstanceId != null && correlatedFlowStepId != null) {
// As owner of the container hosting the component emiting this MONIT traces, we MUST be able to get
// MONIT traces associated to the parent flow because it is running on a Petals container of the same
// PEtals ESB topology.
if (!this.processFlowStepWithItsParent(currentFlowTree, flowTrees, flows, correlatedFlowInstanceId,
correlatedFlowStepId)) {
throw new BuildException(String.format("The parent flow '%s' is required for flow step '%s/%s'",
correlatedFlowInstanceId, currentFlowTree.getFlow().getFlowId(), currentFlowStep.getId()),
this.getLocation());
}
}
}
}
/**
* @param currentFlowTree
* @param flowTrees
* @param flows
* @param correlatedFlowInstanceId
* @param correlatedFlowStepId
* @return {@code true} if the parent flow instance associated to the correlation information was found all flow
* instances
*/
private boolean processFlowStepWithItsParent(final FlowTreeNode currentFlowTree,
final Map flowTrees, final Set flows, final String correlatedFlowInstanceId,
final String correlatedFlowStepId) {
final Flow parentFlow = this.searchParentFlow(flows, correlatedFlowInstanceId, correlatedFlowStepId);
if (parentFlow != null) {
// It's a correlated child flow
final FlowTreeNode parentTreeNode = flowTrees.get(correlatedFlowInstanceId);
if (parentTreeNode != null) {
// We have already loop over the parent tree, we can link directly the correlated child flow to its
// parent
parentTreeNode.addChildFlowTreeNode(currentFlowTree);
currentFlowTree.addParentFlowTreeNode(parentTreeNode);
} else {
// We haven't already loop over the parent tree, we must create a flow tree associated to the
// parent before to add the correlated child flow. The flow tree will be complete later when we
// will loop over it
final FlowTreeNode newParentTreeNode = new FlowTreeNode(null, null);
flowTrees.put(correlatedFlowInstanceId, newParentTreeNode);
newParentTreeNode.addChildFlowTreeNode(currentFlowTree);
currentFlowTree.addParentFlowTreeNode(newParentTreeNode);
}
return true;
} else {
return false;
}
}
/**
*
* @param flows
* @param correlatedFlowInstanceId
* @param correlatedFlowStepId
* @return The parent flow, or {@code null} if no correlated flow instance identifier and no correlated flow step
* identifier are set simultaneously.
* @throws BuildException
* If correlated flow instance identifier and/or correlated flow step identifier are invalid: malformed
* or does not identify a flow step in all flows
*/
private Flow searchParentFlow(final Set flows, final String correlatedFlowInstanceId,
final String correlatedFlowStepId) throws BuildException {
if (correlatedFlowInstanceId != null && correlatedFlowStepId != null
&& !correlatedFlowInstanceId.trim().isEmpty() && !correlatedFlowStepId.trim().isEmpty()) {
for (final Flow flow : flows) {
if (flow.getFlowId().equals(correlatedFlowInstanceId)) {
if (flow.getRoot().findDescendant(correlatedFlowStepId) != null) {
return flow;
}
// Here, no parent flow step was found in steps of the parent flow instance
throw new BuildException(String.format(
"No parent flow step found for given identifiers in the parent flow instance: flowInstanceId=%s, flowStepId=%s.",
correlatedFlowInstanceId, correlatedFlowStepId), this.getLocation());
}
}
// Here, no parent flow instance was found in all know flow instances
return null;
} else {
return null;
}
}
/**
*
* Validate the parameter 'id
'.
*
*
* The parameter should not be null or empty.
*
*
* @throws BuildException
* The parameter has an invalid value
*/
private void validateIdParameter() throws BuildException {
if (this.id == null) {
throw new BuildIdMissingException(this.getLocation());
}
if (this.id.isEmpty()) {
throw new BuildIdEmptyException(this.getLocation());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy