001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.impl; 018 019import java.io.Serializable; 020 021import org.apache.logging.log4j.core.pattern.PlainTextRenderer; 022import org.apache.logging.log4j.core.pattern.TextRenderer; 023 024/** 025 * Wraps and extends the concept of the JRE's final class {@link StackTraceElement} by adding more location information. 026 * <p> 027 * Complements a StackTraceElement with: 028 * </p> 029 * <ul> 030 * <li>exact: whether the class was obtained via {@link sun.reflect.Reflection#getCallerClass(int)}</li> 031 * <li>location: a classpath element or a jar</li> 032 * <li>version</li> 033 * </ul> 034 */ 035public final class ExtendedStackTraceElement implements Serializable { 036 037 private static final long serialVersionUID = -2171069569241280505L; 038 039 private final ExtendedClassInfo extraClassInfo; 040 041 private final StackTraceElement stackTraceElement; 042 043 public ExtendedStackTraceElement(final StackTraceElement stackTraceElement, 044 final ExtendedClassInfo extraClassInfo) { 045 this.stackTraceElement = stackTraceElement; 046 this.extraClassInfo = extraClassInfo; 047 } 048 049 /** 050 * Called from Jackson for XML and JSON IO. 051 */ 052 public ExtendedStackTraceElement(final String declaringClass, final String methodName, final String fileName, 053 final int lineNumber, final boolean exact, final String location, final String version) { 054 this(new StackTraceElement(declaringClass, methodName, fileName, lineNumber), 055 new ExtendedClassInfo(exact, location, version)); 056 } 057 058 @Override 059 public boolean equals(final Object obj) { 060 if (this == obj) { 061 return true; 062 } 063 if (obj == null) { 064 return false; 065 } 066 if (!(obj instanceof ExtendedStackTraceElement)) { 067 return false; 068 } 069 final ExtendedStackTraceElement other = (ExtendedStackTraceElement) obj; 070 if (this.extraClassInfo == null) { 071 if (other.extraClassInfo != null) { 072 return false; 073 } 074 } else if (!this.extraClassInfo.equals(other.extraClassInfo)) { 075 return false; 076 } 077 if (this.stackTraceElement == null) { 078 if (other.stackTraceElement != null) { 079 return false; 080 } 081 } else if (!this.stackTraceElement.equals(other.stackTraceElement)) { 082 return false; 083 } 084 return true; 085 } 086 087 public String getClassName() { 088 return this.stackTraceElement.getClassName(); 089 } 090 091 public boolean getExact() { 092 return this.extraClassInfo.getExact(); 093 } 094 095 public ExtendedClassInfo getExtraClassInfo() { 096 return this.extraClassInfo; 097 } 098 099 public String getFileName() { 100 return this.stackTraceElement.getFileName(); 101 } 102 103 public int getLineNumber() { 104 return this.stackTraceElement.getLineNumber(); 105 } 106 107 public String getLocation() { 108 return this.extraClassInfo.getLocation(); 109 } 110 111 public String getMethodName() { 112 return this.stackTraceElement.getMethodName(); 113 } 114 115 public StackTraceElement getStackTraceElement() { 116 return this.stackTraceElement; 117 } 118 119 public String getVersion() { 120 return this.extraClassInfo.getVersion(); 121 } 122 123 @Override 124 public int hashCode() { 125 final int prime = 31; 126 int result = 1; 127 result = prime * result + ((this.extraClassInfo == null) ? 0 : this.extraClassInfo.hashCode()); 128 result = prime * result + ((this.stackTraceElement == null) ? 0 : this.stackTraceElement.hashCode()); 129 return result; 130 } 131 132 public boolean isNativeMethod() { 133 return this.stackTraceElement.isNativeMethod(); 134 } 135 136 void renderOn(final StringBuilder output, final TextRenderer textRenderer) { 137 render(this.stackTraceElement, output, textRenderer); 138 textRenderer.render(" ", output, "Text"); 139 this.extraClassInfo.renderOn(output, textRenderer); 140 } 141 142 private void render(final StackTraceElement stElement, final StringBuilder output, final TextRenderer textRenderer) { 143 final String fileName = stElement.getFileName(); 144 final int lineNumber = stElement.getLineNumber(); 145 textRenderer.render(getClassName(), output, "StackTraceElement.ClassName"); 146 textRenderer.render(".", output, "StackTraceElement.ClassMethodSeparator"); 147 textRenderer.render(stElement.getMethodName(), output, "StackTraceElement.MethodName"); 148 if (stElement.isNativeMethod()) { 149 textRenderer.render("(Native Method)", output, "StackTraceElement.NativeMethod"); 150 } else if (fileName != null && lineNumber >= 0) { 151 textRenderer.render("(", output, "StackTraceElement.Container"); 152 textRenderer.render(fileName, output, "StackTraceElement.FileName"); 153 textRenderer.render(":", output, "StackTraceElement.ContainerSeparator"); 154 textRenderer.render(Integer.toString(lineNumber), output, "StackTraceElement.LineNumber"); 155 textRenderer.render(")", output, "StackTraceElement.Container"); 156 } else if (fileName != null) { 157 textRenderer.render("(", output, "StackTraceElement.Container"); 158 textRenderer.render(fileName, output, "StackTraceElement.FileName"); 159 textRenderer.render(")", output, "StackTraceElement.Container"); 160 } else { 161 textRenderer.render("(", output, "StackTraceElement.Container"); 162 textRenderer.render("Unknown Source", output, "StackTraceElement.UnknownSource"); 163 textRenderer.render(")", output, "StackTraceElement.Container"); 164 } 165 } 166 167 @Override 168 public String toString() { 169 final StringBuilder sb = new StringBuilder(); 170 renderOn(sb, PlainTextRenderer.getInstance()); 171 return sb.toString(); 172 } 173 174}