![JAR search and dependency download from the Maven repository](/logo.png)
com.sun.electric.tool.sandbox.ESandBox Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ESandBox.java
* Written by: Dmitry Nadezhin, Sun Microsystems.
*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) 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.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.sandbox;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
/**
* This abstract class is a framework for stand-alone process which loads "electric.jar (possibly with old Electric version),
* (partially) initializes it and executes there different test Jobs.
* The results of test Jobs is sent to stdout in the folowng format:
*
* StdOut = (JobResult | PrintOutput)*
*
* JobResult = HEADER '\n' JobSuccess LengthString '\n' Byte+ '\n' '!' '\n'
* HEADER = '\x7F'
* JobSuccess = Ok | Exception
* Ok = 'R'
* Exception = 'E'
* LenghtString = DIGIT+ // 10-digit number
*
* PrintOutput = LF | CR | PrintString
* LF = '\n'
* CR = '\r'
* PrintString = LengthByte Byte+ // contains (LengthByte - ' ' + 1) bytes
*
* The subclass should contain methods with signature "commandName(String args), which implement commands,
* and a main method like this:
*
* public static void main(String[] args) {
* try {
* File electricJar = new File(args[0]);
* MySandBox m = new MySandBox(electricJar);
* m.loop(System.in);
* } catch (Exception e) {
* e.printStackTrace();
* }
* }
*
* Only single instance of subclasses of this method is allowed in a process.
*
*/
public abstract class ESandBox extends EClassLoader {
private static final PrintStream stdOut = System.out;
private static final OutputStream redirectedStdOut = new OutputStream() {
@Override public void write(int b) { write(new byte[] { (byte)b }, 0, 1); }
@Override public void write(byte b[], int off, int len) { writeStdOut(b, off, len); }
};
static { System.setOut(new PrintStream(redirectedStdOut, false)); }
private static final RunnableTask task = new RunnableTask();
private static ESandBox theSandBox;
private static String command;
private static final Object lock = new Object();
private static byte[] serializedResultOrException;
private static boolean isException;
private final Constructor UniversalJob_constructor = getDeclaredConstructor(defineClass("com.sun.electric.tool.UniversalJob"), String.class, Runnable.class);
/*
* Abstract constructor of a ESandBox.
* It loads classes from specified URL.
* Also first call of this constructor redirects stdout as a size effect.
* @param electricJar URL of "electric.jar" file.
*/
protected ESandBox(URL electricJar) throws IOException, IllegalAccessException, ClassNotFoundException {
super(electricJar);
}
public static void redirectStdOut(String args) {
System.setOut(new PrintStream(redirectedStdOut, false));
}
/**
* Command interpreter which executes commands from command stream.
* Each command is placed at the beginning of command line. Its arguments are after one or more spaces.
* Lines beginning with spaces and empty lines are considered as comments.
* A method like "commandName(String args)" is found by reflexion in subclass of ESandBox.
* @param commandStream a stream with commands.
*/
protected void loop(InputStream commandStream) throws InstantiationException, IllegalAccessException, InvocationTargetException, IOException {
synchronized (lock) {
if (theSandBox != null)
throw new IllegalStateException("SandBox already instantiated");
theSandBox = this;
}
command = "redirectStdOut";
(new ServerManagerThread()).start();
BufferedReader commandReader = new BufferedReader(new InputStreamReader(commandStream));
for (int i = 0;;) {
synchronized (lock) {
try {
while (serializedResultOrException == null)
lock.wait();
} catch (InterruptedException e) {
}
}
Object result = null;
if (serializedResultOrException.length != 0) {
try {
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(serializedResultOrException));
result = in.readObject();
in.close();
} catch (Throwable e) {
result = new Exception(e);
}
}
writeStdOut(serializedResultOrException, isException);
serializedResultOrException = null;
command = commandReader.readLine();
if (command == null)
System.exit(0);
Object job = createJob(command);
Job_startJob.invoke(job);
}
}
private class ServerManagerThread extends Thread {
ServerManagerThread() {
super("ServerManager");
}
@Override
public void run() {
try {
if (Job_initJobManager1 != null || Job_initJobManager2 != null || Job_initJobManager3 != null) {
Object ui = MainUserInterfaceDummy_constructor.newInstance();
Object jobMode = JobMode_SERVER.get(null);
// Object jobMode = JobMode_BATCH.get(null);
if (Job_setThreadMode1 != null)
Job_setThreadMode1.invoke(null, jobMode, ui);
else if (Job_setThreadMode2 != null)
Job_setThreadMode2.invoke(null, jobMode, ui);
Object job = createJob("SandBox");
if (Job_initJobManager1 != null)
Job_initJobManager1.invoke(null, 1, job, null, null);
else if (Job_initJobManager2 != null)
Job_initJobManager2.invoke(null, 1, job, null);
else if (Job_initJobManager3 != null)
Job_initJobManager3.invoke(null, 1, job);
} else {
Object job = createJob("SandBox");
Job_startJob.invoke(job);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private Object createJob(String jobName) throws InstantiationException, IllegalAccessException, InvocationTargetException {
return UniversalJob_constructor.newInstance(jobName, task);
}
private static class RunnableTask implements Runnable, Serializable {
public void run() {
String cmd, args;
int i = command.indexOf(' ');
if (i >= 0 ) {
cmd = command.substring(0, i);
args = command.substring(i);
} else {
cmd = command;
args = "";
}
while (args.startsWith(" "))
args = args.substring(1);
Object result = null;
Exception exception = null;
try {
if (cmd.length() > 0) {
Method method = theSandBox.getClass().getMethod(cmd, String.class);
result = method.invoke(theSandBox, args);
}
} catch (Exception e) {
exception = e;
} catch (Throwable e) {
exception = new Exception("Error", e);
exception.fillInStackTrace();
}
byte[] serialized = null;
try {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteStream);
out.writeObject(exception != null ? exception : result);
out.flush();
serialized = byteStream.toByteArray();
} catch (Throwable e) {
exception = new Exception("Serialization Error", e);
exception.fillInStackTrace();
try {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteStream);
out.writeObject(exception);
out.flush();
serialized = byteStream.toByteArray();
} catch (Throwable e2) {
serialized = new byte[0];
}
}
synchronized (lock) {
try {
while (ESandBox.serializedResultOrException != null)
lock.wait();
} catch (InterruptedException e) {
System.out.println("Interrupted");
Thread.currentThread().interrupt();
}
isException = exception != null;
ESandBox.serializedResultOrException = serialized;
lock.notify();
}
}
}
private static final char MIN_LENGTH_CHAR = ' ';
private static final char HEADER_CHAR = 0x7F;
private static final int STRLEN_WIDTH = Integer.toString(Integer.MAX_VALUE).length();
private static final int HEADER_LEN = 3 + STRLEN_WIDTH + 1;
private static final int TRAILER_LEN = 3;
private static synchronized void writeStdOut(byte b[], int off, int len) {
while (len > 0 && (b[off] == '\n' || b[off] == '\r')) {
stdOut.write(b[off]);
off++;
len--;
}
while (len > 0) {
int l = Math.min(len, HEADER_CHAR - MIN_LENGTH_CHAR);
stdOut.write(MIN_LENGTH_CHAR + l - 1);
stdOut.write(b, off, l);
off += l;
len -= l;
}
}
private static synchronized void writeStdOut(byte[] b, boolean isException) {
stdOut.write(HEADER_CHAR);
stdOut.write('\n');
stdOut.write(isException ? 'E' : 'R');
String s = Integer.toString(b.length);
while (s.length() < STRLEN_WIDTH)
s = '0' + s;
for (int i = 0; i < s.length(); i++)
stdOut.write(s.charAt(i));
stdOut.write('\n');
stdOut.write(b, 0, b.length);
stdOut.write('\n');
stdOut.write('!');
stdOut.write('\n');
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy