001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, 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 v1.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.core.status;
015
016import java.util.ArrayList;
017import java.util.Iterator;
018import java.util.List;
019import java.util.Objects;
020
021abstract public class StatusBase implements Status {
022
023    static private final List<Status> EMPTY_LIST = new ArrayList<Status>(0);
024
025    int level;
026    final String message;
027    final Object origin;
028    List<Status> childrenList;
029    Throwable throwable;
030    long timestamp;
031
032    StatusBase(int level, String msg, Object origin) {
033        this(level, msg, origin, null);
034    }
035
036    StatusBase(int level, String msg, Object origin, Throwable t) {
037        this.level = level;
038        this.message = msg;
039        this.origin = origin;
040        this.throwable = t;
041        this.timestamp = System.currentTimeMillis();
042    }
043
044    public synchronized void add(Status child) {
045        if (child == null) {
046            throw new NullPointerException("Null values are not valid Status.");
047        }
048        if (childrenList == null) {
049            childrenList = new ArrayList<Status>();
050        }
051        childrenList.add(child);
052    }
053
054    public synchronized boolean hasChildren() {
055        return ((childrenList != null) && (childrenList.size() > 0));
056    }
057
058    public synchronized Iterator<Status> iterator() {
059        if (childrenList != null) {
060            return childrenList.iterator();
061        } else {
062            return EMPTY_LIST.iterator();
063        }
064    }
065
066    public synchronized boolean remove(Status statusToRemove) {
067        if (childrenList == null) {
068            return false;
069        }
070        // TODO also search in childrens' children
071        return childrenList.remove(statusToRemove);
072    }
073
074    public int getLevel() {
075        return level;
076    }
077
078    // status messages are not supposed to contain cycles.
079    // cyclic status arrangements are like to cause deadlocks
080    // when this method is called from different thread on
081    // different status objects lying on the same cycle
082    public synchronized int getEffectiveLevel() {
083        int result = level;
084        int effLevel;
085
086        Iterator<Status> it = iterator();
087        Status s;
088        while (it.hasNext()) {
089            s = (Status) it.next();
090            effLevel = s.getEffectiveLevel();
091            if (effLevel > result) {
092                result = effLevel;
093            }
094        }
095        return result;
096    }
097
098    public String getMessage() {
099        return message;
100    }
101
102    public Object getOrigin() {
103        return origin;
104    }
105
106    public Throwable getThrowable() {
107        return throwable;
108    }
109
110    public long getTimestamp() {
111        return timestamp;
112    }
113
114    @Override
115    public String toString() {
116        StringBuilder buf = new StringBuilder();
117        switch (getEffectiveLevel()) {
118        case INFO:
119            buf.append("INFO");
120            break;
121        case WARN:
122            buf.append("WARN");
123            break;
124        case ERROR:
125            buf.append("ERROR");
126            break;
127        }
128        if (origin != null) {
129            buf.append(" in ");
130            buf.append(origin);
131            buf.append(" -");
132        }
133
134        buf.append(" ");
135        buf.append(message);
136
137        if (throwable != null) {
138            buf.append(" ");
139            buf.append(throwable);
140        }
141
142        return buf.toString();
143    }
144
145    @Override
146    public boolean equals(Object o) {
147        if (this == o)
148            return true;
149        if (o == null || getClass() != o.getClass())
150            return false;
151        StatusBase that = (StatusBase) o;
152        return level == that.level && timestamp == that.timestamp && Objects.equals(message, that.message);
153    }
154
155
156
157    @Override
158    public int hashCode() {
159        return Objects.hash(level, message, timestamp);
160    }
161
162}