001/*
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v2.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.classic.spi;
015
016import java.io.Serializable;
017import java.util.Arrays;
018
019public class ThrowableProxyVO implements IThrowableProxy, Serializable {
020
021    private static final long serialVersionUID = -773438177285807139L;
022
023    private String className;
024    private String overridingMessage;
025    private String message;
026    private int commonFramesCount;
027    private StackTraceElementProxy[] stackTraceElementProxyArray;
028    private IThrowableProxy cause;
029    private IThrowableProxy[] suppressed;
030    private boolean cyclic;
031
032    public String getMessage() {
033        return message;
034    }
035    /**
036     * Return the overriding message if any. This method returns null
037     * if there is no overriding message.
038     *
039     * <p>Overriding message exists only if the original throwable implementation overrides the toString() method.</p>
040     *
041     * @return the overriding message or null
042     * @since 1.5.22
043     */
044    @Override
045    public String getOverridingMessage() { return overridingMessage;}
046
047    public String getClassName() {
048        return className;
049    }
050
051    public int getCommonFrames() {
052        return commonFramesCount;
053    }
054
055    public IThrowableProxy getCause() {
056        return cause;
057    }
058
059    public StackTraceElementProxy[] getStackTraceElementProxyArray() {
060        return stackTraceElementProxyArray;
061    }
062
063    public IThrowableProxy[] getSuppressed() {
064        return suppressed;
065    }
066
067    public boolean isCyclic() {
068        return cyclic;
069    }
070
071    /**
072     * Returns a new {@link ThrowableProxyVOBuilder} for constructing a
073     * {@link ThrowableProxyVO} field by field.
074     *
075     * <p>This is a supplement to {@link #build(IThrowableProxy)}, which copies
076     * an existing {@link IThrowableProxy} in one step.</p>
077     *
078     * @return a new builder instance
079     * @since 1.6.2
080     */
081    public static ThrowableProxyVOBuilder builder() {
082        return new ThrowableProxyVOBuilder();
083    }
084
085    // package-private setters used by ThrowableProxyVOBuilder
086
087    void setClassName(String className) {
088        this.className = className;
089    }
090
091    void setMessage(String message) {
092        this.message = message;
093    }
094
095    void setOverridingMessage(String overridingMessage) {
096        this.overridingMessage = overridingMessage;
097    }
098
099    void setCommonFramesCount(int commonFramesCount) {
100        this.commonFramesCount = commonFramesCount;
101    }
102
103    void setStackTraceElementProxyArray(StackTraceElementProxy[] stackTraceElementProxyArray) {
104        this.stackTraceElementProxyArray = stackTraceElementProxyArray;
105    }
106
107    void setCause(IThrowableProxy cause) {
108        this.cause = cause;
109    }
110
111    void setSuppressed(IThrowableProxy[] suppressed) {
112        this.suppressed = suppressed;
113    }
114
115    void setCyclic(boolean cyclic) {
116        this.cyclic = cyclic;
117    }
118
119    @Override
120    public int hashCode() {
121        final int prime = 31;
122        int result = 1;
123        result = prime * result + ((className == null) ? 0 : className.hashCode());
124        return result;
125    }
126
127    @Override
128    public boolean equals(Object obj) {
129        if (this == obj)
130            return true;
131        if (obj == null)
132            return false;
133        if (getClass() != obj.getClass())
134            return false;
135        final ThrowableProxyVO other = (ThrowableProxyVO) obj;
136
137        if (className == null) {
138            if (other.className != null)
139                return false;
140        } else if (!className.equals(other.className))
141            return false;
142
143        if (!Arrays.equals(stackTraceElementProxyArray, other.stackTraceElementProxyArray))
144            return false;
145
146        if (!Arrays.equals(suppressed, other.suppressed))
147            return false;
148
149        if (cause == null) {
150            if (other.cause != null)
151                return false;
152        } else if (!cause.equals(other.cause))
153            return false;
154
155        return true;
156    }
157
158    public static ThrowableProxyVO build(IThrowableProxy throwableProxy) {
159        if (throwableProxy == null) {
160            return null;
161        }
162        ThrowableProxyVO tpvo = new ThrowableProxyVO();
163        tpvo.className = throwableProxy.getClassName();
164        tpvo.message = throwableProxy.getMessage();
165        tpvo.overridingMessage = throwableProxy.getOverridingMessage();
166        tpvo.commonFramesCount = throwableProxy.getCommonFrames();
167        tpvo.stackTraceElementProxyArray = throwableProxy.getStackTraceElementProxyArray();
168        tpvo.cyclic = throwableProxy.isCyclic();
169
170        IThrowableProxy cause = throwableProxy.getCause();
171        if (cause != null) {
172            tpvo.cause = ThrowableProxyVO.build(cause);
173        }
174        IThrowableProxy[] suppressed = throwableProxy.getSuppressed();
175        if (suppressed != null) {
176            tpvo.suppressed = new IThrowableProxy[suppressed.length];
177            for (int i = 0; i < suppressed.length; i++) {
178                tpvo.suppressed[i] = ThrowableProxyVO.build(suppressed[i]);
179            }
180        }
181
182        return tpvo;
183    }
184}