package rocks.inspectit.shared.cs.ci.business.impl; import java.util.UUID; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlRootElement; import org.apache.commons.lang.StringUtils; import rocks.inspectit.shared.all.cmr.service.ICachedDataService; import rocks.inspectit.shared.all.communication.data.InvocationSequenceData; import rocks.inspectit.shared.cs.ci.business.expression.AbstractExpression; import rocks.inspectit.shared.cs.ci.business.expression.impl.BooleanExpression; import rocks.inspectit.shared.cs.ci.business.expression.impl.NameExtractionExpression; /** * Configuration element defining a business transaction context. * * @author Alexander Wert * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "business-transaction") public class BusinessTransactionDefinition implements IMatchingRuleProvider { /** * The name of the default business transaction. */ public static final String UNKNOWN_BUSINESS_TX = "Unknown Transaction"; /** * The default identifier. */ public static final int DEFAULT_ID = 0; /** * Default {@link BusinessTransactionDefinition} instance. */ public static final BusinessTransactionDefinition DEFAULT_BUSINESS_TRANSACTION_DEFINITION = new BusinessTransactionDefinition(BusinessTransactionDefinition.DEFAULT_ID, UNKNOWN_BUSINESS_TX, new BooleanExpression(true, true)); /** * Identifier of the business transaction. Needs to be unique! */ @XmlAttribute(name = "id", required = true) private int id = (int) UUID.randomUUID().getMostSignificantBits(); /** * Name of the business transaction. Needs to be unique! */ @XmlAttribute(name = "name", required = true) private String businessTransactionDefinitionName; /** * Source of the string value to be compared against the snippet. */ @XmlElementRef(name = "nameExtractionExpression", required = false) private NameExtractionExpression nameExtractionExpression; /** * Description. */ @XmlAttribute(name = "description") private String description; /** * Rule definition for matching measurement data to business transactions. */ @XmlElementRef private AbstractExpression matchingRuleExpression = new BooleanExpression(false); /** * Default Constructor. */ public BusinessTransactionDefinition() { } /** * Constructor. * * @param businessTransactionName * name of the business transaction */ public BusinessTransactionDefinition(String businessTransactionName) { this.businessTransactionDefinitionName = businessTransactionName; } /** * Constructor. * * @param id * unique identifier to use for the {@link BusinessTransactionDefinition} * @param businessTransactionName * name of the business transaction * @param matchingRuleExpression * matching rule to use for recognition of this business transaction */ public BusinessTransactionDefinition(int id, String businessTransactionName, AbstractExpression matchingRuleExpression) { this(businessTransactionName); this.matchingRuleExpression = matchingRuleExpression; this.id = id; } /** * Indicates whether the name of the business transaction shell be extracted dynamically from * the measurement data. * * @return true, if dynamic extraction shell be used. */ public boolean dynamicNameExtractionActive() { return null != getNameExtractionExpression(); } /** * Determines the business transaction name for the given {@link InvocationSequenceData} using * the passed {@link BusinessTransactionDefinition}. * * @param invocSequence * {@link InvocationSequenceData} to determine the business transaction name for. * @param cachedDataService * {@link ICachedDataService} instance for retrieving method names, etc. * @return a business transaction name */ public String determineBusinessTransactionName(InvocationSequenceData invocSequence, ICachedDataService cachedDataService) { String businessTxName; if (dynamicNameExtractionActive()) { businessTxName = extractNameDynamically(invocSequence, cachedDataService, 0); if (null == businessTxName) { businessTxName = getBusinessTransactionDefinitionName() + NameExtractionExpression.UNKNOWN_DYNAMIC_BUSINESS_TRANSACTION_POSTFIX; } else if (StringUtils.isEmpty(businessTxName)) { businessTxName = getBusinessTransactionDefinitionName() + NameExtractionExpression.EMPTY_DYNAMIC_BUSINESS_TRANSACTION_POSTFIX; } } else { businessTxName = getBusinessTransactionDefinitionName(); } return businessTxName; } /** * Extracts the business transaction name dynamically from the {@link InvocationSequenceData} by * recursively iterating over the invocation sequence. * * @param invocSequence * {@link InvocationSequenceData} to extract the business transaction from. * @param cachedDataService * {@link ICachedDataService} instance for retrieving method names, etc. * @param depth * current recursion depth. THis is used stop the recursion at a specified maximum * search depth. * @return extracted name */ private String extractNameDynamically(InvocationSequenceData invocSequence, ICachedDataService cachedDataService, int depth) { String name = getNameExtractionExpression().extractName(invocSequence, cachedDataService); if ((null == name) && (null != invocSequence.getNestedSequences())) { if ((getNameExtractionExpression().getMaxSearchDepth() < 0) || (depth < getNameExtractionExpression().getMaxSearchDepth())) { for (InvocationSequenceData child : invocSequence.getNestedSequences()) { name = extractNameDynamically(child, cachedDataService, depth + 1); if (null != name) { return name; } } } } return name; } /** * {@inheritDoc} */ @Override public boolean isChangeable() { return getId() != DEFAULT_ID; } /** * Returns the name of the business transaction. * * @return the name of the business transaction */ public String getBusinessTransactionDefinitionName() { return businessTransactionDefinitionName; } /** * Sets the name of the business transaction. * * @param businessTransactionName * New value for the name of the business transaction */ public void setBusinessTransactionDefinitionName(String businessTransactionName) { this.businessTransactionDefinitionName = businessTransactionName; } /** * {@inheritDoc} */ @Override public AbstractExpression getMatchingRuleExpression() { return matchingRuleExpression; } /** * {@inheritDoc} */ @Override public void setMatchingRuleExpression(AbstractExpression matchingRuleExpression) { this.matchingRuleExpression = matchingRuleExpression; } /** * Returns the identifier of this business transaction. * * @return Returns the identifier of this business transaction */ public int getId() { return id; } /** * Returns the description text. * * @return Returns the description text. */ public String getDescription() { return description; } /** * Sets the description text. * * @param description * New value for the description text. */ public void setDescription(String description) { this.description = description; } /** * Gets {@link #nameExtractionExpression}. * * @return {@link #nameExtractionExpression} */ public NameExtractionExpression getNameExtractionExpression() { return nameExtractionExpression; } /** * Sets {@link #nameExtractionExpression}. * * @param nameExtractionExpression * New value for {@link #nameExtractionExpression} */ public void setNameExtractionExpression(NameExtractionExpression nameExtractionExpression) { this.nameExtractionExpression = nameExtractionExpression; } /** * {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = (prime * result) + id; return result; } /** * {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } BusinessTransactionDefinition other = (BusinessTransactionDefinition) obj; if (id != other.id) { return false; } return true; } }