/*******************************************************************************
* Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://robocode.sourceforge.net/license/epl-v10.html
*
* Contributors:
* Mathew A. Nelson
* - Initial API and implementation
* Flemming N. Larsen
* - Code cleanup
* - Fixed potential NullPointerException in getLoadingRobotProxy()
* - Added getRobotClasses() and getRobotProxies() for the
* RobocodeSecurityManager
* Robert D. Maupin
* - Replaced old collection types like Vector and Hashtable with
* synchronized List and HashMap
*******************************************************************************/
package net.sf.robocode.host.security;
import net.sf.robocode.host.IHostedThread;
import net.sf.robocode.host.IThreadManager;
import net.sf.robocode.host.io.RobotFileOutputStream;
import net.sf.robocode.host.io.RobotFileSystemManager;
import robocode.exception.RobotException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* @author Mathew A. Nelson (original)
* @author Flemming N. Larsen (contributor)
* @author Robert D. Maupin (contributor)
*/
public class ThreadManager implements IThreadManager {
private final PrintStream syserr = System.err;
private final List<Thread> safeThreads = new CopyOnWriteArrayList<Thread>();
private final List<ThreadGroup> safeThreadGroups = new CopyOnWriteArrayList<ThreadGroup>();
private final List<ThreadGroup> groups = new CopyOnWriteArrayList<ThreadGroup>();
private final List<Thread> outputStreamThreads = new CopyOnWriteArrayList<Thread>();
private final List<IHostedThread> robots = new CopyOnWriteArrayList<IHostedThread>();
private Thread robotLoaderThread;
private IHostedThread loadingRobot;
public ThreadManager() {}
public void addSafeThread(Thread safeThread) {
safeThreads.add(safeThread);
}
public void removeSafeThread(Thread safeThread) {
safeThreads.remove(safeThread);
}
public void addSafeThreadGroup(ThreadGroup safeThreadGroup) {
safeThreadGroups.add(safeThreadGroup);
}
public void addThreadGroup(ThreadGroup g, IHostedThread robotProxy) {
if (!groups.contains(g)) {
groups.add(g);
robots.add(robotProxy);
}
}
public synchronized IHostedThread getLoadingRobot() {
return loadingRobot;
}
public synchronized IHostedThread getLoadingRobotProxy(Thread t) {
if (t != null && robotLoaderThread != null
&& (t.equals(robotLoaderThread)
|| (t.getThreadGroup() != null && t.getThreadGroup().equals(robotLoaderThread.getThreadGroup())))) {
return loadingRobot;
}
return null;
}
public synchronized IHostedThread getLoadedOrLoadingRobotProxy(Thread t) {
IHostedThread robotProxy = getRobotProxy(t);
if (robotProxy == null) {
robotProxy = getLoadingRobotProxy(t);
}
return robotProxy;
}
public IHostedThread getRobotProxy(Thread t) {
ThreadGroup g = t.getThreadGroup();
if (g == null) {
return null;
}
int index = groups.indexOf(g);
if (index == -1) {
return null;
}
return robots.get(index);
}
public void reset() {
groups.clear();
robots.clear();
}
public synchronized void setLoadingRobot(IHostedThread newLoadingRobotProxy) {
if (newLoadingRobotProxy == null) {
this.robotLoaderThread = null;
loadingRobot = null;
} else {
this.robotLoaderThread = Thread.currentThread();
loadingRobot = newLoadingRobotProxy;
}
}
public boolean isSafeThread() {
return isSafeThread(Thread.currentThread());
}
public FileOutputStream createRobotFileStream(String fileName, boolean append) throws IOException {
final Thread c = Thread.currentThread();
final IHostedThread robotProxy = getRobotProxy(c);
if (robotProxy == null) {
syserr.println("RobotProxy is null");
return null;
}
if (!robotProxy.getStatics().isAdvancedRobot()) {
throw new RobotException("Only advanced robots could create files");
}
final File dir = robotProxy.getRobotFileSystemManager().getWritableDirectory();
if (!dir.exists()) {
robotProxy.println("SYSTEM: Creating a data directory for you.");
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
outputStreamThreads.add(c);
if (!dir.exists() && !dir.mkdirs()) {
syserr.println("Can't create dir " + dir.toString());
}
return null;
}
});
}
final RobotFileSystemManager fileSystemManager = robotProxy.getRobotFileSystemManager();
File f = new File(fileName);
long len;
if (f.exists()) {
len = f.length();
} else {
fileSystemManager.checkQuota();
len = 0;
}
if (!append) {
fileSystemManager.adjustQuota(-len);
}
outputStreamThreads.add(c);
return new RobotFileOutputStream(fileName, append, fileSystemManager);
}
public boolean checkRobotFileStream() {
final Thread c = Thread.currentThread();
synchronized (outputStreamThreads) {
if (outputStreamThreads.contains(c)) {
outputStreamThreads.remove(c);
return true;
}
}
return false;
}
public boolean isSafeThread(Thread c) {
try {
if (safeThreads.contains(c)) {
return true;
}
for (ThreadGroup tg : safeThreadGroups) {
if (c.getThreadGroup() == tg) {
safeThreads.add(c);
return true;
}
}
return false;
} catch (Exception e) {
syserr.println("Exception checking safe thread: ");
e.printStackTrace(syserr);
return false;
}
}
public PrintStream getRobotOutputStream() {
Thread c = Thread.currentThread();
if (isSafeThread(c)) {
return null;
}
IHostedThread robotProxy = getLoadedOrLoadingRobotProxy(c);
return (robotProxy != null) ? robotProxy.getOut() : null;
}
public void printlnToRobot(String s) {
final PrintStream stream = getRobotOutputStream();
if (stream != null) {
stream.println(s);
}
}
}