/**
* Copyright 2014 SAP AG
*
* Licensed 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.spotter.ext.detection.est;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Trace representation.
*
* @author Alexander Wert
*
*/
public class Trace implements Iterable<Trace> {
private static final int HASH_CONSTANT_2 = 1237;
private static final int HASH_CONSTANT_1 = 1231;
private List<Trace> subTraces;
private Trace parent;
private String methodName;
private long startTime;
private long exitTime;
private boolean sendMethod;
private long overhead;
private long payload;
/**
* Constructor.
*/
public Trace() {
setParent(null);
}
/**
* Constructor.
*
* @param parent
* parent method
*/
public Trace(Trace parent) {
setParent(parent);
}
/**
* Constructor.
*
* @param methodName
* name of the current method
*/
public Trace(String methodName) {
setParent(null);
setMethodName(methodName);
}
/**
* Constructor.
*
* @param methodName
* name of the current method
* @param parent
* parent method
*/
public Trace(Trace parent, String methodName) {
setParent(parent);
setMethodName(methodName);
}
/**
* @return the subTraces
*/
public List<Trace> getSubTraces() {
if (subTraces == null) {
subTraces = new ArrayList<>();
}
return subTraces;
}
/**
* @return the methodName
*/
public String getMethodName() {
return methodName;
}
/**
* @param methodName
* the methodName to set
*/
public void setMethodName(String methodName) {
this.methodName = methodName;
}
/**
* @return the startTime
*/
public long getStartTime() {
return startTime;
}
/**
* @param startTime
* the startTime to set
*/
public void setStartTime(long startTime) {
this.startTime = startTime;
}
/**
* @return the exitTime
*/
public long getExitTime() {
return exitTime;
}
/**
* @param exitTime
* the exitTime to set
*/
public void setExitTime(long exitTime) {
this.exitTime = exitTime;
}
/**
* @return the parent
*/
public Trace getParent() {
return parent;
}
/**
* @param parent
* the parent to set
*/
public void setParent(Trace parent) {
this.parent = parent;
if (parent != null && !parent.getSubTraces().contains(this)) {
parent.getSubTraces().add(this);
}
}
@Override
public String toString() {
int depth = 0;
Trace parent = getParent();
while (parent != null) {
depth++;
parent = parent.getParent();
}
StringBuilder indention = new StringBuilder();
for (int i = 0; i < depth; i++) {
indention.append(" ");
}
StringBuilder strBuilder = new StringBuilder();
strBuilder.append(indention.toString());
strBuilder.append(getMethodName());
strBuilder.append("\n");
for (Trace child : getSubTraces()) {
strBuilder.append(child.toString());
}
return strBuilder.toString();
}
/**
*
* @param other
* trace to compare with
* @return returns true if other trace represents the same operation
* sequence
*/
public boolean similarTrace(Trace other) {
if (!getMethodName().equals(other.getMethodName())) {
return false;
}
for (int i = 0; i < getSubTraces().size(); i++) {
if (!getSubTraces().get(i).similarTrace(other.getSubTraces().get(i))) {
return false;
}
}
return true;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((methodName == null) ? 0 : methodName.hashCode());
result = prime * result + (sendMethod ? HASH_CONSTANT_1 : HASH_CONSTANT_2);
result = prime * result + ((subTraces == null) ? 0 : subTraces.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Trace other = (Trace) obj;
if (methodName == null) {
if (other.methodName != null) {
return false;
}
} else if (!methodName.equals(other.methodName)) {
return false;
}
if (sendMethod != other.sendMethod) {
return false;
}
if (subTraces == null) {
if (other.subTraces != null) {
return false;
}
} else if (!subTraces.equals(other.subTraces)) {
return false;
}
return true;
}
@Override
public Iterator<Trace> iterator() {
return new TraceIterator(this);
}
/**
* @return the sendMethod
*/
public boolean isSendMethod() {
return sendMethod;
}
/**
* @param sendMethod
* the sendMethod to set
*/
public void setSendMethod(boolean sendMethod) {
this.sendMethod = sendMethod;
}
/**
* @return the overhead
*/
public long getOverhead() {
return overhead;
}
/**
* @param overhead
* the overhead to set
*/
public void setOverhead(long overhead) {
this.overhead = overhead;
}
/**
* @return the payload
*/
public long getPayload() {
return payload;
}
/**
* @param payload
* the payload to set
*/
public void setPayload(long payload) {
this.payload = payload;
}
/**
* Iterator for the trace object.
*
* @author Alexander Wert
*
*/
public class TraceIterator implements Iterator<Trace> {
private Trace originTrace;
private Trace currentTrace;
private Map<Integer, Integer> levelChildMapping;
private int currentLevel = 0;
private boolean finished = false;
/**
* Constructor.
*
* @param trace
* trace to iterate over.
*/
public TraceIterator(Trace trace) {
this.originTrace = trace;
this.currentTrace = trace;
levelChildMapping = new HashMap<>();
}
@Override
public boolean hasNext() {
if (finished) {
return false;
}
return currentTrace != null;
}
@Override
public Trace next() {
if (finished) {
return null;
}
Trace result = currentTrace;
prepareNext();
return result;
}
private void prepareNext() {
if (currentTrace != null) {
if (!levelChildMapping.containsKey(currentLevel)) {
levelChildMapping.put(currentLevel, 0);
}
int currentChildIndex = levelChildMapping.get(currentLevel);
Trace tempTrace = currentTrace;
while (tempTrace.getSubTraces().size() <= currentChildIndex) {
if (tempTrace == originTrace) {
break;
}
levelChildMapping.remove(currentLevel);
currentLevel--;
tempTrace = tempTrace.getParent();
currentChildIndex = levelChildMapping.get(currentLevel);
}
if (tempTrace.getSubTraces().size() <= currentChildIndex) {
finished = true;
currentTrace = null;
return;
}
currentTrace = tempTrace.getSubTraces().get(currentChildIndex);
levelChildMapping.put(currentLevel, currentChildIndex + 1);
currentLevel++;
return;
}
}
@Override
public void remove() {
// not supported
}
}
}