/* * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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 org.apache.synapse.aspects.flow.statistics.util; import org.apache.synapse.MessageContext; import org.apache.synapse.SynapseConstants; import org.apache.synapse.aspects.flow.statistics.collectors.RuntimeStatisticCollector; import org.apache.synapse.aspects.flow.statistics.data.raw.StatisticsLog; import org.apache.synapse.aspects.flow.statistics.publishing.PublishingEvent; import org.apache.synapse.aspects.flow.statistics.publishing.PublishingFlow; import org.apache.synapse.aspects.flow.statistics.publishing.PublishingPayload; import org.apache.synapse.aspects.flow.statistics.publishing.PublishingPayloadEvent; import org.apache.synapse.commons.json.JsonUtil; import org.apache.synapse.core.axis2.Axis2MessageContext; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * Provides various methods used for tracing data collections. */ public class TracingDataCollectionHelper { /** * Extract payload from the synapse message context. * * @param messageContext synapse message context * @return payload */ public static String collectPayload(MessageContext messageContext) { String payload = null; try { org.apache.axis2.context.MessageContext a2mc = ((Axis2MessageContext) messageContext).getAxis2MessageContext(); if (JsonUtil.hasAJsonPayload(a2mc)) { payload = JsonUtil.jsonPayloadToString(a2mc); } else { payload = messageContext.getEnvelope().toString(); } } catch (Exception e) { // SOAP envelop is not created yet payload = "NONE"; } return payload; } /** * Extract properties from the synapse message context. * * @param synCtx synapse message context * @return property map */ public static Map<String, Object> extractContextProperties(MessageContext synCtx) { Set<String> propertySet = synCtx.getPropertyKeySet(); Map<String, Object> propertyMap = new TreeMap<>(); for (String property : propertySet) { Object propertyValue = synCtx.getProperty(property); propertyMap.put(property, propertyValue); } // Remove message-flow-tracer properties propertyMap.remove(SynapseConstants.STATISTICS_STACK); propertyMap.remove(StatisticsConstants.STAT_COLLECTOR_PROPERTY); return propertyMap; } /** * Extract transport headers from the synapse message context. * * @param synCtx synapse message context * @return transport headers map */ public static Map<String, Object> extractTransportProperties(MessageContext synCtx) { Map<String, Object> transportPropertyMap = new TreeMap<>(); Axis2MessageContext axis2smc = (Axis2MessageContext) synCtx; org.apache.axis2.context.MessageContext axis2MessageCtx = axis2smc.getAxis2MessageContext(); Object headers = axis2MessageCtx.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS); if (headers != null && headers instanceof Map) { Map headersMap = (Map) headers; Set<String> axis2PropertySet = headersMap.keySet(); for (String entry : axis2PropertySet) { transportPropertyMap.put(entry, headersMap.get(entry)); } } // Adding important transport related properties if (axis2MessageCtx.getTo() != null) { transportPropertyMap.put(SynapseConstants.HEADER_TO, axis2MessageCtx.getTo().getAddress()); } if (axis2MessageCtx.getFrom() != null) { transportPropertyMap.put(SynapseConstants.HEADER_FROM, axis2MessageCtx.getFrom().getAddress()); } if (axis2MessageCtx.getWSAAction() != null) { transportPropertyMap.put("WSAction", axis2MessageCtx.getWSAAction()); } if (axis2MessageCtx.getSoapAction() != null) { transportPropertyMap.put("SOAPAction", axis2MessageCtx.getSoapAction()); } if (axis2MessageCtx.getReplyTo() != null) { transportPropertyMap.put(SynapseConstants.HEADER_REPLY_TO, axis2MessageCtx.getReplyTo().getAddress()); } if (axis2MessageCtx.getMessageID() != null) { transportPropertyMap.put(SynapseConstants.HEADER_MESSAGE_ID, axis2MessageCtx.getMessageID()); } // Remove unnecessary properties if (transportPropertyMap.get("Cookie") != null) { transportPropertyMap.remove("Cookie"); } return transportPropertyMap; } public static PublishingFlow createPublishingFlow(List<StatisticsLog> messageFlowLogs) { // Data structure using to serialize thr statistic data while publishing. PublishingFlow publishingFlow = new PublishingFlow(); // Payload map which contains all the payloads of the message flow. Map<String, PublishingPayload> payloadMap = new HashMap<>(); // Constants final String REFER = "#REFER:"; final String BEFORE = "before-"; final String AFTER = "after-"; final Integer BEFORE_PAYLOAD = 8; // 8th attribute setting @PublishingEvent final Integer AFTER_PAYLOAD = 9; // 9th attribute setting @PublishingEvent String entryPoint = messageFlowLogs.get(0).getComponentName(); String flowId = messageFlowLogs.get(0).getMessageFlowId(); Integer entrypointHashcode = messageFlowLogs.get(0).getHashCode(); boolean isTracingEnabledForFlow = messageFlowLogs.get(0).isTracingEnabled(); for (int index = 0; index < messageFlowLogs.size(); index++) { StatisticsLog currentStatLog = messageFlowLogs.get(index); if (currentStatLog == null) { continue; } // Add each event to Publishing Flow publishingFlow.addEvent(new PublishingEvent(flowId, index, currentStatLog, entryPoint, entrypointHashcode)); // Skip the rest of things, if message tracing is disabled if (!RuntimeStatisticCollector.isCollectingPayloads()) { continue; } // Skip flow is tracing is not enabled for the flow (from UI) if (!isTracingEnabledForFlow) { continue; } // Update children's immediateParent index List<Integer> childrenOfCurrent = currentStatLog.getChildren(); for(Integer child:childrenOfCurrent) { messageFlowLogs.get(child).setImmediateParent(currentStatLog.getCurrentIndex()); } if (currentStatLog.getBeforePayload() != null && currentStatLog.getAfterPayload() == null) { currentStatLog.setAfterPayload(currentStatLog.getBeforePayload()); } if (currentStatLog.getBeforePayload() == null) { int parentIndex = currentStatLog.getImmediateParent(); StatisticsLog parentStatLog = messageFlowLogs.get(parentIndex); if (parentStatLog.getAfterPayload().startsWith(REFER)) { // Parent also referring to after-payload currentStatLog.setBeforePayload(parentStatLog.getAfterPayload()); currentStatLog.setAfterPayload(parentStatLog.getAfterPayload()); String referringIndex = parentStatLog.getAfterPayload().split(":")[1]; payloadMap.get(AFTER + referringIndex) .addEvent(new PublishingPayloadEvent(index, BEFORE_PAYLOAD)); payloadMap.get(AFTER + referringIndex) .addEvent(new PublishingPayloadEvent(index, AFTER_PAYLOAD)); } else { // Create a new after-payload reference currentStatLog.setBeforePayload(REFER + parentIndex); currentStatLog.setAfterPayload(REFER + parentIndex); payloadMap.get(AFTER + parentIndex) .addEvent(new PublishingPayloadEvent(index, BEFORE_PAYLOAD)); payloadMap.get(AFTER + parentIndex) .addEvent(new PublishingPayloadEvent(index, AFTER_PAYLOAD)); } } else { // For content altering components PublishingPayload publishingPayloadBefore = new PublishingPayload(); publishingPayloadBefore.setPayload(currentStatLog.getBeforePayload()); publishingPayloadBefore.addEvent(new PublishingPayloadEvent(index, BEFORE_PAYLOAD)); payloadMap.put(BEFORE + index, publishingPayloadBefore); PublishingPayload publishingPayloadAfter = new PublishingPayload(); publishingPayloadAfter.setPayload(currentStatLog.getAfterPayload()); publishingPayloadAfter.addEvent(new PublishingPayloadEvent(index, AFTER_PAYLOAD)); payloadMap.put(AFTER + index, publishingPayloadAfter); } } publishingFlow.setMessageFlowId(flowId); // Move all payloads to publishingFlow object publishingFlow.setPayloads(payloadMap.values()); return publishingFlow; } }