001package com.avaje.ebean.bean; 002 003import java.io.Serializable; 004import java.util.Arrays; 005 006/** 007 * Represent the call stack (stack trace elements). 008 * <p> 009 * Used with a query to identify a CallStackQuery for AutoTune automatic query 010 * tuning. 011 * </p> 012 * <p> 013 * This is used so that a single query called from different methods can be 014 * tuned for each different call stack. 015 * </p> 016 * <p> 017 * Note the call stack is trimmed to remove the common ebean internal elements. 018 * </p> 019 */ 020public final class CallStack implements Serializable { 021 022 private static final long serialVersionUID = -8590644046907438579L; 023 024 private final String zeroHash; 025 private final String pathHash; 026 027 private final StackTraceElement[] callStack; 028 029 public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) { 030 this.callStack = callStack; 031 this.zeroHash = enc(zeroHash); 032 this.pathHash = enc(pathHash); 033 } 034 035 public int hashCode() { 036 int hc = 0; 037 for (int i = 0; i < callStack.length; i++) { 038 hc = 31 * hc + callStack[i].hashCode(); 039 } 040 return hc; 041 } 042 043 public boolean equals(Object obj) { 044 if (obj == this) { 045 return true; 046 } 047 if (!(obj instanceof CallStack)) { 048 return false; 049 } 050 CallStack e = (CallStack) obj; 051 return Arrays.equals(callStack, e.callStack); 052 } 053 054 /** 055 * Return the first element of the call stack. 056 */ 057 public StackTraceElement getFirstStackTraceElement() { 058 return callStack[0]; 059 } 060 061 /** 062 * Return the call stack. 063 */ 064 public StackTraceElement[] getCallStack() { 065 return callStack; 066 } 067 068 /** 069 * Return the hash for the first stack element. 070 */ 071 public String getZeroHash() { 072 return zeroHash; 073 } 074 075 /** 076 * Return the hash for the stack elements (excluding first stack element). 077 */ 078 public String getPathHash() { 079 return pathHash; 080 } 081 082 public String toString() { 083 return zeroHash + ":" + pathHash + ":" + callStack[0]; 084 } 085 086 /** 087 * Return the call stack lines appended with the given newLine string. 088 */ 089 public String description(String newLine) { 090 StringBuilder sb = new StringBuilder(400); 091 for (int i = 0; i < callStack.length; i++) { 092 sb.append(callStack[i].toString()).append(newLine); 093 } 094 return sb.toString(); 095 } 096 097 public String getOriginKey(int queryHash) { 098 return enc(queryHash)+ "." + zeroHash + "." + pathHash; 099 } 100 101 private static final int radix = 1 << 6; 102 private static final int mask = radix - 1; 103 104 /** 105 * Convert the integer to unsigned base 64. 106 */ 107 public static String enc(int i) { 108 char[] buf = new char[32]; 109 int charPos = 32; 110 do { 111 buf[--charPos] = intToBase64[i & mask]; 112 i >>>= 6; 113 } while (i != 0); 114 115 return new String(buf, charPos, (32 - charPos)); 116 } 117 118 private static final char intToBase64[] = { 119 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 120 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 121 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 122 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 123 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' 124 }; 125}