This module can be considered as an extension to the External Execution Module that provides an API (NativeExecutionAPI) to execute and control external system processes not only on the local machine, but on remote systems as well. As it uses External Execution Module as a base for execution control, process' Input/Output and integration with the IDE are handled in the same way.
The differences are:Currently the module doesn't provide any SPI.
Three main API classes are:
ExecutionEnvironment,
NativeProcess and
NativeProcessBuilder.
ExecutionEnvironmant describes where the process needs to be
started (i.e. it identifies a host and, if needed, provides information
for establishing ssh connection with that host (i.e. username and
ssh-port to use)).
ConnectionManager
(that is also a part of the API)
handles all ssh connections and is responsible for establishing those
connection (ask for passwords, etc.)
NativeProcessBuilder is a factory for a NativeProcess that can be
used with an ExecutionService to create and start system process.
The module was designed in the same manner as ExtExecution Support and can be considered as an extension of that module. It introduces it's own ProcessBuilder (NativeProcessBuilder) that can be used with an ExecutionDescriptor and an ExecutionService from the ExtExecution Support Module. The NativeProcessBuilder is a factory for a NativeProcess, which is an extension of java.lang.Process with two additional methods: getPID() and getState() to receive system process' pid and state respectively.
Below are several examples of usage.
ExecutionEnvironment env = new ExecutionEnvironment(userName, host); NativeProcessBuilder npb = new NativeProcessBuilder(env, "/bin/ls"); npb = npb.setArguments(".").setWorkingDirectory("/tmp"); ExecutionDescriptor descr = new ExecutionDescriptor().controllable(true); ExecutionService service = ExecutionService.newService(npb, descr, "test"); Future<Integer> result = service.run(); Integer exitCode = null; try { exitCode = result.get(); } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } catch (ExecutionException ex) { Exceptions.printStackTrace(ex); } System.out.println("Exit code is " + exitCode);
ChangeListener listener = new ChangeListener() { public void stateChanged(ChangeEvent e) { NativeProcess process = (NativeProcess) e.getSource(); State newState = process.getState(); if (newState == State.STARTING) { return; } if (newState == State.ERROR) { System.out.println("Unable to start process!"); return; } System.out.println("Process " + process.toString() + " [" + process.getPID() + "] -> " + newState); } }; ... NativeProcessBuilder npb = new NativeProcessBuilder(env, "/bin/ls"); npb = npb.setArguments(".").setWorkingDirectory("/tmp"); npb = npb.addNativeProcessListener(listener); ...
... ExternalTerminal term = ExternalTerminalProvider.getTerminal("gnome-terminal").setTitle("My title"); NativeProcessBuilder npb = new NativeProcessBuilder(env, "/bin/ls"); npb = npb.setArguments(".").setWorkingDirectory("/tmp"); npb = npb.useExternalTerminal(term); ...
ExecutionEnvironment ee = new ExecutionEnvironment(user, host, port); ConnectionManager cm = ConnectionManager.getInstance(); Runnable onConnect = new Runnable() { public void run() { DialogDisplayer.getDefault().notify(new DialogDescriptor.Message("Host connected!")); } }; AsynchronousAction connectAction = cm.getConnectToAction(ee, onConnect); // To invoke it immideately (and synchroniously) connectAction.invoke(); // Or add it to some UI ... JPanel panel = new JPanel(new BorderLayout()); panel.add(new JButton(connectAction), BorderLayout.CENTER); DialogDisplayer.getDefault().createDialog( new DialogDescriptor(panel, "Connection Test")).setVisible(true); ...Question (arch-time): What are the time estimates of the work? Answer:
It is not final yet.
Question (arch-quality): How will the quality of your code be tested and how are future regressions going to be prevented? Answer:Most of the API functionality is covered by unit tests. Same applies to future enhancements.
Question (arch-where): Where one can find sources for your module? Answer:
The sources for the module are in the NetBeans Mercurial repositories.
These modules are required in project.xml:
The module was written to support D-Light functionality, so the focus was Solaris/Linux environment. It was not tested under other environments. For remote execution it is required that remote host is running ssh server. For privileged execution it is required that remote host runs Solaris 10+. For privileged support a small native executable is implemented and used. For terminal support a shell script (wrapper) is used.
Question (dep-jre): Which version of JRE do you need (1.2, 1.3, 1.4, etc.)? Answer:This module was developed using JDK 1.5
Question (dep-jrejdk): Do you require the JDK or is the JRE enough? Answer:JRE is enough.
jar with this module + jar with jsch + native executable for privileged execxution
Question (deploy-nbm): Can you deploy an NBM via the Update Center? Answer:Not yet. It is not final yet.
Question (deploy-shared): Do you need to be installed in the shared location only, or in the user directory only, or can your module be installed anywhere? Answer:Anywhere
Question (deploy-packages): Are packages of your module made inaccessible by not declaring them public? Answer:Only API packages are exported.
Question (deploy-dependencies): What do other modules need to do to declare a dependency on this one, in addition to or instead of the normal module dependency declaration (e.g. tokens to require)? Answer:Nothing.
Not yet.
Question (compat-standards): Does the module implement or define any standards? Is the implementation exact or does it deviate somehow? Answer:No.
Question (compat-version): Can your module coexist with earlier and future versions of itself? Can you correctly read all old settings? Will future versions be able to read your current settings? Can you read or politely ignore settings stored by a future version? Answer:The only settings this module stores is an encrypted user password (if he/she agreed to do so)... It is not planned to change the format of these settings in future...
Question (compat-deprecation): How the introduction of your project influences functionality provided by previous version of the product? Answer:This module in an extension rather than deprecation of External Execution Support.
java.io.File
directly?
Answer:
Yes.
Question (resources-layer): Does your module provide own layer? Does it create any files or folders in it? What it is trying to communicate by that and with which components? Answer:Yes. Terminal support is implemented so that it reads different terminals 'configuration' from the NativeExecution/ExtTerminalSupport folder. Terminal 'configurations' describe what options should be passed to a specific terminal (gnome-terminal, xterm) in order to start a process from within it.
Question (resources-read): Does your module read any resources from layers? For what purpose? Answer:No.
Question (resources-mask): Does your module mask/hide/override any resources provided by other modules in their layers? Answer:No.
Question (resources-preferences): Does your module uses preferences via Preferences API? Does your module use NbPreferences or or regular JDK Preferences ? Does it read, write or both ? Does it share preferences with other modules ? If so, then why ? Answer:
Yes. Reads and Writes and doesn't share with others.
User's password (encrypted) is stored in
NbPreferences.forModule(RemoteUserInfo.class)
org.openide.util.Lookup
or any similar technology to find any components to communicate with? Which ones?
Answer:
No. (At least for now)
Question (lookup-register): Do you register anything into lookup for other code to find? Answer:Nothing.
Question (lookup-remove): Do you remove entries of other modules from lookup? Answer:No.
System.getProperty
) property?
On a similar note, is there something interesting that you
pass to java.util.logging.Logger
? Or do you observe
what others log?
Answer:
None of them are 'public'. There are several properties that are used in debugging purposes.
Question (exec-component): Is execution of your code influenced by any (string) property of any of your components? Answer:There are no public properties. There are some for debugging purposes.
Question (exec-ant-tasks): Do you define or register any ant tasks that other can use? Answer:None.
Question (exec-classloader): Does your code create its own class loader(s)? Answer:No.
Question (exec-reflection): Does your code use Java Reflection to execute other code? Answer:No.
Question (exec-privateaccess): Are you aware of any other parts of the system calling some of your methods by reflection? Answer:No.
Question (exec-process): Do you execute an external process from your module? How do you ensure that the result is the same on different platforms? Do you parse output? Do you depend on result code? Answer:Yes. The API provides support to do so. The result code, input and output stream content does not define API as this is forwarded to the client of this module.
Question (exec-introspection): Does your module use any kind of runtime type information (instanceof
,
work with java.lang.Class
, etc.)?
Answer:
No.
Question (exec-threading): What threading models, if any, does your module adhere to? How the project behaves with respect to threading? Answer:It is supposed to be thread safe and can be accessed from any thread.
Question (security-policy): Does your functionality require modifications to the standard policy file? Answer:This module uses JSch library (jsch) This library has already been used in, for example, C/C++ Support Module
Question (security-grant): Does your code grant additional rights to some other code? Answer:No.
None.
Question (format-dnd): Which protocols (if any) does your code understand during Drag & Drop? Answer:None.
Question (format-clipboard): Which data flavors (if any) does your code read from or insert to the clipboard (by access to clipboard on means calling methods onjava.awt.datatransfer.Transferable
?
Answer:
None.
No.
Question (perf-exit): Does your module run any code on exit? Answer:On JVM shutdown module tries to terminate any running process executed through the API.
Question (perf-scale): Which external criteria influence the performance of your program (size of file in editor, number of files in menu, in source directory, etc.) and how well your code scales? Answer:Number of threads depending on number of spawned processes (n) increases lineary.
Question (perf-limit): Are there any hard-coded or practical limits in the number or size of elements your code can handle? Answer:On very intensive output of spawned process, the performance may be affected. Currently no any check of this is implemented.
Question (perf-mem): How much memory does your component consume? Estimate with a relation to the number of windows, etc. Answer:Current implementation provides means for redirecting process' output/error to a IOTab/StringBuffer... Depending on output, this may consume significant amount of memory...
Question (perf-wakeup): Does any piece of your code wake up periodically and do something even when the system is otherwise idle (no user interaction)? Answer:No.
Question (perf-progress): Does your module execute any long-running tasks? Answer:Processes that executed via provided API can take long time. Also for remote execution connection to an other host(s) is initiated. All these tasks are performed in non-AWT thread.
Question (perf-huge_dialogs): Does your module contain any dialogs or wizards with a large number of GUI controls such as combo boxes, lists, trees, or text areas? Answer:There are two dialogs: one to ask user password to connect to a host (in case of remote execution); another one - to ask for priveleged user's password to grant execution privileges for running process.
Question (perf-menus): Does your module use dynamically updated context menus, or context-sensitive actions with complicated and slow enablement logic? Answer:No.
Question (perf-spi): How the performance of the plugged in code will be enforced? Answer:No SPI way to plug in foreign code.