# HG changeset patch
# User Andrew Krasny
# Date 1339007056 -14400
# Node ID b7462934d0f478ec56ba94a2479a83fd901766e2
# Parent a308c29718f4533fc177b6e098812e969276f92b
[mq]: EXEC_API
diff --git a/libs.jna/nbproject/project.xml b/libs.jna/nbproject/project.xml
--- a/libs.jna/nbproject/project.xml
+++ b/libs.jna/nbproject/project.xml
@@ -71,15 +71,17 @@
org.jrubyorg.netbeans.core.browser.xulrunnerorg.netbeans.core.nativeaccess
+ org.netbeans.libs.svnClientAdapter.svnkitorg.netbeans.modules.dlight.nativeexecutionorg.netbeans.modules.extexecution.destroy
+ org.netbeans.modules.ide.executionorg.netbeans.modules.keyring.impl
+ org.netbeans.modules.masterfs.linux
+ org.netbeans.modules.masterfs.macosx
+ org.netbeans.modules.masterfs.solarisorg.netbeans.modules.masterfs.windows
- org.netbeans.modules.masterfs.linux
- org.netbeans.modules.masterfs.solaris
- org.netbeans.modules.masterfs.macosx
+ org.netbeans.modules.nativeexecution.implorg.netbeans.modules.python.qshell
- org.netbeans.libs.svnClientAdapter.svnkitcom.sun.jnacom.sun.jna.ptrcom.sun.jna.win32
diff --git a/nativeexecution.impl/build.xml b/nativeexecution.impl/build.xml
new file mode 100755
--- /dev/null
+++ b/nativeexecution.impl/build.xml
@@ -0,0 +1,5 @@
+
+
+ Builds, tests, and runs the project org.netbeans.modules.nativeexecution.impl
+
+
diff --git a/nativeexecution.impl/manifest.mf b/nativeexecution.impl/manifest.mf
new file mode 100755
--- /dev/null
+++ b/nativeexecution.impl/manifest.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+AutoUpdate-Show-In-Client: false
+OpenIDE-Module: org.netbeans.modules.nativeexecution.impl
+OpenIDE-Module-Implementation-Version: 1
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/nativeexecution/impl/resources/Bundle.properties
+OpenIDE-Module-Provides: ConnectionService.localhost, ConnectionService.ssh
diff --git a/nativeexecution.impl/nbproject/project.properties b/nativeexecution.impl/nbproject/project.properties
new file mode 100755
--- /dev/null
+++ b/nativeexecution.impl/nbproject/project.properties
@@ -0,0 +1,5 @@
+is.autoload=true
+javac.source=1.6
+javac.compilerargs=-Xlint -Xlint:-serial
+spec.version.base=1.0
+
diff --git a/nativeexecution.impl/nbproject/project.xml b/nativeexecution.impl/nbproject/project.xml
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/nbproject/project.xml
@@ -0,0 +1,87 @@
+
+
+ org.netbeans.modules.apisupport.project
+
+
+ org.netbeans.modules.nativeexecution.impl
+
+
+ com.jcraft.jsch
+
+
+
+ 0.1.43
+
+
+
+ org.netbeans.api.progress
+
+
+
+ 1
+ 1.28
+
+
+
+ org.netbeans.libs.jna
+
+
+
+ 1
+ 1.4
+
+
+
+ org.netbeans.modules.nativeexecution
+
+
+
+ 1.0
+
+
+
+ org.openide.dialogs
+
+
+
+ 7.25
+
+
+
+ org.openide.util
+
+
+
+ 8.24
+
+
+
+ org.openide.util.lookup
+
+
+
+ 8.15
+
+
+
+ org.openide.windows
+
+
+
+ 6.55
+
+
+
+
+
+ unit
+
+ org.netbeans.libs.junit4
+
+
+
+
+
+
+
+
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/ExecutionLogger.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/ExecutionLogger.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/ExecutionLogger.java
@@ -0,0 +1,188 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import java.util.logging.StreamHandler;
+import javax.swing.SwingUtilities;
+
+/**
+ *
+ * @author akrasny
+ */
+public final class ExecutionLogger extends Logger {
+
+ private static final boolean assertionsEnabled;
+ private static final ExecutionLogger instance = new ExecutionLogger();
+ private static final Map map = new WeakHashMap();
+
+ static {
+ boolean ea = false;
+ assert (ea = true);
+ assertionsEnabled = ea;
+ String level_str = System.getProperty("ide.execution.logger.level", "INFO").toUpperCase(); // NOI18N
+ Level level = Level.INFO;
+
+ try {
+ level = Level.parse(level_str);
+ } catch (IllegalArgumentException ex) {
+ }
+
+ instance.addHandler(new LoggerHandler());
+ instance.setLevel(level);
+ }
+ private static final long startTimeMillis = System.currentTimeMillis();
+
+ private static class LoggerHandler extends StreamHandler {
+
+ public LoggerHandler() {
+ setOutputStream(System.out);
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ record.setMessage("[" + (record.getMillis() - startTimeMillis) + " ms.] " + record.getMessage()); // NOI18N
+ super.publish(record);
+ super.flush();
+ }
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public void close() throws SecurityException {
+ }
+ }
+
+ private ExecutionLogger() {
+ super("nativeexecution.impl.logger", null); // NOI18N
+ setLevel(Level.ALL);
+ }
+
+ public static ExecutionLogger getInstance() {
+ return instance;
+ }
+
+ public Ref reportStart(String descr) {
+ Ref r = new Ref();
+ log(Level.INFO, "{0} STARTED", descr); // NOI18N
+ synchronized (map) {
+ map.put(r, descr);
+ }
+ return r;
+ }
+
+ public void reportDone(Ref ref) {
+ String descr;
+ synchronized (map) {
+ descr = map.remove(ref);
+ }
+ if (descr == null) {
+ return;
+ }
+ log(Level.INFO, "{0} FINISHED in {1} ms.", new Object[]{descr, System.currentTimeMillis() - ref.ts}); // NOI18N
+ }
+
+ public static void assertTrue(boolean value) {
+ if (assertionsEnabled && !value) {
+ String message = "Assertion error"; // NOI18N
+ instance.log(Level.SEVERE, message, new Exception(message));
+ }
+ }
+
+ public static void assertTrue(boolean value, String message) {
+ if (assertionsEnabled && !value) {
+ instance.log(Level.SEVERE, message, new Exception(message));
+ }
+ }
+
+ public static void assertFalse(boolean value) {
+ if (assertionsEnabled && value) {
+ String message = "Assertion error"; // NOI18N
+ instance.log(Level.SEVERE, message, new Exception(message));
+ }
+ }
+
+ public static void assertFalse(boolean value, String message) {
+ if (assertionsEnabled && value) {
+ instance.log(Level.SEVERE, message, new Exception(message));
+ }
+ }
+
+ public static void assertNonUiThread(String message) {
+ if (assertionsEnabled && SwingUtilities.isEventDispatchThread()) {
+ instance.log(Level.FINE, message, new Exception(message));
+ }
+ }
+
+ public static void assertNonUiThread() {
+ assertNonUiThread("Should not be called from UI thread"); // NOI18N
+ }
+
+ public static void fullThreadDump(String title) {
+ final Set> stack = Thread.getAllStackTraces().entrySet();
+ System.err.printf("----- %s Start Thread Dump-----\n", title == null ? "" : title); // NOI18N
+ for (Map.Entry entry : stack) {
+ System.err.println(entry.getKey().getName());
+ for (StackTraceElement element : entry.getValue()) {
+ System.err.println("\tat " + element.toString()); // NOI18N
+ }
+ System.err.println();
+ }
+ System.err.println("----- End Thread Dump-----"); // NOI18N
+ }
+
+ public static class Ref {
+
+ private final long ts;
+
+ private Ref() {
+ this.ts = System.currentTimeMillis();
+ }
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/common/AbstractNativeProcessImpl.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/common/AbstractNativeProcessImpl.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/common/AbstractNativeProcessImpl.java
@@ -0,0 +1,202 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.common;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessImplementation;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+import org.openide.util.Utilities;
+
+/**
+ *
+ * @author akrasny
+ */
+public abstract class AbstractNativeProcessImpl implements NativeProcessImplementation {
+
+ private final NativeProcessParams params;
+ private InputStream inputStream;
+ private InputStream errorStream;
+ private OutputStream outputStream;
+ private int pid;
+
+ public AbstractNativeProcessImpl(NativeProcessParams params) {
+ this.params = params;
+ }
+
+ public final NativeProcessImplementation createAndStart() throws NativeExecutionException {
+ ProcessStreams streams;
+
+ try {
+ String shellScript = params.getShellScript();
+
+ if (shellScript != null) {
+ streams = create(params.getShell(), params.getShellScript());
+ } else {
+ streams = create(params.getCommand());
+ }
+
+ inputStream = streams.is;
+ errorStream = streams.es;
+ outputStream = streams.os;
+ pid = streams.pid;
+ } catch (Throwable ex) {
+ throw new NativeExecutionException(ex);
+ }
+
+ return this;
+ }
+
+ protected final NativeProcessParams getParams() {
+ return params;
+ }
+
+ abstract protected ProcessStreams create(List command) throws NativeExecutionException;
+
+ abstract protected ProcessStreams create(String shell, String script) throws NativeExecutionException;
+
+ @Override
+ public int getPID() {
+ return pid;
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return outputStream;
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return inputStream;
+ }
+
+ @Override
+ public InputStream getErrorStream() {
+ return errorStream;
+ }
+
+ protected String commandToCommandLine(final List cmd) {
+ /**
+ * See IZ#168186 - Wrongly interpreted "$" symbol in arguments
+ *
+ * The magic below is all about making run/debug act identically in case
+ * of ExternalTerminal
+ */
+ StringBuilder sb = new StringBuilder();
+
+ String exec = cmd.get(0);
+
+ sb.append(quoteSpecialChars(exec)).append(' ');
+
+ String[] sarg = new String[1];
+
+ boolean escape;
+
+ for (int i = 1; i < cmd.size(); i++) {
+ String arg = cmd.get(i);
+ escape = false;
+ sarg[0] = arg;
+ arg = Utilities.escapeParameters(sarg);
+
+ sb.append('"');
+
+ if ((arg.startsWith("'") && arg.endsWith("'")) || // NOI18N
+ (arg.startsWith("\"") && arg.endsWith("\""))) { // NOI18N
+ arg = arg.substring(1, arg.length() - 1);
+ escape = true;
+ }
+
+ if (escape) {
+ char pc = 'x';
+
+ for (char c : arg.toCharArray()) {
+ if (c == '$' && pc != '\\') {
+ sb.append('\\');
+ }
+ sb.append(c);
+ pc = c;
+ }
+ } else {
+ sb.append(arg);
+ }
+
+ sb.append("\" "); // NOI18N
+ }
+
+ if (params.isRedirectError()) {
+ sb.append(" 2>&1"); // NOI18N
+ }
+
+ return sb.toString().trim();
+ }
+
+ private String quoteSpecialChars(String orig) {
+ StringBuilder sb = new StringBuilder();
+ String escapeChars = " &\"'()!"; // NOI18N
+
+ for (char c : orig.toCharArray()) {
+ if (escapeChars.indexOf(c) >= 0) { // NOI18N
+ sb.append('\\');
+ }
+ sb.append(c);
+ }
+
+ return sb.toString();
+ }
+
+ protected static final class ProcessStreams {
+
+ private final InputStream is;
+ private final InputStream es;
+ private final OutputStream os;
+ private final int pid;
+
+ public ProcessStreams(InputStream is, InputStream es, OutputStream os, int pid) {
+ this.is = is;
+ this.es = es;
+ this.os = os;
+ this.pid = pid;
+ }
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/common/ShellBasedConnectionInfoProvider.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/common/ShellBasedConnectionInfoProvider.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/common/ShellBasedConnectionInfoProvider.java
@@ -0,0 +1,195 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.common;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.EnvironmentMap;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcessBuilder;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfo;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfoProvider;
+import org.netbeans.modules.nativeexecution.util.ProcessInputProvider;
+import org.netbeans.modules.nativeexecution.util.ProcessOutputProcessor;
+import org.netbeans.modules.nativeexecution.util.ProcessUtils;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Andrew
+ */
+public final class ShellBasedConnectionInfoProvider implements ConnectionInfoProvider {
+
+ private static final ShellBasedConnectionInfoProvider instance = new ShellBasedConnectionInfoProvider();
+
+ public static ShellBasedConnectionInfoProvider getInstance() {
+ return instance;
+ }
+
+ private ShellBasedConnectionInfoProvider() {
+ }
+
+ @Override
+ public ConnectionInfo getConnectionInfo(Connection connection) throws NativeExecutionException {
+ NativeProcessBuilder npb = connection.newProcessBuilder();
+ npb.setShellScript("/bin/sh", "/bin/sh -s"); // NOI18N
+ final Map map = new HashMap();
+ final EnvironmentMap env = EnvironmentMap.createCaseSensitive(':');
+ ProcessUtils.execute(npb, new ProcessOutputProcessor() {
+
+ FetcherState state = FetcherState.NONE;
+
+ @Override
+ /**
+ * This method relies on the contract: - each property is a SINGLE
+ * line in format NAME=VALUE - '=' MUST be present on each line
+ */
+ public void processLine(CharSequence line) {
+ int idx = 0;
+ int length = line.length();
+
+ if (length == 0) {
+ return;
+ }
+
+ if ("@@@@@INFO".equals(line)) { // NOI18N
+ state = FetcherState.INFO;
+ return;
+ }
+
+ if ("@@@@@ENV".equals(line)) { // NOI18N
+ state = FetcherState.ENV;
+ return;
+ }
+
+ if (state == FetcherState.NONE) {
+ return;
+ }
+
+ while (idx < length && line.charAt(idx) != '=') {
+ idx++;
+ }
+
+ if (idx >= length) {
+ return;
+// throw new InternalError("Bad line: '" + line + "'"); // NOI18N
+ }
+
+ String name = line.subSequence(0, idx).toString();
+ String value = line.subSequence(idx + 1, length).toString();
+
+ switch (state) {
+ case ENV:
+ env.put(name, value);
+ break;
+ case INFO:
+ map.put(name, value);
+ break;
+ }
+ }
+ }, null, new ProcessInputProvider() {
+
+ @Override
+ public void start(BufferedWriter bw) {
+ try {
+ bw.append("NB_KEY=").append(getNBKey()).append('\n'); // NOI18N
+ InputStream in = getClass().getClassLoader().getResourceAsStream("org/netbeans/modules/nativeexecution/impl/resources/hostinfo.sh"); // NOI18N
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while ((line = br.readLine()) != null) {
+ bw.append(line).append('\n');
+ }
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ } finally {
+ try {
+ bw.close();
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+ });
+
+ return new ConnectionInfo() {
+
+ @Override
+ public EnvironmentMap getEnvironmentMap() {
+ return env;
+ }
+
+ @Override
+ public Map getProperties() {
+ return map;
+ }
+ };
+ }
+
+ /**
+ * @return unique key of the current NB instance, introduced to fix bug
+ * #176526
+ */
+ private String getNBKey() {
+ // use NB userdir to prevent local collisions
+ int hashCode = System.getProperty("netbeans.user", "").hashCode();
+ try {
+ // use host name to prevent remote collisions
+ InetAddress localhost = InetAddress.getLocalHost();
+ hashCode = 3 * hashCode + 5 * localhost.getHostName().hashCode();
+ } catch (UnknownHostException ex) {
+ }
+ return Integer.toHexString(hashCode);
+ }
+
+ private enum FetcherState {
+
+ INFO, ENV, NONE
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/Bundle.properties b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/Bundle.properties
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/Bundle.properties
@@ -0,0 +1,42 @@
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+#
+# Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+# Other names may be trademarks of their respective owners.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common
+# Development and Distribution License("CDDL") (collectively, the
+# "License"). You may not use this file except in compliance with the
+# License. You can obtain a copy of the License at
+# http://www.netbeans.org/cddl-gplv2.html
+# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+# specific language governing permissions and limitations under the
+# License. When distributing the software, include this License Header
+# Notice in each file and include the License file at
+# nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the GPL Version 2 section of the License file that
+# accompanied this code. If applicable, add the following below the
+# License Header, with the fields enclosed by brackets [] replaced by
+# your own identifying information:
+# "Portions Copyrighted [year] [name of copyright owner]"
+#
+# If you wish your version of this file to be governed by only the CDDL
+# or only the GPL Version 2, indicate your decision by adding
+# "[Contributor] elects to include this software in this distribution
+# under the [CDDL or GPL Version 2] license." If you do not indicate a
+# single choice of license, a recipient has the option to distribute
+# your version of this file under either the CDDL, the GPL Version 2 or
+# to extend the choice of license to its licensees as provided above.
+# However, if you add GPL Version 2 code and therefore, elected the GPL
+# Version 2 license, then the option applies only if the new code is
+# made subject to such option by the copyright holder.
+#
+# Contributor(s):
+#
+# Portions Copyrighted 2012 Sun Microsystems, Inc.
+
+TITLE_YN_Warning=Warning
+MSG_PasswordInteractive={0} {1}
diff --git a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/jsch/JSchChannelsSupport.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchChannelsSupport.java
copy from dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/jsch/JSchChannelsSupport.java
copy to nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchChannelsSupport.java
--- a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/jsch/JSchChannelsSupport.java
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchChannelsSupport.java
@@ -36,14 +36,14 @@
*
* Portions Copyrighted 2010 Sun Microsystems, Inc.
*/
-package org.netbeans.modules.nativeexecution.jsch;
+package org.netbeans.modules.nativeexecution.impl.jsch;
import com.jcraft.jsch.Channel;
-import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
-import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -51,16 +51,15 @@
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
-import org.netbeans.modules.nativeexecution.api.util.PasswordManager;
-import org.netbeans.modules.nativeexecution.support.Logger;
-import org.netbeans.modules.nativeexecution.support.RemoteUserInfo;
-import org.openide.util.Cancellable;
+import org.netbeans.modules.nativeexecution.api.ConnectionCancelledException;
+import org.netbeans.modules.nativeexecution.api.ConnectionException;
+import org.netbeans.modules.nativeexecution.impl.ExecutionLogger;
+import org.netbeans.modules.nativeexecution.spi.AuthDataProvider;
+import org.openide.util.Exceptions;
/**
*
@@ -68,21 +67,23 @@
*/
public final class JSchChannelsSupport {
- private static final java.util.logging.Logger log = Logger.getInstance();
+ private static final ExecutionLogger log = ExecutionLogger.getInstance();
private static final int JSCH_CONNECTION_RETRY = Integer.getInteger("jsch.connection.retry", 3); // NOI18N
private static final int JSCH_CONNECTION_TIMEOUT = Integer.getInteger("jsch.connection.timeout", 10000); // NOI18N
private static final int JSCH_SESSIONS_PER_ENV = Integer.getInteger("jsch.sessions.per.env", 10); // NOI18N
private static final int JSCH_CHANNELS_PER_SESSION = Integer.getInteger("jsch.channels.per.session", 10); // NOI18N
- private static final boolean UNIT_TEST_MODE = Boolean.getBoolean("nativeexecution.mode.unittest"); // NOI18N
private static final boolean USE_JZLIB = Boolean.getBoolean("jzlib"); // NOI18N
private static final HashMap jschSessionConfig = new HashMap();
private final JSch jsch;
+ private final String user;
+ private final String host;
+ private final int port;
private final RemoteUserInfo userInfo;
- private final ExecutionEnvironment env;
private final ReentrantLock sessionsLock = new ReentrantLock();
private final Condition sessionAvailable = sessionsLock.newCondition();
// AtomicInteger stores a number of available channels for the session
- // We use ConcurrentHashMap to be able fast isConnected() check; in most other cases sessions is guarded bu "this"
+ // We use ConcurrentHashMap to be able to provide fast isConnected() check;
+ // in most other cases sessions variable is guarded by "this"
private final ConcurrentHashMap sessions = new ConcurrentHashMap();
private final Set knownChannels = new HashSet();
@@ -103,18 +104,48 @@
}
}
}
+ private final URI uri;
- public JSchChannelsSupport(JSch jsch, ExecutionEnvironment env) {
+ private JSchChannelsSupport(JSch jsch, URI uri, String user, String host, Integer port, RemoteUserInfo userInfo) {
this.jsch = jsch;
- this.env = env;
- this.userInfo = new RemoteUserInfo(env, !UNIT_TEST_MODE);
+ this.uri = uri;
+ this.user = user;
+ this.host = host;
+ this.port = port;
+ this.userInfo = userInfo;
}
- public ChannelShell getShellChannel(boolean waitIfNoAvailable) throws JSchException, IOException, InterruptedException {
- return (ChannelShell) acquireChannel("shell", waitIfNoAvailable); // NOI18N
+ public static JSchChannelsSupport get(URI uri, AuthDataProvider dataProvider) throws InterruptedException {
+ String user_ = dataProvider.getProperty(uri, String.class, AuthDataProvider.USERNAME);
+ String host_ = dataProvider.getProperty(uri, String.class, AuthDataProvider.HOST);
+ Integer port_ = dataProvider.getProperty(uri, Integer.class, AuthDataProvider.PORT);
+ RemoteUserInfo userInfo_ = new RemoteUserInfo(uri, dataProvider);
+ JSch jsch_ = new JSch();
+ initJsch(jsch_, uri, dataProvider);
+
+ return new JSchChannelsSupport(jsch_, uri, user_, host_, port_, userInfo_);
}
- public synchronized Channel acquireChannel(String type, boolean waitIfNoAvailable) throws JSchException, IOException, InterruptedException {
+ private static void initJsch(JSch jsch, URI uri, AuthDataProvider dataProvider) throws InterruptedException {
+ try {
+ jsch.removeAllIdentity();
+ String authType = dataProvider.getProperty(uri, String.class, "AuthType");
+ String knownHostsFile = dataProvider.getProperty(uri, String.class, "KnownHostsFile");
+ String sshKeyFile = dataProvider.getProperty(uri, String.class, "SSHKeyFile");
+
+ if (knownHostsFile != null) {
+ jsch.setKnownHosts(knownHostsFile);
+ }
+
+ if ("SSHKey".equals(authType) && sshKeyFile != null) {
+ jsch.addIdentity(sshKeyFile);
+ }
+ } catch (JSchException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+
+ public synchronized Channel acquireChannel(String type, boolean waitIfNoAvailable) throws ConnectionException {
JSchException exception = null;
for (int i = 0; i < JSCH_CONNECTION_RETRY; i++) {
@@ -126,14 +157,19 @@
try {
sessionsLock.lock();
while (session == null) {
- sessionAvailable.await();
+ try {
+ sessionAvailable.await();
+ } catch (InterruptedException ex) {
+ Thread.interrupted();
+ throw new ConnectionCancelledException(uri);
+ }
session = findFreeSession();
}
} finally {
sessionsLock.unlock();
}
} else {
- throw new IOException("All " + JSCH_SESSIONS_PER_ENV + " sessions for " + env.getDisplayName() + " are fully loaded"); // NOI18N
+ throw new ConnectionException(uri, "All " + JSCH_SESSIONS_PER_ENV + " sessions for " + host + " are fully loaded"); // NOI18N
}
}
}
@@ -164,7 +200,7 @@
// exception is set; or there was another exception => it was thrown
// already
assert exception != null;
- throw exception;
+ throw new ConnectionException(uri, exception);
}
public boolean isConnected() {
@@ -178,11 +214,10 @@
return false;
}
- public synchronized void reconnect(ExecutionEnvironment env) throws IOException, JSchException, InterruptedException {
- disconnect();
- connect();
- }
-
+// public synchronized void reconnect(ExecutionEnvironment env) throws ConnectionException {
+// disconnect();
+// connect();
+// }
private Session findFreeSession() {
for (Entry entry : sessions.entrySet()) {
Session s = entry.getKey();
@@ -198,7 +233,7 @@
return null;
}
- public synchronized void connect() throws JSchException, InterruptedException {
+ public synchronized void connect() throws ConnectionException {
if (isConnected()) {
return;
}
@@ -212,56 +247,35 @@
}
}
- private Session startNewSession(boolean acquireChannel) throws JSchException, InterruptedException {
+ private Session startNewSession(boolean acquireChannel) throws ConnectionException {
Session newSession = null;
- final AtomicBoolean cancelled = new AtomicBoolean(false);
+ try {
+ newSession = jsch.getSession(user, host, port);
+ newSession.setUserInfo(userInfo);
- ConnectingProgressHandle.startHandle(env, new Cancellable() {
-
- @Override
- public boolean cancel() {
- cancelled.set(true);
- return true;
- }
- });
-
- try {
- while (!cancelled.get()) {
- try {
- newSession = jsch.getSession(env.getUser(), env.getHostAddress(), env.getSSHPort());
- newSession.setUserInfo(userInfo);
-
- for (Entry entry : jschSessionConfig.entrySet()) {
- newSession.setConfig(entry.getKey(), entry.getValue());
- }
-
- if (USE_JZLIB) {
- newSession.setConfig("compression.s2c", "zlib@openssh.com,zlib,none"); // NOI18N
- newSession.setConfig("compression.c2s", "zlib@openssh.com,zlib,none"); // NOI18N
- newSession.setConfig("compression_level", "9"); // NOI18N
- }
-
- newSession.connect(JSCH_CONNECTION_TIMEOUT);
- break;
- } catch (JSchException ex) {
- if (!UNIT_TEST_MODE && "Auth fail".equals(ex.getMessage())) { // NOI18N
- PasswordManager.getInstance().clearPassword(env);
- } else {
- throw ex;
- }
- }
+ for (Entry entry : jschSessionConfig.entrySet()) {
+ newSession.setConfig(entry.getKey(), entry.getValue());
}
- if (cancelled.get()) {
- throw new InterruptedException("StartNewSession was cancelled ..."); // NOI18N
+ if (USE_JZLIB) {
+ newSession.setConfig("compression.s2c", "zlib@openssh.com,zlib,none"); // NOI18N
+ newSession.setConfig("compression.c2s", "zlib@openssh.com,zlib,none"); // NOI18N
+ newSession.setConfig("compression_level", "9"); // NOI18N
}
- sessions.put(newSession, new AtomicInteger(JSCH_CHANNELS_PER_SESSION - (acquireChannel ? 1 : 0)));
+ newSession.connect(JSCH_CONNECTION_TIMEOUT);
+ } catch (JSchException ex) {
+ if (ex.getCause() instanceof InterruptedIOException) {
+ throw new ConnectionCancelledException(uri);
+ }
+ throw new ConnectionException(uri, ex);
+ } finally {
+ // TODO: notify that password could be eraised
+ }
- log.log(Level.FINE, "New session [{0}] started.", new Object[]{System.identityHashCode(newSession)}); // NOI18N
- } finally {
- ConnectingProgressHandle.stopHandle(env);
- }
+ sessions.put(newSession, new AtomicInteger(JSCH_CHANNELS_PER_SESSION - (acquireChannel ? 1 : 0)));
+
+ log.log(Level.FINE, "New session [{0}] started.", new Object[]{System.identityHashCode(newSession)}); // NOI18N
return newSession;
}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchConnection.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchConnection.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchConnection.java
@@ -0,0 +1,126 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.jsch;
+
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.ChannelShell;
+import com.jcraft.jsch.JSchException;
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.api.BrokenConnectionException;
+import org.netbeans.modules.nativeexecution.api.ConnectionException;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.impl.common.ShellBasedConnectionInfoProvider;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessCreator;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+/**
+ *
+ * @author akrasny
+ */
+public class JSchConnection implements ConnectionImplementation {
+
+ private final JSchChannelsSupport cs;
+ private final String name;
+ private final URI uri;
+ private final Lookup lookup;
+
+ public JSchConnection(URI uri, JSchChannelsSupport cs) {
+ String user = uri.getUserInfo();
+ StringBuilder sb = new StringBuilder();
+ sb.append(uri.getScheme()).append("://").append(user.replaceAll(":.*", ":***")).append("@").append(uri.getHost()); // NOI18N
+ name = sb.toString();
+ this.cs = cs;
+ this.uri = uri;
+ this.lookup = Lookups.fixed(ShellBasedConnectionInfoProvider.getInstance());
+ }
+
+ @Override
+ public NativeProcessCreator newProcessBuilderImpl() throws NativeExecutionException {
+ if (!cs.isConnected()) {
+ throw new BrokenConnectionException(uri);
+ }
+
+ return new JSchProcessCreator(this);
+ }
+
+ @Override
+ public boolean isConnected() {
+ return cs.isConnected();
+ }
+
+ @SuppressWarnings("Unchecked")
+ ChannelExec getChannelExec(boolean waitIfNoAvailable) throws ConnectionException {
+ return (ChannelExec) cs.acquireChannel("exec", waitIfNoAvailable); // NOI18N
+ }
+
+ @SuppressWarnings("Unchecked")
+ ChannelShell getChannelShell(boolean waitIfNoAvailable) throws ConnectionException {
+ return (ChannelShell) cs.acquireChannel("shell", waitIfNoAvailable); // NOI18N
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ void releaseChannel(Channel channel) throws JSchException {
+ cs.releaseChannel(channel);
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return lookup;
+ }
+
+ @Override
+ public void disconnect() {
+ cs.disconnect();
+ }
+
+ @Override
+ public URI getURI() {
+ return uri;
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchConnector.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchConnector.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchConnector.java
@@ -0,0 +1,157 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.jsch;
+
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.netbeans.modules.nativeexecution.api.ConnectionException;
+import org.netbeans.modules.nativeexecution.api.DestinationUnreachableException;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.impl.ExecutionLogger;
+import org.netbeans.modules.nativeexecution.impl.ExecutionLogger.Ref;
+import org.netbeans.modules.nativeexecution.spi.AuthDataProvider;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.spi.ConnectorImplementation;
+import org.openide.util.RequestProcessor;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author akrasny
+ */
+@ServiceProvider(service = org.netbeans.modules.nativeexecution.spi.ConnectorImplementation.class, path = "ConnectionService/ssh", position = 10)
+public final class JSchConnector implements ConnectorImplementation {
+
+ private static final ExecutionLogger log = ExecutionLogger.getInstance();
+ private static final int SOCKET_CREATION_TIMEOUT = Integer.getInteger("socket.connection.timeout", 10000); // NOI18N
+
+ @Override
+ public ConnectionImplementation connectTo(final URI uri, final AuthDataProvider authDataProvider) throws InterruptedException, NativeExecutionException {
+ Ref start = log.reportStart("Connecting to " + uri);
+ try {
+
+ String host = authDataProvider.getProperty(uri, String.class, AuthDataProvider.HOST);
+ Integer port = authDataProvider.getProperty(uri, Integer.class, AuthDataProvider.PORT);
+
+ if (!isReachable(host, port)) {
+ throw new DestinationUnreachableException(uri);
+ }
+
+ JSchChannelsSupport cs = JSchChannelsSupport.get(uri, authDataProvider);
+ cs.connect();
+
+ // OK. Connection established.
+ return new JSchConnection(uri, cs);
+ } finally {
+ log.reportDone(start);
+ }
+ }
+
+ private boolean isReachable(final String host, final Integer port) {
+ // TODO: review!
+ // This ping-thread-related work makes sense if there are systems
+ // where interrupting a thread that is in socket.connect() doesn't
+ // work as expected. Do we know such systems?
+
+ // IZ#165591 - Trying to connect to wrong host breaks remote host setup (for other hosts)
+ // To prevent this first try to just open a socket and
+ // go to the jsch code in case of success only.
+
+ // The important thing here is that we still need to be interruptable
+ // In case of wrong IP address (unreachable) the SocketImpl's connect()
+ // method may hang in system call for a long period of time, being
+ // insensitive to interrupts.
+ // So do this in a separate thread...
+
+ Callable checker = new Callable() {
+
+ @Override
+ public Boolean call() throws Exception {
+ final Socket socket = new Socket();
+ final SocketAddress addressToConnect = new InetSocketAddress(host, port);
+ try {
+ socket.connect(addressToConnect, SOCKET_CREATION_TIMEOUT);
+ } catch (Exception ioe) {
+ return false;
+ } finally {
+ socket.close();
+ }
+ return true;
+ }
+ };
+
+ RequestProcessor pingThread = new RequestProcessor("ping " + host + ":" + port, 1); // NOI18N
+ final Future task = pingThread.submit(checker); // NOI18N
+
+ while (!task.isDone()) {
+ try {
+ task.get(500, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ex) {
+ Thread.interrupted();
+ task.cancel(true);
+ } catch (ExecutionException ex) {
+ // normally should never happen
+ } catch (TimeoutException ex) {
+ // OK.. still be waiting
+ }
+ }
+
+ boolean result = false;
+
+ if (task.isDone()) {
+ try {
+ result = task.get();
+ } catch (Exception ex) {
+ // normally should never happen
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchDefaultAuthDataProvider.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchDefaultAuthDataProvider.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchDefaultAuthDataProvider.java
@@ -0,0 +1,89 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.jsch;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.spi.AuthDataProvider;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author akrasny
+ */
+@ServiceProvider(service = org.netbeans.modules.nativeexecution.spi.AuthDataProvider.class, path = "ConnectionService/ssh", position = 10)
+public final class JSchDefaultAuthDataProvider implements AuthDataProvider {
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T getProperty(URI uri, Class clazz, final String name, Object... misc) {
+ if (String.class.equals(clazz) && AuthDataProvider.USERNAME.equals(name)) {
+ String userinfo = uri.getUserInfo();
+ int pos = userinfo.indexOf(':');
+ return (T) (pos < 0 ? userinfo : userinfo.substring(0, pos));
+ }
+
+ if (String.class.equals(clazz) && AuthDataProvider.HOST.equals(name)) {
+ return (T) uri.getHost();
+ }
+
+ if (Integer.class.equals(clazz) && AuthDataProvider.PORT.equals(name)) {
+ int port = uri.getPort();
+ if (port <= 0) {
+ port = 22;
+ }
+ return (T) Integer.valueOf(port);
+ }
+
+ if (char[].class.equals(clazz) && AuthDataProvider.PASSWORD.equals(name)) {
+ if ("password".equals(misc[0])) {
+ String userinfo = uri.getUserInfo();
+ int pos = userinfo.indexOf(':');
+ if (pos > 0) {
+ return (T) userinfo.substring(pos + 1).toCharArray();
+ }
+ }
+ // TODO: Ask user ...
+ }
+
+ return null;
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchProcessCreator.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchProcessCreator.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchProcessCreator.java
@@ -0,0 +1,92 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.jsch;
+
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessCreator;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessImplementation;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+
+/**
+ *
+ * @author akrasny
+ */
+public final class JSchProcessCreator implements NativeProcessCreator {
+
+ private final JSchConnection connectionImpl;
+
+ public JSchProcessCreator(JSchConnection impl) {
+ this.connectionImpl = impl;
+ }
+
+ @Override
+ public Map> getSupportedProperties() {
+ return JSchProcessParams.getSupportedProperties();
+ }
+
+ @Override
+ public NativeProcessImplementation createAndStart(NativeProcessParams params) throws NativeExecutionException {
+ if (params.getShellScript() == null && params.getCommand() == null) {
+ throw new NullPointerException("Command is not specified"); // NOI18N
+ }
+
+ RemoteProcessImpl processImpl;
+
+// if (info.isPty()) {
+// process = new PtyProcess(info);
+// } else {
+ processImpl = new RemoteProcessImpl(connectionImpl, params);
+// }
+
+
+ return processImpl.createAndStart();
+ }
+ // protected T validatePropertyValue(String propertyName, T value) throws IllegalArgumentException {
+// if (value instanceof Charset) {
+// if (!Charset.isSupported(((Charset) value).name())) {
+// throw new IllegalArgumentException("Unsupported charset " + ((Charset) value).name());
+// }
+// }
+// return value;
+// }
+}
\ No newline at end of file
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchProcessParams.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchProcessParams.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchProcessParams.java
@@ -0,0 +1,90 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.jsch;
+
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+
+/**
+ *
+ * @author Andrew
+ */
+final class JSchProcessParams {
+
+ private static final Map> props = new HashMap>();
+
+ static {
+ props.put("commandCharset", Charset.class); // NOI18N
+ props.put("outputCharset", Charset.class); // NOI18N
+ props.put("AgentForvarding", Boolean.class); // NOI18N
+ props.put("XForvarding", Boolean.class); // NOI18N
+ props.put("ptyMode", Boolean.class); // NOI18N
+ props.put("ptyType", String.class); // NOI18N
+ props.put("terminalMode", byte[].class); // NOI18N
+// props.put("ptySize", Rectangle.class); // NOI18N
+ }
+
+ static Map> getSupportedProperties() {
+ return Collections.unmodifiableMap(props);
+ }
+
+ static Charset getCommandCharset(NativeProcessParams params) {
+ Charset charset = params.getProperty(Charset.class, "commandCharset"); // NOI18N
+ if (charset == null || !Charset.isSupported(charset.name())) {
+ charset = Charset.isSupported("UTF-8") // NOI18N
+ ? Charset.forName("UTF-8") : // NOI18N
+ Charset.defaultCharset(); // NOI18N
+ }
+ return charset;
+ }
+
+ public boolean isXForvarding(NativeProcessParams params) {
+ return params.getProperty(Boolean.class, "XForvarding"); // NOI18N
+ }
+
+ boolean isPty(NativeProcessParams params) {
+ return params.getProperty(Boolean.class, "ptyMode"); // NOI18N
+ }
+}
diff --git a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/JschSupport.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchSupport.java
copy from dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/JschSupport.java
copy to nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchSupport.java
--- a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/JschSupport.java
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchSupport.java
@@ -39,64 +39,76 @@
*
* Portions Copyrighted 2010 Sun Microsystems, Inc.
*/
-package org.netbeans.modules.nativeexecution;
+package org.netbeans.modules.nativeexecution.impl.jsch;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
-import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSchException;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.logging.Level;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
-import org.netbeans.modules.nativeexecution.support.Logger;
+import java.util.logging.Logger;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.impl.ExecutionLogger;
/**
*
* @author ak119685
*/
-public final class JschSupport {
+public final class JSchSupport {
private static final int JSCH_CONNECTION_TIMEOUT = Integer.getInteger("jsch.connection.timeout", 10000); // NOI18N
- private final static java.util.logging.Logger log = Logger.getInstance();
+ private final static Logger log = ExecutionLogger.getInstance();
- private JschSupport() {
+ private JSchSupport() {
}
/**
- * Starts the specified command (executable + params) on the specified ExecutionEnvironment.
+ * Starts the specified command (executable + params) within the specified
+ * jsch connection.
*
- * @param env - environment to execute in
+ * @param connection - connection to execute in
* @param command - executable + params to execute
* @param params - (optional) channel params. May be null.
- * @return I/O streams and opened execution JSch channel. Never returns NULL.
+ * @return I/O streams and opened execution JSch channel. Never returns
+ * NULL.
* @throws IOException - if unable to aquire an execution channel
- * @throws JSchException - if JSch exception occured
+ * @throws JSchException - if JSch exception occurred
* @throws InterruptedException - if the thread was interrupted
*/
- public static ChannelStreams startCommand(final ExecutionEnvironment env, final String command, final ChannelParams params)
- throws IOException, JSchException, InterruptedException {
+ public static ChannelStreams startCommand(final JSchConnection connection, final String command, final ChannelParams params)
+ throws NativeExecutionException {
JSchWorker worker = new JSchWorker() {
@Override
- public ChannelStreams call() throws JSchException, IOException, InterruptedException {
- ChannelExec echannel = (ChannelExec) ConnectionManagerAccessor.getDefault().openAndAcquireChannel(env, "exec", true); // NOI18N
+ public ChannelStreams call() throws NativeExecutionException {
+ ChannelExec echannel = connection.getChannelExec(true);
if (echannel == null) {
- throw new IOException("Cannot open exec channel on " + env + " for " + command); // NOI18N
+ throw new NativeExecutionException("Cannot open exec channel on " + connection.toString() + " for " + command); // NOI18N
}
echannel.setCommand(command);
echannel.setXForwarding(params == null ? false : params.x11forward);
- echannel.connect(JSCH_CONNECTION_TIMEOUT);
- return new ChannelStreams(echannel,
- echannel.getInputStream(),
- echannel.getErrStream(),
- echannel.getOutputStream());
+ try {
+ echannel.connect(JSCH_CONNECTION_TIMEOUT);
+ } catch (JSchException ex) {
+ throw new NativeExecutionException(ex);
+ }
+
+ ChannelStreams streams;
+ try {
+ streams = new ChannelStreams(echannel,
+ echannel.getInputStream(),
+ echannel.getErrStream(),
+ echannel.getOutputStream());
+ } catch (IOException ex) {
+ throw new NativeExecutionException(ex);
+ }
+
+ return streams;
}
@Override
@@ -105,73 +117,74 @@
}
};
- return start(worker, env, 2);
+ return start(worker, connection, 2);
}
- public static ChannelStreams startLoginShellSession(final ExecutionEnvironment env) throws IOException, JSchException, InterruptedException {
- JSchWorker worker = new JSchWorker() {
-
- @Override
- public ChannelStreams call() throws InterruptedException, JSchException, IOException {
- ChannelShell shell = (ChannelShell) ConnectionManagerAccessor.getDefault().openAndAcquireChannel(env, "shell", true); // NOI18N
-
- if (shell == null) {
- throw new IOException("Cannot open shell channel on " + env); // NOI18N
- }
-
- shell.setPty(false);
- shell.connect(JSCH_CONNECTION_TIMEOUT);
-
- return new ChannelStreams(shell,
- shell.getInputStream(),
- new ByteArrayInputStream(new byte[0]),
- shell.getOutputStream());
- }
-
- @Override
- public String toString() {
- return "shell session for " + env.getDisplayName(); // NOI18N
- }
- };
-
- return start(worker, env, 2);
- }
-
- private synchronized static ChannelStreams start(final JSchWorker worker, final ExecutionEnvironment env, final int attempts) throws IOException, JSchException, InterruptedException {
+// public static ChannelStreams startLoginShellSession(final JSchConnection connection) throws IOException, JSchException, InterruptedException {
+// JSchWorker worker = new JSchWorker() {
+//
+// @Override
+// public ChannelStreams call() throws InterruptedException, JSchException, IOException {
+// ChannelShell shell = (ChannelShell) ConnectionManagerAccessor.getDefault().openAndAcquireChannel(env, "shell", true); // NOI18N
+//
+// if (shell == null) {
+// throw new IOException("Cannot open shell channel on " + env); // NOI18N
+// }
+//
+// shell.setPty(false);
+// shell.connect(JSCH_CONNECTION_TIMEOUT);
+//
+// return new ChannelStreams(shell,
+// shell.getInputStream(),
+// new ByteArrayInputStream(new byte[0]),
+// shell.getOutputStream());
+// }
+//
+// @Override
+// public String toString() {
+// return "shell session for " + env.getDisplayName(); // NOI18N
+// }
+// };
+//
+// return start(worker, env, 2);
+// }
+ private synchronized static ChannelStreams start(final JSchWorker worker, final JSchConnection connection, final int attempts) throws NativeExecutionException {
int retry = attempts;
while (retry-- > 0) {
- try {
- return worker.call();
- } catch (JSchException ex) {
- String message = ex.getMessage();
- Throwable cause = ex.getCause();
- if (cause != null && cause instanceof NullPointerException) {
- // Jsch bug... retry?
- log.log(Level.INFO, "JSch exception opening channel to " + env + ". Retrying", ex); // NOI18N
- } else if ("java.io.InterruptedIOException".equals(message)) { // NOI18N
- log.log(Level.INFO, "JSch exception opening channel to " + env + ". Retrying in 0.5 seconds", ex); // NOI18N
- try {
- Thread.sleep(500);
- } catch (InterruptedException ex1) {
- Thread.currentThread().interrupt();
- break;
- }
- } else if ("channel is not opened.".equals(message)) { // NOI18N
- log.log(Level.INFO, "JSch exception opening channel to " + env + ". Reconnecting and retrying", ex); // NOI18N
- // Now reconnect disconnects old session and creates new, so this might help
- ConnectionManagerAccessor.getDefault().reconnect(env);
-
- } else {
- throw ex;
- }
- } catch (NullPointerException npe) {
- // Jsch bug... retry? ;)
- log.log(Level.FINE, "Exception from JSch", npe); // NOI18N
- }
+// try {
+ return worker.call();
+// } catch (NativeExecutionException ex) {
+// if (ex.getCause() instanceof JSchException) {
+// String message = ex.getMessage();
+// Throwable cause = ex.getCause();
+// if (cause != null && cause instanceof NullPointerException) {
+// // Jsch bug... retry?
+// log.log(Level.INFO, "JSch exception opening channel to " + env + ". Retrying", ex); // NOI18N
+// } else if ("java.io.InterruptedIOException".equals(message)) { // NOI18N
+// log.log(Level.INFO, "JSch exception opening channel to " + env + ". Retrying in 0.5 seconds", ex); // NOI18N
+// try {
+// Thread.sleep(500);
+// } catch (InterruptedException ex1) {
+// Thread.currentThread().interrupt();
+// break;
+// }
+// } else if ("channel is not opened.".equals(message)) { // NOI18N
+// log.log(Level.INFO, "JSch exception opening channel to " + env + ". Reconnecting and retrying", ex); // NOI18N
+// // Now reconnect disconnects old session and creates new, so this might help
+// // ConnectionManagerAccessor.getDefault().reconnect(env);
+//
+// } else {
+// throw ex;
+// }
+// }
+// } catch (NullPointerException npe) {
+// // Jsch bug... retry? ;)
+// log.log(Level.FINE, "Exception from JSch", npe); // NOI18N
+// }
}
- throw new IOException("Failed to execute " + worker.toString()); // NOI18N
+ throw new NativeExecutionException("Failed to execute " + worker.toString()); // NOI18N
}
public final static class ChannelStreams {
@@ -201,6 +214,6 @@
private static interface JSchWorker {
- T call() throws InterruptedException, IOException, JSchException;
+ T call() throws NativeExecutionException;
}
}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/RemoteProcessImpl.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/RemoteProcessImpl.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/RemoteProcessImpl.java
@@ -0,0 +1,192 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.jsch;
+
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.JSchException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.impl.ExecutionLogger;
+import org.netbeans.modules.nativeexecution.impl.ExecutionLogger.Ref;
+import org.netbeans.modules.nativeexecution.impl.common.AbstractNativeProcessImpl;
+import org.netbeans.modules.nativeexecution.impl.jsch.JSchSupport.ChannelParams;
+import org.netbeans.modules.nativeexecution.impl.jsch.JSchSupport.ChannelStreams;
+import org.netbeans.modules.nativeexecution.impl.util.EnvironmentMapWriter;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+import org.netbeans.modules.nativeexecution.util.SignalUtils;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author akrasny
+ */
+final class RemoteProcessImpl extends AbstractNativeProcessImpl {
+
+ private final JSchConnection connection;
+ private final Charset commandCharset;
+ private Channel channel;
+ private String displayName = ""; // NOI18N
+
+ RemoteProcessImpl(JSchConnection connection, NativeProcessParams params) {
+ super(params);
+ this.connection = connection;
+ commandCharset = JSchProcessParams.getCommandCharset(params);
+ }
+
+ @Override
+ protected ProcessStreams create(List command) throws NativeExecutionException {
+ displayName = Arrays.toString(command.toArray(new String[command.size()]));
+ return createImpl("exec " + commandToCommandLine(command)); // NOI18N
+ }
+
+ @Override
+ protected ProcessStreams create(String shell, String script) throws NativeExecutionException {
+ displayName = script;
+ return createImpl(script + "; exit"); // NOI18N
+ }
+
+ private ProcessStreams createImpl(String cmdLine) throws NativeExecutionException {
+ try {
+ ChannelParams params = new ChannelParams();
+ ChannelStreams streams = JSchSupport.startCommand(connection, "/bin/sh -s", params); // NOI18N
+ channel = streams.channel;
+ OutputStreamWriter writer = new OutputStreamWriter(streams.in, commandCharset);
+
+ // 1. get the PID of the shell
+ int token = 1000000 + new Random().nextInt(1000000);
+ write(writer, "echo " + token + "$$"); // NOI18N
+
+ ProcessStreams result = new ProcessStreams(streams.out, streams.err, streams.in, readPID(token, streams.out));
+
+ final String workingDirectory = getParams().getWorkingDirectory();
+
+ // 2. cd to working directory
+ if (workingDirectory != null) {
+ write(writer, "cd \"" + workingDirectory + "\" || exit 1"); // NOI18N
+ }
+
+ if (!channel.isConnected()) {
+ // Wrong directory ...
+ return result;
+ }
+
+ // 3. set environment
+ EnvironmentMapWriter.write(writer, getParams().getEnvironment());
+
+ // 5. finally do exec
+ write(writer, cmdLine);
+
+ return result;
+ } catch (IOException ex) {
+ throw new NativeExecutionException(ex);
+ }
+ }
+
+ @Override
+ public int waitResult() throws InterruptedException {
+ Ref logRef = ExecutionLogger.getInstance().reportStart(toString());
+ try {
+ while (channel.isConnected()) {
+ Thread.sleep(200);
+ }
+
+ return channel.getExitStatus();
+ } finally {
+ try {
+ connection.releaseChannel(channel);
+ } catch (JSchException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ ExecutionLogger.getInstance().reportDone(logRef);
+ }
+ }
+
+ private int readPID(int token, final InputStream is) throws IOException {
+ int c, pid = 0;
+ boolean found = false;
+
+ while (true) {
+ c = is.read();
+
+ if (c >= '0' && c <= '9') {
+ pid = pid * 10 + (c - '0');
+ if (pid == token) {
+ pid = 0;
+ found = true;
+ }
+ } else {
+ if (found) {
+ break;
+ }
+ }
+ }
+
+ return pid;
+ }
+
+ private void write(OutputStreamWriter writer, String data) throws IOException {
+ writer.write(data);
+ writer.write("\n");
+ writer.flush();
+ }
+
+ @Override
+ public void destroy() {
+ try {
+ channel.sendSignal(SignalUtils.Signal.SIGINT.name());
+ } catch (Exception ex) {
+ // Exceptions.printStackTrace(ex);
+ }
+ channel.disconnect();
+ }
+
+ @Override
+ public String toString() {
+ return displayName;
+ }
+}
diff --git a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/RemoteUserInfo.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/RemoteUserInfo.java
copy from dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/RemoteUserInfo.java
copy to nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/RemoteUserInfo.java
--- a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/RemoteUserInfo.java
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/RemoteUserInfo.java
@@ -39,143 +39,89 @@
*
* Portions Copyrighted 2009 Sun Microsystems, Inc.
*/
-package org.netbeans.modules.nativeexecution.support;
+package org.netbeans.modules.nativeexecution.impl.jsch;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
-import java.awt.Component;
+import java.net.URI;
import java.util.Arrays;
-import java.util.concurrent.CancellationException;
-import javax.swing.JOptionPane;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
-import org.netbeans.modules.nativeexecution.api.util.PasswordManager;
-import org.netbeans.modules.nativeexecution.support.ui.CertPassphraseDlg;
-import org.netbeans.modules.nativeexecution.support.ui.PasswordDlg;
-import org.openide.util.Mutex;
+import javax.security.auth.callback.PasswordCallback;
+import org.netbeans.modules.nativeexecution.spi.AuthDataProvider;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
-import org.openide.windows.WindowManager;
final public class RemoteUserInfo implements UserInfo, UIKeyboardInteractive {
- private final static Object lock = RemoteUserInfo.class.getName() + "Lock"; // NOI18N
- private final static PasswordManager pm = PasswordManager.getInstance();
- private final Component parent;
- private final ExecutionEnvironment env;
- private volatile Component parentWindow = null;
- private String passphrase = null;
- private volatile String password = null;
- private final boolean allowInterraction;
+ private final AuthDataProvider dataProvider;
+ private PasswordCallback callback;
+ private final URI uri;
- public RemoteUserInfo(ExecutionEnvironment env, boolean allowToAskForPassword) {
- this.env = env;
- this.allowInterraction = allowToAskForPassword;
- Mutex.EVENT.readAccess(new Runnable() {
-
- @Override
- public void run() {
- parentWindow = WindowManager.getDefault().getMainWindow();
- }
- });
- parent = parentWindow;
+ public RemoteUserInfo(URI uri, AuthDataProvider dataProvider) {
+ this.uri = uri;
+ this.dataProvider = dataProvider;
}
@Override
public String getPassphrase() {
- String result = passphrase;
- // Never store passphrase in memory
- // Only for short a period. Between prompt and following get.
- passphrase = null;
- return result;
+ if (callback == null || callback.getPassword() == null) {
+ return null;
+ }
+
+ char[] pwd = callback.getPassword();
+ // jsch interface requires a String object ;(
+ String passphrase = new String(pwd);
+ Arrays.fill(pwd, 'x');
+ return passphrase;
}
@Override
public String getPassword() {
- char[] saved = pm.getPassword(env);
- if (saved != null) {
- return new String(saved);
+ if (callback == null || callback.getPassword() == null) {
+ return null;
}
- String result = password;
- // Never store password in memory
- // Only for short a period. Between prompt and following get.
- password = null;
- return result;
+ char[] pwd = callback.getPassword();
+ // jsch interface requires a String object ;(
+ String password = new String(pwd);
+ Arrays.fill(pwd, 'x');
+ return password;
}
@Override
public boolean promptPassword(String message) {
- synchronized (lock) {
- if (pm.getPassword(env) != null) {
- return true;
- }
+ callback = new PasswordCallback(message, false);
+ char[] pwd = dataProvider.getProperty(uri, char[].class, AuthDataProvider.PASSWORD, "password", message); // NOI18N
+ if (pwd != null) {
+ callback.setPassword(pwd);
+ return true;
+ }
- if (!allowInterraction) {
- return false;
- }
-
- boolean result;
-
- PasswordDlg pwdDlg = new PasswordDlg();
-
- synchronized (lock) {
- result = pwdDlg.askPassword(env);
- }
-
- if (result) {
- char[] clearPassword = pwdDlg.getPassword();
- pm.storePassword(env, clearPassword, pwdDlg.isRememberPassword());
- Arrays.fill(clearPassword, (char) 0);
- pwdDlg.clearPassword();
- return true;
- } else {
- throw new CancellationException(loc("USER_AUTH_CANCELED")); // NOI18N
- }
- }
+ return false;
}
@Override
- public boolean promptPassphrase(String arg0) {
- if (!allowInterraction) {
- return false;
+ public boolean promptPassphrase(String message) {
+ char[] pwd = dataProvider.getProperty(uri, char[].class, AuthDataProvider.PASSWORD, "passphrase", message); // NOI18N
+ if (pwd != null) {
+ callback.setPassword(pwd);
+ return true;
}
- synchronized (lock) {
- boolean result;
-
- CertPassphraseDlg pwdDlg = new CertPassphraseDlg();
-
- result = pwdDlg.askPassword(env, arg0);
-
- if (result) {
- passphrase = new String(pwdDlg.getPassword());
- pwdDlg.clearPassword();
- return true;
- } else {
- throw new CancellationException(loc("USER_AUTH_CANCELED")); // NOI18N
- }
- }
+ return false;
}
@Override
- public boolean promptYesNo(String str) {
- Object[] options = {"yes", "no"}; // NOI18N
- int foo;
-
- synchronized (lock) {
- foo = JOptionPane.showOptionDialog(parent, str,
- loc("TITLE_YN_Warning"), // NOI18N
- JOptionPane.DEFAULT_OPTION,
- JOptionPane.WARNING_MESSAGE, null, options, options[0]);
- }
-
- return foo == 0;
+ public boolean promptYesNo(String message) {
+ NotifyDescriptor nd = new NotifyDescriptor.Confirmation(message, NbBundle.getMessage(RemoteUserInfo.class, "TITLE_YN_Warning"));
+ DialogDisplayer.getDefault().notify(nd);
+ return nd.getValue() == NotifyDescriptor.YES_OPTION;
}
@Override
public void showMessage(String message) {
- synchronized (lock) {
- JOptionPane.showMessageDialog(parent, message);
- }
+ NotifyDescriptor nd = new NotifyDescriptor.Message(message);
+ DialogDisplayer.getDefault().notify(nd);
}
@Override
@@ -187,7 +133,7 @@
if (prompt.length == 1 && !echo[0]) {
// this is a password request
- if (!promptPassword(loc("MSG_PasswordInteractive", // NOI18N
+ if (!promptPassword(NbBundle.getMessage(RemoteUserInfo.class, "MSG_PasswordInteractive", // NOI18N
destination, prompt[0]))) {
return null;
} else {
@@ -203,8 +149,4 @@
return null;
}
}
-
- private static String loc(String key, String... params) {
- return NbBundle.getMessage(RemoteUserInfo.class, key, params);
- }
}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalConnection.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalConnection.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalConnection.java
@@ -0,0 +1,110 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.local;
+
+import java.net.InetAddress;
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.impl.common.ShellBasedConnectionInfoProvider;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessCreator;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+/**
+ *
+ * @author akrasny
+ */
+public final class LocalConnection implements ConnectionImplementation {
+
+ private static final LocalConnection instance = new LocalConnection();
+ private final Lookup lookup;
+ private final URI uri;
+
+ private LocalConnection() {
+ lookup = Lookups.fixed(ShellBasedConnectionInfoProvider.getInstance());
+ URI localuri = null;
+ try {
+ String user = System.getProperty("user.name"); // NOI18N
+ InetAddress addr = InetAddress.getLocalHost();
+ String hostname = addr.getHostName();
+ localuri = new URI("localhost://" + user + "@" + hostname); // NOI18N
+ } catch (Exception ex) {
+ throw new InternalError("Unable to detect localhost's URI"); // NOI18N
+ } finally {
+ uri = localuri;
+ }
+ }
+
+ static LocalConnection getInstance() {
+ return instance;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return true;
+ }
+
+ @Override
+ public NativeProcessCreator newProcessBuilderImpl() throws NativeExecutionException {
+ return new LocalProcessCreator();
+ }
+
+ @Override
+ public String toString() {
+ return "localhost";
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return lookup;
+ }
+
+ @Override
+ public void disconnect() {
+ }
+
+ @Override
+ public URI getURI() {
+ return uri;
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalConnector.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalConnector.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalConnector.java
@@ -0,0 +1,80 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.local;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.impl.jsch.JSchConnector;
+import org.netbeans.modules.nativeexecution.spi.AuthDataProvider;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.spi.ConnectorImplementation;
+import org.netbeans.modules.nativeexecution.util.URIMatcher;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author akrasny
+ */
+@ServiceProvider(service = org.netbeans.modules.nativeexecution.spi.ConnectorImplementation.class, path = "ConnectionService/localhost", position = 10)
+public final class LocalConnector implements ConnectorImplementation {
+
+ @Override
+ public ConnectionImplementation connectTo(final URI uri, final AuthDataProvider authDataProvider) throws InterruptedException, NativeExecutionException {
+ LocalConnection local = LocalConnection.getInstance();
+
+ if (new URIMatcher(local.getURI()).isIdenticalURI(uri)) {
+ return local;
+ }
+
+ try {
+ // TODO: Maybe ask user what to do...
+ URI remoteSSH = new URI("ssh://" + uri.getUserInfo() + "@" + uri.getHost() + ":22"); // NOI18N
+ JSchConnector jschConnector = Lookups.forPath("ConnectionService/ssh").lookup(JSchConnector.class); // NOI18N
+ return jschConnector.connectTo(remoteSSH, authDataProvider);
+ } catch (URISyntaxException ex) {
+ }
+
+ return null;
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessCreator.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessCreator.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessCreator.java
@@ -0,0 +1,68 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.local;
+
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessCreator;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessImplementation;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+
+/**
+ *
+ * @author akrasny
+ */
+final class LocalProcessCreator implements NativeProcessCreator {
+
+ @Override
+ public Map> getSupportedProperties() {
+ return LocalProcessParams.getSupportedProperties();
+ }
+
+ @Override
+ public NativeProcessImplementation createAndStart(NativeProcessParams params) throws NativeExecutionException {
+ if (params.getShellScript() == null && params.getCommand() == null) {
+ throw new NullPointerException("Command is not specified"); // NOI18N
+ }
+ return new LocalProcessImpl(params).createAndStart();
+ }
+}
\ No newline at end of file
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessImpl.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessImpl.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessImpl.java
@@ -0,0 +1,119 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.local;
+
+import com.sun.jna.Pointer;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.impl.common.AbstractNativeProcessImpl;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+
+/**
+ *
+ * @author akrasny
+ */
+final class LocalProcessImpl extends AbstractNativeProcessImpl {
+
+ private Process process;
+
+ LocalProcessImpl(final NativeProcessParams params) {
+ super(params);
+ }
+
+ @Override
+ protected ProcessStreams create(List command) throws NativeExecutionException {
+ ProcessBuilder pb = new ProcessBuilder(command);
+ Map env = getParams().getEnvironment();
+ if (!env.isEmpty()) {
+ Map penv = pb.environment();
+ penv.clear();
+ penv.putAll(env);
+ }
+ try {
+ process = pb.start();
+ } catch (IOException ex) {
+ throw new NativeExecutionException(ex);
+ }
+
+ int pid = -1;
+
+ try {
+ String className = process.getClass().getName();
+ if ("java.lang.Win32Process".equals(className) || "java.lang.ProcessImpl".equals(className)) { // NOI18N
+ Field f = process.getClass().getDeclaredField("handle"); // NOI18N
+ f.setAccessible(true);
+ long phandle = f.getLong(process);
+
+ Win32APISupport kernel = Win32APISupport.instance;
+ Win32APISupport.HANDLE handle = new Win32APISupport.HANDLE();
+ handle.setPointer(Pointer.createConstant(phandle));
+ pid = kernel.GetProcessId(handle);
+ } else if ("java.lang.UNIXProcess".equals(className)) { // NOI18N
+ Field f = process.getClass().getDeclaredField("pid"); // NOI18N
+ f.setAccessible(true);
+ pid = f.getInt(process);
+ }
+ } catch (Throwable e) {
+ }
+
+ return new ProcessStreams(process.getInputStream(), process.getErrorStream(), process.getOutputStream(), pid);
+ }
+
+ @Override
+ protected ProcessStreams create(String shell, String script) throws NativeExecutionException {
+ return create(Arrays.asList(shell, "-c", script)); // NOI18N
+ }
+
+ @Override
+ public void destroy() {
+ process.destroy();
+ }
+
+ @Override
+ public int waitResult() throws InterruptedException {
+ return process.waitFor();
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessParams.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessParams.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessParams.java
@@ -0,0 +1,68 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.local;
+
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author akrasny
+ */
+final class LocalProcessParams {
+
+ private static final Map> props = new HashMap>();
+
+ static {
+ props.put("commandCharset", Charset.class); // NOI18N
+ props.put("outputCharset", Charset.class); // NOI18N
+ props.put("ptyMode", Boolean.class); // NOI18N
+ props.put("ptyType", String.class); // NOI18N
+ props.put("terminalMode", byte[].class); // NOI18N
+ }
+
+ public static Map> getSupportedProperties() {
+ return Collections.unmodifiableMap(props);
+ }
+}
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalURIIdentifier.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalURIIdentifier.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/LocalURIIdentifier.java
@@ -0,0 +1,78 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.local;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.spi.URIIdentifier;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author akrasny
+ */
+@ServiceProvider(service = org.netbeans.modules.nativeexecution.spi.URIIdentifier.class, path = "ConnectionService/localhost", position = 100)
+public class LocalURIIdentifier implements URIIdentifier {
+
+ private final URI localhost = LocalConnection.getInstance().getURI();
+
+ @Override
+ public boolean areIdentical(URI uri1, URI uri2) {
+ String host1 = uri1.getHost();
+ String host2 = uri2.getHost();
+ if (host1 == null) {
+ host1 = localhost.getHost();
+ }
+ if (host2 == null) {
+ host2 = localhost.getHost();
+ }
+
+ String user1 = uri1.getUserInfo();
+ String user2 = uri2.getUserInfo();
+ if (user1 == null) {
+ user1 = localhost.getUserInfo();
+ }
+ if (user2 == null) {
+ user2 = localhost.getUserInfo();
+ }
+ return host1.equals(host2) && user1.equals(user2);
+ }
+}
diff --git a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/Win32APISupport.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/Win32APISupport.java
copy from dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/Win32APISupport.java
copy to nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/Win32APISupport.java
--- a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/Win32APISupport.java
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/local/Win32APISupport.java
@@ -39,7 +39,7 @@
*
* Portions Copyrighted 2009 Sun Microsystems, Inc.
*/
-package org.netbeans.modules.nativeexecution.support;
+package org.netbeans.modules.nativeexecution.impl.local;
import com.sun.jna.FromNativeContext;
import com.sun.jna.Native;
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/resources/Bundle.properties b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/resources/Bundle.properties
new file mode 100755
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/resources/Bundle.properties
@@ -0,0 +1,2 @@
+OpenIDE-Module-Name=Native Execution Implementation
+
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/resources/hostinfo.sh b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/resources/hostinfo.sh
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/resources/hostinfo.sh
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
+HOSTNAME=`uname -n`
+OS=`uname -s`
+CPUTYPE=`uname -p`
+BITNESS=32
+
+LS=/bin/ls
+OSFAMILY=
+DATETIME=`date -u +'%Y-%m-%d %H:%M:%S'`
+
+if [ "${OS}" = "SunOS" ]; then
+ BITNESS=`isainfo -b`
+ OSFAMILY="SOLARIS"
+ OSNAME="SunOS"
+ OSBUILD=`head -1 /etc/release | sed -e "s/^ *//"`
+ CPUNUM=`/usr/sbin/psrinfo -v | grep "^Status of" | wc -l | sed 's/^ *//'`
+else
+ if [ "${OS}" = "Darwin" ]; then
+ sysctl hw.cpu64bit_capable | grep -q "1$"
+ if [ $? -eq 0 ]; then
+ BITNESS=64
+ fi
+ else
+ uname -a | egrep "x86_64|WOW64" >/dev/null
+ if [ $? -eq 0 ]; then
+ BITNESS=64
+ fi
+ fi
+
+ if [ -f "/etc/sun-release" ]; then
+ OSNAME="${OS}-JDS"
+ OSBUILD=`head -1 /etc/sun-release`
+ elif [ -f /etc/SuSE-release ]; then
+ OSNAME="${OS}-SuSE"
+ OSBUILD=`cat /etc/SuSE-release | tr "\n" " "`;
+ elif [ -f /etc/redhat-release ]; then
+ OSNAME="${OS}-Redhat"
+ OSBUILD=`head -1 /etc/redhat-release`
+ elif [ -f /etc/gentoo-release ]; then
+ OSNAME="${OS}-Gentoo"
+ OSBUILD=`head -1 /etc/gentoo-release`
+ elif [ -f /etc/lsb-release ]; then
+ OSNAME="${OS}-"`cat /etc/lsb-release | grep DISTRIB_ID | sed 's/.*=//'`
+ OSBUILD=`cat /etc/lsb-release | grep DISTRIB_DESCRIPTION | sed 's/.*=//' | sed 's/"//g'`
+ fi
+fi
+
+OSFAMILY=${OSFAMILY:-`echo ${OS} | grep _NT- >/dev/null && echo WINDOWS`}
+OSFAMILY=${OSFAMILY:-`test "$OS" = "Darwin" && echo MACOSX`}
+OSFAMILY=${OSFAMILY:-`test "$OS" = "Linux" && echo LINUX`}
+OSFAMILY=${OSFAMILY:-${OS}}
+
+CPUFAMILY=`(echo ${CPUTYPE} | egrep "^i|x86_64|athlon|Intel" >/dev/null && echo x86) || echo ${CPUTYPE}`
+if [ "${CPUFAMILY}" != "x86" -a "${CPUFAMILY}" != "sparc" ]; then
+ CPUTYPE=`uname -m`
+fi
+CPUFAMILY=`(echo ${CPUTYPE} | egrep "^i|x86_64|athlon|Intel" >/dev/null && echo x86) || echo ${CPUTYPE}`
+
+USERDIRBASE=${HOME}
+
+if [ "${OSFAMILY}" = "LINUX" ]; then
+ CPUNUM=`cat /proc/cpuinfo | grep processor | wc -l | sed 's/^ *//'`
+elif [ "${OSFAMILY}" = "WINDOWS" ]; then
+ CPUNUM=$NUMBER_OF_PROCESSORS
+ OSNAME=`uname`
+ USERDIRBASE=${USERPROFILE}
+elif [ "${OSFAMILY}" = "MACOSX" ]; then
+ CPUNUM=`hostinfo | awk '/processor.*logical/{print $1}'`
+ OSNAME="MacOSX"
+ OSBUILD=`hostinfo | sed -n '/kernel version/{n;p;}' | sed 's/[ ]*\([^:]*\).*/\1/'`
+fi
+
+USER=${USER:-`logname 2>/dev/null`}
+USER=${USER:-${USERNAME}}
+TMPBASE=${TMPBASE:-/var/tmp}
+
+SUFFIX=0
+TMPDIRBASE=${TMPBASE}/nbexec_${USER}
+mkdir -p ${TMPDIRBASE}
+while [ ! -w ${TMPDIRBASE} -a ${SUFFIX} -lt 5 ]; do
+ echo "Warning: ${TMPDIRBASE} is not writable">&2
+ SUFFIX=`expr 1 + ${SUFFIX}`
+ TMPDIRBASE=${TMPBASE}/nbexec_${USER}_${SUFFIX}
+ /bin/mkdir -p ${TMPDIRBASE} 2>/dev/null
+done
+
+if [ -w ${TMPDIRBASE} ]; then
+ SUFFIX=0
+ TMPBASE=${TMPDIRBASE}
+ TMPDIRBASE=${TMPBASE}/${NB_KEY}
+ mkdir -p ${TMPDIRBASE}
+ while [ ! -w ${TMPDIRBASE} -a ${SUFFIX} -lt 5 ]; do
+ echo "Warning: ${TMPDIRBASE} is not writable">&2
+ SUFFIX=`expr 1 + ${SUFFIX}`
+ TMPDIRBASE=${TMPBASE}/${NB_KEY}_${SUFFIX}
+ /bin/mkdir -p ${TMPDIRBASE} 2>/dev/null
+ done
+fi
+
+if [ ! -w ${TMPDIRBASE} ]; then
+ TMPDIRBASE=${TMPBASE}
+fi
+
+if [ ! -w ${TMPDIRBASE} ]; then
+ echo "Error: {TMPDIRBASE} is not writable">&2
+fi
+
+ID=`LC_MESSAGES=C /usr/bin/id`
+
+echo
+echo @@@@@INFO
+echo BITNESS=${BITNESS}
+echo CPUFAMILY=${CPUFAMILY}
+echo CPUNUM=${CPUNUM}
+echo CPUTYPE=${CPUTYPE}
+echo HOSTNAME=${HOSTNAME}
+echo OSNAME=${OSNAME}
+echo OSBUILD=${OSBUILD}
+echo OSFAMILY=${OSFAMILY}
+echo USER=${USER}
+echo SHELL=${SHELL}
+echo USERDIRBASE=${USERDIRBASE}
+echo TMPDIRBASE=${TMPDIRBASE}
+echo DATETIME=${DATETIME}
+echo ID=${ID}
+echo @@@@@ENV
+env
+exit 0
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/util/EnvironmentMapWriter.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/util/EnvironmentMapWriter.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/util/EnvironmentMapWriter.java
@@ -0,0 +1,97 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.util;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.regex.Pattern;
+import org.netbeans.modules.nativeexecution.impl.ExecutionLogger;
+
+/**
+ *
+ * @author akrasny
+ */
+public final class EnvironmentMapWriter {
+
+ public static final HashSet varsNotForExport = new HashSet(Arrays.asList(
+ "SSH_AUTH_SOCK", "SSH_CONNECTION", "SSH_CLIENT", "SSH_TTY", "TZ", "HZ", "SHELL" // NOI18N
+ ));
+
+ private EnvironmentMapWriter() {
+ }
+
+ public static void write(OutputStreamWriter writer, Map environmentMap) throws IOException {
+ if (environmentMap.entrySet().isEmpty()) {
+ return;
+ }
+ // Very simple sanity check of vars...
+ Pattern pattern = Pattern.compile("[a-zA-Z0-9_]+"); // NOI18N
+
+ for (Map.Entry entry : environmentMap.entrySet()) {
+ String name = entry.getKey();
+
+ if (varsNotForExport.contains(name)) {
+ continue;
+ }
+
+ String value = entry.getValue();
+ // check capitalized key by pattern
+ if (!pattern.matcher(name).matches()) {
+ ExecutionLogger.getInstance().log(Level.WARNING,
+ "Will not pass environment variable named {0} as it contains non alpha-numeric characters", name); // NOI18N
+ continue;
+ }
+
+ if (value.indexOf('"') >= 0) { // NOI18N
+ value = value.replace("\"", "\\\""); // NOI18N
+ }
+
+ writer.write(name + "=\"" + value + "\" && export " + name + "\n"); // NOI18N
+ }
+
+ writer.flush();
+ }
+}
diff --git a/nativeexecution.impl/test/unit/src/org/netbeans/modules/nativeexecution/impl/jsch/RemoteProcessImplTest.java b/nativeexecution.impl/test/unit/src/org/netbeans/modules/nativeexecution/impl/jsch/RemoteProcessImplTest.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/test/unit/src/org/netbeans/modules/nativeexecution/impl/jsch/RemoteProcessImplTest.java
@@ -0,0 +1,148 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.jsch;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.junit.After;
+import org.junit.AfterClass;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.netbeans.modules.nativeexecution.access.ConnectionAccessor;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.ConnectionManager;
+import org.netbeans.modules.nativeexecution.api.EnvironmentMap;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcessBuilder;
+import org.netbeans.modules.nativeexecution.spi.AuthDataProvider;
+import org.netbeans.modules.nativeexecution.util.ProcessUtils;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Andrew
+ */
+public class RemoteProcessImplTest {
+
+ private URI remoteURI = null;
+
+ public RemoteProcessImplTest() {
+ String host = System.getProperty("ne.remote.host"); // NOI18N
+ if (host != null) {
+ try {
+ remoteURI = new URI("ssh://tester@" + host + ":22"); // NOI18N
+ } catch (URISyntaxException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ @Test
+ public void testEnvironmentMap() throws Exception {
+ if (remoteURI == null) {
+ System.out.println("Skipped. To proceed, please use -Dne.remote.host= in test.run.args parameters list.");
+ System.out.println("It is expected that host can be logged in by user 'tester' with a password 'tester'.");
+ return;
+ }
+
+ Connection c = null;
+ try {
+ c = ConnectionManager.connect(remoteURI, new AuthDataProviderImpl());
+ NativeProcessBuilder pb = c.newProcessBuilder();
+ EnvironmentMap env = pb.getEnvironmentMap();
+ assertNotNull("EnvironmentMap is never NULL", env);
+ assertFalse("Environment map should not be empty", env.isEmpty());
+ env.put("testEnvironmentMap", "some-value");
+
+ assertNull("testEnvironmentMap should NOT be in the map of other process builder",
+ c.newProcessBuilder().getEnvironmentMap().get("testEnvironmentMap"));
+
+ assertTrue("testEnvironmentMap should be in the map", "some-value".equals(env.get("testEnvironmentMap")));
+ assertTrue("testEnvironmentMap should be in the map", "some-value".equals(pb.getEnvironmentMap().get("testEnvironmentMap")));
+
+ pb.setCommand("env");
+ ProcessUtils.ExitStatus status = ProcessUtils.execute(pb);
+ String data = "\n" + status.output + "\n";
+ String[] split = data.split("\n");
+
+ assertTrue(Math.abs(100 - (split.length * 100 / env.size())) < 10);
+ assertTrue("testEnvironmentMap should be in the env", data.indexOf("\ntestEnvironmentMap=some-value\n") > 0);
+ } finally {
+ if (c != null) {
+ ConnectionAccessor.getDefault().getImpl(c).disconnect();
+ }
+ }
+ }
+
+ private static class AuthDataProviderImpl implements AuthDataProvider {
+
+ @Override
+ public T getProperty(URI uri, Class clazz, String name, Object... misc) {
+ Object result = null;
+
+ if (String.class.equals(clazz) && "KnownHostsFile".equals(name)) {
+ result = System.getProperty("user.home") + "/.ssh/known_hosts";
+ } else if (char[].class.equals(clazz) && AuthDataProvider.PASSWORD.equals(name)) {
+ result = new char[]{'t', 'e', 's', 't', 'e', 'r'};
+ }
+
+ return clazz.cast(result);
+ }
+ }
+}
diff --git a/nativeexecution.impl/test/unit/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessTest.java b/nativeexecution.impl/test/unit/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessTest.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/test/unit/src/org/netbeans/modules/nativeexecution/impl/local/LocalProcessTest.java
@@ -0,0 +1,143 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.local;
+
+import java.net.URI;
+import org.junit.After;
+import org.junit.AfterClass;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.ConnectionManager;
+import org.netbeans.modules.nativeexecution.api.EnvironmentMap;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcessBuilder;
+import org.netbeans.modules.nativeexecution.util.ProcessUtils;
+import org.netbeans.modules.nativeexecution.util.ProcessUtils.ExitStatus;
+
+/**
+ *
+ * @author akrasny
+ */
+public class LocalProcessTest {
+
+ public LocalProcessTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of create method, of class LocalProcess.
+ */
+ @Test
+ public void testCreate() throws Exception {
+ Connection connection1 = ConnectionManager.getConnection(new URI("localhost"));
+ Connection connection2 = ConnectionManager.getConnection(connection1.getURI());
+ Connection connection3 = ConnectionManager.getLocalConnection();
+
+ assertEquals(connection1, connection2);
+ assertEquals(connection2, connection3);
+
+ assertTrue(connection1 == connection2);
+ assertTrue(connection2 == connection3);
+
+ assertTrue(connection1.isConnected());
+ assertTrue(connection2.isConnected());
+ assertTrue(connection3.isConnected());
+ }
+
+ @Test
+ public void testEnvironmentMap() throws Exception {
+ Connection c = ConnectionManager.getLocalConnection();
+ NativeProcessBuilder pb = c.newProcessBuilder();
+ EnvironmentMap env = pb.getEnvironmentMap();
+ assertNotNull("EnvironmentMap is never NULL", env);
+ assertFalse("Environment map should not be empty", env.isEmpty());
+ env.put("testEnvironmentMap", "some-value");
+
+ assertNull("testEnvironmentMap should NOT be in the map of other process builder",
+ c.newProcessBuilder().getEnvironmentMap().get("testEnvironmentMap"));
+
+ assertTrue("testEnvironmentMap should be in the map", "some-value".equals(env.get("testEnvironmentMap")));
+ assertTrue("testEnvironmentMap should be in the map", "some-value".equals(pb.getEnvironmentMap().get("testEnvironmentMap")));
+
+ pb.setCommand("env");
+ ExitStatus status = ProcessUtils.execute(pb);
+ String data = "\n" + status.output + "\n";
+ String[] split = data.split("\n");
+
+ assertTrue(Math.abs(100 - (split.length * 100 / env.size())) < 10);
+ assertTrue("testEnvironmentMap should be in the env", data.indexOf("\ntestEnvironmentMap=some-value\n") > 0);
+ }
+//
+// @Test
+// public void testEnvironmentMap() throws Exception {
+// Connection c = ConnectionManager.getLocalConnection();
+// NativeProcessBuilder pb = c.newProcessBuilder().setCommand("/bin/ls", "/tmp");
+// ExitStatus result = ProcessUtils.execute(pb);
+// System.out.println(result.output);
+//
+// pb.getEnvironmentMap().dump(System.out);
+// System.out.println("----");
+// Map environment = new ProcessBuilder("").environment();
+// for (Map.Entry entry : environment.entrySet()) {
+// System.out.println(entry.getKey() + " = " + entry.getValue());
+// }
+//
+// ConnectionManager.getLocalConnection();
+// }
+}
diff --git a/nativeexecution/arch.xml b/nativeexecution/arch.xml
new file mode 100644
--- /dev/null
+++ b/nativeexecution/arch.xml
@@ -0,0 +1,1200 @@
+
+
+]>
+
+
+
+ &api-questions;
+
+
+
+
+
+ Native Execution API is intended to provide a flexible and extendable
+ aid for running external processes on a local or remote hosts.
+
+
+ The module itself doesn't provide any specific implementation. It
+ also doesn't make any strict obligations on what is considered to be a
+ Process or a Host. But it has some assumptions regarging those
+ entities though...
+
+
+ But first, two words about what this module is about and what it is not.
+ This module is NOT about hosts management nor it is about connections
+ management system (in sense of UI elements, persistance, etc.). This
+ module is almost entirely about establishing a connection to some
+ destination target (usually a host), running a process there and
+ getting back it's I/O. Also some basic utilities are provided that
+ could make these tasks easier to achieve.
+
+
+ From the SPI implementor point of view this module is a set of
+ extension points to introduce own notion of Process/Connection
+ and add own implementation without a need to deal (a lot) with
+ threading and other annoying issues...
+
+
+ This API/SPI was written while keeping in mind a previous experiense
+ with NativeExecution module. An attempt to re-design some questinoable
+ approaches used in the previous implementation has been made.
+
+ Requirements for the module:
+
+
Extensibility - provide a way for adding new authorization
+ schemes, new transport layers
+
Separatation between host (whatever it could be), user,
+ authorization way and transport
+
+
Clear error-flow
+
Clear threading model
+
Clear control over streams encodings
+
Easy to use utilities
+
+
+ The entity a user of this API starts with is a Connection.
+ Any connection is identified by an URI. ConnectionManager is asked
+ to give a connection for some URI and this Connection becames a
+ provider of a NativeProcessBuilder which in turn can be used to
+ start a NativeProcess in the context of that Connection.
+
+
+ A scheme of an URI passed to the ConnectionManager is used to lookup
+ an SPI implementor that can initiate, establish and provide a connection.
+ All SPI implementors that deal with particular 'kind' of connections
+ are registered in "ConnectionService/<scheme>" lookup path.
+
+
+
+
+
+
+
+
+ There are already many users on an old API. The intention (and
+ success metric) is to move all client of the old API to this one.
+
+ Unit tests will be provided. Also there should be no regression in
+ old API client's functionality.
+
+
+
+
+
+
+
+
+ This module should became a public replacement for dlight.nativeexecution module.
+
+ As API is changed all friend-modules should be modified to use this new one.
+ In most cases this should not be difficult, but taking into accont the
+ number of 'old' API clients (100+ friend modules) this task could take a while.
+ Estimation is two months.
+
+
+
+
+
+
+
+
+ This module could be used for running external processes on a local and
+ remote hosts. It is extendable and SPI implementors could provide different
+ implementation of connections and processes... But at least two
+ implementations are to be provided together with this module (in a
+ separate implementation module).
+
+ They are for starting local processes ("localhost" scheme) and remote
+ processes using Jsch services ("ssh" scheme).
+
+ Common usage is:
+
+
+ This module provides an API/SPI be used for running external
+ processes on a local or remote hosts.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Process-related API from dlight.nativeexecution is planned to be
+ first deprecated and then, when transition is done, demoved from
+ the product.
+
+
+
+
+
+
+
+
+ Yes. Currently it has no UI except a ProgressBar which indicates a
+ connection to a remote host progress.
+
+
+
+
+
+
+
+
+ N/A
+
+
+
+
+
+
+
+
+ There is no any persistance in this module (at least for now).
+
+ Module is extendable with SPI provided.
+
+
+
+
+
+
+
+
+ jre 1.6+
+
+
+
+
+
+
+
+
+ JRE is enough.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ none. The default implementation of remote processes support uses jsch.
+ But this is a different (implementation) module.
+
+
+
+
+
+
+
+
+ This module is almos a pure API/SPI so it is platform-independent.
+
+ Implementation module with support of Windows, Linux, Solaris and MacOS
+ will be provided.
+
+
+
+
+
+
+
+
+ This module needs implementation of the "localhost" scheme support.
+ OpenIDE-Module-Needs: ConnectionService.localhost
+
+
+
+
+
+
+
+
+ just JAR.
+
+
+
+
+
+
+
+
+ Yes.
+
+
+
+
+
+
+
+
+ There are several public API/SPI packages provided by this module.
+
+
+
+
+
+
+
+
+ Installation location doesn't not matter, but as this module will
+ become a part of the ide cluster, most likely it will be in a shared
+ location.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ See ConnectionInfoProvider javadoc.
+
+
+
+
+
+
+
+
+ There are connection-specific properties that could be of any kind.
+ SPI implementor defines pairs of property name -- class and later
+ API clients are expected to get/set defined properties of defined
+ classes. Runtime type checking is performed in put/get methods. See
+ javadoc for NativeProcessBuilder, AuthDataProvider.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ Yes. This module is about starting external processes. It is up to
+ client to work with a result of execution.
+
+
+
+
+
+
+
+
+ "ide.execution.logger.level" is used to define a logger level.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ Some classes (most) are thread-safe, others are not. If class is not
+ thread-safe, it is described in a javadoc.
+
+
+
+
+
+
+ N/A
+
+
+
+
+
+
+
+
+ N/A
+
+
+
+
+
+
+
+
+ N/A
+
+
+
+
+
+
+
+
+ Yes, Lookup is in use. Connection has an associated Lookup that is
+ explored to get implementations of some specific services
+ (like ConnectionInfoProvider, SignalSupportProvider).
+ Also AuthDataProvider, URIIdentifier and Connector implementations
+ are registered in the global lookup within a "ConnectionService/<scheme>"
+ path.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ N/A
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ Yes. They are run outside the ETD.
+
+
+
+
+
+
+
+
+ N/A
+
+
+
+
+
+
+
+
+ There is a code that can be plugged in and that can influence the
+ performance (like listeners implementations, as they are notified
+ synchroniously). But this is done outside the EDT...
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ Yes. There is a thread that is started once a second to test if all
+ known connections are still alive.
+
+ This thread exists only if there are listeners that are waiting for
+ "connection lost" event and only if there is at least one active
+ connection.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
diff --git a/nativeexecution/build.xml b/nativeexecution/build.xml
new file mode 100755
--- /dev/null
+++ b/nativeexecution/build.xml
@@ -0,0 +1,5 @@
+
+
+ Builds, tests, and runs the project org.netbeans.modules.nativeexecution
+
+
diff --git a/nativeexecution/manifest.mf b/nativeexecution/manifest.mf
new file mode 100755
--- /dev/null
+++ b/nativeexecution/manifest.mf
@@ -0,0 +1,7 @@
+Manifest-Version: 1.0
+AutoUpdate-Show-In-Client: false
+OpenIDE-Module: org.netbeans.modules.nativeexecution
+OpenIDE-Module-Implementation-Version: 1
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/nativeexecution/resources/Bundle.properties
+OpenIDE-Module-Needs: ConnectionService.localhost
+
diff --git a/nativeexecution/nbproject/project.properties b/nativeexecution/nbproject/project.properties
new file mode 100755
--- /dev/null
+++ b/nativeexecution/nbproject/project.properties
@@ -0,0 +1,5 @@
+javac.source=1.6
+javac.compilerargs=-Xlint -Xlint:-serial
+javadoc.arch=${basedir}/arch.xml
+spec.version.base=1.0
+
diff --git a/nativeexecution/nbproject/project.xml b/nativeexecution/nbproject/project.xml
new file mode 100644
--- /dev/null
+++ b/nativeexecution/nbproject/project.xml
@@ -0,0 +1,93 @@
+
+
+ org.netbeans.modules.apisupport.project
+
+
+ org.netbeans.modules.nativeexecution
+
+
+ org.netbeans.api.progress
+
+
+
+ 1
+ 1.28
+
+
+
+ org.openide.modules
+
+
+
+ 7.32
+
+
+
+ org.openide.util
+
+
+
+ 8.24
+
+
+
+ org.openide.util.lookup
+
+
+
+ 8.15
+
+
+
+
+
+ unit
+
+ org.netbeans.api.progress
+
+
+
+ org.netbeans.libs.junit4
+
+
+
+ org.netbeans.modules.nativeexecution.impl
+
+
+
+
+ org.netbeans.modules.nbjunit
+
+
+
+
+ org.netbeans.modules.progress.ui
+
+
+
+
+ org.openide.dialogs
+
+
+
+ org.openide.util
+
+
+
+
+ org.openide.util.lookup
+
+
+
+
+
+ org.netbeans.modules.nativeexecution.api
+ org.netbeans.modules.nativeexecution.api.process
+ org.netbeans.modules.nativeexecution.spi
+ org.netbeans.modules.nativeexecution.spi.process
+ org.netbeans.modules.nativeexecution.spi.support
+ org.netbeans.modules.nativeexecution.util
+
+
+
+
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/ExecutionLogger.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/ExecutionLogger.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/ExecutionLogger.java
@@ -0,0 +1,161 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import java.util.logging.StreamHandler;
+import javax.swing.SwingUtilities;
+
+/**
+ * Logger that is used in the Execution's code.
+ *
+ * Has some utility methods...
+ *
+ * @author akrasny
+ */
+public final class ExecutionLogger extends Logger {
+
+ private static final boolean assertionsEnabled;
+ private static final ExecutionLogger instance = new ExecutionLogger();
+
+ static {
+ boolean ea = false;
+ assert (ea = true);
+ assertionsEnabled = ea;
+ String level_str = System.getProperty("ide.execution.logger.level", "INFO").toUpperCase(); // NOI18N
+ Level level = Level.INFO;
+
+ try {
+ level = Level.parse(level_str);
+ } catch (IllegalArgumentException ex) {
+ }
+
+ instance.addHandler(new LoggerHandler());
+ instance.setLevel(level);
+ }
+ private static final long startTimeMillis = System.currentTimeMillis();
+
+ private static class LoggerHandler extends StreamHandler {
+
+ LoggerHandler() {
+ setOutputStream(System.out);
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ String msg = getFormatter().format(record);
+ System.out.println("[" + (record.getMillis() - startTimeMillis) + " ms.] " + msg); // NOI18N
+ record.setMessage("[" + (record.getMillis() - startTimeMillis) + " ms.] " + record.getMessage()); // NOI18N
+ super.publish(record);
+ }
+
+ @Override
+ public void flush() {
+ super.flush();
+ }
+
+ @Override
+ public void close() throws SecurityException {
+ }
+ }
+
+ private ExecutionLogger() {
+ super("ide.execution.logger", null); // NOI18N
+ }
+
+ public static ExecutionLogger getInstance() {
+ return instance;
+ }
+
+ public static void assertTrue(boolean value) {
+ if (assertionsEnabled && !value) {
+ String message = "Assertion error"; // NOI18N
+ instance.log(Level.SEVERE, message, new Exception(message));
+ }
+ }
+
+ public static void assertTrue(boolean value, String message) {
+ if (assertionsEnabled && !value) {
+ instance.log(Level.SEVERE, message, new Exception(message));
+ }
+ }
+
+ public static void assertFalse(boolean value) {
+ if (assertionsEnabled && value) {
+ String message = "Assertion error"; // NOI18N
+ instance.log(Level.SEVERE, message, new Exception(message));
+ }
+ }
+
+ public static void assertFalse(boolean value, String message) {
+ if (assertionsEnabled && value) {
+ instance.log(Level.SEVERE, message, new Exception(message));
+ }
+ }
+
+ public static void assertNonUiThread(String message) {
+ if (assertionsEnabled && SwingUtilities.isEventDispatchThread()) {
+ instance.log(Level.FINE, message, new Exception(message));
+ }
+ }
+
+ public static void assertNonUiThread() {
+ assertNonUiThread("Should not be called from UI thread"); // NOI18N
+ }
+
+ public static void fullThreadDump(String title) {
+ final Set> stack = Thread.getAllStackTraces().entrySet();
+ System.err.printf("----- %s Start Thread Dump-----\n", title == null ? "" : title); // NOI18N
+ for (Map.Entry entry : stack) {
+ System.err.println(entry.getKey().getName());
+ for (StackTraceElement element : entry.getValue()) {
+ System.err.println("\tat " + element.toString()); // NOI18N
+ }
+ System.err.println();
+ }
+ System.err.println("----- End Thread Dump-----"); // NOI18N
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/access/ConnectionAccessor.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/ConnectionAccessor.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/ConnectionAccessor.java
@@ -0,0 +1,86 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.access;
+
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @author akrasny
+ */
+public abstract class ConnectionAccessor {
+
+ private static volatile ConnectionAccessor DEFAULT;
+
+ public static void setDefault(ConnectionAccessor accessor) {
+ if (DEFAULT != null) {
+ throw new IllegalStateException(
+ "ConnectionManagerAccessor is already defined"); // NOI18N
+ }
+
+ DEFAULT = accessor;
+ }
+
+ public static synchronized ConnectionAccessor getDefault() {
+ if (DEFAULT != null) {
+ return DEFAULT;
+ }
+
+ try {
+ Class.forName(Connection.class.getName(), true,
+ Connection.class.getClassLoader());
+ } catch (ClassNotFoundException ex) {
+ }
+
+ return DEFAULT;
+ }
+
+ public abstract Connection createConnection(ConnectionImplementation impl);
+
+ public abstract Lookup getConnectionLookup(Connection connection);
+
+ public abstract void setImpl(Connection connection, ConnectionImplementation impl);
+
+ public abstract ConnectionImplementation getImpl(Connection connection);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/access/EnvironmentMapAccessor.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/EnvironmentMapAccessor.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/EnvironmentMapAccessor.java
@@ -0,0 +1,82 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.access;
+
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+import org.netbeans.modules.nativeexecution.api.EnvironmentMap;
+
+/**
+ *
+ * @author akrasny
+ */
+public abstract class EnvironmentMapAccessor {
+
+ private static volatile EnvironmentMapAccessor DEFAULT;
+
+ public static void setDefault(EnvironmentMapAccessor accessor) {
+ if (DEFAULT != null) {
+ throw new IllegalStateException(
+ "ConnectionManagerAccessor is already defined"); // NOI18N
+ }
+
+ DEFAULT = accessor;
+ }
+
+ public static synchronized EnvironmentMapAccessor getDefault() {
+ if (DEFAULT != null) {
+ return DEFAULT;
+ }
+
+ try {
+ Class.forName(EnvironmentMap.class.getName(), true,
+ EnvironmentMap.class.getClassLoader());
+ } catch (ClassNotFoundException ex) {
+ }
+
+ return DEFAULT;
+ }
+
+ public abstract void store(EnvironmentMap envMap, Preferences envprop) throws BackingStoreException;
+
+ public abstract EnvironmentMap load(Preferences envprop) throws BackingStoreException;
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/access/NativeProcessAccessor.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/NativeProcessAccessor.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/NativeProcessAccessor.java
@@ -0,0 +1,82 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.access;
+
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcess;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+
+/**
+ *
+ * @author akrasny
+ */
+public abstract class NativeProcessAccessor {
+
+ private static volatile NativeProcessAccessor DEFAULT;
+
+ public static void setDefault(NativeProcessAccessor accessor) {
+ if (DEFAULT != null) {
+ throw new IllegalStateException(
+ "NativeProcessAccessor is already defined"); // NOI18N
+ }
+
+ DEFAULT = accessor;
+ }
+
+ public static synchronized NativeProcessAccessor getDefault() {
+ if (DEFAULT != null) {
+ return DEFAULT;
+ }
+
+ try {
+ Class.forName(NativeProcess.class.getName(), true,
+ NativeProcess.class.getClassLoader());
+ } catch (ClassNotFoundException ex) {
+ }
+
+ return DEFAULT;
+ }
+
+ public abstract NativeProcessParams getProcessParams(final NativeProcess process);
+
+ public abstract Connection getConnection(final NativeProcess process);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/access/NativeProcessBuilderFactory.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/NativeProcessBuilderFactory.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/NativeProcessBuilderFactory.java
@@ -0,0 +1,80 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.access;
+
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcessBuilder;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessCreator;
+
+/**
+ *
+ * @author akrasny
+ */
+public abstract class NativeProcessBuilderFactory {
+
+ private static volatile NativeProcessBuilderFactory DEFAULT;
+
+ public static void setDefault(NativeProcessBuilderFactory accessor) {
+ if (DEFAULT != null) {
+ throw new IllegalStateException(
+ "NativeProcessBuilderFactory is already defined"); // NOI18N
+ }
+
+ DEFAULT = accessor;
+ }
+
+ public static synchronized NativeProcessBuilderFactory getDefault() {
+ if (DEFAULT != null) {
+ return DEFAULT;
+ }
+
+ try {
+ Class.forName(NativeProcessBuilder.class.getName(), true,
+ NativeProcessBuilder.class.getClassLoader());
+ } catch (ClassNotFoundException ex) {
+ }
+
+ return DEFAULT;
+ }
+
+ public abstract NativeProcessBuilder newProcessBuilder(NativeProcessCreator impl, Connection connection);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/access/NativeProcessParamsFactory.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/NativeProcessParamsFactory.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/access/NativeProcessParamsFactory.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.access;
+
+import java.util.List;
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+
+/**
+ *
+ * @author akrasny
+ */
+public abstract class NativeProcessParamsFactory {
+
+ private static volatile NativeProcessParamsFactory DEFAULT;
+
+ public static void setDefault(NativeProcessParamsFactory accessor) {
+ if (DEFAULT != null) {
+ throw new IllegalStateException(
+ "NativeProcessParamsFactory is already defined"); // NOI18N
+ }
+
+ DEFAULT = accessor;
+ }
+
+ public static synchronized NativeProcessParamsFactory getDefault() {
+ if (DEFAULT != null) {
+ return DEFAULT;
+ }
+
+ try {
+ Class.forName(NativeProcessParams.class.getName(), true,
+ NativeProcessParams.class.getClassLoader());
+ } catch (ClassNotFoundException ex) {
+ }
+
+ return DEFAULT;
+ }
+
+ public abstract NativeProcessParams newNativeProcessParams(Connection connection,
+ Map connectionInfo, Map environmentMap,
+ Map properties, List command, String shell,
+ String shellScript, boolean redirectError, String wdir);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/BrokenConnectionException.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/BrokenConnectionException.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/BrokenConnectionException.java
@@ -0,0 +1,62 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+
+/**
+ * Extension of the ConnectionException that is thrown when some action that
+ * requires an active connection is invoked on a dead one.
+ *
+ * @author akrasny
+ */
+public class BrokenConnectionException extends ConnectionException {
+
+ /**
+ * Constructs a new BrokenConnectionException.
+ *
+ * @param uri an URI of the broken connection.
+ */
+ public BrokenConnectionException(URI uri) {
+ super(uri, "HOST_NOT_CONNECTED"); // NOI18N
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/Bundle.properties b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/Bundle.properties
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/Bundle.properties
@@ -0,0 +1,43 @@
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+#
+# Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+# Other names may be trademarks of their respective owners.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common
+# Development and Distribution License("CDDL") (collectively, the
+# "License"). You may not use this file except in compliance with the
+# License. You can obtain a copy of the License at
+# http://www.netbeans.org/cddl-gplv2.html
+# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+# specific language governing permissions and limitations under the
+# License. When distributing the software, include this License Header
+# Notice in each file and include the License file at
+# nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the GPL Version 2 section of the License file that
+# accompanied this code. If applicable, add the following below the
+# License Header, with the fields enclosed by brackets [] replaced by
+# your own identifying information:
+# "Portions Copyrighted [year] [name of copyright owner]"
+#
+# If you wish your version of this file to be governed by only the CDDL
+# or only the GPL Version 2, indicate your decision by adding
+# "[Contributor] elects to include this software in this distribution
+# under the [CDDL or GPL Version 2] license." If you do not indicate a
+# single choice of license, a recipient has the option to distribute
+# your version of this file under either the CDDL, the GPL Version 2 or
+# to extend the choice of license to its licensees as provided above.
+# However, if you add GPL Version 2 code and therefore, elected the GPL
+# Version 2 license, then the option applies only if the new code is
+# made subject to such option by the copyright holder.
+#
+# Contributor(s):
+#
+# Portions Copyrighted 2012 Sun Microsystems, Inc.
+
+ConnectionManager.progress.message=Connection progress
+ConnectionManager.progress.connectTo=Connecting to {0}
+ConnectionManager.progress.fetchingInfo=Getting connection info
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/Connection.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/Connection.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/Connection.java
@@ -0,0 +1,167 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.access.ConnectionAccessor;
+import org.netbeans.modules.nativeexecution.access.NativeProcessBuilderFactory;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcessBuilder;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.spi.ConnectorImplementation;
+import org.netbeans.modules.nativeexecution.spi.URIIdentifier;
+import org.openide.util.Lookup;
+
+/**
+ * A connection (execution session).
+ *
+ *
Connection provides an access to a {@link ProcessBuilder} in the context
+ * of the associated session. One should use services provided by the
+ * {@link ConnectionManager} class to get a Connection.
+ *
+ * @author akrasny
+ */
+public final class Connection {
+
+ private final Object implLock = new Object();
+ private ConnectionImplementation impl;
+
+ /**
+ * Constructs a new API object for provided implementation.
+ *
+ * @param uri an URI this connection is associated with.
+ */
+ private Connection(ConnectionImplementation impl) {
+ this.impl = impl;
+ }
+
+ /**
+ * Returns an actual URI this connection is associated with.
+ *
+ * @return an URI this connection is associated with.
+ * @see ConnectorImplementation
+ * @see URIIdentifier
+ */
+ public URI getURI() {
+ synchronized (implLock) {
+ return impl.getURI();
+ }
+ }
+
+ /**
+ * Tests if the connection is alive.
+ *
+ * @return true if connection is established, false otherwise.
+ */
+ public boolean isConnected() {
+ synchronized (implLock) {
+ return impl == null ? false : impl.isConnected();
+ }
+ }
+
+ /**
+ * Creates a new {@link NativeProcessBuilder} to be used for starting
+ * processes within this connection.
+ *
+ * @return a new not configured {@link NativeProcessBuilder}.
+ * @throws NativeExecutionException if some problem occurred
+ */
+ public NativeProcessBuilder newProcessBuilder() throws NativeExecutionException {
+ synchronized (implLock) {
+ if (!isConnected()) {
+ throw new BrokenConnectionException(impl.getURI());
+ }
+
+ return NativeProcessBuilderFactory.getDefault().newProcessBuilder(impl.newProcessBuilderImpl(), this);
+ }
+ }
+
+ /**
+ * Returns a human-readable string representation of the connection.
+ *
+ * @return a string representation of the connection.
+ */
+ @Override
+ public String toString() {
+ synchronized (implLock) {
+ return impl.toString();
+ }
+ }
+
+ //
+ private static class ConnectionAccessorImpl extends ConnectionAccessor {
+
+ @Override
+ public Lookup getConnectionLookup(Connection connection) {
+ ConnectionImplementation impl;
+
+ synchronized (connection.implLock) {
+ impl = connection.impl;
+ }
+
+ return impl == null ? Lookup.EMPTY : impl.getLookup();
+ }
+
+ @Override
+ public Connection createConnection(ConnectionImplementation impl) {
+ return new Connection(impl);
+ }
+
+ @Override
+ public void setImpl(Connection connection, ConnectionImplementation impl) {
+ synchronized (connection.implLock) {
+ connection.impl = impl;
+ }
+ }
+
+ @Override
+ public ConnectionImplementation getImpl(Connection connection) {
+ synchronized (connection.implLock) {
+ return connection.impl;
+ }
+ }
+ }
+
+ static {
+ ConnectionAccessor.setDefault(new ConnectionAccessorImpl());
+ }
+ //
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionCancelledException.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionCancelledException.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionCancelledException.java
@@ -0,0 +1,62 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+
+/**
+ * Extension of the ConnectionException that denotes user-driven interruption of
+ * a connection process.
+ *
+ * @author akrasny
+ */
+public class ConnectionCancelledException extends ConnectionException {
+
+ /**
+ * Constructs a new ConnectionCancelledException instance.
+ *
+ * @param uri an URI of the canceled connection.
+ */
+ public ConnectionCancelledException(URI uri) {
+ super(uri, "CONNECTION_CANCELLED"); // NOI18N
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionException.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionException.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionException.java
@@ -0,0 +1,96 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+
+/**
+ * This exception is thrown if any connection-related problem occurs.
+ *
+ * @author akrasny
+ */
+public class ConnectionException extends NativeExecutionException {
+
+ private final URI uri;
+
+ /**
+ * Constructs a ConnectionException with the specified detail message and
+ * nested exception.
+ *
+ * @param uri an URI of the connection.
+ * @param msg the detail message.
+ * @param cause the nested exception.
+ */
+ public ConnectionException(URI uri, String msg, Throwable cause) {
+ super(msg, cause);
+ this.uri = uri;
+ }
+
+ /**
+ * Constructs a ConnectionException with the specified detailed message.
+ *
+ * @param uri an URI of the connection.
+ * @param msg the detail message.
+ */
+ public ConnectionException(URI uri, String msg) {
+ this(uri, msg, null);
+ }
+
+ /**
+ * Constructs a ConnectionException with the specified nested exception.
+ *
+ * @param uri an URI of the connection
+ * @param cause the nested exception
+ */
+ public ConnectionException(URI uri, Throwable cause) {
+ this(uri, cause == null ? null : cause.getMessage(), cause);
+ }
+
+ /**
+ * Returns an URI of the connection destination.
+ *
+ * @return the URI of the connection destination.
+ */
+ public final URI getURI() {
+ return uri;
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionManager.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionManager.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionManager.java
@@ -0,0 +1,237 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.access.ConnectionAccessor;
+import org.netbeans.modules.nativeexecution.api.ConnectionStateChangeEvent.State;
+import org.netbeans.modules.nativeexecution.common.ConnectionListeners;
+import org.netbeans.modules.nativeexecution.common.ConnectionsPool;
+import org.netbeans.modules.nativeexecution.common.Connector;
+import org.netbeans.modules.nativeexecution.spi.AuthDataProvider;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.spi.URIIdentifier;
+import org.openide.util.Exceptions;
+
+/**
+ * An entry-point class for getting a {@link Connection} to the desired
+ * destination.
+ *
+ *
All ConnectionManager's methods are thread-safe.
+ *
+ * @author akrasny
+ */
+public final class ConnectionManager {
+
+ private static final Connection LOCAL_CONNECTION;
+
+ static {
+ Connection local = null;
+ try {
+ local = ConnectionManager.connect(new URI("localhost"), null); // NOI18N
+ } catch (Throwable th) {
+ Exceptions.printStackTrace(th);
+ } finally {
+ LOCAL_CONNECTION = local;
+ }
+ }
+
+ private ConnectionManager() {
+ }
+
+ /**
+ * Returns a connection to a local host.
+ *
+ *
This connection is always active (connected) and doesn't require any
+ * authorization.
+ *
+ * @return the connection to a localhost (current host, current user).
+ */
+ public static Connection getLocalConnection() {
+ return LOCAL_CONNECTION;
+ }
+
+ /**
+ *
+ * Returns previously established {@link Connection} identified by the same
+ * or equivalent URI.
+ *
+ *
This method is fast and could be invoked from the EDT.
+ *
+ *
There is a notion of equivalent URIs that could verbally differ, but
+ * denote the same destination. See {@link URIIdentifier}.
+ *
+ *
+ * @param uri the URI that identifies a connection to get.
+ * @return previously established active connection or {@code null}, if no
+ * active connection exists.
+ *
+ * @see URIIdentifier
+ */
+ public static Connection getConnection(final URI uri) {
+ Connection connection = ConnectionsPool.get(uri);
+
+ if (connection == null || !connection.isConnected()) {
+ return null;
+ }
+
+ return connection;
+ }
+
+ /**
+ * An implicit request to establish a connection with a destination
+ * identified by the provided URI.
+ *
+ *
This method acts like {@code connect(uri, null)}
+ *
+ * @param uri the URI of a desired connection destination.
+ * @see #connect(URI, AuthDataProvider)
+ * @throws NativeExecutionException if connection process was canceled or
+ * failed by any other reason.
+ */
+ public static Connection connect(URI uri) throws NativeExecutionException {
+ return connect(uri, null);
+ }
+
+ /**
+ * An implicit request to establish a connection with the destination
+ * identified by the provided URI using provided additional source of
+ * authentication data.
+ *
+ *
No new connection is established if a connection identified by this or
+ * equivalent URI already exists. The existent one is returned instead.
+ *
+ *
Infrastructure asks passed {@link AuthDataProvider} to provide any
+ * authentication data needed for connection establishment. In case no
+ * requested info is provided by the passed provider, the default one
+ * (supplied by an SPI implementor) is queried. Each of these providers
+ * could initiate user interaction in order to get needed information.
+ *
+ *
This method could be called from any thread (including ETD). In latter
+ * case a modal dialog with a progress bar is used to avoid UI
+ * deadlocks.
+ *
+ *
Note that provider may return a connection with an URI that is
+ * absolutely different from the passed one. This could happen, for example,
+ * when request connection to an URI that doesn't precisely identifies the
+ * final destination - like {@code ssh://testhost}. In this case
+ * AuthDataProvider could be asked to provide a user name and the URI of a
+ * connection could be changed to {@code ssh://user@testhost}.
+ *
+ * @param uri the URI of a desired connection destination.
+ * @param authProvider provider of authentication data needed for connection
+ * establishment.
+ *
+ * @throws NativeExecutionException if connection process was canceled or
+ * failed by any other reason.
+ */
+ public static Connection connect(URI uri, AuthDataProvider authProvider) throws NativeExecutionException {
+ Connection connection = ConnectionsPool.get(uri);
+
+ if (connection != null && connection.isConnected()) {
+ return connection;
+ }
+
+ ConnectionAccessor access = ConnectionAccessor.getDefault();
+ ConnectionImplementation impl = Connector.connect(uri, authProvider);
+ assert impl != null;
+
+ if (connection == null) {
+ connection = access.createConnection(impl);
+ ConnectionsPool.add(connection);
+ } else {
+ access.setImpl(connection, impl);
+ }
+
+ ConnectionStateChangeEvent ev = new ConnectionStateChangeEvent(connection.getURI(), State.CONNECTION_ESTABLISHED);
+ ConnectionListeners.notifyListeners(connection.getURI(), ev);
+ return connection;
+ }
+
+ /**
+ * An implicit request to close previously established connection.
+ *
+ * @param c Connection to terminate
+ */
+ static void disconnect(Connection c) {
+ if (!c.isConnected()) {
+ return;
+ }
+
+ ConnectionListeners.stopTrackingTask();
+ ConnectionAccessor access = ConnectionAccessor.getDefault();
+ access.getImpl(c).disconnect();
+ if (!c.isConnected()) {
+ ConnectionStateChangeEvent ev = new ConnectionStateChangeEvent(c.getURI(), State.CONNECTION_CLOSED);
+ ConnectionListeners.notifyListeners(c.getURI(), ev);
+ }
+ }
+
+ /**
+ * Adds a listener to state changes of a connection to a given URI.
+ *
+ *
It permits you to listen to a connection which is not established
+ * yet, or continue listening to it after it is disconnected, reconnected,
+ * etc.
+ *
+ *
A listener can listen to any number of URIs. Note that listeners are
+ * always held weakly - if the listener is collected, it is quietly
+ * removed.
+ *
+ * @param listener ConnectionStateChangeListener to listen to changes in
+ * Connection state.
+ * @param uri URI of the Connection target (even not connected yet existing)
+ */
+ public static void addConnectionStateChangeListener(ConnectionStateChangeListener listener, URI uri) {
+ ConnectionListeners.addConnectionStateChangeListener(listener, uri);
+ }
+
+ /**
+ * Removes a listener to state changes of a given connection destination.
+ *
+ * @param listener ConnectionStateChangeListener to be removed
+ * @param uri URI of the Connection target
+ */
+ public static void removeConnectionStateChangeListener(ConnectionStateChangeListener listener, URI uri) {
+ ConnectionListeners.removeConnectionStateChangeListener(listener, uri);
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionStateChangeEvent.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionStateChangeEvent.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionStateChangeEvent.java
@@ -0,0 +1,113 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+import java.util.EventObject;
+
+/**
+ * An Event object that provides information about the source of a
+ * connection-related event.
+ *
+ *
+ * {@link ConnectionStateChangeEvent}s are sent to registered {@link ConnectionStateChangeListener}s
+ * when status of some connection changes.
+ *
+ * @see ConnectionManager
+ *
+ * @author akrasny
+ */
+public final class ConnectionStateChangeEvent extends EventObject {
+
+ private static final long serialVersionUID = 1L;
+ private final State state;
+
+ /**
+ * Constructs a new {@link ConnectionStateChangeEvent}.
+ *
+ * @param uri an URI of the connection this event belongs to.
+ * @param state the new {@link State} of the connection.
+ */
+ public ConnectionStateChangeEvent(URI uri, State state) {
+ super(uri);
+ this.state = state;
+ }
+
+ /**
+ * Returns a {@link State} this event was generated for.
+ *
+ * @return the {@link State} of the connection this event was issued for.
+ */
+ public State getState() {
+ return state;
+ }
+
+ /**
+ * Returns the {@link URI} this event relates to.
+ *
+ * @return the related {@link URI}.
+ */
+ @Override
+ public URI getSource() {
+ return (URI) super.getSource();
+ }
+
+ /**
+ * Enumeration of possible {@link State}s that events are generated for.
+ */
+ public enum State {
+
+ /**
+ * Issued when a new connection is established.
+ */
+ CONNECTION_ESTABLISHED,
+ /**
+ * Issued when a connection is implicitly terminated.
+ */
+ CONNECTION_CLOSED,
+ /**
+ * Issued when infrastructure detects that connection is not active
+ * while no implicit termination was performed.
+ */
+ CONNECTION_LOST
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionStateChangeListener.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionStateChangeListener.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/ConnectionStateChangeListener.java
@@ -0,0 +1,69 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.util.EventListener;
+
+/**
+ * Used to be notified about active connections state changes.
+ *
+ *
+ * @author akrasny
+ */
+public interface ConnectionStateChangeListener extends EventListener {
+
+ /**
+ * Is invoked on connection state change.
+ *
+ *
It is guaranteed that events are delivered in the same order they
+ * occur.
+ *
+ *
For implicit actions (connect/disconnect) events are sent
+ * synchronously and instantly. But there is an event that is asynchronous
+ * by it's nature - it is when connection is lost. In this case there could
+ * be a delay in event delivery until after infrastructure detects a broken
+ * connection.
+ *
+ * @param event the event that describes a state change.
+ */
+ public void connectionStateChanged(ConnectionStateChangeEvent event);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/DestinationUnreachableException.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/DestinationUnreachableException.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/DestinationUnreachableException.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+
+/**
+ * Extension of the ConnectionException that denotes that connection target
+ * point is not accessible.
+ *
+ * @author akrasny
+ */
+public class DestinationUnreachableException extends ConnectionException {
+
+ /**
+ * Constructs a new DestinationUnreachableException exception with the
+ * destination URI.
+ *
+ * @param uri an URI of the unreachable destination.
+ */
+ public DestinationUnreachableException(URI uri) {
+ super(uri, "DESTINATION_UNREACHABLE"); // NOI18N
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/EnvironmentMap.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/EnvironmentMap.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/EnvironmentMap.java
@@ -0,0 +1,239 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+import org.netbeans.modules.nativeexecution.access.EnvironmentMapAccessor;
+import org.netbeans.modules.nativeexecution.util.MacroMap;
+import org.openide.util.Exceptions;
+
+/**
+ * An extension of a {@link MacroMap} extended with methods to work on PATH-like
+ * variables.
+ *
+ *
This collection is NOT thread-safe.
+ *
+ * @author akrasny
+ */
+public final class EnvironmentMap extends MacroMap implements Cloneable {
+
+ private final char pathSeparator;
+ private final Mode mode;
+
+ private EnvironmentMap(Mode mode, char pathSeparator, Comparator super String> comparator) {
+ super(comparator);
+ this.mode = mode;
+ this.pathSeparator = pathSeparator;
+ }
+
+ private EnvironmentMap(Mode mode, MacroMap map, char pathSeparator) {
+ super(map);
+ this.mode = mode;
+ this.pathSeparator = pathSeparator;
+ }
+
+ /**
+ * Returns a new empty {@link EnvironmentMap} with a specified {@code pathSeparator}
+ * to be used when dealing with PATH-like variables and that uses a
+ * case-sensitive algorithm for comparing variable names.
+ *
+ * @param pathSeparator a char to be used as a separator when dealing with
+ * PATH-like variables.
+ * @return new empty case-sensitive {@link EnvironmentMap}.
+ */
+ public static EnvironmentMap createCaseSensitive(char pathSeparator) {
+ return new EnvironmentMap(Mode.CaseSensitive, pathSeparator, null);
+ }
+
+ /**
+ * Returns a new empty {@link EnvironmentMap} with a specified {@code pathSeparator}
+ * to be used when dealing with PATH-like variables and that uses a
+ * case-preserving algorithm for comparing variable names.
+ *
+ * @param pathSeparator a char to be used as a separator when dealing with
+ * PATH-like variables.
+ * @return new empty case-preserving {@link EnvironmentMap}.
+ */
+ public static EnvironmentMap createCasePreserving(char pathSeparator) {
+ Collator collator = Collator.getInstance(Locale.US);
+ collator.setStrength(Collator.PRIMARY);
+ return new EnvironmentMap(Mode.CasePreserving, pathSeparator, collator);
+ }
+
+ /**
+ * Prepends provided path to the value of the specified variable.
+ *
+ *
As a result a variable with the name {@code name} will contain {@code path}
+ * at the first place. Also if the same path was already in the list of
+ * paths, that 'old' entry will be removed to avoid unneeded
+ * duplications.
+ *
+ *
If specified variable was not defined yet before this method
+ * invocation, it will have the only entry - this new path.
+ *
+ * @param name the name of the variable to change.
+ * @param path the path element to add to the list of path elements. Could
+ * be {@code null}, but in this case method does nothing.
+ */
+ public void prependPath(String name, String path) {
+ if (path == null) {
+ return;
+ }
+
+ String oldpath = get(name);
+ String newPath = path + (oldpath == null ? "" : (pathSeparator) + oldpath); // NOI18N
+ put(name, reducePath(newPath));
+ }
+
+ /**
+ * Appends provided path to the value of the specified variable.
+ *
+ *
As a result a {@code path} will be appended to a value of variable
+ * with the name {@code name}. If the same path was already in the list of
+ * paths the value of the variable will remain unchanged.
+ *
+ *
If the variable named {@code name} was not defined yet before this
+ * method invocation, the variable will have the only entry - this new
+ * path.
+ *
+ * @param name the name of the variable to change.
+ * @param path the path element to append to the list of path elements.
+ * Could be {@code null}, but in this case method does nothing.
+ */
+ public void appendPath(String name, String path) {
+ if (path == null) {
+ return;
+ }
+
+ String oldpath = get(name);
+ String newPath = (oldpath == null ? "" : oldpath + (pathSeparator)) + path; // NOI18N
+ put(name, reducePath(newPath));
+ }
+
+ private String reducePath(String path) {
+ if (path.isEmpty()) {
+ return path;
+ }
+
+ LinkedHashSet elems = new LinkedHashSet();
+ String e;
+ elems.addAll(Arrays.asList(path.split("" + pathSeparator))); // NOI18N
+ StringBuilder sb = new StringBuilder();
+ for (String elem : elems) {
+ e = elem.trim();
+ if (e.isEmpty()) {
+ continue;
+ }
+ sb.append(pathSeparator).append(e);
+ }
+ return sb.substring(1);
+ }
+
+ /**
+ * Deep copy of the map.
+ *
+ * @return a copy of this map with the same characteristics (path separator,
+ * case sensitivity).
+ * @throws CloneNotSupportedException
+ */
+ @Override
+ public EnvironmentMap clone() throws CloneNotSupportedException {
+ MacroMap map = super.clone();
+ return new EnvironmentMap(mode, map, pathSeparator);
+ }
+
+ private enum Mode {
+
+ CaseSensitive,
+ CasePreserving
+ }
+
+ //
+ private static class EnvironmentMapAccessorImpl extends EnvironmentMapAccessor {
+
+ @Override
+ public void store(EnvironmentMap envMap, Preferences envprop) throws BackingStoreException {
+ try {
+ EnvironmentMap copy = envMap.clone();
+ envprop.put("*pathSeparator", "" + copy.pathSeparator);
+ envprop.put("*mode", "" + copy.mode.name());
+ for (Map.Entry entry : copy.entrySet()) {
+ envprop.put(entry.getKey(), entry.getValue());
+ }
+ envprop.flush();
+ } catch (CloneNotSupportedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+
+ @Override
+ public EnvironmentMap load(Preferences envprop) throws BackingStoreException {
+ List keys = new ArrayList(Arrays.asList(envprop.keys()));
+ keys.remove("*pathSeparator"); // NOI18N
+ keys.remove("*mode"); // NOI18N
+ String sps = envprop.get("*pathSeparator", ":"); // NOI18N
+ String smode = envprop.get("*mode", Mode.CaseSensitive.name()); // NOI18N
+
+ char ps = sps.charAt(0);
+ Mode mode = Mode.valueOf(smode);
+ EnvironmentMap map = Mode.CaseSensitive.equals(mode) ? createCaseSensitive(ps) : createCasePreserving(ps);
+ for (String key : keys) {
+ map.put(key, envprop.get(key, "")); // NOI18N
+ }
+ return map;
+ }
+ }
+
+ static {
+ EnvironmentMapAccessor.setDefault(new EnvironmentMapAccessorImpl());
+ }
+ //
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeExecutionException.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeExecutionException.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeExecutionException.java
@@ -0,0 +1,85 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+/**
+ * The root exception of all execution-related exceptions.
+ *
+ * This exception is thrown if any execution problem occurs.
+ *
+ * @author akrasny
+ */
+public class NativeExecutionException extends Exception {
+
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a NativeExecutionException with the specified, detailed
+ * message.
+ *
+ * @param msg the detail message.
+ */
+ public NativeExecutionException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a NativeExecutionException with the specified detail message
+ * and nested exception.
+ *
+ * @param msg the detail message.
+ * @param cause the nested exception.
+ */
+ public NativeExecutionException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Constructs a NativeExecutionException with the specified nested
+ * exception.
+ *
+ * @param cause the nested exception.
+ */
+ public NativeExecutionException(Throwable cause) {
+ super(cause.getMessage(), cause);
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/NativeProcess.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/NativeProcess.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/NativeProcess.java
@@ -0,0 +1,340 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api.process;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+import org.netbeans.modules.nativeexecution.access.NativeProcessAccessor;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.api.process.ProcessStateChangeEvent.State;
+import org.netbeans.modules.nativeexecution.common.ProcessStateChangeNotifier;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessCreator;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessImplementation;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+import org.openide.util.Exceptions;
+import org.openide.util.RequestProcessor;
+
+/**
+ * An object that represents an external process.
+ *
+ * @author akrasny
+ */
+public final class NativeProcess extends Process {
+
+ private static final RequestProcessor waitThreadPool = new RequestProcessor("Process waitThreadPool", 50); // NOI18N
+ private final ReentrantLock stateLock = new ReentrantLock();
+ private final ProcessStateChangeNotifier notifier;
+ private final NativeProcessCreator creator;
+ private final NativeProcessParams params;
+ private final AtomicBoolean killed = new AtomicBoolean(false);
+ private State state = State.INITIAL;
+ private NativeProcessImplementation processImpl;
+ private Future waitTask = null;
+ private InputStream inputStream;
+ private InputStream errorStream;
+ private OutputStream outputStream;
+
+ static {
+ NativeProcessAccessor.setDefault(new NativeProcessAccessorImpl());
+ }
+
+ NativeProcess(NativeProcessCreator creator, NativeProcessParams params, ProcessStateChangeNotifier notifier) {
+ this.creator = creator;
+ this.params = params;
+ this.notifier = notifier;
+ inputStream = new ByteArrayInputStream(new byte[0]);
+ errorStream = new ByteArrayInputStream(new byte[0]);
+ outputStream = new ByteArrayOutputStream();
+ }
+
+ NativeProcess start() throws NativeExecutionException {
+ try {
+ setState(State.STARTING);
+ processImpl = creator.createAndStart(params);
+
+ inputStream = processImpl.getInputStream();
+ errorStream = processImpl.getErrorStream();
+ outputStream = processImpl.getOutputStream();
+
+ setState(State.RUNNING);
+
+ waitTask = waitThreadPool.submit(new Callable() {
+
+ @Override
+ public Integer call() throws Exception {
+ Thread.currentThread().setName("Waiting for " + processImpl.toString()); // NOI18N
+ int exitCode = -1;
+
+ try {
+ exitCode = processImpl.waitResult();
+ setState(State.FINISHED);
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ setState(State.CANCELLED);
+ killProcess();
+ return exitCode;
+ } catch (Exception ex) {
+ setState(State.ERROR);
+ killProcess();
+ throw ex;
+ } catch (Throwable th) {
+ setState(State.ERROR);
+ killProcess();
+ throw new java.util.concurrent.ExecutionException(th);
+ }
+
+ return exitCode;
+ }
+ });
+ } catch (Throwable ex) {
+ throw new NativeExecutionException(ex);
+ }
+
+ return this;
+ }
+
+ private void killProcess() {
+ if (killed.getAndSet(true)) {
+ return;
+ }
+
+ processImpl.destroy();
+ }
+
+ /**
+ * Returns a current state of the process.
+ *
+ * @return the current state.
+ */
+ public State getState() {
+ State result;
+ stateLock.lock();
+ try {
+ result = state;
+ } finally {
+ stateLock.unlock();
+ }
+ return result;
+ }
+
+ private boolean isFinalState(final State state) {
+ return state == State.CANCELLED || state == State.ERROR || state == State.FINISHED;
+ }
+
+ /**
+ * Sets a current state of the process.
+ *
+ * There is a notion of a final state. Once a process was set into one of
+ * the final state, it's state will not change.
+ *
+ * A final state is one of the CANCELLED, ERROR or FINISHED.
+ *
+ * @param state a new state of the process.
+ */
+ private void setState(final State state) {
+ stateLock.lock();
+ try {
+ if (this.state == state || isFinalState(this.state)) {
+ return;
+ }
+
+ this.state = state;
+
+ if (notifier != null) {
+ notifier.notifyProcessStateChange(state);
+ }
+ } finally {
+ stateLock.unlock();
+ }
+ }
+
+ /**
+ * Returns a PID of the process.
+ *
+ * PID is provided by implementors of an SPI. By convention, if PID cannot
+ * be provided, -1 is returned.
+ *
+ * @return the PID of the process or -1 if real PID cannot be provided.
+ */
+ public int getPID() {
+ return processImpl.getPID();
+ }
+
+ /**
+ * Gets the output stream of the process.
+ *
+ *
Output to the stream is piped into the standard input stream of the
+ * process represented by this {@link NativeProcess} object.
+ *
+ * @return the output stream connected to the normal input of the process.
+ */
+ @Override
+ public OutputStream getOutputStream() {
+ return outputStream;
+ }
+
+ /**
+ * Gets the input stream of the process.
+ *
+ *
The stream obtains data piped from the standard output stream of the
+ * process represented by this {@link NativeProcess} object.
+ *
+ * @return the input stream connected to the normal output of the process.
+ */
+ @Override
+ public InputStream getInputStream() {
+ return inputStream;
+ }
+
+ /**
+ * Gets the error stream of the process.
+ *
+ *
The stream obtains data piped from the error output stream of the
+ * process represented by this {@link NativeProcess} object.
+ *
+ * @return the input stream connected to the error stream of the process.
+ */
+ @Override
+ public InputStream getErrorStream() {
+ return errorStream;
+ }
+
+ /**
+ * Causes the current thread to wait, if necessary, until the process
+ * represented by this {@link NativeProcess} object has terminated.
+ *
+ *
This method returns immediately if the process has already terminated.
+ * If the process has not yet terminated, the calling thread will be blocked
+ * until the process exits.
+ *
+ * @return the exit value of the process. By convention, 0 indicates normal
+ * termination.
+ * @throws InterruptedException if the current thread is interrupted by
+ * another thread while it is waiting, then the wait is ended and an
+ * InterruptedException is thrown.
+ */
+ @Override
+ public int waitFor() throws InterruptedException {
+ try {
+ return waitTask.get();
+ } catch (java.util.concurrent.ExecutionException ex) {
+ // Should not happen.
+ // Exception here could mean that there are problems in
+ // implementation
+ Exceptions.printStackTrace(ex);
+ throw new InternalError(ex.toString());
+ }
+ }
+
+ /**
+ * Returns the exit value for the process.
+ *
+ *
{@link IllegalThreadStateException} is thrown if process is not
+ * terminated yet.
+ *
+ * @return the exit value of the process represented by this {@link NativeProcess}
+ * object. By convention, the value {@code 0} indicates normal termination.
+ */
+ @Override
+ public int exitValue() {
+ if (!waitTask.isDone()) {
+ // Process not started/finished yet...
+ throw new IllegalThreadStateException();
+ }
+
+ try {
+ return waitTask.get();
+ } catch (InterruptedException ex) {
+ // Should not happen
+ Thread.interrupted();
+ return -1;
+ } catch (java.util.concurrent.ExecutionException ex) {
+ // Should not happen.
+ // Exception here could mean that there are problems in
+ // implementation
+ Exceptions.printStackTrace(ex);
+ throw new InternalError(ex.toString());
+ }
+ }
+
+ /**
+ * Kills the subprocess.
+ *
+ * The subprocess represented by this {@link NativeProcess} object is
+ * forcibly terminated.
+ */
+ @Override
+ public void destroy() {
+ waitTask.cancel(true);
+ }
+
+ /**
+ * Returns a human-readable identification of the
+ * {@link NativeProcess}.
+ *
+ * @return string that identifies the {@link NativeProcess}.
+ */
+ @Override
+ public String toString() {
+ return "/PID=" + getPID() + "/ " + processImpl.toString(); // NOI18N
+ }
+
+ private static class NativeProcessAccessorImpl extends NativeProcessAccessor {
+
+ @Override
+ public Connection getConnection(NativeProcess process) {
+ return process.params.getConnection();
+ }
+
+ @Override
+ public NativeProcessParams getProcessParams(NativeProcess process) {
+ return process.params;
+ }
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/NativeProcessBuilder.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/NativeProcessBuilder.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/NativeProcessBuilder.java
@@ -0,0 +1,368 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api.process;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+import org.netbeans.modules.nativeexecution.access.NativeProcessBuilderFactory;
+import org.netbeans.modules.nativeexecution.access.NativeProcessParamsFactory;
+import org.netbeans.modules.nativeexecution.api.BrokenConnectionException;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.ConnectionManager;
+import org.netbeans.modules.nativeexecution.api.EnvironmentMap;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.api.process.ProcessStateChangeEvent.State;
+import org.netbeans.modules.nativeexecution.common.ConnectionsInfo;
+import org.netbeans.modules.nativeexecution.common.ProcessStateChangeNotifier;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessCreator;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfo;
+import org.openide.util.RequestProcessor;
+
+/**
+ * This class is used to create an external processes.
+ *
+ *
Each NativeProcessBuilder instance manages a collection of process
+ * attributes. The {@link #call()} method creates a new {@link NativeProcess}
+ * instance with those attributes. The {@link #call()} method can be invoked
+ * repeatedly from the same instance to create new processes with identical or
+ * related attributes.
+ *
+ *
There are several common attributes that could be configured directly by
+ * invoking appropriate methods. Additional {@link Connection}-specific
+ * attributes could be provided by a specific implementation. Access to those
+ * attributes is done using {@link #getSupportedProperties()} and {@link #setProperty(String, Object)}
+ * methods.
+ *
+ *
Modifying a NativeProcessBuilder's attributes will affect processes
+ * subsequently started by it's {@link #call()} method, but will never affect
+ * previously started processes.
+ *
+ *
This class is NOT thread-safe.
+ *
+ * @see ConnectionManager
+ * @author akrasny
+ */
+public final class NativeProcessBuilder implements Callable {
+
+ private final NativeProcessCreator creator;
+ private final Connection connection;
+ private final Map> supportedProperties;
+ private final Map properties = new HashMap();
+ private final List listeners = new ArrayList();
+ private final EnvironmentMap environmentMap;
+ private List command;
+ private boolean redirectError;
+ private String shellScript;
+ private String shell;
+ private String wdir;
+
+ /**
+ * Creates a new instance of NativeProcessBuilder.
+ *
+ * @param connection the {@link Connection} to use for this builder.
+ * @param supportedProperties a map of supported configurable properties.
+ */
+ private NativeProcessBuilder(NativeProcessCreator creator, Connection connection) {
+ Map> propDescr = creator.getSupportedProperties();
+ ConnectionInfo info = ConnectionsInfo.getConnectionInfo(connection.getURI());
+ this.creator = creator;
+ this.connection = connection;
+ this.supportedProperties = propDescr == null
+ ? Collections.>emptyMap()
+ : Collections.unmodifiableMap(propDescr);
+ EnvironmentMap envMapCopy = null;
+ try {
+ envMapCopy = (info == null || info.getEnvironmentMap() == null)
+ ? EnvironmentMap.createCaseSensitive(':')
+ : info.getEnvironmentMap().clone();
+ } catch (CloneNotSupportedException ex) {
+ } finally {
+ environmentMap = envMapCopy == null ? EnvironmentMap.createCaseSensitive(':') : envMapCopy;
+ }
+ }
+
+ /**
+ * Adds a listener to the list that is notified each time a state of any {@link NativeProcess}
+ * created by this builder changes.
+ *
+ *
Added listener will be passed to every subsequently created
+ * NativeProcess. Already running NativeProcess will not see any changes in
+ * the listeners list.
+ *
+ * @param listener the {@link ProcessStateChangeListener} to add.
+ */
+ public NativeProcessBuilder addProcessListener(ProcessStateChangeListener listener) {
+ listeners.add(listener);
+ return this;
+ }
+
+ /**
+ * Sets the Command attribute.
+ *
+ *
Sets an executable and arguments of the process to start. This method
+ * does a copy of the command list. No any validation is performed.
+ *
+ *
Note that setting a command with this method erases any data
+ * configured with the {@link #setShellScript(String, String)} method.
+ *
+ *
+ * @param executable the executable to start.
+ * @param arguments the list of arguments that will be passed to the
+ * executable.
+ * @return This process builder.
+ * @see #setShellScript(String, String)
+ */
+ public NativeProcessBuilder setCommand(String executable, String... arguments) {
+ command = new ArrayList(arguments.length + 1);
+ command.add(executable);
+ command.addAll(Arrays.asList(arguments));
+ shell = null;
+ shellScript = null;
+ return this;
+ }
+
+ /**
+ * Sets the ShellScript attribute.
+ *
+ *
+ *
Defines a shell script (text) that should be interpreted by the
+ * specified shell.
+ *
+ *
In case of using {@code /bin/sh}, that would be the same as calling
+ * {@code setCommand("/bin/sh", "-s")} and writing a script to it's input
+ * stream.
+ *
+ *
Note that setting a command with this method erases any data
+ * configured with the {@link #setCommand(String, String[])} method.
+ *
+ * @param shell the shell to use. If {@code null}, then default user's shell
+ * is used.
+ * @param script the script to be passed to the shell.
+ * @return This process builder.
+ * @see #setShellScript(String, String)
+ */
+ public NativeProcessBuilder setShellScript(String shell, String script) {
+ this.shell = shell;
+ this.shellScript = script;
+ command = null;
+ return this;
+ }
+
+ /**
+ * Configures a working directory attribute.
+ *
+ *
Process subsequently created by the call() method on this builder
+ * will be executed with this directory as a current working dir.
+ *
+ *
The default value is undefined.
+ *
+ * @param workingDirectory working directory to start a process in.
+ * @return This process builder.
+ */
+ public NativeProcessBuilder setWorkingDirectory(String workingDirectory) {
+ this.wdir = workingDirectory;
+ return this;
+ }
+
+ /**
+ * Configures a error stream redirection attribute.
+ *
+ *
If this property is true, then any error output generated by processes
+ * subsequently started by this builder will be merged with the standard
+ * output, so that both can be read using a stream returned by
+ * {@code NativeProcess.getInputStream()} method.
+ *
+ *
The initial value is false.
+ *
+ * @param redirectErrorStream the new value of the attribute.
+ * @return This process builder.
+ */
+ public NativeProcessBuilder redirectErrorStream(boolean redirectErrorStream) {
+ this.redirectError = redirectErrorStream;
+ return this;
+ }
+
+ /**
+ * Returns a string map view of this process builder's environment.
+ *
+ *
Whenever a process builder is created, the environment is initialized
+ * to a copy of the {@link Connection}'s environment (if applicable).
+ * Processes subsequently started by this builder will use this map as their
+ * environment.
+ *
+ * @return This process builder's environment.
+ */
+ public EnvironmentMap getEnvironmentMap() {
+ return environmentMap;
+ }
+
+ /**
+ * Returns unmodifiable map of all extra properties configurable with this
+ * builder.
+ *
+ * @return unmodifiable map of all configurable properties.
+ */
+ public Map> getSupportedProperties() {
+ return supportedProperties;
+ }
+
+ /**
+ * Setter for additional builder implementation specific properties.
+ *
+ *
IllegalArgumentException will be thrown if builder doesn't know about
+ * the property or if passed value has an unexpected type.
+ *
+ *
+ * @param propertyName the name of a property to set.
+ * @param value the value of a property.
+ * @return This process builder.
+ * @see #getSupportedProperties()
+ */
+ public NativeProcessBuilder setProperty(String propertyName, Object value) {
+ if (!supportedProperties.containsKey(propertyName)) {
+ throw new IllegalArgumentException("Unsupported property: " + propertyName); // NOI18N
+ }
+
+ if (value == null) {
+ properties.remove(propertyName);
+ return this;
+ }
+
+ Class> clazz = supportedProperties.get(propertyName);
+
+ if (!clazz.isAssignableFrom(value.getClass())) {
+ throw new IllegalArgumentException("Wrong property type: " + clazz.getName() + " expected for " + propertyName + " but " + value.getClass() + " was provided"); // NOI18N
+ }
+
+ properties.put(propertyName, value);
+ return this;
+ }
+
+ /**
+ * Starts a new process using the attributes of this process builder.
+ *
+ * @return a new {@link NativeProcess}.
+ * @throws NativeExecutionException if process cannot be created.
+ */
+ @Override
+ public NativeProcess call() throws NativeExecutionException {
+ if (!connection.isConnected()) {
+ throw new BrokenConnectionException(connection.getURI());
+ }
+
+ final AtomicReference pref = new AtomicReference();
+ final ReentrantLock lock = new ReentrantLock();
+
+ ProcessStateChangeNotifier notifyer = null;
+
+ if (!listeners.isEmpty()) {
+ final List ll = new ArrayList(listeners);
+ final RequestProcessor notificationThread = new RequestProcessor();
+ notifyer = new ProcessStateChangeNotifier() {
+
+ @Override
+ public void notifyProcessStateChange(final State newProcessState) {
+ notificationThread.post(new Runnable() {
+
+ @Override
+ public void run() {
+ lock.lock();
+ try {
+ ProcessStateChangeEvent evt = new ProcessStateChangeEvent(pref.get(), newProcessState);
+ for (ProcessStateChangeListener l : ll) {
+ l.processStateChanged(evt);
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ });
+ }
+ };
+ }
+
+ ConnectionInfo connectionInfo = ConnectionsInfo.getConnectionInfo(connection.getURI());
+
+ NativeProcessParams params = NativeProcessParamsFactory.getDefault().newNativeProcessParams(
+ connection,
+ connectionInfo == null ? null : connectionInfo.getProperties(),
+ environmentMap.toMap(),
+ new HashMap(properties),
+ command,
+ shell,
+ shellScript,
+ redirectError,
+ wdir);
+
+ lock.lock();
+ try {
+
+ NativeProcess result = new NativeProcess(creator, params, notifyer);
+ pref.set(result);
+ return result.start();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ //
+ static {
+ NativeProcessBuilderFactory.setDefault(new NativeProcessBuilderFactoryImpl());
+ }
+
+ private static class NativeProcessBuilderFactoryImpl extends NativeProcessBuilderFactory {
+
+ @Override
+ public NativeProcessBuilder newProcessBuilder(NativeProcessCreator impl, Connection connection) {
+ return new NativeProcessBuilder(impl, connection);
+ }
+ }
+ //
+}
\ No newline at end of file
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/ProcessStateChangeEvent.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/ProcessStateChangeEvent.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/ProcessStateChangeEvent.java
@@ -0,0 +1,142 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api.process;
+
+import java.util.EventObject;
+
+/**
+ * ProcessStateChangeEvent is used to notify interested parties that state of
+ * the source's process has changed.
+ *
+ * @author akrasny
+ */
+public final class ProcessStateChangeEvent extends EventObject {
+
+ private static final long serialVersionUID = 1L;
+ private final State state;
+ private final long ts;
+
+ /**
+ * Constructs a new ProcessStateChangeEvent event.
+ *
+ * @param process the process that originated the event.
+ * @param state the new state of the process.
+ */
+ public ProcessStateChangeEvent(NativeProcess process, State state) {
+ this(process, state, System.nanoTime());
+ }
+
+ /**
+ * Constructs a new ProcessStateChangeEvent event.
+ *
+ * @param process the process that originated the event.
+ * @param state the new state of the process.
+ * @param nanoTime the exact time of the event.
+ */
+ public ProcessStateChangeEvent(NativeProcess process, State state, long nanoTime) {
+ super(process);
+ this.state = state;
+ this.ts = nanoTime;
+ }
+
+ /**
+ * Returns a state of the process on the moment of this event creation.
+ *
+ * @return the state of the process on the moment of this event creation.
+ */
+ public State getState() {
+ return state;
+ }
+
+ /**
+ * Returns the source {@link NativeProcess} for this event.
+ *
+ * @return the event source
+ */
+ @Override
+ public NativeProcess getSource() {
+ return (NativeProcess) super.getSource();
+ }
+
+ /**
+ * Returns the timestamp of when this event occurred.
+ *
+ * @return this event's timestamp.
+ */
+ public long getEventNanoTime() {
+ return ts;
+ }
+
+ /**
+ * Enumerates all possible states of a {@link NativeProcess}.
+ */
+ public enum State {
+
+ /**
+ * Native process is in an Initial state. This means that it has not
+ * been started yet.
+ */
+ INITIAL,
+ /**
+ * Native process is starting. This means that it has been submitted,
+ * but no PID is received so far.
+ */
+ STARTING,
+ /**
+ * Native process runs. This means that process successfully started and
+ * it's PID is already known.
+ */
+ RUNNING,
+ /**
+ * Native process exited.
+ */
+ FINISHED,
+ /**
+ * Native process submission failed due to some exception.
+ */
+ ERROR,
+ /**
+ * Native process forcibly terminated.
+ */
+ CANCELLED
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/ProcessStateChangeListener.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/ProcessStateChangeListener.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/api/process/ProcessStateChangeListener.java
@@ -0,0 +1,79 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api.process;
+
+import java.util.EventListener;
+
+/**
+ * A listener that, added passed to a NativeProcessBuilders will be notified on
+ * changes in a state of NativeProcesses created by those builder.
+ *
+ * @author akrasny
+ */
+public interface ProcessStateChangeListener extends EventListener {
+
+ /**
+ * Is invoked once process has changed it's state.
+ *
+ *
+ * Process has determinated order of states it can be set to:
+ * INITIAL ---> STARTING ---> RUNNING ---> FINISHED
+ * |-> CANCELLED |-> CENCELLED |-> CANCELLED
+ * |-> ERROR |-> ERROR |-> ERROR
+ *
+ * CANCELLED, ERROR and FINISHED are terminal states.
+ *
+ *
+ *
It is guaranteed that:
listeners are notified in the same
+ * (per process) not EDT thread;
listener receives events in the
+ * order they occur;
once process reaches it's final (terminal)
+ * state, no further events will be generated for that process.
+ *
+ *
+ *
Note: listeners are notified asynchronously relative a process
+ * itself. This means that at a time of event delivery the real state of a
+ * process may already differ.
+ *
+ * @param evt the event this notification is about
+ */
+ public void processStateChanged(ProcessStateChangeEvent evt);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/common/Bundle.properties b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/Bundle.properties
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/Bundle.properties
@@ -0,0 +1,43 @@
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+#
+# Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+# Other names may be trademarks of their respective owners.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common
+# Development and Distribution License("CDDL") (collectively, the
+# "License"). You may not use this file except in compliance with the
+# License. You can obtain a copy of the License at
+# http://www.netbeans.org/cddl-gplv2.html
+# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+# specific language governing permissions and limitations under the
+# License. When distributing the software, include this License Header
+# Notice in each file and include the License file at
+# nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the GPL Version 2 section of the License file that
+# accompanied this code. If applicable, add the following below the
+# License Header, with the fields enclosed by brackets [] replaced by
+# your own identifying information:
+# "Portions Copyrighted [year] [name of copyright owner]"
+#
+# If you wish your version of this file to be governed by only the CDDL
+# or only the GPL Version 2, indicate your decision by adding
+# "[Contributor] elects to include this software in this distribution
+# under the [CDDL or GPL Version 2] license." If you do not indicate a
+# single choice of license, a recipient has the option to distribute
+# your version of this file under either the CDDL, the GPL Version 2 or
+# to extend the choice of license to its licensees as provided above.
+# However, if you add GPL Version 2 code and therefore, elected the GPL
+# Version 2 license, then the option applies only if the new code is
+# made subject to such option by the copyright holder.
+#
+# Contributor(s):
+#
+# Portions Copyrighted 2012 Sun Microsystems, Inc.
+
+Connector.progress.message=Connection progress
+Connector.progress.connectTo=Connecting to {0}
+Connector.progress.fetchingInfo=Getting connection info
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionListeners.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionListeners.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionListeners.java
@@ -0,0 +1,204 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.common;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.ConnectionManager;
+import org.netbeans.modules.nativeexecution.api.ConnectionStateChangeEvent;
+import org.netbeans.modules.nativeexecution.api.ConnectionStateChangeEvent.State;
+import org.netbeans.modules.nativeexecution.api.ConnectionStateChangeListener;
+import org.netbeans.modules.nativeexecution.util.URIMatcher;
+import org.openide.util.RequestProcessor;
+import org.openide.util.RequestProcessor.Task;
+import org.openide.util.WeakSet;
+
+/**
+ *
+ * @author akrasny
+ */
+public final class ConnectionListeners {
+
+ private static final RequestProcessor RP = new RequestProcessor("ConnectionListeners", 1); // NOI18N
+ private static final Map> map =
+ new HashMap>();
+ // always accessed from the single-thread RP
+ private static final List active = new ArrayList();
+ private static final Task ttask = RP.create(new TrackTask(), true);
+
+ private ConnectionListeners() {
+ }
+
+ public static void addConnectionStateChangeListener(ConnectionStateChangeListener listener, URI uri) {
+ URIMatcher m = new URIMatcher(uri);
+
+ synchronized (map) {
+ for (Map.Entry> entry : map.entrySet()) {
+ if (m.isIdenticalURI(entry.getKey())) {
+ entry.getValue().add(listener);
+ return;
+ }
+ }
+
+ WeakSet set = new WeakSet();
+ set.add(listener);
+ map.put(uri, new WeakSet(set));
+ }
+
+ ttask.schedule(0);
+ }
+
+ public static void removeConnectionStateChangeListener(ConnectionStateChangeListener listener, URI uri) {
+ URIMatcher m = new URIMatcher(uri);
+
+ synchronized (map) {
+ for (Map.Entry> entry : map.entrySet()) {
+ if (m.isIdenticalURI(entry.getKey())) {
+ entry.getValue().remove(listener);
+ return;
+ }
+ }
+ }
+ }
+
+ public static void notifyListeners(URI uri, ConnectionStateChangeEvent ev) {
+ RP.post(new NotificationTask(uri, ev)).waitFinished();
+ }
+
+ // When disconnect is called, first connection get closed and then listeners
+ // are notified. If at the same time tracking task is running, it may detect
+ // that connection is closed before it gets removed from the list of active
+ // connections and hence decide that connection was lost and notify
+ // listeners with CONNECTION_LOST event (which is wrong in this situation).
+ // To avoid this - just stop the TrackingTask before doing real disconnect.
+ // Called from ConnectionManager.
+ //
+ public static void stopTrackingTask() {
+ ttask.cancel();
+ ttask.waitFinished();
+ }
+
+ private static class NotificationTask implements Runnable {
+
+ private final URI uri;
+ private final ConnectionStateChangeEvent ev;
+
+ public NotificationTask(URI uri, ConnectionStateChangeEvent ev) {
+ this.uri = uri;
+ this.ev = ev;
+ }
+
+ @Override
+ public void run() {
+ URIMatcher m = new URIMatcher(uri);
+ List toNotify = new ArrayList();
+
+ synchronized (map) {
+ for (Map.Entry> entry : map.entrySet()) {
+ if (m.isIdenticalURI(entry.getKey())) {
+ WeakSet set = entry.getValue();
+ for (ConnectionStateChangeListener l : set) {
+ toNotify.add(l);
+ }
+ }
+ }
+ }
+
+ for (ConnectionStateChangeListener l : toNotify) {
+ l.connectionStateChanged(ev);
+ }
+
+ boolean activated = State.CONNECTION_ESTABLISHED.equals(ev.getState());
+
+ Iterator it = active.iterator();
+ while (it.hasNext()) {
+ if (m.isIdenticalURI(it.next())) {
+ assert !activated;
+ it.remove();
+ }
+ }
+
+ if (activated) {
+ active.add(uri);
+ }
+
+ ttask.schedule(0);
+ }
+ }
+
+ /**
+ * This task periodically asks registered active connections for their state
+ * and detects lost connections...
+ */
+ private static class TrackTask implements Runnable {
+
+ @Override
+ public void run() {
+ List lost = new ArrayList();
+
+ boolean restart = false;
+
+ for (URI uri : active) {
+ Connection c = ConnectionManager.getConnection(uri);
+ if (c != null && c.isConnected()) {
+ restart = true;
+ continue;
+ }
+
+ lost.add(uri);
+ }
+
+ for (URI uri : lost) {
+ notifyListeners(uri, new ConnectionStateChangeEvent(uri, State.CONNECTION_LOST));
+ }
+
+ if (restart) {
+ ttask.schedule(1000);
+ }
+ }
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionServiceLookup.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionServiceLookup.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionServiceLookup.java
@@ -0,0 +1,74 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.common;
+
+import java.net.URI;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+/**
+ *
+ * @author akrasny
+ */
+public final class ConnectionServiceLookup {
+
+ private ConnectionServiceLookup() {
+ }
+
+ public static Lookup getServiceLookup(URI uri) {
+ String scheme = uri.getScheme();
+ if (scheme == null) {
+ String src = uri.toString();
+ StringBuilder sb = new StringBuilder();
+ for (char c : src.toCharArray()) {
+ if (Character.isLetterOrDigit(c)) {
+ sb.append(c);
+ } else {
+ break;
+ }
+ }
+ scheme = sb.toString();
+ }
+ Lookup lookup = Lookups.forPath("ConnectionService/" + scheme); // NOI18N
+ return lookup;
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionsInfo.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionsInfo.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionsInfo.java
@@ -0,0 +1,150 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.common;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.access.ConnectionAccessor;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.EnvironmentMap;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfo;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfoProvider;
+import org.netbeans.modules.nativeexecution.util.URIMatcher;
+import org.openide.util.Lookup;
+
+/**
+ * An entry point for getting {@link Connection} information from providers.
+ *
+ * @author akrasny
+ */
+public final class ConnectionsInfo {
+
+ private static final Map infoCache = new HashMap();
+
+ private ConnectionsInfo() {
+ }
+
+ public static ConnectionInfo getConnectionInfo(URI uri) {
+ synchronized (infoCache) {
+ URIMatcher m = new URIMatcher(uri);
+ for (Map.Entry entry : infoCache.entrySet()) {
+ if (m.isIdenticalURI(entry.getKey())) {
+ return entry.getValue();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public static void setConnectionInfo(URI uri, ConnectionInfo info) {
+ synchronized (infoCache) {
+ URIMatcher m = new URIMatcher(uri);
+ for (Map.Entry entry : infoCache.entrySet()) {
+ if (m.isIdenticalURI(entry.getKey())) {
+ entry.setValue(info);
+ return;
+ }
+ }
+ infoCache.put(uri, info);
+ }
+ }
+
+ public static void refreshConnectionInfo(final Connection connection) {
+ final ConnectionAccessor access = ConnectionAccessor.getDefault();
+ final Lookup lookup = access.getConnectionLookup(connection);
+
+ if (lookup == null) {
+ return;
+ }
+
+ final Collection extends ConnectionInfoProvider> providers =
+ lookup.lookupAll(ConnectionInfoProvider.class);
+
+ final ProxyInfo info = new ProxyInfo();
+
+ for (ConnectionInfoProvider provider : providers) {
+ try {
+ ConnectionInfo data = provider.getConnectionInfo(connection);
+ if (data != null) {
+ EnvironmentMap map = data.getEnvironmentMap();
+
+ if (info.map == null) {
+ try {
+ info.map = map.clone();
+ } catch (CloneNotSupportedException ex) {
+ // Exceptions.printStackTrace(ex);
+ }
+ } else {
+ for (Map.Entry entry : map.entrySet()) {
+ info.map.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ info.properties.putAll(data.getProperties());
+ }
+ } catch (NativeExecutionException ex) {
+ }
+ }
+
+ setConnectionInfo(connection.getURI(), info);
+ }
+
+ private static final class ProxyInfo implements ConnectionInfo {
+
+ final Map properties = new HashMap();
+ EnvironmentMap map = null;
+
+ @Override
+ public EnvironmentMap getEnvironmentMap() {
+ return map;
+ }
+
+ @Override
+ public Map getProperties() {
+ return properties;
+ }
+ }
+}
\ No newline at end of file
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionsPool.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionsPool.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionsPool.java
@@ -0,0 +1,85 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.common;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.util.URIMatcher;
+import org.openide.util.WeakSet;
+
+/**
+ * In-memory pool of all ever-known at least once established connections.
+ *
+ * @author Andrew
+ */
+public final class ConnectionsPool {
+
+ private static final WeakSet pool = new WeakSet();
+
+ private ConnectionsPool() {
+ }
+
+ public static void add(Connection connection) {
+ URIMatcher m = new URIMatcher(connection.getURI());
+
+ synchronized (pool) {
+ for (Connection c : pool) {
+ if (m.isIdenticalURI(c.getURI())) {
+ return;
+ }
+ }
+ pool.add(connection);
+ }
+ }
+
+ public static Connection get(URI uri) {
+ URIMatcher m = new URIMatcher(uri);
+ synchronized (pool) {
+ for (Connection c : pool) {
+ if (m.isIdenticalURI(c.getURI())) {
+ return c;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionsRegistry.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionsRegistry.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ConnectionsRegistry.java
@@ -0,0 +1,302 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.common;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+import javax.swing.event.ChangeListener;
+import org.netbeans.modules.nativeexecution.access.ConnectionAccessor;
+import org.netbeans.modules.nativeexecution.access.EnvironmentMapAccessor;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.EnvironmentMap;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfo;
+import org.netbeans.modules.nativeexecution.util.URIMatcher;
+import org.openide.util.ChangeSupport;
+import org.openide.util.Exceptions;
+import org.openide.util.NbPreferences;
+import org.openide.util.RequestProcessor;
+import org.openide.util.RequestProcessor.Task;
+
+/**
+ *
+ * @author akrasny
+ */
+public final class ConnectionsRegistry {
+//
+// private static final RequestProcessor RP = new RequestProcessor(ConnectionsRegistry.class.getName(), 1);
+// private static final ConnectionsRegistry instance = new ConnectionsRegistry();
+// private final AtomicReference restoreTask = new AtomicReference();
+// private final CopyOnWriteArraySet connections = new CopyOnWriteArraySet();
+// private final ChangeSupport cs = new ChangeSupport(this);
+// private final Task writeTask;
+//
+// static {
+// instance.init();
+// }
+//
+// private ConnectionsRegistry() {
+// writeTask = RP.create(new Runnable() {
+//
+// @Override
+// public void run() {
+// storeImpl();
+// }
+// }, true);
+// }
+//
+// private void init() {
+// restoreTask.set(RP.post(new Runnable() {
+//
+// @Override
+// public void run() {
+// connections.addAll(restoreImpl());
+// }
+// }));
+// }
+//
+// public static ConnectionsRegistry getInstance() {
+// Task r = instance.restoreTask.get();
+// if (r != null) {
+// r.waitFinished();
+// instance.restoreTask.set(null);
+// }
+// return instance;
+// }
+//
+// public Connection getConnection(URI uri) {
+// URIMatcher matcher = new URIMatcher(uri);
+// for (Connection connection : connections) {
+// if (matcher.isIdenticalURI(connection.getURI())) {
+// return connection;
+// }
+// }
+// return null;
+// }
+//
+// public List getConnections() {
+// return Arrays.asList(connections.toArray(new Connection[connections.size()]));
+// }
+//
+// public void addChangeListener(ChangeListener listener) {
+// cs.addChangeListener(listener);
+// }
+//
+// public void removeChangeListener(ChangeListener listener) {
+// cs.addChangeListener(listener);
+// }
+//
+// public void addConnection(Connection connection) {
+// connections.add(connection);
+// changed();
+// }
+//
+// public void removeConnection(Connection connection) {
+// connections.remove(connection);
+// Connections.setConnectionInfo(connection.getURI(), null);
+// changed();
+// }
+//
+// private void changed() {
+// writeTask.schedule(0);
+// cs.fireChange();
+// }
+//
+// private void storeImpl() {
+// List data = getConnections();
+// Preferences props = NbPreferences.forModule(ConnectionsRegistry.class);
+// try {
+// props.clear();
+//
+// for (Connection connection : data) {
+// final URI uri = connection.getURI();
+// Preferences cprop = props.node(toFileName(uri));
+// ConnectionInfo info = Connections.getConnectionInfo(uri);
+// if (info != null) {
+// EnvironmentMap envMap = info.getEnvironmentMap();
+// if (envMap != null) {
+// Preferences envprop = cprop.node("env"); // NOI18N
+// EnvironmentMapAccessor.getDefault().store(envMap, envprop);
+// envprop.flush();
+// }
+//
+// Map connprop = info.getProperties();
+// if (connprop != null) {
+// Preferences infoprop = cprop.node("props"); // NOI18N
+// for (Map.Entry entry : connprop.entrySet()) {
+// infoprop.put(entry.getKey(), entry.getValue());
+// }
+// infoprop.flush();
+// }
+// }
+// cprop.flush();
+// }
+//
+// props.flush();
+// } catch (BackingStoreException ex) {
+// Exceptions.printStackTrace(ex);
+// }
+// }
+//
+// private static List restoreImpl() {
+// ConnectionAccessor access = ConnectionAccessor.getDefault();
+// Preferences props = NbPreferences.forModule(ConnectionsRegistry.class);
+// List result = new LinkedList();
+// try {
+// for (String fname : props.childrenNames()) {
+// URI uri = fromFileName(fname);
+// if (uri == null) {
+// continue;
+// }
+//
+// Connection connection = access.createConnection(uri);
+// Preferences cprops = props.node(fname);
+// Preferences envprop = cprops.node("env"); // NOI18N
+// final EnvironmentMap envmap = EnvironmentMapAccessor.getDefault().load(envprop);
+//
+// Preferences infoprop = cprops.node("props"); // NOI18N
+// final Map connprop = new HashMap();
+// for (String key : infoprop.keys()) {
+// connprop.put(key, infoprop.get(key, "")); // NOI18N
+// }
+//
+// Connections.setConnectionInfo(uri, new ConnectionInfo() {
+//
+// @Override
+// public EnvironmentMap getEnvironmentMap() {
+// return envmap;
+// }
+//
+// @Override
+// public Map getProperties() {
+// return connprop;
+// }
+// });
+//
+// getInstance().addConnection(connection);
+// }
+// } catch (BackingStoreException ex) {
+// Exceptions.printStackTrace(ex);
+// }
+// return result;
+// }
+//
+// private static String toFileName(URI uri) {
+// String id = uri.toString();
+// StringBuilder res = new StringBuilder();
+// for (char c : id.toCharArray()) {
+// switch (c) {
+// case '/':
+// res.append("%s");
+// break;
+// case ':':
+// res.append("%c");
+// break;
+// case '%':
+// res.append("%%"); // NOI18N
+// break;
+// default:
+// res.append(c);
+// }
+// }
+// return res.toString();
+// }
+//
+// private static URI fromFileName(String envName) {
+// StringBuilder res = new StringBuilder();
+// char[] chars = envName.toCharArray();
+// for (int i = 0; i < chars.length; i++) {
+// char c = chars[i];
+// if (c == '%') {
+// if (++i == chars.length) {
+// return null;
+// }
+// switch (chars[i]) {
+// case '%':
+// res.append('%');
+// break;
+// case 'c':
+// res.append(':');
+// break;
+// case 's':
+// res.append('/');
+// break;
+// }
+// } else {
+// res.append(c);
+// }
+// }
+//
+// try {
+// return URI.create(res.toString());
+// } catch (IllegalArgumentException ex) {
+// }
+//
+// return null;
+// }
+//
+// void waitReady(final boolean shutdown) {
+// try {
+// RP.submit(new Runnable() {
+//
+// @Override
+// public void run() {
+// if (shutdown) {
+// RP.shutdown();
+// }
+// }
+// }).get();
+// } catch (InterruptedException ex) {
+// Exceptions.printStackTrace(ex);
+// } catch (ExecutionException ex) {
+// Exceptions.printStackTrace(ex);
+// }
+// }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/common/Connector.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/Connector.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/Connector.java
@@ -0,0 +1,192 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.common;
+
+import java.net.URI;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.swing.SwingUtilities;
+import org.netbeans.api.progress.ProgressHandle;
+import org.netbeans.api.progress.ProgressHandleFactory;
+import org.netbeans.api.progress.ProgressRunnable;
+import org.netbeans.api.progress.ProgressUtils;
+import org.netbeans.modules.nativeexecution.access.ConnectionAccessor;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.ConnectionCancelledException;
+import org.netbeans.modules.nativeexecution.api.ConnectionException;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.spi.AuthDataProvider;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.spi.ConnectorImplementation;
+import org.openide.util.Cancellable;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author akrasny
+ */
+public final class Connector {
+
+ public static ConnectionImplementation connect(URI uri, AuthDataProvider authDataProvider) throws NativeExecutionException {
+ return connectImpl(uri, authDataProvider);
+ }
+
+ private static ConnectionImplementation connectImpl(final URI uri, final AuthDataProvider authDataProvider) throws NativeExecutionException {
+ final AtomicReference resultRef = new AtomicReference();
+ final AtomicReference exRef = new AtomicReference();
+ final String msg = NbBundle.getMessage(Connector.class, "Connector.progress.message"); // NOI18N
+ final ProgressRunnableImpl connectionTask = new ProgressRunnableImpl(
+ uri, authDataProvider, resultRef, exRef,
+ SwingUtilities.isEventDispatchThread() ? null : Thread.currentThread());
+
+ if (SwingUtilities.isEventDispatchThread()) {
+ ProgressUtils.showProgressDialogAndRun(connectionTask, msg, true);
+ } else {
+ ProgressHandle progressHandle = ProgressHandleFactory.createHandle(msg, connectionTask);
+ try {
+ progressHandle.start();
+ progressHandle.switchToIndeterminate();
+ connectionTask.run(progressHandle);
+ } finally {
+ progressHandle.finish();
+ }
+ }
+
+ NativeExecutionException exception = exRef.get();
+
+ if (exception != null) {
+ throw exception;
+ }
+
+ return resultRef.get();
+ }
+
+ private static class ProxyAuthDataProvider implements AuthDataProvider {
+
+ private final AuthDataProvider defaultProvider;
+ private final AuthDataProvider origProvider;
+
+ private ProxyAuthDataProvider(Lookup lookup, AuthDataProvider authDataProvider) {
+ this.origProvider = authDataProvider;
+ this.defaultProvider = lookup.lookup(AuthDataProvider.class);
+ }
+
+ @Override
+ public T getProperty(URI uri, Class clazz, String name, Object... misc) {
+ T result = origProvider == null ? null
+ : origProvider.getProperty(uri, clazz, name, misc);
+ if (result == null && defaultProvider != null) {
+ result = defaultProvider.getProperty(uri, clazz, name, misc);
+ }
+ return result;
+ }
+ }
+
+ private static class ProgressRunnableImpl implements ProgressRunnable, Cancellable {
+
+ private final URI uri;
+ private final AuthDataProvider authDataProvider;
+ private final AtomicReference resultRef;
+ private final AtomicReference exRef;
+ private final Thread thread;
+
+ public ProgressRunnableImpl(URI uri, AuthDataProvider authDataProvider,
+ AtomicReference resultRef, AtomicReference exRef,
+ Thread thread) {
+ this.uri = uri;
+ this.authDataProvider = authDataProvider;
+ this.resultRef = resultRef;
+ this.exRef = exRef;
+ this.thread = thread;
+ }
+
+ @Override
+ public Void run(final ProgressHandle handle) {
+ final ConnectionAccessor access = ConnectionAccessor.getDefault();
+ final Lookup lookup = ConnectionServiceLookup.getServiceLookup(uri);
+ final AuthDataProvider provider = new ProxyAuthDataProvider(lookup, authDataProvider);
+
+ for (ConnectorImplementation connector : lookup.lookupAll(ConnectorImplementation.class)) {
+ try {
+ ConnectionImplementation connectionImpl = connector.connectTo(uri, provider);
+
+ if (connectionImpl == null) {
+ continue;
+ }
+
+ // We create a new Connection, but without any registration
+ // in any registry... It's too early - need to get it's
+ // info first (But for this we need a Connection, as getting
+ // info may require starting some processes using this
+ // connection
+ Connection tmpConnection = access.createConnection(connectionImpl);
+
+ handle.setDisplayName(NbBundle.getMessage(Connector.class,
+ "Connector.progress.fetchingInfo")); // NOI18N
+
+ ConnectionsInfo.refreshConnectionInfo(tmpConnection);
+ resultRef.set(connectionImpl);
+
+ // done
+ return null;
+ } catch (NativeExecutionException ex) {
+ exRef.compareAndSet(null, ex);
+ } catch (InterruptedException ex) {
+ exRef.compareAndSet(null, new ConnectionCancelledException(uri));
+ break;
+ }
+ }
+
+ exRef.compareAndSet(null, new NativeExecutionException("Unsupported connection scheme: " + uri)); // NOI18N
+ return null;
+ }
+
+ @Override
+ public boolean cancel() {
+ exRef.compareAndSet(null, new ConnectionCancelledException(uri));
+ if (thread != null) {
+ thread.interrupt();
+ }
+ return true;
+ }
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ProcessStateChangeNotifier.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ProcessStateChangeNotifier.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/common/ProcessStateChangeNotifier.java
@@ -0,0 +1,53 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.common;
+
+import org.netbeans.modules.nativeexecution.api.process.ProcessStateChangeEvent.State;
+
+/**
+ *
+ * @author akrasny
+ */
+public interface ProcessStateChangeNotifier {
+
+ public void notifyProcessStateChange(final State newProcessState);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/resources/Bundle.properties b/nativeexecution/src/org/netbeans/modules/nativeexecution/resources/Bundle.properties
new file mode 100755
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/resources/Bundle.properties
@@ -0,0 +1,2 @@
+OpenIDE-Module-Name=Native Execution API
+
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/AuthDataProvider.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/AuthDataProvider.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/AuthDataProvider.java
@@ -0,0 +1,122 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.common.Connector;
+
+/**
+ * An interface to be implemented to provide an authorization/authentication
+ * data needed by a {@link ConnectorImplementation} to establish a {@link ConnectionImplementation}.
+ *
+ *
{@link AuthDataProvider} has a set of constants that represent commonly
+ * used identifiers for some authorization/authentication info.
+ *
+ *
The data that is required to establish a connection depends on a nature
+ * of the connection and features supported by a {@link ConnectorImplementation}.
+ * In a simple case this could be just a username and a password. In other cases
+ * this could be a location of some secret file, passphrase or any other
+ * data.
+ *
+ *
In some cases implementor could extract needed information from the
+ * destination URI. In other cases it could look into some database or ask user
+ * to provide some input.
+ *
+ *
Possible usage:
+ *
+ * Connection c = ConnectionManager.connect(new URI("ssh://tester@testhost"), new AuthDataProvider {
+ *
+ * public T getProperty(URI uri, Class clazz, String name, Object... misc) {
+ * Object result = null;
+ *
+ * if (String.class.equals(clazz) && "KnownHostsFile".equals(name)) {
+ * result = System.getProperty("user.home") + "/.ssh/known_hosts";
+ * } else if (char[].class.equals(clazz) && AuthDataProvider.PASSWORD.equals(name)) {
+ * result = new char[]{'t', 'e', 's', 't', 'e', 'r'};
+ * }
+ *
+ * return clazz.cast(result);
+ * }
+ * });
+ *
+ *
+ *
+ * @author akrasny
+ */
+public interface AuthDataProvider {
+
+ /**
+ * Common identifier used for requesting a username.
+ */
+ public static final String USERNAME = "username"; // NOI18N
+ /**
+ * Common identifier used for requesting a user password.
+ */
+ public static final String PASSWORD = "password"; // NOI18N
+ /**
+ * Common identifier used for requesting a host name.
+ */
+ public static final String HOST = "host"; // NOI18N
+ /**
+ * Common identifier used for requesting a port number.
+ */
+ public static final String PORT = "port"; // NOI18N
+
+ /**
+ * Returns a requested property of a specified class or {@code null} if no
+ * property available and could not be retrieved.
+ *
+ *
It is guaranteed that this method is called from outside the EDT.
+ * Implementor could initiate UI interaction with a user to get needed
+ * input.
+ *
+ * @param uri the URI of the connection destination.
+ * @param clazz the expected class of the property.
+ * @param name the name of the requested property.
+ * @param misc any additional data that {@link Connector} may decide to
+ * provide to the SPI implementor to make it easier/possible to provide
+ * requested into.
+ * @return a requested property of the requested type or {@code null}, if
+ * property is not available.
+ */
+ public T getProperty(URI uri, Class clazz, String name, Object... misc);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/ConnectionImplementation.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/ConnectionImplementation.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/ConnectionImplementation.java
@@ -0,0 +1,98 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessCreator;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfoProvider;
+import org.netbeans.modules.nativeexecution.spi.support.SignalSupportProvider;
+import org.openide.util.Lookup;
+
+/**
+ * Interface to be implemented by SPI providers.
+ *
+ * @author akrasny
+ */
+public interface ConnectionImplementation {
+
+ /**
+ * Creates a new {@link NativeProcessCreator} instance.
+ *
+ * @return a new not configured {@link NativeProcessCreator}
+ * @throws NativeExecutionException if some problem occurs
+ */
+ public NativeProcessCreator newProcessBuilderImpl() throws NativeExecutionException;
+
+ /**
+ * Returns a {@link Lookup} associated with the connection.
+ *
+ *
For now this lookup is not exposed to the API users. It is used by
+ * the infrastructure to get implementation of SPI services providers for
+ * the connection.
+ *
+ * @return the {@link Lookup} associated with this connection.
+ *
+ * @see ConnectionInfoProvider
+ * @see SignalSupportProvider
+ */
+ public Lookup getLookup();
+
+ /**
+ * A request to close the connection.
+ */
+ public void disconnect();
+
+ /**
+ * Returns an actual URI this connection is associated with.
+ *
+ * @return an URI this connection is associated with.
+ */
+ public URI getURI();
+
+ /**
+ * Tests if the connection is alive.
+ *
+ * @return true if connection is established, false otherwise.
+ */
+ public boolean isConnected();
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/ConnectorImplementation.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/ConnectorImplementation.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/ConnectorImplementation.java
@@ -0,0 +1,92 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.ConnectionManager;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+
+/**
+ * SPI for providing a way of {@link Connection} establishment.
+ *
+ *
SPI implementation must be registers in the global lookup within a
+ * {@code "ConnectionService/"} path.
+ *
+ *
Once the {@link ConnectionManager} is asked to establish a new connection
+ * with the destination identified by an URI, it extracts a scheme part
+ * of the URI and looks for an implementor of this SPI in the corresponding
+ * lookup path to pass control over to it.
+ *
+ * @author akrasny
+ */
+public interface ConnectorImplementation {
+
+ /**
+ * A request to establish a new connection.
+ *
+ *
It is guaranteed that:
method is called from outside the
+ * EDT;
method is called non concurrently;
+ *
+ *
Implementation should return a new instance on each subsequent
+ * call.
+ *
+ *
It is not required that ConnectorImplementation uses the originally passed URI
+ * for establishing a connection. ConnectorImplementation may choose to re-direct a
+ * request to a different connector with a different URI.
+ *
+ *
Normally ConnectorImplementation should not directly interact with a user.
+ * ConnectorImplementation just asks authDataProvider to provide all needed
+ * information.
+ *
+ *
+ * @param uri an URI of the requested destination.
+ * @param authDataProvider the provider of information needed for connection
+ * establishment.
+ * @return a new instance of {@link ConnectionImplementation} that represents newly
+ * established connection.
+ * @throws NativeExecutionException is thrown if connection cannot be
+ * established for some reason.
+ * @throws InterruptedException if calling thread was interrupted.
+ */
+ public ConnectionImplementation connectTo(final URI uri, final AuthDataProvider authDataProvider) throws InterruptedException, NativeExecutionException;
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/URIIdentifier.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/URIIdentifier.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/URIIdentifier.java
@@ -0,0 +1,73 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.api.ConnectionManager;
+
+/**
+ * SPI provider may register an identifier for URIs of a certain kind (certain
+ * scheme).
+ *
+ *
Should be registered in the global Lookup within a
+ * {@code ConnectionService/} path.
+ *
+ *
{@link ConnectionManager} uses registered URIIdentifiers to compare URIs
+ * equality. As an example URIs {@code ssh://user:password@host} and {@code ssh://user@host}
+ * could denote the same connection end point.
+ *
+ *
If no Identifier registered for a particular scheme, URI's equals() method
+ * is used.
+ *
+ * @author akrasny
+ */
+public interface URIIdentifier {
+
+ /**
+ * Tests whether these URIs denote the same connection.
+ *
+ * @param uri1 the first URI to compare
+ * @param uri2 the second URI to compare
+ * @return true if these URIs are the same from SPI provider point of view.
+ */
+ public boolean areIdentical(final URI uri1, final URI uri2);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/process/NativeProcessCreator.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/process/NativeProcessCreator.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/process/NativeProcessCreator.java
@@ -0,0 +1,76 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi.process;
+
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcessBuilder;
+
+/**
+ * An SPI interface for providing process creator implementation.
+ *
+ * @author akrasny
+ */
+public interface NativeProcessCreator {
+
+ /**
+ * Returns a map of non-standard attributes supported by this creator.
+ *
+ * @return the map of supported non-standard attributes.
+ * @see NativeProcessBuilder
+ */
+ public Map> getSupportedProperties();
+
+ /**
+ * Takes parameters configured by a {@link NativeProcessBuilder} and starts
+ * a new process in accordance to that parameters.
+ *
+ * @param params parameters configured with a {@link NativeProcessBuilder}.
+ * Never {@code null}.
+ *
+ * @return a new started process implementation.
+ *
+ * @throws NativeExecutionException is thrown if process cannot be started.
+ */
+ public NativeProcessImplementation createAndStart(
+ final NativeProcessParams params) throws NativeExecutionException;
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/process/NativeProcessImplementation.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/process/NativeProcessImplementation.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/process/NativeProcessImplementation.java
@@ -0,0 +1,114 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi.process;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ *
+ * @author akrasny
+ */
+public interface NativeProcessImplementation {
+
+ /**
+ * Returns a PID of the process.
+ *
+ * @return the PID of the process or -1 if real PID cannot be provided.
+ */
+ public int getPID();
+
+ /**
+ * Returns the output stream of the process.
+ *
+ *
Output to the stream should be piped into the input stream of the
+ * process.
+ *
+ * @return the output stream connected to the input of the process.
+ */
+ public OutputStream getOutputStream();
+
+ /**
+ * Returns the input stream of the process.
+ *
+ *
The stream should obtain data piped from the output stream of the
+ * process.
+ *
+ * @return the input stream connected to the output stream of the process.
+ */
+ public InputStream getInputStream();
+
+ /**
+ * Returns the error stream of the process.
+ *
+ *
The stream should obtain data piped from the error output stream of
+ * the process.
+ *
+ * @return the input stream connected to the error stream of the process.
+ */
+ public InputStream getErrorStream();
+
+ /**
+ * Implementation should cause the current thread to wait, if necessary,
+ * until the process has terminated.
+ *
+ *
This method should return immediately if the process has already
+ * terminated. If the process has not yet terminated, the calling thread
+ * should be blocked until the process exits.
+ *
+ * @return the exit value of the process. By convention, 0 indicates normal
+ * termination.
+ * @throws InterruptedException if the current thread is interrupted by
+ * another thread while it is waiting, then the wait is ended and an
+ * InterruptedException is thrown.
+ */
+ public int waitResult() throws InterruptedException;
+
+ /**
+ * Implementation-specific termination of the underlying system process.
+ *
+ *
It is guaranteed that this method is called only once. Implementation
+ * should not (but may) wait for the actual termination before returning
+ * from the call.
+ */
+ public void destroy();
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/process/NativeProcessParams.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/process/NativeProcessParams.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/process/NativeProcessParams.java
@@ -0,0 +1,208 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi.process;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.access.NativeProcessParamsFactory;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcess;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcessBuilder;
+
+/**
+ * Parameters constructed by a {@link NativeProcessBuilder} to be used for
+ * {@link NativeProcess} creation.
+ *
+ *
This is an immutable object.
+ *
+ * @author akrasny
+ */
+public final class NativeProcessParams {
+
+ private final Connection connection;
+ private final Map connectionInfo;
+ private final Map properties;
+ private final Map environment;
+ private final List command;
+ private final boolean redirectError;
+ private final String shellScript;
+ private final String shell;
+ private final String wdir;
+
+ private NativeProcessParams(Connection connection, Map connectionInfo,
+ Map environmentMap, Map properties,
+ List command, String shell, String shellScript,
+ boolean redirectError, String wdir) {
+ this.connection = connection;
+ this.connectionInfo = connectionInfo;
+ this.environment = environmentMap;
+ this.properties = properties;
+ this.command = command;
+ this.shell = shell;
+ this.shellScript = shellScript;
+ this.redirectError = redirectError;
+ this.wdir = wdir;
+ }
+
+ /**
+ * Returns an immutable list of a command to be started and it's arguments.
+ *
+ *
There are two mutually exclusive attributes - a shell script and a
+ * list of a command with it's arguments. Only one of these attributes could
+ * be set.
+ *
+ * @return an immutable list of a command and it's arguments.
+ */
+ public List getCommand() {
+ return Collections.unmodifiableList(command);
+ }
+
+ /**
+ * Returns a shell script to be started.
+ *
+ *
There are two mutually exclusive attributes - a shell script and a
+ * list of a command with it's arguments. Only one of these attributes could
+ * be set.
+ *
+ * @return a shell script to start.
+ */
+ public String getShellScript() {
+ return shellScript;
+ }
+
+ /**
+ * A shell to be used to start a specified shell script (if any).
+ *
+ * @see #getShellScript()
+ * @return a path to the shell to be used to start a specified shell script.
+ */
+ public String getShell() {
+ return shell;
+ }
+
+ /**
+ * Returns an immutable map of all attributes associated with the current
+ * {@link Connection}.
+ *
+ * @return an immutable map of all attributes associated with the current
+ * {@link Connection}.
+ */
+ public Map getConnectionInfo() {
+ return Collections.unmodifiableMap(connectionInfo);
+ }
+
+ /**
+ * Returns a requested property of a specified class or {@code null} if no
+ * property with this name defined.
+ *
+ * @param clazz the expected class of the property.
+ * @param propertyName the name of the requested property.
+ *
+ * @return a requested property of the requested type or {@code null}, if
+ * property is not defined.
+ */
+ public T getProperty(Class clazz, String propertyName) {
+ Object val = properties.get(propertyName);
+ if (val != null && clazz.isAssignableFrom(val.getClass())) {
+ return clazz.cast(val);
+ }
+ return null;
+ }
+
+ /**
+ * A working directory process should be started in.
+ *
+ * @return the working directory where process should be started.
+ */
+ public String getWorkingDirectory() {
+ return wdir;
+ }
+
+ /**
+ * Tells whether standard error and standard output of a process should be
+ * merged together.
+ *
+ * @return {@code true} if output and error streams should be merged.
+ */
+ public boolean isRedirectError() {
+ return redirectError;
+ }
+
+ /**
+ * Returns configured immutable map of environment variables to be set
+ * before process creation.
+ *
+ * @return an immutable map of environment variables.
+ */
+ public Map getEnvironment() {
+ return Collections.unmodifiableMap(environment);
+ }
+
+ /**
+ * Returns a {@link Connection} this process should be started in.
+ *
+ * @return the {@link Connection} this process should be started in.
+ */
+ public Connection getConnection() {
+ return connection;
+ }
+
+ //
+ static {
+ NativeProcessParamsFactory.setDefault(new NativeProcessParamsFactoryImpl());
+ }
+
+ private static class NativeProcessParamsFactoryImpl extends NativeProcessParamsFactory {
+
+ @Override
+ public NativeProcessParams newNativeProcessParams(Connection connection,
+ Map connectionInfo, Map env,
+ Map properties, List command,
+ String shell, String shellScript, boolean redirectError, String wdir) {
+ NativeProcessParams params = new NativeProcessParams(connection, connectionInfo, env,
+ properties, command, shell, shellScript, redirectError, wdir);
+ return params;
+ }
+ }
+ //
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/ConnectionInfo.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/ConnectionInfo.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/ConnectionInfo.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi.support;
+
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.EnvironmentMap;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.util.HostInfo;
+import org.openide.util.Lookup;
+
+/**
+ * Connection info is just a map of String-String properties and an initial
+ * {@link EnvironmentMap} of the {@link Connection}.
+ *
+ *
{@link ConnectionImplementation} SPI implementors use this interface to provide a
+ * map of connection-specific properties. For this implementations of {@link ConnectionInfoProvider}
+ * should be put into connection's {@link Lookup} (See {@link ConnectionImplementation}).
+ * Information from all SPI implementors is collected and merged altogether by
+ * the execution infrastructure before making a final association with the {@link Connection}.
+ *
+ *
Note: {@link HostInfo} is constructed from the known subset of these
+ * properties. SPI implementor should make sure that expected properties are
+ * provided if they want HostInfo service to provide a meaningful
+ * information.
+ *
+ * @see HostInfo
+ */
+public interface ConnectionInfo {
+
+ /**
+ * Returns an EnvironmentMap filled with variables discovered by the
+ * implementation.
+ *
+ * @return the populated EnvironmentMap.
+ */
+ public EnvironmentMap getEnvironmentMap();
+
+ /**
+ * Returns a map of attributes to be associated with the connection.
+ *
+ * @return the map of connection attributes.
+ */
+ public Map getProperties();
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/ConnectionInfoProvider.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/ConnectionInfoProvider.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/ConnectionInfoProvider.java
@@ -0,0 +1,94 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi.support;
+
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.util.HostInfo;
+
+/**
+ *
+ * Provides a discovered list of connection-specific properties.
+ *
+ *
Among other usages, this information is used to construct a {@link HostInfo}
+ * object to provide an easy access to the most common host-specific
+ * attributes.
+ *
+ *
Implementors of {@link ConnectionInfoProvider} could provide following
+ * properties that are used by the {@link HostInfo} class:
+ *
+ *
+ *
+ * ------------+------------------------------------------------------
+ * Name | Possible values (otherwise will be set to UNKNOWN)
+ * ------------+------------------------------------------------------
+ * CPUFAMILY | SPARC, X86
+ * BITNESS | 32, 64
+ * OSFAMILY | SOLARIS, LINUX, WINDOWS, MACOSX
+ * OSBUILD | <any string>
+ * OSNAME | <any string>
+ * CPUNUM | <any positive integer>
+ *
+ *
+ * @author akrasny
+ */
+public interface ConnectionInfoProvider {
+
+ /**
+ * A method to be implemented by an SPI provider.
+ *
+ *
It is guaranteed that this method is invoked outside the EDT and not
+ * concurrently for the same connection.
+ *
+ *
Implementor should not do any caching of the collected data. This
+ * method is called at least once during a connection establishment process,
+ * but could be called again if implicit refresh is requested.
+ *
+ *
Note: gathering {@link ConnectionInfo} from the SPI implementors is a
+ * part of connection process and {@link Connection} is considered to be
+ * established (and publicly available) when only after all providers are
+ * done with this task.
+ *
+ * @return a {@link ConnectionInfo} discovered by an implementor.
+ */
+ public ConnectionInfo getConnectionInfo(Connection connection) throws NativeExecutionException;
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/SignalSupport.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/SignalSupport.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/SignalSupport.java
@@ -0,0 +1,114 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi.support;
+
+import org.netbeans.modules.nativeexecution.api.process.NativeProcess;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.util.SignalUtils.Signal;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * An extension point for providing a signals support.
+ *
+ *
Implementors of the {@link ConnectionImplementation} SPI could register their
+ * implementation of the
+ * {@link SignalSupportProvider} in the {@link Lookup} associated with the
+ * connection.
+ *
+ *
By convention if implementation cannot perform a task,
+ * {@link UnsupportedOperationException} is thrown.
+ *
+ * @author akrasny
+ */
+public interface SignalSupport {
+
+ /**
+ * A request to send a signal to a specific process.
+ *
+ * @param process {@link NativeProcess} to signal.
+ * @param signal the {@link Signal} to be send.
+ */
+ public void signal(NativeProcess process, Signal signal);
+
+ /**
+ * A request to send a signal to a group the process belongs to.
+ *
+ * @param process {@link NativeProcess} which group should receive a signal.
+ * @param signal the {@link Signal} to be send.
+ */
+ public void signalGrp(NativeProcess process, Signal signal);
+
+ /**
+ * A request to send a signal with an attached value to a specific process.
+ *
+ * @param process {@link NativeProcess} to signal.
+ * @param signal the {@link Signal} to be send.
+ * @param value the value to send together with the signal.
+ */
+ public void sigqueue(NativeProcess process, Signal signal, int value);
+
+ /**
+ * A request to send a signal to a specific process.
+ *
+ * @param pid a PID of a process to signal.
+ * @param signal the {@link Signal} to be send.
+ */
+ public void signal(int pid, Signal signal);
+
+ /**
+ * A request to send a signal to a group the process belongs to.
+ *
+ * @param pid the PID of a process which group should receive a signal.
+ * @param signal the {@link Signal} to be send.
+ */
+ public void signalGrp(int pid, Signal signal);
+
+ /**
+ * A request to send a signal with an attached value to a specific process.
+ *
+ * @param pid the PID of a process to signal.
+ * @param signal the {@link Signal} to be send.
+ * @param value the value to send together with the signal.
+ */
+ public void sigqueue(int pid, Signal signal, int value);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/SignalSupportProvider.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/SignalSupportProvider.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/spi/support/SignalSupportProvider.java
@@ -0,0 +1,67 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.spi.support;
+
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.openide.util.Lookup;
+
+/**
+ * Provider of {@link SignalSupport} for a specific {@link Connection}.
+ *
+ *
Implementors of the {@link ConnectionImplementation} SPI could register their
+ * implementation of the {@link SignalSupportProvider} in the {@link Lookup}
+ * associated with the connection.
+ *
+ * @author akrasny
+ */
+public interface SignalSupportProvider {
+
+ /**
+ * Returns a {@link SignalSupport} implementation for a specific {@link Connection}.
+ *
+ * @param connection connection to get {@link SignalSupport} for.
+ * @return the {@link SignalSupport} implementation for the specified {@link Connection}.
+ *
+ */
+ public SignalSupport getSignalSupport(Connection connection);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/Computable.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/Computable.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/Computable.java
@@ -0,0 +1,69 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2009 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+
+/**
+ * An interface for calculating a result based on a single parameter.
+ *
+ * This interface is most useful in conjuction with the {@link TasksCachedProcessor}
+ * class.
+ *
+ * @param
the parameter type.
+ * @param the result type.
+ *
+ * @see TasksCachedProcessor
+ * @author akrasny
+ */
+public interface Computable
{
+
+ /**
+ * A method that does an actual computation.
+ *
+ * @param taskArguments the input parameter.
+ * @return a result of a computation.
+ * @throws NativeExecutionException in case of any problem occur during the
+ * computation.
+ */
+ R compute(P taskArguments) throws NativeExecutionException;
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/HostInfo.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/HostInfo.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/HostInfo.java
@@ -0,0 +1,289 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.util.Collections;
+import java.util.Map;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.common.ConnectionsInfo;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfo;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfoProvider;
+
+/**
+ * Utility class to extract commonly used information about a host from data
+ * provider by the {@link ConnectionInfoProvider} SPI implementors.
+ *
+ *
This class gives an easy access to the most common host-specific
+ * attributes.
+ *
+ *
Note: It is supposed that in most cases there is some host behind a
+ * {@link Connection}. Theoretically there could be connections where host info
+ * (entirely or partially) is not applicable. For such connections HostInfo
+ * attributes will be set to {@code "UNKNOWN"} value.
+ *
+ * @see ConnectionInfoProvider
+ *
+ * @author akrasny
+ */
+public final class HostInfo {
+
+ private static final String UNKNOWN = "UNKNOWN"; // NOI18N
+ private final Map info;
+ private final OS os;
+ private final int cpuNum;
+ private final CpuFamily cpuFamily;
+
+ private HostInfo(Map info) {
+ this.info = info;
+ assert info != null;
+ OSFamily osFamily = get("OSFAMILY", OSFamily.UNKNOWN); // NOI18N
+ Bitness bitness = get("BITNESS", Bitness._32); // NOI18N
+ String osBuild = get("OSBUILD", UNKNOWN); // NOI18N
+ String osName = get("OSNAME", UNKNOWN); // NOI18N
+ cpuFamily = get("CPUFAMILY", CpuFamily.UNKNOWN); // NOI18N
+ cpuNum = get("CPUNUM", 1); // NOI18N
+ os = new OS(osFamily, osName, osBuild, bitness);
+ }
+
+ /**
+ * Getter of HostInfo object for a specified Connection.
+ *
+ * @param connection connection to get info for.
+ * @return a HostInfo to the connection.
+ */
+ public static HostInfo getFor(final Connection connection) {
+ // TODO: optimize - do some caching
+ ConnectionInfo ci = ConnectionsInfo.getConnectionInfo(connection.getURI());
+ return ci == null ? new HostInfo(Collections.emptyMap())
+ : new HostInfo(ci.getProperties());
+ }
+
+ /**
+ * Returns an OS object
+ *
+ * @return the OS object
+ */
+ public OS getOS() {
+ return os;
+ }
+
+ /**
+ * Returns a number of CPUs on the host.
+ *
+ * @return the number of CPUs on the host.
+ */
+ public int getCpuNum() {
+ return cpuNum;
+ }
+
+ /**
+ * Returns CpuFamily information.
+ *
+ * @return CpuFamily information.
+ */
+ public CpuFamily getCpuFamily() {
+ return cpuFamily;
+ }
+
+ /**
+ * Test weather this is a Windows system.
+ *
+ * @return true if and only if getOS().getFamily() is OSFamily.WINDOWS
+ */
+ public boolean isWindows() {
+ return OSFamily.WINDOWS.equals(os.family);
+ }
+
+ /**
+ * Tests weather this is a Unix-like system.
+ *
+ * @return true if OSFamily is one of LINUX, MACOSX or SOLARIS
+ */
+ public boolean isUnix() {
+ switch (os.family) {
+ case LINUX:
+ case MACOSX:
+ case SOLARIS:
+ return true;
+ case WINDOWS:
+ return false;
+ case UNKNOWN:
+ return false;
+ default:
+ throw new IllegalStateException("Unexpected OSFamily: " + this); //NOI18N
+ }
+ }
+
+ /**
+ * List of known CPU families property values.
+ */
+ public enum CpuFamily {
+
+ SPARC, X86, UNKNOWN;
+ }
+
+ /**
+ * List of known OS families property values.
+ */
+ public enum OSFamily {
+
+ SOLARIS, LINUX, WINDOWS, MACOSX, UNKNOWN;
+ }
+
+ /**
+ * Bitness of the OS kernel - either 32 or 64 bits.
+ */
+ public enum Bitness {
+
+ _32,
+ _64;
+
+ static Bitness valueOf(int bitness) {
+ return bitness == 64 ? _64 : _32;
+ }
+
+ @Override
+ public String toString() {
+ return (this == _32) ? "32" : "64"; // NOI18N
+ }
+ }
+
+ /**
+ * Information about an operating system.
+ */
+ public static final class OS {
+
+ private final OSFamily family;
+ private final String name;
+ private final String version;
+ private final Bitness bitness;
+
+ /**
+ * Constructs new OS object with provided attributes.
+ *
+ * @param family OS family
+ * @param name OS name
+ * @param version OS version string
+ * @param bitness OS operating bitness mode.
+ */
+ private OS(OSFamily family, String name, String version, Bitness bitness) {
+ this.family = family;
+ this.name = name;
+ this.version = version;
+ this.bitness = bitness;
+ }
+
+ /**
+ * Returns a bitness of the OS kernel.
+ *
+ * @return the bitness of the OS kernel
+ */
+ public Bitness getBitness() {
+ return bitness;
+ }
+
+ /**
+ * Returns an OS family attribute.
+ *
+ * @return the OS family attribute.
+ */
+ public OSFamily getFamily() {
+ return family;
+ }
+
+ /**
+ * Returns a name of the OS
+ *
+ * @return the name of OS.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns a version string of the OS.
+ *
+ * @return the version string of the OS.
+ */
+ public String getVersion() {
+ return version;
+ }
+ }
+
+ //
+ @SuppressWarnings("unchecked")
+ private > T get(String name, T defaultValue) {
+ String val = info.get(name);
+ if (val == null) {
+ return defaultValue;
+ }
+
+ try {
+ T result = (T) Enum.valueOf(defaultValue.getClass(), val.toUpperCase());
+ return result;
+ } catch (Throwable ex) {
+ return defaultValue;
+ }
+ }
+
+ private String get(String name, String defaultValue) {
+ String val = info.get(name);
+ if (val == null) {
+ return defaultValue;
+ }
+ return val;
+ }
+
+ private int get(String name, int defaultValue) {
+ String val = info.get(name);
+ if (val == null) {
+ return defaultValue;
+ }
+ try {
+ int res = Integer.parseInt(val);
+ return res;
+ } catch (Throwable th) {
+ return defaultValue;
+ }
+ }
+ //
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/MacroExpander.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/MacroExpander.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/MacroExpander.java
@@ -0,0 +1,191 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.text.ParseException;
+import java.util.Map;
+
+/**
+ * A simple class that expands all macros in a String using definitions taken
+ * from a dictionary map.
+ *
+ * @author akrasny
+ */
+public final class MacroExpander {
+
+ private static final int[][] ttable = new int[][]{
+ {0, 0, 0, 1, 0, 0},
+ {2, 3, 3, 10, 4, 3},
+ {2, 2, 5, 6, 5, 5},
+ {7, 7, 8, 8, 8, 9},
+ {7, 3, 3, 3, 8, 8}
+ };
+
+ private MacroExpander() {
+ }
+
+ private static int getCharClass(char c) {
+ if (c == '_' || (c >= 'A' && c <= 'Z') || c >= 'a' && c <= 'z') {
+ return 0;
+ }
+
+ if (c >= '0' && c <= '9') {
+ return 1;
+ }
+
+ if (c == '$') {
+ return 3;
+ }
+
+ if (c == '{') {
+ return 4;
+ }
+
+ if (c == '}') {
+ return 5;
+ }
+
+ return 2;
+ }
+
+ private static String valueOf(String macro, Map map) {
+ String result = map.get(macro);
+ return result == null ? "${" + macro + "}" : result; // NOI18N
+ }
+
+ /**
+ * Parses the given string and replaces all it's macros with values from the
+ * provided dictionary.
+ *
+ *
Macros in the form {@code $NAME} and {@code ${NAME}} are
+ * supported.
+ *
+ *
Any macro that is not in the dictionary is left in the string (in the
+ * {@code ${NAME}} form).
+ *
+ *
Current implementation does a single pass of expansion:
+ *
+ * the result of a string {@code "C=${B}"} expansion with a dictionary
+ * {@code ["A=VALUE", "B=$A"]} is {@code "C=${A}"}.
+ *
+ * @param stringToExpand string with macros to be expanded.
+ * @param dictionary key-value pairs of macros definition.
+ * @return a string with all macros substituted with their values taken from
+ * the dictionary.
+ * @throws ParseException if string cannot be parsed
+ */
+ public static String expandMacros(final String stringToExpand,
+ final Map dictionary) throws ParseException {
+
+ if (stringToExpand == null || stringToExpand.length() == 0) {
+ return stringToExpand;
+ }
+
+ StringBuilder res = new StringBuilder();
+ StringBuilder buf = new StringBuilder();
+
+ int state = 0, pos = 0, mpos = -1;
+ int length = stringToExpand.length();
+ char c;
+
+ while (pos <= length) {
+ c = pos == length ? 0 : stringToExpand.charAt(pos);
+
+ switch (ttable[state][getCharClass(c)]) {
+ case 0:
+ if (c != 0) {
+ res.append(c);
+ }
+ break;
+ case 1:
+ mpos = pos;
+ buf.setLength(0);
+ state = 1;
+ break;
+ case 2:
+ buf.append(c);
+ state = 2;
+ break;
+ case 3:
+ res.append(stringToExpand.subSequence(mpos, pos + (c == 0 ? 0 : 1)));
+ buf.setLength(0);
+ state = 0;
+ break;
+ case 4:
+ state = 4;
+ break;
+ case 5:
+ res.append(valueOf(buf.toString().trim(), dictionary));
+ pos--;
+ buf.setLength(0);
+ state = 0;
+ break;
+ case 6:
+ res.append(valueOf(buf.toString().trim(), dictionary));
+ mpos = pos;
+ buf.setLength(0);
+ state = 1;
+ break;
+ case 7:
+ buf.append(c);
+ state = 3;
+ break;
+ case 8:
+ throw new ParseException("Bad substitution", pos); // NOI18N
+ case 9:
+ res.append(valueOf(buf.toString().trim(), dictionary));
+ buf.setLength(0);
+ state = 0;
+ break;
+ case 10:
+ res.append(stringToExpand.subSequence(mpos, pos));
+ pos--;
+ buf.setLength(0);
+ state = 0;
+ break;
+ }
+ pos++;
+ }
+
+ return res.toString();
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/MacroMap.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/MacroMap.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/MacroMap.java
@@ -0,0 +1,316 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.io.PrintStream;
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * Map of key-value String pairs.
+ *
+ * An implementation of Map interface that can do macro expansion on insertion
+ * and preserves an order of insertions.
+ *
+ * The following formats of macros are supported:
+ *
+ * ${NAME}
+ * $NAME
+ *
+ *
+ * Not thread safe
+ *
+ * @author akrasny
+ */
+public class MacroMap implements Cloneable {
+
+ private Map dictionary;
+ private final LinkedHashMap map;
+ private final Comparator super String> comparator;
+
+ /**
+ * Creates a new map with no specific keys comparator. The result is the
+ * same as if {@code MacroMap(null)} is called.
+ */
+ public MacroMap() {
+ this((Comparator super String>) null);
+ }
+
+ /**
+ * Creates a new map with a specified keys comparator.
+ *
+ * @param comparator the comparator to be used in keys comparisons.
+ */
+ public MacroMap(Comparator super String> comparator) {
+ this.comparator = comparator;
+ this.map = new LinkedHashMap();
+ }
+
+ protected MacroMap(MacroMap map) {
+ this.comparator = map.comparator;
+ this.map = new LinkedHashMap();
+ for (Map.Entry entry : map.entrySet()) {
+ this.map.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Adds a new key-value pair to the map.
+ *
+ *
The {@link #put(String, String)} method works as follows:
+ *
+ *
+ * MacroMap m = new MacroMap()
+ * m.put("ANT_HOME", "/bin");
+ * m.put("PATH", "$ANT_HOME");
+ * m.put("PATH", "${PATH}:/usr/bin");
+ *
+ *
+ * as a result the key "PATH" will be associated with the value
+ * "${ANT_HOME}:/usr/bin".
+ *
+ *
The only (possibly) altered value on insertion is the inserted value
+ * itself. The only macro that is expanded is the key-named macro. (See the
+ * above example - $ANT_HOME is not expanded in the value of PATH)
+ *
+ *
Comparator is used for comparing key.
+ *
+ * @param key the key of an entry
+ * @param value the new value of an entry
+ * @return a previous value associated with the key
+ */
+ public final String put(String key, String value) {
+ if (comparator != null) {
+ for (String k : map.keySet()) {
+ if (comparator.compare(k, key) == 0) {
+ return putImpl(k, value);
+ }
+ }
+ }
+ return putImpl(key, value);
+ }
+
+ /**
+ * Returns a value associated with a key.
+ *
+ * @param key the key to get value for or {@code null} if no value is
+ * associated.
+ * @return the value associated with a key.
+ */
+ public final String get(Object key) {
+ if (comparator != null) {
+ for (String k : map.keySet()) {
+ if (comparator.compare(k, (String) key) == 0) {
+ return map.get(k);
+ }
+ }
+ }
+ return map.get((String) key);
+ }
+
+ private String putImpl(String key, String value) {
+ String result = value;
+
+ TreeMap oneElementMap = comparator == null
+ ? new TreeMap()
+ : new TreeMap(comparator);
+
+ String val = get(key);
+
+ if (val != null) {
+ oneElementMap.put(key, val);
+ }
+
+ if (dictionary != null) {
+ oneElementMap.putAll(dictionary);
+ }
+
+ try {
+ result = MacroExpander.expandMacros(value, oneElementMap);
+ } catch (ParseException ex) {
+ }
+
+ return map.put(key, result);
+ }
+
+ /**
+ * Returns a new map, based on this map, but with all possible macros
+ * expanded.
+ *
+ * This method tries to expand all macros in the map. Any recursion will be
+ * left unexpanded. Unknown macros will remain untouched.
+ *
+ * @return a new map with expanded macros.
+ */
+// public final Map reduce() {
+// throw new NotImplementedException("Not implemented yet");
+// }
+ /**
+ * Defines a NAME-VALUE pairs that are to be used in expansion while not
+ * being a part of this map.
+ *
+ * @param dictionary an additional key-value entries that are used in
+ * expansion.
+ */
+ public final void setDictionary(Map dictionary) {
+ this.dictionary = new HashMap(dictionary);
+ }
+
+ /**
+ * A string representation of the map.
+ *
+ * @return the string representation.
+ */
+ @Override
+ public final String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("{"); // NOI18N
+
+ for (Map.Entry entry : entrySet()) {
+ buf.append(entry.getKey());
+ buf.append(" = "); // NOI18N
+ buf.append(entry.getValue());
+ buf.append(", "); // NOI18N
+ }
+
+ buf.append("}"); // NOI18N
+ return buf.toString();
+ }
+
+ /**
+ * A convenient way for printing out the map.
+ *
+ * @param out stream to out map to.
+ */
+ public final void dump(PrintStream out) {
+ out.println("---- Map Dump ----"); // NOI18N
+ for (Map.Entry entry : entrySet()) {
+ out.println(entry.getKey() + " = " + entry.getValue()); // NOI18N
+ }
+ out.println("------------------"); // NOI18N
+ }
+
+ /**
+ * Removes entry from the map.
+ *
+ * @param key the key to remove entry for.
+ * @return a value previously associated with the key.
+ */
+ public final String remove(Object key) {
+ if (!(key instanceof String)) {
+ return null;
+ }
+
+ if (comparator != null) {
+ for (String k : map.keySet()) {
+ if (comparator.compare(k, (String) key) == 0) {
+ key = k;
+ break;
+ }
+ }
+ }
+ return map.remove((String) key);
+ }
+
+ /**
+ * Returns an entry set of the map in the same order as they have been
+ * added.
+ *
+ * @return the entry set.
+ */
+ public final Set> entrySet() {
+ return map.entrySet();
+ }
+
+ /**
+ * Returns the number of key-value mappings in this map.
+ *
+ * @return the number of key-value mappings in this map
+ */
+ public final int size() {
+ return map.size();
+ }
+
+ /**
+ * Returns {@code true} if this map contains no key-value mappings.
+ *
+ * @return {@code true} if this map contains no key-value mappings
+ */
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * Removes all entries from this map.
+ *
+ * The map becomes empty after this call returns.
+ */
+ public void clear() {
+ map.clear();
+ }
+
+ /**
+ * Returns an unmodifiable copy of this map as a {@code Map}
+ * collection.
+ *
+ * @return unmodifiable copy
+ */
+ public Map toMap() {
+ return Collections.unmodifiableMap(new LinkedHashMap(map));
+ }
+
+ /**
+ * Returns a deep copy of the MacroMap.
+ */
+ @Override
+ public MacroMap clone() throws CloneNotSupportedException {
+ MacroMap clone = (MacroMap) super.clone();
+ return new MacroMap(clone);
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/ProcessInputProvider.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/ProcessInputProvider.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/ProcessInputProvider.java
@@ -0,0 +1,64 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.io.BufferedWriter;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcess;
+
+/**
+ * Used in {@link ProcessUtils} to provide an input to a started process.
+ *
+ * @author akrasny
+ */
+public interface ProcessInputProvider {
+
+ /**
+ * Is called once {@link NativeProcess} is started.
+ *
+ * An encoding of the passed BufferedWriter is configured based on used
+ * ProcessBuilder's attributes (or set to "UTF-8" if not configured
+ * otherwise).
+ *
+ * @param bw BufferedWriter that wraps process's output stream.
+ */
+ public void start(BufferedWriter bw);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/ProcessOutputProcessor.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/ProcessOutputProcessor.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/ProcessOutputProcessor.java
@@ -0,0 +1,59 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+/**
+ * Used in {@link ProcessUtils} to process an output of a started process.
+ *
+ * @author akrasny
+ */
+public interface ProcessOutputProcessor {
+
+ /**
+ * Is called for each line of the process's output.
+ *
+ * The line's coding is a process's output encoding...
+ *
+ * @param line the line of process's output.
+ */
+ public void processLine(final CharSequence line);
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/ProcessUtils.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/ProcessUtils.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/ProcessUtils.java
@@ -0,0 +1,591 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import org.netbeans.modules.nativeexecution.ExecutionLogger;
+import org.netbeans.modules.nativeexecution.access.NativeProcessAccessor;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcess;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcessBuilder;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+import org.netbeans.modules.nativeexecution.util.SignalUtils.Signal;
+import org.openide.util.Exceptions;
+import org.openide.util.RequestProcessor;
+import org.openide.util.RequestProcessor.Task;
+
+/**
+ * Useful utilities that handle starting of an external process, handling it's
+ * streams and so on..
+ *
+ * All methods are static.
+ *
+ * @author akrasny
+ */
+public final class ProcessUtils {
+
+ private static final RequestProcessor RP = new RequestProcessor("ProcessUtils", 50); // NOI18N
+
+ private ProcessUtils() {
+ }
+
+ private static int waitAndProcess(final Process process,
+ final ProcessOutputProcessor outputProcessor,
+ final ProcessOutputProcessor errorProcessor,
+ final ProcessInputProvider inputProvider) throws NativeExecutionException {
+ final Task readOutput, readError;
+ Task writeInput = null;
+ boolean interrupted = false;
+
+ try {
+ Charset charset = getProcessOutputCharset(process);
+
+ readOutput = RP.post(new OutputReader("Read output from " + process.toString(), // NOI18N
+ process.getInputStream(), charset, outputProcessor));
+ readError = RP.post(new OutputReader("Read error from " + process.toString(), // NOI18N
+ process.getErrorStream(), charset, errorProcessor));
+ if (inputProvider != null) {
+ charset = getProcessInputCharset(process);
+ writeInput = RP.post(new InputWriter("Write input to " + process.toString(), // NOI18N
+ process.getOutputStream(), charset, inputProvider));
+ }
+
+ int result = -1;
+
+ try {
+ result = process.waitFor();
+ } catch (InterruptedException ex) {
+ // Means THIS thread was interrupted
+ Thread.interrupted();
+ interrupted = true;
+
+ // process is running, readers are running...
+ // need to stop all these activities as the only consumer of the
+ // execute() doesn't need it now ...
+
+ process.destroy();
+
+ if (readOutput != null) {
+ readOutput.cancel();
+ }
+
+ if (readError != null) {
+ readError.cancel();
+ }
+ } finally {
+ if (writeInput != null) {
+ writeInput.cancel();
+ }
+
+ if (readOutput != null) {
+ readOutput.waitFinished();
+ }
+
+ if (readError != null) {
+ readError.waitFinished();
+ }
+
+ if (writeInput != null) {
+ writeInput.waitFinished();
+ }
+ }
+
+ return result;
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Starts a new process using already configured processBuilder, waits for
+ * its completion and returns it's exit code.
+ *
+ *
+ * outputProcessor or
+ * errorProcessor could be provided to process output/error
+ * streams. Their {@code ProcessOutputProcessor.processLine(CharSequence)}
+ * methods will be invoked (each in it's own thread) on each new line read
+ * from the process's output/error streams. Processors could be null - in
+ * this case streams still will be read-out, but disregarded.
+ * Character encoding to be used is taken from
+ * NativeProcessBuilder's parameter "outputCharset" of class
+ * Charset.class (or default, which is "UTF-8" on systems that support it,
+ * if not configured).
+ *
+ *
+ * inputProvider could be specified to feed a data to process's
+ * input stream. It's {@code ProcessInputProvider.start()} method will be
+ * invoked in a separate thread once process is started. Character
+ * encoding to be used is taken from
+ * NativeProcessBuilder's parameter "inputCharset" of class
+ * Charset.class (or default, which is "UTF-8" on systems that
+ * support it, if not configured).
+ *
+ *
Threading Model:
+ *
+ * This is a blocking method. Invoking thread is blocked until it's
+ * completion. Two or three additional threads will be started
+ * depending on weather inputProvider is specified or not. There is no any
+ * synchronization between those threads. If outputProcessor stuck
+ * process may not finish (if internal buffer is not big enough to fit all
+ * the output). Process may finish before all it's output it processed. But
+ * this method will not return before that.
+ *
+ *
Thread interruption:
+ *
+ * If invoking thread is interrupted while it is waiting for the process to
+ * finish, the process will be terminated (See {@link #destroy(NativeProcess)}),
+ * all reader/writer threads will be terminated and method will return.
+ * Thread's interrupt status will be set to true.
+ *
+ * @param processBuilder configured process builder to use
+ * @param outputProcessor processor of process's output stream. Could be
+ * null.
+ * @param errorProcessor processor of process's error stream. Could be null.
+ * @param inputProvider writer to process's input stream. Could be null.
+ * @return process's exit code. By convention exit code 0 means successful
+ * execution.
+ * @throws NativeExecutionException in case of any problem
+ * NativeExecutionException is thrown.
+ */
+ public static int execute(final NativeProcessBuilder processBuilder,
+ final ProcessOutputProcessor outputProcessor,
+ final ProcessOutputProcessor errorProcessor,
+ final ProcessInputProvider inputProvider) throws NativeExecutionException {
+ Process process;
+ try {
+ process = processBuilder.call();
+ } catch (NativeExecutionException ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new NativeExecutionException(ex);
+ }
+ return waitAndProcess(process, outputProcessor, errorProcessor, inputProvider);
+ }
+
+ /**
+ * Starts a new process using already configured processBuilder, waits for
+ * its completion and returns it's exit code.
+ *
+ *
This is almost the same as {@link #execute(NativeProcessBuilder,
+ * ProcessOutputProcessor, ProcessOutputProcessor, ProcessInputProvider)}
+ * but works with
+ * java.lang.ProcessBuilder class. Character encoding to
+ * be used is "UTF-8" on systems that support it, or whatever default is
+ * otherwise.
+ *
+ * @see #execute(NativeProcessBuilder, ProcessOutputProcessor,
+ * ProcessOutputProcessor, ProcessInputProvider)
+ * @param processBuilder configured process builder to use
+ * @param outputProcessor processor of process's output stream. Could be
+ * null.
+ * @param errorProcessor processor of process's error stream. Could be null.
+ * @param inputProvider writer to process's input stream. Could be null.
+ * @return process's exit code. By convention exit code 0 means successful
+ * execution.
+ * @throws NativeExecutionException in case of any problem
+ * NativeExecutionException is thrown.
+ */
+ public static int execute(final ProcessBuilder processBuilder,
+ final ProcessOutputProcessor outputProcessor,
+ final ProcessOutputProcessor errorProcessor,
+ final ProcessInputProvider inputProvider) throws NativeExecutionException {
+ Process process;
+ try {
+ process = processBuilder.start();
+ } catch (Exception ex) {
+ throw new NativeExecutionException("", ex);
+ }
+ return waitAndProcess(process, outputProcessor, errorProcessor, inputProvider);
+ }
+
+ /**
+ * Starts a new process using already configured processBuilder, waits for
+ * its completion and returns it's ExitStatus.
+ *
+ * This method doesn't provide any input to the process! So process's input
+ * stream is force-closed once process is started. This means that process
+ * that requires any input will fail. Otherwise invocation of such process
+ * would block the current thread.
Threading model and encodings to be
+ * used are the same as described in
+ * {@link #execute(NativeProcessBuilder, ProcessOutputProcessor, ProcessOutputProcessor, ProcessInputProvider)}.
+ *
+ *
+ * @param processBuilder configured process builder to be used
+ * @return ExitStatus exit status of the process with it's exit code,
+ * read-out output and error
+ * @throws NativeExecutionException in case of error
+ * NativeExecutionException is thrown
+ * @see #execute(NativeProcessBuilder,
+ * ProcessOutputProcessor,ProcessOutputProcessor, ProcessInputProvider).
+ */
+ public static ExitStatus execute(final NativeProcessBuilder processBuilder) throws NativeExecutionException {
+ final StringBuilder output = new StringBuilder();
+ final StringBuilder error = new StringBuilder();
+
+ int rc = execute(processBuilder, new ProcessOutputProcessor() {
+
+ @Override
+ public void processLine(CharSequence line) {
+ output.append(line).append('\n');
+ }
+ }, new ProcessOutputProcessor() {
+
+ @Override
+ public void processLine(CharSequence line) {
+ error.append(line).append('\n');
+ }
+ }, new ProcessInputProvider() {
+
+ @Override
+ public void start(BufferedWriter bw) {
+ try {
+ bw.close();
+ } catch (IOException ex) {
+ // ignore
+ }
+ }
+ });
+
+ return new ExitStatus(rc, output.subSequence(0, output.length()), error.subSequence(0, error.length()));
+ }
+
+ /**
+ * Starts a new process using already configured processBuilder, waits for
+ * its completion and returns it's ExitStatus.
+ *
+ *
See {@link #execute(NativeProcessBuilder)} for details. The only
+ * difference is that this method works with
+ * java.lang.ProcessBuilder and "UTF-8" encoding is used.
+ *
+ * @param processBuilder configured process builder to be used
+ * @return ExitStatus exit status of the process with it's exit code,
+ * read-out output and error
+ * @throws NativeExecutionException in case of error
+ * NativeExecutionException is thrown
+ * @see #execute(NativeProcessBuilder)
+ */
+ public static ExitStatus execute(final ProcessBuilder processBuilder) throws NativeExecutionException {
+ final StringBuilder output = new StringBuilder();
+ final StringBuilder error = new StringBuilder();
+
+ int rc = execute(processBuilder, new ProcessOutputProcessor() {
+
+ @Override
+ public void processLine(CharSequence line) {
+ output.append(line).append('\n');
+ }
+ }, new ProcessOutputProcessor() {
+
+ @Override
+ public void processLine(CharSequence line) {
+ error.append(line).append('\n');
+ }
+ }, new ProcessInputProvider() {
+
+ @Override
+ public void start(BufferedWriter bw) {
+ try {
+ bw.close();
+ } catch (IOException ex) {
+ // ignore
+ }
+ }
+ });
+
+ return new ExitStatus(rc, output.subSequence(0, output.length()), error.subSequence(0, output.length()));
+ }
+
+ /**
+ * Kills the subprocess.
+ *
+ * The subprocess represented by this Process object is forcibly terminated.
+ *
+ * This method tries to terminate a process in several ways. The first
+ * attempt is to call it's {@code Process.destroy()} method. On some systems
+ * this may fail (i.e. if the process is in the syscall). On failure this
+ * method will try to send SIGINT to the process's group (on systems that
+ * support that). The last attempt is to send SIGKILL (in 5 seconds).
+ *
+ * This is not a (long) blocking method. Process may still remain alive on
+ * return.
+ *
+ * @param process process to terminate (not necessarily NativeProcess)
+ */
+ public static void destroy(final NativeProcess process) {
+ // First attempt is just call destroy() on the process
+ process.destroy();
+
+ // In case the process is in a system call (sleep, read, for example)
+ // this will not have a desired effect - in this case
+ // will send SIGTERM signal..
+
+ try {
+ process.exitValue();
+ // No exception means successful termination
+ return;
+ } catch (IllegalThreadStateException ex) {
+ }
+
+ try {
+ SignalUtils.signalGrp(process, Signal.SIGINT);
+ RP.schedule(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ process.exitValue();
+ // No exception means successful termination
+ return;
+ } catch (IllegalThreadStateException ex) {
+ }
+ try {
+ SignalUtils.signalGrp(process, Signal.SIGTERM);
+ } catch (UnsupportedOperationException ex) {
+ // ignore
+ }
+ }
+ }, 5, TimeUnit.SECONDS);
+ } catch (UnsupportedOperationException ex) {
+ // ignore
+ }
+ }
+
+ /**
+ * Returns a PID of the passed process.
+ *
+ * @param p the Process to get PID for.
+ * @return a PID of the process or -1 if PID cannot be detected.
+ */
+ public static int getPID(Process p) {
+ if (p instanceof NativeProcess) {
+ return ((NativeProcess) p).getPID();
+ }
+
+ // TODO: implement
+ return -1;
+ }
+
+ private static Charset getProcessOutputCharset(Process process) {
+ return getCharset("outputCharset", process); // NOI18N
+ }
+
+ private static Charset getProcessInputCharset(Process process) {
+ return getCharset("inputCharset", process); // NOI18N
+ }
+
+ private static Charset getCharset(String paramName, Process process) {
+
+ Charset charset = null;
+
+ if (process instanceof NativeProcess) {
+ NativeProcess np = (NativeProcess) process;
+ NativeProcessAccessor access = NativeProcessAccessor.getDefault();
+ NativeProcessParams params = access.getProcessParams(np);
+ charset = params.getProperty(Charset.class, paramName);
+ }
+
+ if (charset == null || !Charset.isSupported(charset.name())) {
+ charset = Charset.isSupported("UTF-8") // NOI18N
+ ? Charset.forName("UTF-8") : // NOI18N
+ Charset.defaultCharset(); // NOI18N
+ ExecutionLogger.getInstance().log(Level.FINE,
+ "{0} is not set or is not supported - use {1}", // NOI18N
+ new Object[]{paramName, charset.name()});
+ }
+
+ return charset;
+ }
+
+ /**
+ * Simple class that represents process's exit status: exit code and data
+ * read-out from it's output and error streams.
+ */
+ public static final class ExitStatus {
+
+ /**
+ * The exit code of the Process.
+ *
+ *
By convention, exit code {@code == 0} indicates normal
+ * termination.
+ */
+ public final int exitCode;
+ /**
+ * The data read from process's error stream.
+ */
+ public final CharSequence error;
+ /**
+ * The data read from process's output stream.
+ */
+ public final CharSequence output;
+
+ private ExitStatus(int exitCode, CharSequence output, CharSequence error) {
+ this.exitCode = exitCode;
+ this.error = error;
+ this.output = output;
+ }
+
+ /**
+ * Tests weather the Process was terminated normally.
+ *
+ *
By convention, exit code {@code == 0} indicates normal termination.
+ *
+ *
+ *
This method return true if and only if exitCode == 0.
+ *
+ * @return true if and only if exitCode == 0.
+ */
+ public boolean isOK() {
+ return exitCode == 0;
+ }
+
+ /**
+ * Returns user-friendly string representation of the ExitStatus.
+ *
+ * @return string representation of the status.
+ */
+ @Override
+ public String toString() {
+ return "ExitStatus " + "exitCode=" + exitCode + "\nerror=" + error + "\noutput=" + output; // NOI18N
+ }
+ }
+
+ private static class OutputReader implements Runnable {
+
+ private final ProcessOutputProcessor outputProcessor;
+ private final String name;
+ private final InputStream stream;
+ private final Charset charset;
+
+ public OutputReader(String name, InputStream stream, Charset charset, ProcessOutputProcessor outputProcessor) {
+ this.name = name;
+ this.stream = stream;
+ this.outputProcessor = outputProcessor;
+ this.charset = charset;
+ }
+
+ @Override
+ public void run() {
+ BufferedReader br = null;
+
+ try {
+ Thread.currentThread().setName(name);
+ br = new BufferedReader(new InputStreamReader(stream, charset));
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (outputProcessor != null) {
+ outputProcessor.processLine(line);
+ }
+ }
+ } catch (Exception ex) {
+ Exceptions.printStackTrace(ex);
+ } finally {
+ if (br != null) {
+ try {
+ br.close();
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+ }
+ }
+
+ private static class InputWriter implements Runnable {
+
+ private final String name;
+ private final OutputStream stream;
+ private final ProcessInputProvider outputProcessor;
+ private final Charset charset;
+
+ public InputWriter(String name, OutputStream stream, Charset charset, ProcessInputProvider inputProvider) {
+ this.name = name;
+ this.stream = stream;
+ this.outputProcessor = inputProvider;
+ this.charset = charset;
+ }
+
+ @Override
+ public void run() {
+ BufferedWriter bw = null;
+
+ try {
+ Thread.currentThread().setName(name);
+ OutputStreamWriter osw = new OutputStreamWriter(stream, charset);
+ bw = new BufferedWriter(osw);
+ outputProcessor.start(bw);
+ } catch (Exception ex) {
+ Exceptions.printStackTrace(ex);
+ } finally {
+ if (bw != null) {
+ try {
+ bw.close();
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/SignalUtils.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/SignalUtils.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/SignalUtils.java
@@ -0,0 +1,260 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.access.ConnectionAccessor;
+import org.netbeans.modules.nativeexecution.access.NativeProcessAccessor;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.ConnectionManager;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcess;
+import org.netbeans.modules.nativeexecution.spi.support.SignalSupport;
+import org.netbeans.modules.nativeexecution.spi.support.SignalSupportProvider;
+import org.openide.util.Lookup;
+
+/**
+ * Some systems support Signal mechanism for sending asynchronous events to a
+ * given process.
+ *
+ * This is an API class for delivering signals to a process.
+ *
+ * Note: signals-related functionality could be unavailable on some systems or
+ * irrelevant to some processes.
+ *
+ * @author akrasny
+ */
+public final class SignalUtils {
+
+ private static final NativeProcessAccessor access = NativeProcessAccessor.getDefault();
+
+ private SignalUtils() {
+ }
+
+ /**
+ * Send a specified signal to a process.
+ *
+ * @param process the process to signal
+ * @param signal the signal to send
+ * @throws UnsupportedOperationException
+ */
+ public static void signal(NativeProcess process, Signal signal) throws UnsupportedOperationException {
+ Connection c = access.getConnection(process);
+ SignalSupport ss = getSignalSupport(c);
+ if (ss != null) {
+ ss.signal(process, signal);
+ }
+ }
+
+ /**
+ * Send a signal with attached value to a process.
+ *
+ * @param process the process to signal
+ * @param signal the signal to send
+ * @param value the value to attach to a signal
+ * @throws UnsupportedOperationException
+ */
+ public static void sigqueue(NativeProcess process, Signal signal, int value) throws UnsupportedOperationException {
+ Connection c = access.getConnection(process);
+ SignalSupport ss = getSignalSupport(c);
+ if (ss != null) {
+ ss.sigqueue(process, signal, value);
+ }
+ }
+
+ /**
+ * Send a signal to a whole group a process belongs to.
+ *
+ * @param process the process (and it's group) to signal
+ * @param signal the signal to send
+ * @throws UnsupportedOperationException
+ */
+ public static void signalGrp(NativeProcess process, SignalUtils.Signal signal) throws UnsupportedOperationException {
+ Connection c = access.getConnection(process);
+ SignalSupport ss = getSignalSupport(c);
+ if (ss != null) {
+ ss.signalGrp(process, signal);
+ }
+ }
+
+ /**
+ * Send a specified signal to a PID in context of the passed Connection.
+ *
+ * @param destination the context URI
+ * @param pid the PID of the process to send signal to
+ * @param signal the signal to send
+ * @throws UnsupportedOperationException
+ */
+ public void signal(URI destination, int pid, SignalUtils.Signal signal) throws UnsupportedOperationException {
+ SignalSupport ss = getSignalSupport(destination);
+ if (ss != null) {
+ ss.signal(pid, signal);
+ }
+ }
+
+ /**
+ * Send a specified signal with an attached value to a PID in context of the
+ * passed Connection.
+ *
+ * @param destination the context URI
+ * @param pid the PID of the process to send signal to
+ * @param signal the signal to send
+ * @param value the value to attach to the signal
+ * @throws UnsupportedOperationException
+ */
+ public void sigqueue(URI destination, int pid, SignalUtils.Signal signal, int value) throws UnsupportedOperationException {
+ SignalSupport ss = getSignalSupport(destination);
+ if (ss != null) {
+ ss.sigqueue(pid, signal, value);
+ }
+ }
+
+ /**
+ * Send a signal to a whole group a process identified by PID belongs to in
+ * context of the passed Connection.
+ *
+ * @param destination the context URI
+ * @param pid the PID of the process to send signal to (as well as to it's
+ * group)
+ * @param signal the signal to send
+ * @throws UnsupportedOperationException
+ */
+ public void signalGrp(URI destination, int pid, SignalUtils.Signal signal) throws UnsupportedOperationException {
+ SignalSupport ss = getSignalSupport(destination);
+ if (ss != null) {
+ ss.signalGrp(pid, signal);
+ }
+ }
+
+ private static SignalSupport getSignalSupport(Connection connection) {
+ Lookup lookup = ConnectionAccessor.getDefault().getConnectionLookup(connection);
+ if (lookup == null) {
+ throw new UnsupportedOperationException();
+ }
+
+ SignalSupportProvider signalSupportProvider = lookup.lookup(SignalSupportProvider.class);
+ if (signalSupportProvider == null) {
+ throw new UnsupportedOperationException();
+ }
+
+ return signalSupportProvider.getSignalSupport(connection);
+ }
+
+ private static SignalSupport getSignalSupport(URI destination) throws UnsupportedOperationException {
+ Connection connection = ConnectionManager.getConnection(destination);
+ if (connection == null) {
+ return null;
+ }
+ return getSignalSupport(connection);
+ }
+
+ /**
+ * Available signals
+ */
+ public enum Signal {
+
+ NULL(0),
+ SIGHUP(1),
+ SIGINT(2),
+ SIGQUIT(3),
+ SIGILL(4),
+ SIGTRAP(5),
+ SIGABRT(6),
+ SIGEMT(7),
+ SIGFPE(8),
+ SIGKILL(9),
+ SIGBUS(10),
+ SIGSEGV(11),
+ SIGSYS(12),
+ SIGPIPE(13),
+ SIGALRM(14),
+ SIGTERM(15),
+ SIGUSR1(16),
+ SIGUSR2(17),
+ SIGCHLD(18),
+ SIGPWR(19),
+ SIGWINCH(20),
+ SIGURG(21),
+ SIGPOLL(22),
+ SIGSTOP(23),
+ SIGTSTP(24),
+ SIGCONT(25),
+ SIGTTIN(26),
+ SIGTTOU(27),
+ SIGVTALRM(28),
+ SIGPROF(29),
+ SIGXCPU(30),
+ SIGWAITING(32),
+ SIGLWP(33),
+ SIGFREEZE(34),
+ SIGTHAW(35),
+ SIGCANCEL(36),
+ SIGLOST(37),
+ SIGXRES(38),
+ SIGJVM1(39);
+ private final int id;
+
+ private Signal(int id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns an integer value of the signal.
+ *
+ * This is OS-dependent value.
+ *
+ * @param os
+ * @return a numeric value of the signal.
+ */
+ public int getID(HostInfo.OSFamily os) {
+ return id;
+ }
+
+ /**
+ * Returns signal name
+ *
+ * @return signal name
+ */
+ public String getID() {
+ return id == 0 ? "0" : name().substring(4); // NOI18N
+ }
+ }
+}
\ No newline at end of file
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/TasksCachedProcessor.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/TasksCachedProcessor.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/TasksCachedProcessor.java
@@ -0,0 +1,160 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2009 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+
+/**
+ * A thread-safe implementation of {@link Computable} interface with an internal
+ * results cache.
+ *
+ * P - task parameter type; R - result type
+ *
+ */
+public final class TasksCachedProcessor
implements Computable
{
+
+ private final ConcurrentMap
> cache = new ConcurrentHashMap
>();
+ private final Computable
computable;
+ private final boolean removeOnCompletion;
+
+ /**
+ * Creates a new instance of processor.
+ *
+ * @param computable a computable that does actual calculations
+ * @param removeOnCompletion if true, the result will be removed from the
+ * cache as soon as it gets available.
+ */
+ public TasksCachedProcessor(Computable
computable, boolean removeOnCompletion) {
+ this.computable = computable;
+ this.removeOnCompletion = removeOnCompletion;
+ }
+
+ public boolean isResultAvailable(final P arg) {
+ Future res = cache.get(arg);
+
+ if (res == null) {
+ return false;
+ }
+
+ return res.isDone() && !res.isCancelled();
+ }
+
+ @Override
+ public R compute(final P arg) throws NativeExecutionException {
+ Future f = cache.get(arg);
+
+ if (f == null) {
+ Callable evaluation = new Callable() {
+
+ @Override
+ public R call() throws NativeExecutionException {
+ return computable.compute(arg);
+ }
+ };
+
+ FutureTask ft = new FutureTask(evaluation);
+ f = cache.putIfAbsent(arg, ft);
+
+ if (f == null) {
+ f = ft;
+ ft.run();
+ }
+ }
+
+ try {
+ return f.get();
+ } catch (Throwable th) {
+ cache.remove(arg, f);
+ if (th instanceof NativeExecutionException) {
+ throw (NativeExecutionException) th;
+ }
+ if (th.getCause() instanceof NativeExecutionException) {
+ throw (NativeExecutionException) th.getCause();
+ }
+ throw new NativeExecutionException("", th);
+ } finally {
+ if (removeOnCompletion) {
+ cache.remove(arg, f);
+ }
+ }
+ }
+
+ /**
+ * Force-remove cached result (if any) for the specified parameter.
+ *
+ * @param param the parameter to remove result for.
+ */
+ public void remove(P param) {
+ Future f = cache.get(param);
+
+ if (f != null && !f.isDone()) {
+ f.cancel(true);
+ }
+
+ cache.remove(param);
+ }
+
+ /**
+ * Clear an internal results cache.
+ */
+ public void resetCache() {
+ // Even if some tasks are in progress it's OK just to clear the cache.
+ // Tasks will not be terminated though...
+ cache.clear();
+ }
+
+ /**
+ * Non-blocking getter for a future result of already running or done task
+ * for the specified parameter.
+ *
+ * @param param - parameter to get future result for.
+ * @return A future result of either currently running or already done task.
+ */
+ public Future getFutureResult(P param) {
+ return cache.get(param);
+ }
+}
diff --git a/nativeexecution/src/org/netbeans/modules/nativeexecution/util/URIMatcher.java b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/URIMatcher.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/src/org/netbeans/modules/nativeexecution/util/URIMatcher.java
@@ -0,0 +1,104 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.net.URI;
+import java.util.concurrent.atomic.AtomicReference;
+import org.netbeans.modules.nativeexecution.common.ConnectionServiceLookup;
+import org.netbeans.modules.nativeexecution.spi.URIIdentifier;
+import org.openide.util.Lookup;
+
+/**
+ * An utility class for testing URIs for equivalence.
+ *
+ *
There is a notion of URIs equivalence. Equivalent URIs could verbally
+ * differ, but denote the same destination.
+ *
+ * @author akrasny
+ */
+public final class URIMatcher {
+
+ private final URI uri;
+ private final AtomicReference lookupRef = new AtomicReference();
+
+ /**
+ * Constructs a new instance of the matcher for the specified URI.
+ *
+ * @param uri URI the matcher should be created for.
+ */
+ public URIMatcher(URI uri) {
+ this.uri = uri;
+ }
+
+ /**
+ * Tests weather the provided uri is equivalent to the uri this matcher was
+ * created for.
+ *
+ * @param uri URI to test for equivalence with the uri this matcher was
+ * created for.
+ *
+ * @return {@code true} if URIs are equivalent.
+ */
+ public boolean isIdenticalURI(final URI uri) {
+ if (this.uri.equals(uri)) {
+ return true;
+ }
+
+ Lookup lookup = lookupRef.get();
+
+ if (lookup == null) {
+ lookup = ConnectionServiceLookup.getServiceLookup(this.uri);
+ Lookup old = lookupRef.getAndSet(lookup);
+ if (old != null) {
+ lookup = old;
+ }
+ }
+
+ for (URIIdentifier identifiers : lookup.lookupAll(URIIdentifier.class)) {
+ if (identifiers.areIdentical(this.uri, uri)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/nativeexecution/test/unit/data/goldenfiles/org/netbeans/modules/nativeexecution/util/MacroMapTest/testPut.pass b/nativeexecution/test/unit/data/goldenfiles/org/netbeans/modules/nativeexecution/util/MacroMapTest/testPut.pass
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/data/goldenfiles/org/netbeans/modules/nativeexecution/util/MacroMapTest/testPut.pass
@@ -0,0 +1,31 @@
+---- Map Dump ----
+A = 1
+C = 2
+B = 3
+------------------
+---- Map Dump ----
+A = 5
+c = 2
+b = 3
+C = 4
+------------------
+---- Map Dump ----
+A = 1
+C = 2
+B = 3
+------------------
+---- Map Dump ----
+A = 5
+c = 2
+b = 3
+C = 4
+------------------
+---- Map Dump ----
+A = 1
+C = 2
+B = 3
+------------------
+---- Map Dump ----
+c = 4
+b = 3
+------------------
diff --git a/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/ConnectionManagerTest.java b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/ConnectionManagerTest.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/ConnectionManagerTest.java
@@ -0,0 +1,247 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+import org.junit.After;
+import org.junit.AfterClass;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @author Andrew
+ */
+public class ConnectionManagerTest {
+
+ public ConnectionManagerTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test that:
+ *
+ *
returned connection is never null
+ *
+ *
same connection is returned in subsequent call
+ *
+ *
same connection is returned for equivalent URIs
+ *
+ *
+ */
+ @Test
+ public void testGetConnection() throws Exception {
+ final URI uri1 = new URI("test://tester@computer:22");
+ final URI uri2 = new URI("test://tester:tester@computer:22");
+
+ Connection c1, c2;
+
+ c1 = ConnectionManager.getConnection(uri1);
+ assertNull("ConnectionManager must return NULL if no ACTIVE connection with equivalent URI exists", c1);
+
+ c2 = ConnectionManager.getConnection(uri2);
+ assertNull("ConnectionManager must return NULL if no ACTIVE connection with equivalent URI exists", c2);
+
+ try {
+ c1 = ConnectionManager.connect(uri1, null);
+ assertTrue("At this point connection should be in connected state", c1.isConnected());
+ assertNotNull("Returned connection is NEVER null", c1);
+ assertTrue("Returned connection is connected", c1.isConnected());
+
+ c2 = ConnectionManager.connect(uri2, null);
+ assertNotNull("Connection exists => returned connection should be not null", c2);
+ assertTrue("Returned connection is connected", c2.isConnected());
+
+ assertEquals("Now connections should be the same", c1, c2);
+
+ ConnectionManager.disconnect(c2);
+
+ assertFalse("connection must be disconnected", c1.isConnected());
+ assertFalse("connection must be disconnected", c2.isConnected());
+
+ } catch (Exception ex) {
+ assertTrue("Unexpected exception", false);
+ }
+
+// c2 = ConnectionManager.connect(uri2, null);
+// assertTrue("At this point connection should be in connected state", c2.isConnected());
+//
+// assertTrue("Once connection was established, there should be a single Connection object for all equivalent URIs", c1 == c2);
+// assertTrue("Once connection was established, there should be a single Connection object for all equivalent URIs", c1 == ConnectionManager.getConnection(uri1));
+// assertTrue("Once connection was established, there should be a single Connection object for all equivalent URIs", c1 == ConnectionManager.getConnection(uri2));
+//
+// ConnectionManager.disconnect(c1);
+//
+// assertFalse("At this point connection should be in disconnected state", c1.isConnected());
+// assertFalse("At this point connection should be in disconnected state", c2.isConnected());
+//
+// c2 = ConnectionManager.getConnection(uri2);
+// assertNotNull("ConnectionManager must always return not NULL connection", c2);
+//
+// assertTrue("Even when connection was disconnected - the same object (if still refferenced) should be returned", c1 == c2);
+// System.out.println(System.identityHashCode(c1));
+// System.out.println(System.identityHashCode(c2));
+//
+// c1 = null;
+// c2 = null;
+// connection1 = null;
+// System.gc();
+//
+// c2 = ConnectionManager.getConnection(uri2);
+// c2 = ConnectionManager.connect(uri2, null);
+//
+// System.out.println(System.identityHashCode(c2));
+// System.out.println("should be true: " + c2.isConnected());
+// c2 = null;
+// System.gc();
+// c2 = ConnectionManager.getConnection(uri2);
+// System.out.println("should be true: " + c2.isConnected());
+ }
+
+ /**
+ * Test of getConnection method, of class ConnectionManager.
+ */
+ @Test
+ public void testGetLocalConnection() throws Exception {
+ }
+// @Test
+// public void testGetConnection() throws Exception {
+// final URI uri = new URI("test://tester@computer:22");
+// final AtomicInteger established = new AtomicInteger(0);
+// final AtomicInteger closed = new AtomicInteger(0);
+// final AtomicInteger lost = new AtomicInteger(0);
+// final AtomicInteger other = new AtomicInteger(0);
+//
+// final ConnectionStateChangeListener listener = new ConnectionStateChangeListener() {
+//
+// @Override
+// public void connectionStateChanged(ConnectionStateChangeEvent ce) {
+// switch (ce.getState()) {
+// case CONNECTION_ESTABLISHED:
+// established.incrementAndGet();
+// break;
+// case CONNECTION_CLOSED:
+// closed.incrementAndGet();
+// break;
+// case CONNECTION_LOST:
+// lost.incrementAndGet();
+// break;
+// default:
+// other.incrementAndGet();
+// }
+// }
+// };
+//
+//
+//// ConnectionsRegistryAccessor.addConnectionListener(listener);
+//
+// JPanel panel = new JPanel(new BorderLayout());
+// JButton button = new JButton("Do it!");
+// button.addActionListener(new ActionListener() {
+//
+// @Override
+// public void actionPerformed(ActionEvent e) {
+// try {
+// Connection connection = ConnectionManager.getConnection(uri);
+// connection.connect(new AuthDataProvider() {
+//
+// @Override
+// public T getProperty(final URI uri, Class clazz, String name, Object... misc) throws InterruptedException {
+// DialogDisplayer.getDefault().notify(new NotifyDescriptor.Confirmation("Enter something for: " + uri + " == " + name));
+// Thread.sleep(100000);
+// return null;
+// }
+// });
+//
+// if (connection != null && Connection.State.CONNECTED.equals(connection.getState())) {
+// assertArrayEquals(new int[]{1, 0, 0, 0},
+// new int[]{established.get(), closed.get(), lost.get(), other.get()});
+//
+// } else {
+// fail("Should be connected");
+// }
+//
+// // new TestConnector().disconnect(connection);
+//
+// // Thread.sleep(3000);
+// System.out.println("HERE!");
+//
+// Connection connection2 = ConnectionManager.getConnection(uri);
+//
+// assertTrue(connection == connection2);
+//
+//// ConnectionsRegistryAccessor.disconnect(connection2);
+//
+// assertArrayEquals(new int[]{1, 1, 0, 0},
+// new int[]{established.get(), closed.get(), lost.get(), other.get()});
+//// ConnectionsRegistryAccessor.removeConnectionListener(listener);
+// } catch (ConnectionCancelledException ex) {
+// System.out.println("Cancelled!");
+// } catch (NativeExecutionException ex) {
+// Exceptions.printStackTrace(ex);
+// }
+// }
+// });
+//
+// panel.add(button);
+// DialogDescriptor dd = new DialogDescriptor(panel, "Request");
+// Dialog dialog = DialogDisplayer.getDefault().createDialog(dd);
+// dialog.setVisible(true);
+// }
+}
diff --git a/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/ConnectionTest.java b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/ConnectionTest.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/ConnectionTest.java
@@ -0,0 +1,172 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import org.junit.After;
+import org.junit.AfterClass;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.netbeans.modules.nativeexecution.util.HostInfo;
+import org.netbeans.modules.nativeexecution.util.HostInfo.CpuFamily;
+import org.netbeans.modules.nativeexecution.util.URIMatcher;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Andrew
+ */
+public class ConnectionTest {
+
+ public ConnectionTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of connect method, of class Connection.
+ */
+ @Test
+ public void testConnectionListeners() throws Exception {
+ try {
+ final URI uri = new URI("test://tester@computer:22");
+ Connection connection = ConnectionManager.getConnection(uri);
+ assertNull("ConnectionManager must return NULL for not existent connection", connection);
+
+ final AtomicReference lstate =
+ new AtomicReference();
+
+ final AtomicInteger count = new AtomicInteger();
+ final ConnectionStateChangeListener listener = new ConnectionStateChangeListener() {
+
+ @Override
+ public void connectionStateChanged(ConnectionStateChangeEvent event) {
+ URIMatcher m = new URIMatcher(uri);
+ assertTrue(m.isIdenticalURI(event.getSource()));
+ lstate.set(event.getState());
+ count.incrementAndGet();
+ }
+ };
+
+ ConnectionManager.addConnectionStateChangeListener(listener, uri);
+
+ // Test that listeners are added weakly
+ ConnectionManager.addConnectionStateChangeListener(new ConnectionStateChangeListener() {
+
+ @Override
+ public void connectionStateChanged(ConnectionStateChangeEvent event) {
+ assertTrue("This listener should not be called!", false);
+ }
+ }, uri);
+
+ System.gc();
+
+ assertEquals(null, lstate.get());
+
+ connection = ConnectionManager.connect(uri, null);
+
+ HostInfo hostInfo = HostInfo.getFor(connection);
+ assertNotNull("HostInfo is never null", hostInfo);
+
+ assertEquals("After connection establishment must receive a CONNECTION_ESTABLISHED event",
+ ConnectionStateChangeEvent.State.CONNECTION_ESTABLISHED, lstate.get());
+
+ assertTrue("After connection establishment must be in CONNECTED state",
+ connection.isConnected());
+ assertEquals("Connected connection must have KNOWN host info", CpuFamily.X86, hostInfo.getCpuFamily());
+
+ ConnectionManager.disconnect(connection);
+
+ hostInfo = HostInfo.getFor(connection);
+ assertEquals("When disconnected with an API call, must get CONNECTION_CLOSED event",
+ ConnectionStateChangeEvent.State.CONNECTION_CLOSED, lstate.get());
+ assertFalse("When disconnected with an API call, must be in DISCONNECTED state",
+ connection.isConnected());
+ assertEquals("Connected connection must have KNOWN host info", CpuFamily.X86, hostInfo.getCpuFamily());
+
+ ConnectionManager.connect(uri, null);
+ assertEquals("On reconnect must get CONNECTION_ESTABLISHED event",
+ ConnectionStateChangeEvent.State.CONNECTION_ESTABLISHED, lstate.get());
+ assertTrue("On reconnect must appear in CONNECTED state",
+ connection.isConnected());
+
+ // Emulate broken connection (disconnected not via API)
+ TestConnector.lastTestConnection.get().disconnect();
+ // Some time may be required to see that connection is broken ...
+ Thread.sleep(1100);
+
+ hostInfo = HostInfo.getFor(connection);
+ assertEquals("When disconnected (non-API) must get CONNECTION_LOST event",
+ ConnectionStateChangeEvent.State.CONNECTION_LOST, lstate.get());
+ assertFalse("When disconnected (non-API) must be in DISCONNECTED state",
+ connection.isConnected());
+ assertEquals("Connected connection must have KNOWN host info", CpuFamily.X86, hostInfo.getCpuFamily());
+
+ ConnectionManager.disconnect(connection);
+ assertEquals("Total notifications. API call to diconnect must not send notification at this point",
+ 4, count.get());
+ } catch (NativeExecutionException ex) {
+ Exceptions.printStackTrace(ex);
+ } catch (URISyntaxException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+}
diff --git a/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/TestConnectionIdentifier.java b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/TestConnectionIdentifier.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/TestConnectionIdentifier.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+import org.netbeans.modules.nativeexecution.spi.URIIdentifier;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author akrasny
+ */
+@ServiceProvider(service = org.netbeans.modules.nativeexecution.spi.URIIdentifier.class, path = "ConnectionService/test", position = 10)
+public class TestConnectionIdentifier implements URIIdentifier {
+
+ @Override
+ public boolean areIdentical(URI uri1, URI uri2) {
+ if (!(uri1.getScheme().equals(uri2.getScheme()))) {
+ return false;
+ }
+
+ String host1 = uri1.getHost();
+ String host2 = uri2.getHost();
+
+ if (host1 == null || host2 == null) {
+ throw new NullPointerException("Test connection URI must define host");
+ }
+
+ String user1 = uri1.getUserInfo();
+ String user2 = uri2.getUserInfo();
+ if (user1 == null || user2 == null) {
+ throw new NullPointerException("Test connection URI must define user");
+ }
+
+ int cpos;
+ if ((cpos = user1.indexOf(':')) > 0) {
+ user1 = user1.substring(0, cpos);
+ }
+ if ((cpos = user2.indexOf(':')) > 0) {
+ user2 = user2.substring(0, cpos);
+ }
+
+ return host1.equals(host2) && user1.equals(user2);
+ }
+}
diff --git a/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/TestConnector.java b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/TestConnector.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/TestConnector.java
@@ -0,0 +1,159 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+import org.netbeans.modules.nativeexecution.spi.AuthDataProvider;
+import org.netbeans.modules.nativeexecution.spi.ConnectionImplementation;
+import org.netbeans.modules.nativeexecution.spi.ConnectorImplementation;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessCreator;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessImplementation;
+import org.netbeans.modules.nativeexecution.spi.process.NativeProcessParams;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfo;
+import org.netbeans.modules.nativeexecution.spi.support.ConnectionInfoProvider;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ServiceProvider;
+
+@ServiceProvider(service = org.netbeans.modules.nativeexecution.spi.ConnectorImplementation.class, path = "ConnectionService/test", position = 10)
+public final class TestConnector implements ConnectorImplementation {
+
+ public static final AtomicReference lastTestConnection = new AtomicReference();
+
+ @Override
+ public ConnectionImplementation connectTo(URI uri, AuthDataProvider authDataProvider) throws InterruptedException, NativeExecutionException {
+ authDataProvider.getProperty(uri, String.class, "test");
+ TestConnection cimpl = new TestConnection(uri);
+ lastTestConnection.set(cimpl);
+ return cimpl;
+ }
+
+ public static class TestConnection implements ConnectionImplementation {
+
+ private boolean closed = false;
+ private final String name;
+ private final URI uri;
+
+ private TestConnection(URI uri) {
+ this.name = "Test connection to " + uri.toString();
+ this.uri = uri;
+ }
+
+ @Override
+ public void disconnect() {
+ closed = true;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public NativeProcessCreator newProcessBuilderImpl() throws NativeExecutionException {
+ return FakeProcessCreator.instance;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return !closed;
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return Lookups.fixed(new ConnectionInfoProvider() {
+
+ @Override
+ public ConnectionInfo getConnectionInfo(Connection connection) throws NativeExecutionException {
+ return new ConnectionInfo() {
+
+ @Override
+ public EnvironmentMap getEnvironmentMap() {
+ EnvironmentMap env = EnvironmentMap.createCasePreserving(':');
+ env.put("TEST_ENV", "flag");
+ return env;
+ }
+
+ @Override
+ public Map getProperties() {
+ Map result = new HashMap();
+ result.put("CPUFAMILY", "X86");
+ return result;
+ }
+ };
+ }
+ });
+ }
+
+ @Override
+ public URI getURI() {
+ return uri;
+ }
+ }
+
+ public static class FakeProcessCreator implements NativeProcessCreator {
+
+ public static final FakeProcessCreator instance = new FakeProcessCreator();
+ public NativeProcessParams params;
+ private static final Map> props = new HashMap>();
+
+ static {
+ props.put("str", CharSequence.class);
+ props.put("bool", Boolean.class);
+ props.put("byteArr", byte[].class);
+ }
+
+ @Override
+ public Map> getSupportedProperties() {
+ return props;
+ }
+
+ @Override
+ public NativeProcessImplementation createAndStart(NativeProcessParams params) throws NativeExecutionException {
+ this.params = params;
+ throw new NativeExecutionException("Not supported");
+ }
+ }
+}
\ No newline at end of file
diff --git a/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/process/NativeProcessParamsTest.java b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/process/NativeProcessParamsTest.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/process/NativeProcessParamsTest.java
@@ -0,0 +1,147 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.api.process;
+
+import java.net.URI;
+import java.util.Map;
+import org.junit.After;
+import org.junit.AfterClass;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.ConnectionManager;
+import org.netbeans.modules.nativeexecution.api.TestConnector;
+import org.netbeans.modules.nativeexecution.api.TestConnector.FakeProcessCreator;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Andrew
+ */
+public class NativeProcessParamsTest {
+
+ public NativeProcessParamsTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ @Test
+ public void testGetProperty() {
+ try {
+ Connection connection = ConnectionManager.connect(new URI("test://user@testhost"));
+ String str = "test";
+ NativeProcessBuilder npb = connection.newProcessBuilder();
+
+ try {
+ npb.setProperty("str", new Integer(1));
+ fail("Exception expected");
+ } catch (IllegalArgumentException ex) {
+ }
+
+ npb.setProperty("str", str);
+ try {
+ npb.call();
+ } catch (Exception e) {
+ }
+ String result = TestConnector.FakeProcessCreator.instance.params.getProperty(String.class, "str");
+ assertEquals(str, result);
+
+ CharSequence cs = TestConnector.FakeProcessCreator.instance.params.getProperty(CharSequence.class, "str");
+ assertEquals(str, cs.toString());
+
+ Integer i = TestConnector.FakeProcessCreator.instance.params.getProperty(Integer.class, "str");
+ assertNull(i);
+
+ try {
+ npb.setProperty("other", new Integer(1));
+ fail("Exception expected");
+ } catch (IllegalArgumentException ex) {
+ }
+
+ try {
+ npb.call();
+ } catch (Exception e) {
+ }
+
+ assertNull(TestConnector.FakeProcessCreator.instance.params.getProperty(String.class, "other"));
+
+ npb.setProperty("bool", false);
+ npb.setProperty("bool", Boolean.TRUE);
+
+ npb.setProperty("byteArr", new byte[]{1, 2, 3});
+ } catch (Exception ex) {
+ Exceptions.printStackTrace(ex);
+ fail();
+ }
+ }
+
+ @Test
+ public void testGetSupportedOptions() {
+ try {
+ FakeProcessCreator npb = new FakeProcessCreator();
+ Map> sp = npb.getSupportedProperties();
+ assertTrue(sp != null && sp.size() == 3);
+ assertEquals(CharSequence.class, sp.get("str"));
+ assertEquals(Boolean.class, sp.get("bool"));
+ assertEquals(byte[].class, sp.get("byteArr"));
+ } catch (Exception ex) {
+ Exceptions.printStackTrace(ex);
+ fail();
+ }
+ }
+}
diff --git a/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/common/ConnectionsRegistryTest.java b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/common/ConnectionsRegistryTest.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/common/ConnectionsRegistryTest.java
@@ -0,0 +1,82 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.common;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.BeforeClass;
+
+/**
+ *
+ * @author Andrew
+ */
+public class ConnectionsRegistryTest {
+
+ public ConnectionsRegistryTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of fromFileName method, of class ConnectionsRegistry.
+ */
+ @Test
+ public void test() {
+
+ }
+}
diff --git a/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/EnvironmentMapTest.java b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/EnvironmentMapTest.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/EnvironmentMapTest.java
@@ -0,0 +1,115 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.After;
+import org.junit.AfterClass;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.netbeans.modules.nativeexecution.api.EnvironmentMap;
+
+/**
+ *
+ * @author Andrew
+ */
+public class EnvironmentMapTest {
+
+ public EnvironmentMapTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of prependPath method, of class EnvironmentMap.
+ */
+ @Test
+ public void testPrependPathVariable() {
+ Map special = new HashMap();
+ special.put("OS", "Win");
+
+ EnvironmentMap map = EnvironmentMap.createCasePreserving(';');
+ map.setDictionary(special);
+ map.put("Path", "");
+ map.put("PATH", "${PATH};${OS}");
+ map.appendPath("path", "");
+
+ assertEquals(1, map.size());
+ assertEquals(";Win;", map.get("path"));
+ String name = map.entrySet().iterator().next().getKey();
+
+ // First time case was exactly Path - it should be preserved
+ assertEquals("Path", name);
+
+
+ special = new HashMap();
+ special.put("OS", "UNIX");
+
+ map = EnvironmentMap.createCaseSensitive(':');
+ map.setDictionary(special);
+ map.put("Path", "");
+ map.put("PATH", "${PATH}:${OS}");
+ map.appendPath("path", "");
+
+ assertEquals(3, map.entrySet().size());
+ assertEquals("", map.get("path"));
+ assertEquals("${PATH}:UNIX", map.get("PATH"));
+ assertEquals("", map.get("Path"));
+ }
+}
diff --git a/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/HostInfoTest.java b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/HostInfoTest.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/HostInfoTest.java
@@ -0,0 +1,100 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.BeforeClass;
+import org.netbeans.modules.nativeexecution.api.Connection;
+import org.netbeans.modules.nativeexecution.api.ConnectionManager;
+import org.netbeans.modules.nativeexecution.api.NativeExecutionException;
+import org.netbeans.modules.nativeexecution.api.process.NativeProcessBuilder;
+import org.netbeans.modules.nativeexecution.util.ProcessUtils.ExitStatus;
+import org.openide.util.Exceptions;
+import org.openide.util.Utilities;
+
+/**
+ *
+ * @author akrasny
+ */
+public class HostInfoTest {
+
+ public HostInfoTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of getFor method, of class HostInfo.
+ */
+ @Test
+ public void testLocal() {
+ Connection local = ConnectionManager.getLocalConnection();
+ HostInfo info = HostInfo.getFor(local);
+ System.out.println(info.getOS().getName());
+ try {
+ NativeProcessBuilder pb = local.newProcessBuilder();
+ pb.setCommand("/bin/uname", "-a");
+ ExitStatus res = ProcessUtils.execute(pb);
+ System.out.println(res.output);
+ } catch (NativeExecutionException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+
+ }
+}
diff --git a/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/MacroMapTest.java b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/MacroMapTest.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/MacroMapTest.java
@@ -0,0 +1,200 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.util;
+
+import java.text.Collator;
+import java.util.Locale;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.netbeans.junit.NbTestCase;
+import org.openide.util.Exceptions;
+import org.openide.util.RequestProcessor;
+
+/**
+ *
+ * @author akrasny
+ */
+public class MacroMapTest extends NbTestCase {
+
+ public MacroMapTest(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ @Override
+ public void setUp() {
+ }
+
+ @After
+ @Override
+ public void tearDown() {
+ }
+
+ @Test
+ public void testX() {
+ final RequestProcessor RP = new RequestProcessor("A", 10);
+ RP.post(new Runnable() {
+
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Invoke thread");
+ doit(RP);
+ }
+ }).waitFinished();
+ System.out.println("ALL done");
+
+ }
+
+ private void doit(RequestProcessor RP) {
+ Future fres = RP.submit(new Callable() {
+
+ @Override
+ public Void call() throws Exception {
+ Thread.currentThread().setName("Process's thread");
+ try {
+ Thread.sleep(100);
+ } finally {
+ System.out.println("Process is DONE");
+ }
+
+ return null;
+ }
+ });
+
+ try {
+ fres.get();
+ System.out.println("HERE is NO exception");
+ } catch (InterruptedException ex) {
+ Thread.interrupted();
+ System.out.println("INVOKE THREAD WAS INTERRUPTED");
+ fres.cancel(true);
+ try {
+ fres.get(1, TimeUnit.SECONDS);
+ } catch (TimeoutException ex1) {
+ System.out.println("FAILED TO STOP!!!!");
+ Exceptions.printStackTrace(ex1);
+ } catch (InterruptedException ex1) {
+ Thread.interrupted();
+ System.out.println("INTERRUPTED AGAIN!!!!");
+ Exceptions.printStackTrace(ex1);
+ } catch (ExecutionException ex1) {
+ System.out.println("STOPPED!!!!");
+ Exceptions.printStackTrace(ex1);
+ }
+ } catch (ExecutionException ex) {
+ System.out.println("PROCESS's THREAD WAS INTERRUPTED");
+ Exceptions.printStackTrace(ex);
+ }
+
+ }
+
+ /**
+ * Test of put method, of class MacroMap.
+ */
+// @Test
+ public void _testPut() {
+ MacroMap map;
+
+ map = new MacroMap();
+ map.put("A", "1");
+ map.put("C", "2");
+ map.put("B", "3");
+ map.dump(getRef());
+
+ map = new MacroMap();
+ map.put("A", "1");
+ map.put("c", "2");
+ map.put("b", "3");
+ map.put("C", "4");
+ map.put("A", "5");
+ map.dump(getRef());
+
+ Collator col = Collator.getInstance(Locale.US);
+ map = new MacroMap(col);
+ map.put("A", "1");
+ map.put("C", "2");
+ map.put("B", "3");
+ map.dump(getRef());
+
+ map = new MacroMap(col);
+ map.put("A", "1");
+ map.put("c", "2");
+ map.put("b", "3");
+ map.put("C", "4");
+ map.put("A", "5");
+ map.dump(getRef());
+
+ col.setStrength(Collator.PRIMARY);
+ map = new MacroMap(col);
+ map.put("A", "1");
+ map.put("C", "2");
+ map.put("B", "3");
+ map.dump(getRef());
+
+ map = new MacroMap(col);
+ map.put("A", "1");
+ map.put("c", "2");
+ map.put("b", "3");
+ map.put("C", "4");
+ map.put("A", "5");
+ map.remove("a");
+ map.dump(getRef());
+
+ compareReferenceFiles();
+ }
+}
diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties
--- a/nbbuild/cluster.properties
+++ b/nbbuild/cluster.properties
@@ -334,6 +334,8 @@
libs.xerces,\
localhistory,\
mercurial,\
+ nativeexecution,\
+ nativeexecution.impl,\
o.apache.commons.codec,\
o.apache.commons.httpclient,\
o.apache.commons.io,\
diff --git a/nbbuild/javadoctools/links.xml b/nbbuild/javadoctools/links.xml
--- a/nbbuild/javadoctools/links.xml
+++ b/nbbuild/javadoctools/links.xml
@@ -216,4 +216,7 @@
+
+
+
diff --git a/nbbuild/javadoctools/properties.xml b/nbbuild/javadoctools/properties.xml
--- a/nbbuild/javadoctools/properties.xml
+++ b/nbbuild/javadoctools/properties.xml
@@ -214,4 +214,7 @@
+
+
+
diff --git a/nbbuild/javadoctools/replaces.xml b/nbbuild/javadoctools/replaces.xml
--- a/nbbuild/javadoctools/replaces.xml
+++ b/nbbuild/javadoctools/replaces.xml
@@ -214,4 +214,7 @@
+
+
+