/*
* This file is part of the Haven & Hearth game client.
* Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and
* Björn Johannessen <johannessen.bjorn@gmail.com>
*
* Redistribution and/or modification of this file is subject to the
* terms of the GNU Lesser General Public License, version 3, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Other parts of this source tree adhere to other copying
* rights. Please see the file `COPYING' in the root directory of the
* source tree for details.
*
* A copy the GNU Lesser General Public License is distributed along
* with the source tree of which this file is a part in the file
* `doc/LPGL-3'. If it is missing for any reason, please see the Free
* Software Foundation's website at <http://www.fsf.org/>, or write
* to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package haven.error;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
public class ErrorHandler extends ThreadGroup {
private final URL errordest;
private static final String[] sysprops = {
"java.version",
"java.vendor",
"os.name",
"os.arch",
"os.version",
};
private final ThreadGroup initial;
private Map<String, Object> props = new HashMap<String, Object>();
private Reporter reporter;
public static void setprop(String key, Object val) {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
if(tg instanceof ErrorHandler)
((ErrorHandler)tg).lsetprop(key, val);
}
public void lsetprop(String key, Object val) {
props.put(key, val);
}
private class Reporter extends Thread {
private Queue<Report> errors = new LinkedList<Report>();
private ErrorStatus status;
public Reporter(ErrorStatus status) {
super(initial, "Error reporter");
setDaemon(true);
this.status = status;
}
public void run() {
while(true) {
synchronized(errors) {
try {
errors.wait();
} catch(InterruptedException e) {
return;
}
Report r;
while((r = errors.poll()) != null) {
try {
doreport(r);
} catch(Exception e) {
status.senderror(e);
}
}
}
}
}
private void doreport(Report r) throws IOException {
if(!status.goterror(r.t))
return;
URLConnection c = errordest.openConnection();
status.connecting();
c.setDoOutput(true);
c.addRequestProperty("Content-Type", "application/x-java-error");
c.connect();
ObjectOutputStream o = new ObjectOutputStream(c.getOutputStream());
status.sending();
o.writeObject(r);
o.close();
InputStream i = c.getInputStream();
byte[] buf = new byte[1024];
while(i.read(buf) >= 0);
i.close();
status.done();
}
public void report(Thread th, Throwable t) {
Report r = new Report(t);
r.props.putAll(props);
r.props.put("thnm", th.getName());
r.props.put("thcl", th.getClass().getName());
synchronized(errors) {
errors.add(r);
errors.notifyAll();
}
try {
r.join();
} catch(InterruptedException e) { /* XXX? */ }
}
}
private void defprops() {
for(String p : sysprops)
props.put(p, System.getProperty(p));
Runtime rt = Runtime.getRuntime();
props.put("cpus", rt.availableProcessors());
InputStream in = ErrorHandler.class.getResourceAsStream("/buildinfo");
try {
try {
if(in != null) {
Properties info = new Properties();
info.load(in);
for(Map.Entry<Object, Object> e : info.entrySet())
props.put("jar." + (String)e.getKey(), e.getValue());
}
} finally {
in.close();
}
} catch(IOException e) {
throw(new Error(e));
}
}
public ErrorHandler(ErrorStatus ui, URL errordest) {
super("Haven client");
this.errordest = errordest;
initial = Thread.currentThread().getThreadGroup();
reporter = new Reporter(ui);
reporter.start();
defprops();
}
public ErrorHandler(URL errordest) {
this(new ErrorStatus.Simple(), errordest);
}
public void sethandler(ErrorStatus handler) {
reporter.status = handler;
}
public void uncaughtException(Thread t, Throwable e) {
reporter.report(t, e);
}
}