package rocks.inspectit.shared.all.communication.data; import java.io.Serializable; import java.sql.Timestamp; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.Entity; import javax.persistence.Transient; import org.codehaus.jackson.annotate.JsonAutoDetect; import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility; import org.codehaus.jackson.annotate.JsonIgnore; import rocks.inspectit.shared.all.cmr.cache.IObjectSizes; import rocks.inspectit.shared.all.communication.MethodSensorData; /** * This is an abstract class for all object that can be found in invocations and should be aware of * it. * * @author Ivan Senic * */ @Entity @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE) public abstract class InvocationAwareData extends MethodSensorData { /** * The serial version uid for this class. */ private static final long serialVersionUID = 1321146768671989693L; /** * Map<Long, MutableInt> that contains the ID of invocation as a key and numbers of object * appearances in this invocation. */ @Transient @JsonIgnore private Map<Long, MutableInt> invocationsParentsIdMap; /** * Default no-args constructor. */ public InvocationAwareData() { } /** * Creates a new instance. * * @param timeStamp * the timestamp. * @param platformIdent * the platform identifier. * @param sensorTypeIdent * the sensor type identifier. * @param methodIdent * the method identifier. */ public InvocationAwareData(Timestamp timeStamp, long platformIdent, long sensorTypeIdent, long methodIdent) { super(timeStamp, platformIdent, sensorTypeIdent, methodIdent); } /** * Creates a new instance. * * @param timeStamp * the timestamp. * @param platformIdent * the platform identifier. * @param sensorTypeIdent * the sensor type identifier. * @param methodIdent * the method identifier. * @param parameterContentData * the parameter contents. */ public InvocationAwareData(Timestamp timeStamp, long platformIdent, long sensorTypeIdent, long methodIdent, List<ParameterContentData> parameterContentData) { super(timeStamp, platformIdent, sensorTypeIdent, methodIdent, parameterContentData); } /** * Adds one invocation sequence data ID to the set of invocation IDs where this object is found. * * @param id * Invocation id. */ public void addInvocationParentId(Long id) { if (null != id) { if (null == invocationsParentsIdMap) { invocationsParentsIdMap = new HashMap<Long, MutableInt>(); } MutableInt count = invocationsParentsIdMap.get(id); if (null != count) { count.increase(); } else { invocationsParentsIdMap.put(id, new MutableInt(1)); } } } /** * Returns set of invocation parents IDS. * * @return Returns set of invocation parents IDS. */ public Set<Long> getInvocationParentsIdSet() { if (null != invocationsParentsIdMap) { return invocationsParentsIdMap.keySet(); } else { return Collections.emptySet(); } } /** * Gets {@link #invocationsParentsIdMap}. * * @return {@link #invocationsParentsIdMap} */ public Map<Long, MutableInt> getInvocationsParentsIdMap() { return invocationsParentsIdMap; } /** * Sets {@link #invocationsParentsIdMap}. * * @param invocationsParentsIdMap * New value for {@link #invocationsParentsIdMap} */ public void setInvocationsParentsIdMap(Map<Long, MutableInt> invocationsParentsIdMap) { this.invocationsParentsIdMap = invocationsParentsIdMap; } /** * Returns how much objects are contained in the invocation parents. * * @return Returns how much objects are contained in the invocation parents. */ public int getObjectsInInvocationsCount() { int count = 0; if (null != invocationsParentsIdMap) { for (MutableInt parentId : invocationsParentsIdMap.values()) { count += parentId.getValue(); } } return count; } /** * Aggregates the data correlated to the invocation parents. Note that this method has to be * called from the subclasses when they implement any kind of aggregation. * * @param invocationAwareData * Data to aggregate to current object. */ public void aggregateInvocationAwareData(InvocationAwareData invocationAwareData) { if (null != invocationAwareData.getInvocationsParentsIdMap()) { if (null == invocationsParentsIdMap) { invocationsParentsIdMap = new HashMap<Long, MutableInt>(); } for (Map.Entry<Long, MutableInt> entry : invocationAwareData.getInvocationsParentsIdMap().entrySet()) { MutableInt count = invocationsParentsIdMap.get(entry.getKey()); if (null != count) { count.add(entry.getValue().getValue()); } else { invocationsParentsIdMap.put(entry.getKey(), new MutableInt(entry.getValue().getValue())); } } } } /** * Returns the percentage of objects that are found in invocations as double. * * @return Double ranging from 0 to 1. */ @JsonIgnore public abstract double getInvocationAffiliationPercentage(); /** * {@inheritDoc} */ public boolean isOnlyFoundInInvocations() { return getInvocationAffiliationPercentage() == 1d; } /** * {@inheritDoc} */ public boolean isOnlyFoundOutsideInvocations() { return getInvocationAffiliationPercentage() == 0d; } /** * {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = (prime * result) + ((invocationsParentsIdMap == null) ? 0 : invocationsParentsIdMap.hashCode()); return result; } /** * {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } InvocationAwareData other = (InvocationAwareData) obj; if (invocationsParentsIdMap == null) { if (other.invocationsParentsIdMap != null) { return false; } } else if (!invocationsParentsIdMap.equals(other.invocationsParentsIdMap)) { return false; } return true; } /** * {@inheritDoc} */ @Override public long getObjectSize(IObjectSizes objectSizes, boolean doAlign) { long size = super.getObjectSize(objectSizes, doAlign); size += objectSizes.getPrimitiveTypesSize(1, 0, 0, 0, 0, 0); if (null != invocationsParentsIdMap) { size += objectSizes.getSizeOfHashMap(invocationsParentsIdMap.size()); size += invocationsParentsIdMap.size() * objectSizes.getSizeOfLongObject(); long sizeOfMutableInt = objectSizes.alignTo8Bytes(objectSizes.getSizeOfObjectHeader() + objectSizes.getPrimitiveTypesSize(0, 0, 1, 0, 0, 0)); size += invocationsParentsIdMap.size() * sizeOfMutableInt; } if (doAlign) { return objectSizes.alignTo8Bytes(size); } else { return size; } } /** * Simple mutable integer class for internal purposes. * * @author Ivan Senic * */ public static class MutableInt implements Serializable { /** * Generated UID. */ private static final long serialVersionUID = -2367937702260302863L; /** * Value. */ private int value; /** * No-arg constructor for serialization. */ public MutableInt() { } /** * Constructor that sets initial value. * * @param value * Initial value. */ public MutableInt(int value) { this.value = value; } /** * @return the value */ public int getValue() { return value; } /** * Increases the value. */ public void increase() { value++; } /** * Adds delta to the value. * * @param delta * Delta. */ public void add(int delta) { value += delta; } /** * {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = (prime * result) + value; 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; } MutableInt other = (MutableInt) obj; if (value != other.value) { return false; } return true; } } }