| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.netbeans.core.execution; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.io.PrintStream; |
| import java.util.*; |
| import java.security.CodeSource; |
| import java.security.PermissionCollection; |
| import java.security.Policy; |
| import org.netbeans.core.startup.Main; |
| |
| import org.openide.execution.NbClassPath; |
| import org.openide.execution.ExecutorTask; |
| import org.openide.util.Lookup; |
| import org.openide.windows.InputOutput; |
| |
| |
| /** Execution that provides support for starting a class with main |
| * |
| * @author Ales Novak |
| * |
| * The class handles redirecting of out/in/err for all tasks in the system. |
| * First instance of TaskIO is created for Corona. So call System.out.println() |
| * from Corona is redirected to a window. |
| * Situation for executed task is following it uses System.out/err/in - because |
| * the task is in some threadgroup it will be recognized and new panel in window |
| * for that task will be created. Further System.out.println() means that |
| * (in System.out is our class now - SysOut) calling thread is found and its threadgroup |
| * is examined - SysOut propagates call to taskIOs in ExecutionEngine. IOTable |
| * look for mapping the threadgroup to TaskIO class (it may create that). TaskIO |
| * is created uninitialized. So if only out is used, err/in are never initialized. |
| * Initializing is lazy - for request. TaskIO.out is an instance of SysPrintStream, |
| * that is redirected to OutputWriter that is redirected to a window. |
| */ |
| @SuppressWarnings("deprecation") // createLibraryPath |
| @org.openide.util.lookup.ServiceProvider(service=org.openide.execution.ExecutionEngine.class) |
| public final class |
| ExecutionEngine extends org.openide.execution.ExecutionEngine { |
| |
| /** base group for all running tasks */ |
| public static final ThreadGroup base = new ThreadGroup("base"); // NOI18N |
| |
| /** used for naming groups */ |
| private int number = 1; |
| |
| /** IO class for corona */ |
| public static final TaskIO systemIO = new TaskIO(); |
| |
| /** maps ThreadGroups to TaskIO */ |
| private static final IOTable taskIOs = new IOTable(base, systemIO); |
| |
| /* table of window:threadgrp */ |
| static private WindowTable wtable = new WindowTable(); |
| |
| /** list of ExecutionListeners */ |
| private HashSet<ExecutionListener> executionListeners = new HashSet<ExecutionListener>(); |
| |
| /** List of running executions */ |
| private List<ExecutorTask> runningTasks = Collections.synchronizedList(new ArrayList<ExecutorTask>( 5 )); |
| |
| static { |
| systemIO.out = new OutputStreamWriter(System.out); |
| systemIO.err = new OutputStreamWriter(System.err); |
| systemIO.in = new java.io.InputStreamReader(System.in); |
| } |
| |
| static final long serialVersionUID =9072488605180080803L; |
| |
| public ExecutionEngine () { |
| /* SysIn is a class that redirects System.in of some running task to |
| a window (probably OutWindow). |
| SysOut/Err are classes that redirect out/err to the window |
| */ |
| System.setIn(new SysIn()); |
| System.setOut(createPrintStream(true)); |
| System.setErr(createPrintStream(false)); |
| } |
| |
| /** Get the default ExecutionEngine instance. |
| * @return the instance, or null if none could be found |
| */ |
| public static ExecutionEngine getExecutionEngine() { |
| ExecutionEngine ee = Lookup.getDefault().lookup(ExecutionEngine.class); |
| if (ee != null) return ee; |
| org.openide.execution.ExecutionEngine ee2 = Lookup.getDefault().lookup(org.openide.execution.ExecutionEngine.class); |
| if (ee2 instanceof ExecutionEngine) return (ExecutionEngine)ee2; |
| return null; |
| } |
| |
| /** Returns a snapshot of a collection of tasks which did not ended yet */ |
| public Collection<ExecutorTask> getRunningTasks() { |
| // toArray is atomic on synchronized list, contrary to just passing |
| // the list to a Collection constructor. |
| return Arrays.asList(runningTasks.toArray(new ExecutorTask[0])); |
| } |
| |
| /** Returns name of running task */ |
| public String getRunningTaskName( ExecutorTask task ) { |
| if ( !runningTasks.contains( task ) || |
| !(task instanceof DefaultSysProcess) ) { |
| return null; |
| } |
| else { |
| return ((DefaultSysProcess)task).getName(); |
| } |
| } |
| |
| /** Should prepare environment for Executor and start it. Is called from |
| * Executor.execute method. |
| * |
| * @param executor to start |
| * @param info about class to start |
| */ |
| public ExecutorTask execute(String name, Runnable run, final InputOutput inout) { |
| TaskThreadGroup g = new TaskThreadGroup(base, "exec_" + name + "_" + number); // NOI18N |
| g.setDaemon(true); |
| ExecutorTaskImpl task = new ExecutorTaskImpl(); |
| synchronized (task.lock) { |
| try { |
| new RunClassThread(g, name, number++, inout, this, task, run); |
| task.lock.wait(); |
| } catch (InterruptedException e) { // #171795 |
| inout.closeInputOutput(); |
| return new ExecutorTask(null) { |
| public @Override void stop() {} |
| public @Override int result() {return 2;} |
| public @Override InputOutput getInputOutput() {return inout;} |
| }; |
| } |
| } |
| return task; |
| } |
| |
| /** Method that allows implementor of the execution engine to provide |
| * class path to all libraries that one could find useful for development |
| * in the system. |
| * |
| * @return class path to libraries |
| */ |
| protected NbClassPath createLibraryPath() { |
| List<File> l = Main.getModuleSystem().getModuleJars(); |
| return new NbClassPath (l.toArray (new File[l.size ()])); |
| } |
| |
| /** adds a listener */ |
| public final void addExecutionListener (ExecutionListener l) { |
| synchronized (executionListeners) { |
| executionListeners.add(l); |
| } |
| } |
| |
| /** removes a listener */ |
| public final void removeExecutionListener (ExecutionListener l) { |
| synchronized (executionListeners) { |
| executionListeners.remove(l); |
| } |
| } |
| |
| /** Creates new PermissionCollection for given CodeSource and given PermissionCollection. |
| * @param cs a CodeSource |
| * @param io an InputOutput |
| * @return PermissionCollection for given CodeSource and InputOutput |
| */ |
| protected final PermissionCollection createPermissions(CodeSource cs, InputOutput io) { |
| PermissionCollection pc = Policy.getPolicy().getPermissions(cs); |
| ThreadGroup grp = Thread.currentThread().getThreadGroup(); |
| return new IOPermissionCollection(io, pc, (grp instanceof TaskThreadGroup ? (TaskThreadGroup) grp: null)); |
| } |
| |
| /** fires event that notifies about new process */ |
| protected final void fireExecutionStarted (ExecutionEvent ev) { |
| runningTasks.add( ev.getProcess() ); |
| @SuppressWarnings("unchecked") |
| Iterator<ExecutionListener> iter = ((HashSet<ExecutionListener>) executionListeners.clone()).iterator(); |
| while (iter.hasNext()) { |
| ExecutionListener l = iter.next(); |
| l.startedExecution(ev); |
| } |
| } |
| |
| /** fires event that notifies about the end of a process */ |
| protected final void fireExecutionFinished (ExecutionEvent ev) { |
| runningTasks.remove( ev.getProcess() ); |
| @SuppressWarnings("unchecked") |
| Iterator<ExecutionListener> iter = ((HashSet<ExecutionListener>) executionListeners.clone()).iterator(); |
| while (iter.hasNext()) { |
| ExecutionListener l = iter.next(); |
| l.finishedExecution(ev); |
| } |
| ev.getProcess().destroyThreadGroup(base); |
| } |
| |
| static void putWindow(java.awt.Window w, TaskThreadGroup tg) { |
| wtable.putTaskWindow(w, tg); |
| } |
| static void closeGroup(ThreadGroup tg) { |
| wtable.closeGroup(tg); |
| } |
| static boolean hasWindows(ThreadGroup tg) { |
| return wtable.hasWindows(tg); |
| } |
| |
| /** |
| * @return IOTable with couples ThreadGroup:TaskIO |
| */ |
| static IOTable getTaskIOs() { |
| return taskIOs; |
| } |
| |
| /** finds top thread group of the calling thread |
| * @return null iff the calling thread is not in any exec group |
| * or exec group of calling thread |
| */ |
| public static ThreadGroup findGroup () { |
| ThreadGroup g = Thread.currentThread().getThreadGroup (); |
| ThreadGroup old = null; |
| while (g != null && g != base) { |
| old = g; |
| g = g.getParent (); |
| } |
| return (g == null) ? null : old; |
| } |
| |
| /** The OutputStream redirects output on behalf of task */ |
| static class SysOut extends OutputStream { |
| |
| /** Is it err or std out? */ |
| boolean std; |
| |
| /** Creates new Stream */ |
| SysOut(boolean std) { |
| this.std = std; |
| } |
| |
| public void write(int b) throws IOException { |
| if (std) { |
| getTaskIOs().getOut().write(b); |
| } else { |
| getTaskIOs().getErr().write (b); |
| } |
| } |
| |
| @Override |
| public void write(byte[] buff, int off, int len) throws IOException { |
| String s = new String (buff, off, len); |
| if (std) { |
| getTaskIOs().getOut().write(s.toCharArray(), 0, s.length()); |
| } else { |
| getTaskIOs().getErr().write(s.toCharArray(), 0, s.length()); |
| } |
| } |
| |
| @Override |
| public void flush() throws IOException { |
| if (std) { |
| getTaskIOs().getOut().flush(); |
| } else { |
| getTaskIOs().getErr().flush(); |
| } |
| } |
| |
| @Override |
| public void close() throws IOException { |
| if (std) { |
| getTaskIOs().getOut().close(); |
| } else { |
| getTaskIOs().getErr().close(); |
| } |
| } |
| } |
| |
| static PrintStream createPrintStream(boolean stdOut) { |
| return new WriterPrintStream(new SysOut(stdOut), stdOut); |
| } |
| |
| } |