/* * Copyright 2013 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.monitoring.impl; import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Queues; import com.google.common.collect.Sets; import gnu.trove.map.TObjectIntMap; import gnu.trove.map.hash.TObjectIntHashMap; import java.lang.ref.WeakReference; import java.util.Deque; import java.util.List; import java.util.Set; public class SingleThreadMonitorImpl implements SingleThreadMonitor { private final String name; private final WeakReference<Thread> ref; private final TObjectIntMap<String> taskCounters = new TObjectIntHashMap<>(); private final Set<String> tasks = Sets.newLinkedHashSet(); private final long id; private Deque<Throwable> errors = Queues.newArrayDeque(); private boolean active; private String lastTask = ""; public SingleThreadMonitorImpl(Thread thread) { Preconditions.checkNotNull(thread, "The parameter 'thread' must not be null"); this.name = thread.getName(); this.ref = new WeakReference<>(thread); this.id = thread.getId(); } @Override public final boolean isAlive() { return ref.get() != null; } @Override public final boolean isActive() { return active; } @Override public final String getLastTask() { return lastTask; } @Override public final String getName() { return name; } @Override public final long getThreadId() { return id; } @Override public final synchronized boolean hasErrors() { return !errors.isEmpty(); } @Override public final synchronized int getNumErrors() { return errors.size(); } @Override public final synchronized Throwable getLastError() { return errors.peekLast(); } @Override public final synchronized List<Throwable> getErrors() { return ImmutableList.copyOf(errors); } @Override public final synchronized void addError(Throwable error) { errors.add(error); } @Override public final synchronized Iterable<String> getTasks() { return ImmutableSet.copyOf(tasks); } @Override public final synchronized long getCounter(String task) { return taskCounters.get(task); } @Override public final synchronized void beginTask(String task) { if (taskCounters.adjustOrPutValue(task, 1, 1) == 1) { tasks.add(task); } active = true; lastTask = task; } @Override public final synchronized void endTask() { active = false; } @Override public String toString() { final StringBuilder b = new StringBuilder(100); b.append(name).append(isAlive() ? " [ALIVE]" : " [DEAD]").append(" Id = ").append(id); for (String task : tasks) { b.append(", ").append(task).append(" = ").append(taskCounters.get(task)); } if (hasErrors()) { b.append(" [Errors = ").append(getNumErrors()).append(", ").append(getLastError().getClass().getSimpleName()).append("]"); } return b.toString(); } @Override public int compareTo(SingleThreadMonitor other) { if (other == null) { return -1; } final boolean alive1 = this.isAlive(); final boolean alive2 = other.isAlive(); final int relAlive = alive1 ? (alive2 ? 0 : -1) : (alive2 ? 1 : 0); if (relAlive == 0) { final boolean active1 = this.isActive(); final boolean active2 = other.isActive(); final int relActive = active1 ? (active2 ? 0 : -1) : (active2 ? 1 : 0); if (relActive == 0) { final String name1 = this.getName(); final String name2 = other.getName(); final int relName = name1.compareTo(name2); if (relName == 0) { final long id1 = this.getThreadId(); final long id2 = other.getThreadId(); return (int) (id1 - id2); } return relName; } return relActive; } return relAlive; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof SingleThreadMonitor) { SingleThreadMonitor other = (SingleThreadMonitor) obj; return Objects.equal(isAlive(), other.isActive()) && Objects.equal(isActive(), other.isActive()) && Objects.equal(name, other.getName()) && Objects.equal(getThreadId(), other.getThreadId()); } return false; } @Override public int hashCode() { return Objects.hashCode(isActive(), isActive(), name, getThreadId()); } }