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     */
017    package org.apache.logging.log4j.core.impl;
018    
019    import java.io.Serializable;
020    
021    import sun.reflect.Reflection;
022    
023    /**
024     * Wraps and extends the concept of the JRE's final class {@link StackTraceElement} by adding more location information.
025     * <p>
026     * Complements a StackTraceElement with:
027     * <ul>
028     * <li>exact: whether the class was obtained via {@link Reflection#getCallerClass()}</li>
029     * <li>location: a classpath element or a jar</li>
030     * <li>version</li>
031     * </ul>
032     * </p>
033     */
034    public final class ExtendedStackTraceElement implements Serializable {
035    
036        private static final long serialVersionUID = -2171069569241280505L;
037    
038        private final ExtendedClassInfo extraClassInfo;
039    
040        private final StackTraceElement stackTraceElement;
041    
042        public ExtendedStackTraceElement(final StackTraceElement stackTraceElement, final ExtendedClassInfo extraClassInfo) {
043            this.stackTraceElement = stackTraceElement;
044            this.extraClassInfo = extraClassInfo;
045        }
046    
047        /**
048         * Called from Jackson for XML and JSON IO.
049         */
050        public ExtendedStackTraceElement(final String declaringClass, final String methodName, final String fileName,
051                final int lineNumber, final boolean exact, final String location, final String version) {
052            this(new StackTraceElement(declaringClass, methodName, fileName, lineNumber), new ExtendedClassInfo(exact,
053                    location, version));
054        }
055    
056        @Override
057        public boolean equals(final Object obj) {
058            if (this == obj) {
059                return true;
060            }
061            if (obj == null) {
062                return false;
063            }
064            if (!(obj instanceof ExtendedStackTraceElement)) {
065                return false;
066            }
067            final ExtendedStackTraceElement other = (ExtendedStackTraceElement) obj;
068            if (this.extraClassInfo == null) {
069                if (other.extraClassInfo != null) {
070                    return false;
071                }
072            } else if (!this.extraClassInfo.equals(other.extraClassInfo)) {
073                return false;
074            }
075            if (this.stackTraceElement == null) {
076                if (other.stackTraceElement != null) {
077                    return false;
078                }
079            } else if (!this.stackTraceElement.equals(other.stackTraceElement)) {
080                return false;
081            }
082            return true;
083        }
084    
085        public String getClassName() {
086            return this.stackTraceElement.getClassName();
087        }
088    
089        public boolean getExact() {
090            return this.extraClassInfo.getExact();
091        }
092    
093        public ExtendedClassInfo getExtraClassInfo() {
094            return this.extraClassInfo;
095        }
096    
097        public String getFileName() {
098            return this.stackTraceElement.getFileName();
099        }
100    
101        public int getLineNumber() {
102            return this.stackTraceElement.getLineNumber();
103        }
104    
105        public String getLocation() {
106            return this.extraClassInfo.getLocation();
107        }
108    
109        public String getMethodName() {
110            return this.stackTraceElement.getMethodName();
111        }
112    
113        public StackTraceElement getStackTraceElement() {
114            return this.stackTraceElement;
115        }
116    
117        public String getVersion() {
118            return this.extraClassInfo.getVersion();
119        }
120    
121        @Override
122        public int hashCode() {
123            final int prime = 31;
124            int result = 1;
125            result = prime * result + ((this.extraClassInfo == null) ? 0 : this.extraClassInfo.hashCode());
126            result = prime * result + ((this.stackTraceElement == null) ? 0 : this.stackTraceElement.hashCode());
127            return result;
128        }
129    
130        public boolean isNativeMethod() {
131            return this.stackTraceElement.isNativeMethod();
132        }
133    
134        @Override
135        public String toString() {
136            final StringBuilder sb = new StringBuilder();
137            sb.append(this.stackTraceElement);
138            sb.append(" ");
139            sb.append(this.extraClassInfo);
140            return sb.toString();
141        }
142    }