blob: 9ed92b587b7e033161a6c5723d69b5757d9477ce [file] [log] [blame]
/*
* 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.openide.execution;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.Permissions;
import org.openide.util.Lookup;
import org.openide.util.RequestProcessor;
import org.openide.util.lookup.Lookups;
import org.openide.windows.InputOutput;
/**
* Engine providing the environment necessary to run long-lived processes.
* May perform tasks such as setting up thread groups, etc.
* Modules should not implement this class.
* <p>
* <b>Note for implementors</b>: it is highly advised that the value {@code Lookup#getDefault} is saved,
* and established in the forked thread before the executed {@link Runnable} is called. This is
* done by OpenIDE libraries If the ExecutionEngine implementation uses {@link RequestProcessor} for
* planning the tasks.
*
* @author Jaroslav Tulach, Ales Novak
*/
public abstract class ExecutionEngine extends Object {
/**
* Run some task in the execution engine.
* @param name a name of the new process
* @param run a runnable to execute
* @param io an I/O handle to automatically redirect system I/O streams in the dynamic scope of the task to,
* or InputOutput.NULL if no such redirection is required
* @return an executor task that can control the execution
*/
public abstract ExecutorTask execute(String name, Runnable run, InputOutput io);
/**
* Users that want to link their classes with NetBeans module classes should do this through
* internal execution. The {@link NbClassLoader} used in internal execution will assume that calling
* this method and giving the permission collection to the class being defined will
* trigger automatic redirection of system output, input, and error streams into the given I/O tab.
* Implementations of the engine should bind the tab and returned permissions.
* Since the permission collection is on the stack when calling methods on {@link System#out} etc.,
* it is possible to find the appropriate tab for redirection.
* @param cs code source to construct the permission collection for
* @param io an I/O tab
* @return a permission collection
*/
protected abstract PermissionCollection createPermissions(CodeSource cs, InputOutput io);
/** 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
* @deprecated There are generally no excuses to be using this method as part of a normal module;
* its exact meaning is vague, and probably not what you want.
*/
protected abstract NbClassPath createLibraryPath ();
/**
* Obtains default instance of the execution engine.
* If default {@link Lookup} contains an instance of {@link ExecutionEngine},
* that is used. Otherwise, a trivial basic implementation is returned with
* the following behavior:
* <ul>
* <li>{@link #execute} just runs the runnable immediately and pretends to be done.
* <li>{@link #createPermissions} just uses {@link AllPermission}. No I/O redirection
* or {@link System#exit} trapping is done.
* <li>{@link #createLibraryPath} produces an empty path.
* </ul>
* This basic implementation is helpful in unit tests and perhaps in standalone usage
* of other libraries.
* @return some execution engine implementation (never null)
* @since 2.16
*/
public static ExecutionEngine getDefault() {
ExecutionEngine ee = (ExecutionEngine) Lookup.getDefault().lookup(ExecutionEngine.class);
if (ee == null) {
ee = new Trivial();
}
return ee;
}
/**
* Dummy fallback implementation, useful for unit tests.
*/
static final class Trivial extends ExecutionEngine {
public Trivial() {}
protected NbClassPath createLibraryPath() {
return new NbClassPath(new String[0]);
}
protected PermissionCollection createPermissions(CodeSource cs, InputOutput io) {
PermissionCollection allPerms = new Permissions();
allPerms.add(new AllPermission());
allPerms.setReadOnly();
return allPerms;
}
public ExecutorTask execute(String name, Runnable run, InputOutput io) {
return new ET(run, name, io);
}
private static final class ET extends ExecutorTask {
private final Lookup originalLookup;
private RequestProcessor.Task task;
private int resultValue;
private final String name;
private final InputOutput io;
public ET(Runnable run, String name, InputOutput io) {
super(run);
this.originalLookup = Lookup.getDefault();
this.resultValue = resultValue;
this.name = name;
this.io = io;
task = RequestProcessor.getDefault().post(this);
}
public void stop() {
task.cancel();
}
public int result() {
waitFinished();
return resultValue;
}
public InputOutput getInputOutput() {
return io;
}
public void run() {
Lookups.executeWith(originalLookup, () -> {
try {
super.run();
} catch (RuntimeException x) {
x.printStackTrace();
resultValue = 1;
}
});
}
}
}
}