001package io.ebean.bean;
002
003import java.io.Serializable;
004import java.util.Arrays;
005
006import static io.ebean.util.EncodeB64.enc;
007
008/**
009 * Represent the call stack (stack trace elements).
010 * <p>
011 * Used with a query to identify a CallStackQuery for AutoTune automatic query
012 * tuning.
013 * </p>
014 * <p>
015 * This is used so that a single query called from different methods can be
016 * tuned for each different call stack.
017 * </p>
018 * <p>
019 * Note the call stack is trimmed to remove the common ebean internal elements.
020 * </p>
021 */
022public final class CallStack implements Serializable, CallOrigin {
023
024  private static final long serialVersionUID = -8590644046907438579L;
025
026  private static final String NEWLINE = "\n";
027
028  private final String zeroHash;
029  private final String pathHash;
030  private final StackTraceElement[] callStack;
031  private final int hc;
032
033  public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
034    this.callStack = callStack;
035    this.zeroHash = enc(zeroHash);
036    this.pathHash = enc(pathHash);
037    this.hc = computeHashCode();
038  }
039
040  private int computeHashCode() {
041    int hc = 0;
042    for (StackTraceElement element : callStack) {
043      hc = 92821 * hc + element.hashCode();
044    }
045    return hc;
046  }
047
048  @Override
049  public String toString() {
050    return zeroHash + ":" + pathHash + ":" + callStack[0];
051  }
052
053  @Override
054  public int hashCode() {
055    return hc;
056  }
057
058  @Override
059  public boolean equals(Object obj) {
060    if (obj == this) {
061      return true;
062    }
063    if (!(obj instanceof CallStack)) {
064      return false;
065    }
066    CallStack e = (CallStack) obj;
067    return Arrays.equals(callStack, e.callStack);
068  }
069
070  /**
071   * Return the first element of the call stack.
072   */
073  @Override
074  public String getTopElement() {
075    return callStack[0].toString();
076  }
077
078  /**
079   * Return the call stack lines appended with the given newLine string.
080   */
081  @Override
082  public String getFullDescription() {
083    StringBuilder sb = new StringBuilder(400);
084    for (int i = 0; i < callStack.length; i++) {
085      if (i > 0) {
086        sb.append(NEWLINE);
087      }
088      sb.append(callStack[i].toString());
089    }
090    return sb.toString();
091  }
092
093  @Override
094  public String getOriginKey(int queryHash) {
095    return enc(queryHash) + "." + zeroHash + "." + pathHash;
096  }
097
098}