package rocks.inspectit.shared.cs.communication.data; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.mutable.MutableDouble; import rocks.inspectit.shared.all.communication.data.HttpTimerData; import rocks.inspectit.shared.all.communication.data.InvocationSequenceData; import rocks.inspectit.shared.all.communication.data.ParameterContentData; import rocks.inspectit.shared.all.communication.data.SqlStatementData; import rocks.inspectit.shared.all.tracing.data.Span; import rocks.inspectit.shared.cs.cmr.service.ISpanService; /** * Helper class to easier query {@link InvocationSequenceData} objects. * * @author Stefan Siegl */ public final class InvocationSequenceDataHelper { /** * Private constructor for utility class. */ private InvocationSequenceDataHelper() { } /** * Checks if the invocation sequence data object itself contains parameters. * * @param data * the <code>InvocationSequenceData</code> object. * @return if this data object contains captured parameters. */ public static boolean hasCapturedParametersInInvocationSequence(InvocationSequenceData data) { return (null != data.getParameterContentData()) && !data.getParameterContentData().isEmpty(); } /** * Checks whether the invocation sequence data object itself or some nested data element * (timerdata) provides captured parameters. * * @param data * the <code>InvocationSequenceData</code> object. * @return whether the invocation sequence data object itself or some nested data element * (timerdata) provides captured parameters. */ public static boolean hasCapturedParameters(InvocationSequenceData data) { if (hasCapturedParametersInInvocationSequence(data)) { return true; } return hasTimerData(data) && (null != data.getTimerData().getParameterContentData()) && !data.getTimerData().getParameterContentData().isEmpty(); } /** * Returns the captured data of the invocation sequence. * * @param data * the <code>InvocationSequenceData</code> object. * @param sorted * if parameters should be sorted by * @return the captured data of the invocation sequence. */ public static List<ParameterContentData> getCapturedParameters(InvocationSequenceData data, boolean sorted) { if (!hasCapturedParameters(data)) { return Collections.emptyList(); } List<ParameterContentData> parameterContents = new ArrayList<ParameterContentData>(); if (CollectionUtils.isNotEmpty(data.getParameterContentData())) { for (ParameterContentData contentData : data.getParameterContentData()) { if (!parameterContents.contains(contentData)) { parameterContents.add(contentData); } } } if (hasTimerData(data)) { if (CollectionUtils.isNotEmpty(data.getTimerData().getParameterContentData())) { for (ParameterContentData contentData : data.getTimerData().getParameterContentData()) { if (!parameterContents.contains(contentData)) { parameterContents.add(contentData); } } } } if (sorted) { Collections.sort(parameterContents); } return parameterContents; } /** * Checks whether this data object contains a timer data object of some sort. * * @param data * the <code>InvocationSequenceData</code> object. * @return whether this data object contains a timer data object. */ public static boolean hasTimerData(InvocationSequenceData data) { return null != data.getTimerData(); } /** * Checks whether this data object contains a http timer data object. * * @param data * the <code>InvocationSequenceData</code> object. * @return whether this data object contains a http timer data object. */ public static boolean hasHttpTimerData(InvocationSequenceData data) { return data.getTimerData() instanceof HttpTimerData; } /** * Checks whether this data object contains a <code>LoggingData</code> object. * * @param data * the <code>InvocationSequenceData</code> object. * @return whether this data object contains a logging data object. */ public static boolean hasLoggingData(InvocationSequenceData data) { return null != data.getLoggingData(); } /** * Checks whether this data object contains exception data. * * @param data * the <code>InvocationSequenceData</code> object. * @return whether this data object contains exception data. */ public static boolean hasExceptionData(InvocationSequenceData data) { return (null != data.getExceptionSensorDataObjects()) && !data.getExceptionSensorDataObjects().isEmpty(); } /** * Checks whether this data object contains SQL data. * * @param data * the <code>InvocationSequenceData</code> object. * @return whether this data object contains SQL data. */ public static boolean hasSQLData(InvocationSequenceData data) { return (null != data.getSqlStatementData()) && (1 == data.getSqlStatementData().getCount()); } /** * If invocation has span ident connected. * * @param data * InvocationSequenceData * @return <code>true</code> if span ident exists in this invocation. */ public static boolean hasSpanIdent(InvocationSequenceData data) { return null != data.getSpanIdent(); } /** * Checks whether this data object has a parent element. * * @param data * the <code>InvocationSequenceData</code> object. * @return whether this data object has a parent element. */ public static boolean hasParentElementInSequence(InvocationSequenceData data) { return null != data.getParentSequence(); } /** * Checks whether this data object is the root element of the invocation. * * @param data * the <code>InvocationSequenceData</code> object. * @return whether this data object is the root element of the invocation. */ public static boolean isRootElementInSequence(InvocationSequenceData data) { return !hasParentElementInSequence(data); } /** * Returns root object of the sequence the given data belongs to by iterating till the tree * root. * * @param data * Invocation * @return Root invocation of the sequence given invocation belongs to. */ public static InvocationSequenceData getRootElementInSequence(InvocationSequenceData data) { InvocationSequenceData invoc = data; while (null != invoc.getParentSequence()) { invoc = invoc.getParentSequence(); } return invoc; } /** * Checks whether this data object has nested SQL statements. * * @param data * {@link InvocationSequenceData} * @return True if it has nested SQLs, false otherwise. */ public static boolean hasNestedSqlStatements(InvocationSequenceData data) { return (null != data.isNestedSqlStatements()) && data.isNestedSqlStatements().booleanValue(); } /** * Checks whether this data object has nested SQL statements. * * @param data * {@link InvocationSequenceData} * @return True if it has nested SQLs, false otherwise. */ public static boolean hasNestedExceptions(InvocationSequenceData data) { return (null != data.isNestedExceptions()) && data.isNestedExceptions().booleanValue(); } /** * Calculates the duration starting from this invocation sequence data element. * * @param data * the {@link InvocationSequenceData}s object. * @return the duration starting from this invocation sequence data element. */ public static double calculateDuration(InvocationSequenceData data) { return calculateDuration(data, null); } /** * Calculates the duration starting from this invocation sequence data element. Includes span * duration as last resource if the span ident exists on the data. * * @param data * the <code>InvocationSequenceData</code> object. * @param spanService * Span service providing the additional span information if needed. * @return the duration starting from this invocation sequence data element. */ public static double calculateDuration(InvocationSequenceData data, ISpanService spanService) { double duration = -1.0d; if (InvocationSequenceDataHelper.hasTimerData(data)) { duration = data.getTimerData().getDuration(); } else if (InvocationSequenceDataHelper.hasSQLData(data)) { duration = data.getSqlStatementData().getDuration(); } else if (InvocationSequenceDataHelper.isRootElementInSequence(data)) { duration = data.getDuration(); } else if ((null != spanService) && hasSpanIdent(data)) { Span span = spanService.get(data.getSpanIdent()); return span.getDuration(); } return duration; } /** * Computes the duration of the nested invocation elements. * * @param data * The data objects which is inspected for its nested elements. * @return The duration of all nested sequences (with their nested sequences as well). */ public static double computeNestedDuration(InvocationSequenceData data) { return computeNestedDuration(data, null); } /** * Computes the duration of the nested invocation elements. Includes span duration as last * resource if the span ident exists on the data. * * @param data * The data objects which is inspected for its nested elements. * @param spanService * Span service providing the additional span information if needed. * @return The duration of all nested sequences (with their nested sequences as well). */ public static double computeNestedDuration(InvocationSequenceData data, ISpanService spanService) { if (data.getNestedSequences().isEmpty()) { return 0; } double nestedDuration = 0d; for (InvocationSequenceData nestedData : data.getNestedSequences()) { double duration = calculateDuration(nestedData, spanService); if (duration != -1.0d) { nestedDuration += duration; } else if (!nestedData.getNestedSequences().isEmpty()) { // nothing was added, but there could be child elements with // time measurements nestedDuration += computeNestedDuration(nestedData, spanService); } } return nestedDuration; } /** * Processes all the {@link SqlStatementData}s in the given invocations creating the list of the * existing statement and calculating the total duration of the statements. * * @param invocationSequenceDataList * Input as list of invocations * @param sqlStatementDataList * List where results will be stored. Needed because of reflection. * @param totalDuration * {@link MutableDouble} where total duration will be stored. */ public static void collectSqlsInInvocations(List<InvocationSequenceData> invocationSequenceDataList, List<SqlStatementData> sqlStatementDataList, MutableDouble totalDuration) { for (InvocationSequenceData invocationSequenceData : invocationSequenceDataList) { if (null != invocationSequenceData.getSqlStatementData()) { sqlStatementDataList.add(invocationSequenceData.getSqlStatementData()); totalDuration.add(invocationSequenceData.getSqlStatementData().getDuration()); } if (CollectionUtils.isNotEmpty(invocationSequenceDataList)) { collectSqlsInInvocations(invocationSequenceData.getNestedSequences(), sqlStatementDataList, totalDuration); } } } }