All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.petals.ant.task.monit.BuildFlowTreesTask Maven / Gradle / Ivy

There is a newer version: 2.9.0
Show newest version
/**
 * 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