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}