+ 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/cnd.execution/build.xml b/cnd.execution/build.xml
new file mode 100755
--- /dev/null
+++ b/cnd.execution/build.xml
@@ -0,0 +1,5 @@
+
+
+ Builds, tests, and runs the project org.netbeans.modules.nativeexecution
+
+
diff --git a/cnd.execution/manifest.mf b/cnd.execution/manifest.mf
new file mode 100755
--- /dev/null
+++ b/cnd.execution/manifest.mf
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+AutoUpdate-Show-In-Client: false
+OpenIDE-Module: org.netbeans.modules.cnd.execution
+OpenIDE-Module-Implementation-Version: 1
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/cnd/execution/resources/Bundle.properties
+OpenIDE-Module-Needs: ConnectionService.localhost
+OpenIDE-Module-Provides: org.netbeans.modules.dlight.spi.terminal.ConnectionProvider
+
diff --git a/cnd.execution/nbproject/project.properties b/cnd.execution/nbproject/project.properties
new file mode 100755
--- /dev/null
+++ b/cnd.execution/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/cnd.execution/nbproject/project.xml b/cnd.execution/nbproject/project.xml
new file mode 100644
--- /dev/null
+++ b/cnd.execution/nbproject/project.xml
@@ -0,0 +1,108 @@
+
+
+ org.netbeans.modules.apisupport.project
+
+
+ org.netbeans.modules.cnd.execution
+
+
+ org.netbeans.api.progress
+
+
+
+ 1
+ 1.28
+
+
+
+ org.netbeans.modules.dlight.terminal
+
+
+
+ 1.14
+
+
+
+ org.netbeans.modules.extexecution
+
+
+
+ 2
+ 1.36
+
+
+
+ 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.nbjunit
+
+
+
+
+ org.netbeans.modules.progress.ui
+
+
+
+
+ org.openide.dialogs
+
+
+
+ org.openide.util
+
+
+
+
+ org.openide.util.lookup
+
+
+
+
+
+ org.netbeans.modules.cnd.execution.api
+ org.netbeans.modules.cnd.execution.api.config
+ org.netbeans.modules.cnd.execution.api.process
+ org.netbeans.modules.cnd.execution.spi
+ org.netbeans.modules.cnd.execution.spi.support
+ org.netbeans.modules.cnd.execution.util
+
+
+
+ bitness
+
+
+
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/ExecutionLogger.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/ExecutionLogger.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution;
+
+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", "SEVERE").toUpperCase(); // NOI18N
+ Level level = Level.SEVERE;
+
+ 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.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/cnd.execution/src/org/netbeans/modules/cnd/execution/NativeProcessFactory.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/NativeProcessFactory.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/NativeProcessFactory.java
@@ -0,0 +1,127 @@
+/*
+ * 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.cnd.execution;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import org.netbeans.api.extexecution.Environment;
+import org.netbeans.modules.cnd.execution.api.NativeExecutionException;
+import org.netbeans.modules.cnd.execution.api.NativeProcessBuilder;
+import org.netbeans.spi.extexecution.EnvironmentFactory;
+import org.netbeans.spi.extexecution.EnvironmentImplementation;
+import org.netbeans.spi.extexecution.ProcessBuilderImplementation2;
+import org.netbeans.spi.extexecution.ProcessParameters;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public class NativeProcessFactory implements ProcessBuilderImplementation2 {
+
+ private final NativeProcessBuilder builder;
+
+ private final Environment environment;
+
+ public NativeProcessFactory(NativeProcessBuilder builder) {
+ this.builder = builder;
+ this.environment = EnvironmentFactory.createEnvironment(new NativeEnvironment());
+ }
+
+ @Override
+ public Environment getEnvironment() {
+ return environment;
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return builder.getLookup();
+ }
+
+ @Override
+ public Process createProcess(ProcessParameters parameters) throws IOException {
+ builder.setCommand(parameters.getExecutable(),
+ parameters.getArguments().toArray(new String[parameters.getArguments().size()]));
+ builder.setWorkingDirectory(parameters.getWorkingDirectory());
+ builder.redirectErrorStream(parameters.isRedirectErrorStream());
+
+ try {
+ return builder.call();
+ } catch (NativeExecutionException ex) {
+ throw new IOException(ex);
+ }
+ }
+
+ private class NativeEnvironment implements EnvironmentImplementation {
+
+ @Override
+ public String getVariable(String name) {
+ return builder.getEnvironmentMap().get(name);
+ }
+
+ @Override
+ public void appendPath(String name, String value) {
+ builder.getEnvironmentMap().appendPath(name, value, false);
+ }
+
+ @Override
+ public void prependPath(String name, String value) {
+ builder.getEnvironmentMap().prependPath(name, value, false);
+ }
+
+ @Override
+ public void setVariable(String name, String value) {
+ builder.getEnvironmentMap().put(name, value, false);
+ }
+
+ @Override
+ public void removeVariable(String name) {
+ builder.getEnvironmentMap().remove(name);
+ }
+
+ @Override
+ public Map values() {
+ return builder.getEnvironmentMap().toMap();
+ }
+ }
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/access/ConnectionAccessor.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/access/ConnectionAccessor.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.access;
+
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/access/EnvironmentMapAccessor.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/access/EnvironmentMapAccessor.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/access/EnvironmentMapAccessor.java
@@ -0,0 +1,88 @@
+/*
+ * 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.cnd.execution.access;
+
+import java.util.Map;
+import org.netbeans.modules.cnd.execution.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;
+ public abstract Map getModifiedVars(EnvironmentMap environmentMap);
+
+ public abstract EnvironmentMap createBasedOn(EnvironmentMap map);
+
+ public abstract EnvironmentMap createCasePreserving(char pathSeparator);
+
+ public abstract EnvironmentMap createCaseSensitive(char pathSeparator);
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/access/NativeProcessAccessor.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/access/NativeProcessAccessor.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.access;
+
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.common.NativeProcess;
+import org.netbeans.modules.cnd.execution.spi.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/cnd.execution/src/org/netbeans/modules/cnd/execution/access/NativeProcessBuilderFactory.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/access/NativeProcessBuilderFactory.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.access;
+
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.NativeProcessBuilder;
+import org.netbeans.modules.cnd.execution.spi.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/cnd.execution/src/org/netbeans/modules/cnd/execution/access/NativeProcessParamsFactory.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/access/NativeProcessParamsFactory.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/access/NativeProcessParamsFactory.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.cnd.execution.access;
+
+import java.util.List;
+import java.util.Map;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessParams;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @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,
+ List command, String shell, String shellScript, boolean redirectError,
+ String wdir, Lookup lookup);
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/api/BrokenConnectionException.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/BrokenConnectionException.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/api/Bundle.properties b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/Bundle.properties
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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/cnd.execution/src/org/netbeans/modules/cnd/execution/api/Connection.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/Connection.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/Connection.java
@@ -0,0 +1,207 @@
+/*
+ * 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.cnd.execution.api;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.ConnectException;
+import java.net.NoRouteToHostException;
+import java.net.URI;
+import org.netbeans.modules.cnd.execution.NativeProcessFactory;
+import org.netbeans.modules.cnd.execution.access.ConnectionAccessor;
+import org.netbeans.modules.cnd.execution.access.NativeProcessBuilderFactory;
+import org.netbeans.modules.cnd.execution.spi.ConnectionImplementation;
+import org.netbeans.modules.cnd.execution.spi.ConnectorImplementation;
+import org.netbeans.modules.cnd.execution.spi.URIIdentifier;
+import org.netbeans.spi.extexecution.ProcessBuilderFactory;
+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 implements org.netbeans.api.extexecution.ProcessBuilder.Provider {
+
+ 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 newNativeProcessBuilder() throws NativeExecutionException {
+ synchronized (implLock) {
+ if (!isConnected()) {
+ throw new BrokenConnectionException(impl.getURI());
+ }
+
+ return NativeProcessBuilderFactory.getDefault().newProcessBuilder(impl.newProcessBuilderImpl(), this);
+ }
+ }
+
+ /**
+ * Creates a new {@link org.netbeans.api.extexecution.ProcessBuilder} to be used for starting
+ * processes within this connection.
+ *
+ * The returned process builder is not thread safe.
+ *
+ * @return new {@link org.netbeans.api.extexecution.ProcessBuilder}.
+ * @throws ConnectException if the connection object is not actually connected
+ * @throws InterruptedIOException if the user interrupted or canceled the
+ * communication
+ * @throws NoRouteToHostException if there is problem with connection to host
+ * @throws IOException if some problem occurred
+ */
+ @Override
+ public org.netbeans.api.extexecution.ProcessBuilder getProcessBuilder()
+ throws ConnectException, InterruptedIOException, NoRouteToHostException, IOException {
+ synchronized (implLock) {
+ if (!isConnected()) {
+ throw new ConnectException(impl.getURI().toString());
+ }
+
+ return ProcessBuilderFactory.createProcessBuilder(
+ new NativeProcessFactory(NativeProcessBuilderFactory.getDefault().newProcessBuilder(impl.newProcessBuilderImpl(), this)),
+ getDisplayName());
+ }
+ }
+
+ /**
+ * 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();
+ }
+ }
+
+ public final boolean isLocal() {
+ return this.equals(ConnectionManager.getLocalConnection());
+ }
+
+ public String getDisplayName() {
+ return 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/cnd.execution/src/org/netbeans/modules/cnd/execution/api/ConnectionException.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/ConnectionException.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/api/ConnectionManager.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/ConnectionManager.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/ConnectionManager.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.cnd.execution.api;
+
+import java.io.IOException;
+import java.net.URI;
+import org.netbeans.api.extexecution.ProcessBuilder;
+import org.netbeans.modules.cnd.execution.access.ConnectionAccessor;
+import org.netbeans.modules.cnd.execution.api.ConnectionStateChangeEvent.State;
+import org.netbeans.modules.cnd.execution.common.ConnectionListeners;
+import org.netbeans.modules.cnd.execution.common.ConnectionsPool;
+import org.netbeans.modules.cnd.execution.common.Connector;
+import org.netbeans.modules.cnd.execution.spi.AuthDataProvider;
+import org.netbeans.modules.cnd.execution.spi.ConnectionImplementation;
+import org.netbeans.modules.cnd.execution.spi.URIIdentifier;
+import org.netbeans.modules.dlight.spi.terminal.ConnectionProvider;
+import org.openide.util.Exceptions;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ * 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 IOException {
+ 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 IOException {
+ 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);
+ }
+
+ @ServiceProvider(service=ConnectionProvider.class)
+ public static class NativeConnectionProvider implements ConnectionProvider {
+
+ @Override
+ public ProcessBuilder.Provider getConnection(URI uri) throws IOException {
+ Connection connection = ConnectionManager.getConnection(uri);
+ if (connection == null) {
+ connection = ConnectionManager.connect(uri);
+ }
+ return connection;
+ }
+
+ @Override
+ public URI getLocal() {
+ return ConnectionManager.getLocalConnection().getURI();
+ }
+
+ }
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/api/ConnectionStateChangeEvent.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/ConnectionStateChangeEvent.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/api/ConnectionStateChangeListener.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/ConnectionStateChangeListener.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/api/EnvironmentMap.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/EnvironmentMap.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/EnvironmentMap.java
@@ -0,0 +1,461 @@
+/*
+ * 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.cnd.execution.api;
+
+import java.io.PrintStream;
+import java.text.Collator;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import org.netbeans.modules.cnd.execution.access.EnvironmentMapAccessor;
+import org.netbeans.modules.cnd.execution.util.MacroExpander;
+
+/**
+ * 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 final class EnvironmentMap implements Cloneable {
+
+ private final Comparator super String> comparator;
+ private final EnvironmentMap baseMap;
+ private final LinkedHashMap ownMap = new LinkedHashMap();
+ private final HashSet removedKeys = new HashSet();
+ private final char pathSeparator;
+
+ static {
+ EnvironmentMapAccessor.setDefault(new Accessor());
+ }
+
+ /**
+ * Creates a new map with a specified keys comparator.
+ *
+ * @param comparator the comparator to be used in keys comparisons.
+ */
+ private EnvironmentMap(EnvironmentMap baseMap) {
+ this.baseMap = baseMap;
+ this.comparator = baseMap.comparator;
+ this.pathSeparator = baseMap.pathSeparator;
+ }
+
+ private EnvironmentMap(Comparator super String> comparator, char pathSeparator) {
+ this.baseMap = null;
+ this.comparator = comparator;
+ this.pathSeparator = pathSeparator;
+ }
+
+ /**
+ * Adds a new key-value pair to the map.
+ *
+ *
The {@link #put(String, String)} method works as follows:
+ *
+ *
+ * EnvironmentMap m = new EnvironmentMap()
+ * 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(final String key, final String value) {
+ return put(key, value, true);
+ }
+
+ // XXX reduce visibility of this
+ public final String put(final String key, final String value, boolean expand) {
+ if (value == null) {
+ throw new NullPointerException("Attempt to set a null value"); // NOI18N
+ }
+ String result = value;
+
+
+ String fixedKey = fixKey(key);
+
+ if (expand) {
+ try {
+ result = MacroExpander.expandMacros(value, toMap());
+ } catch (ParseException ex) {
+ }
+ }
+ removedKeys.remove(fixedKey);
+ return ownMap.put(fixedKey, result);
+
+ }
+
+ protected Comparator super String> getComparator() {
+ return comparator;
+ }
+
+ /**
+ * 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(final String key) {
+ String k = fixKey(key);
+ return getImpl(k);
+ }
+
+ /**
+ * 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) {
+ appendPath(name, path, true);
+ }
+
+ // XXX reduce visibility of this
+ public void appendPath(String name, String path, boolean expand) {
+ if (path == null) {
+ return;
+ }
+
+ String oldpath = get(name);
+ String newPath = (oldpath == null ? "" : oldpath + (pathSeparator)) + path; // NOI18N
+ put(name, reducePath(newPath), expand);
+ }
+
+ /**
+ * 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) {
+ prependPath(name, path, true);
+ }
+
+ // XXX reduce visibility of this
+ public void prependPath(String name, String path, boolean expand) {
+ if (path == null) {
+ return;
+ }
+
+ String oldpath = get(name);
+ String newPath = path + (oldpath == null ? "" : (pathSeparator) + oldpath); // NOI18N
+ put(name, reducePath(newPath), expand);
+ }
+
+ /**
+ * 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(final String key) {
+ String k = fixKey(key);
+ String prevValue = getImpl(k);
+ ownMap.remove(k);
+ removedKeys.add(k);
+ return prevValue;
+ }
+
+ /**
+ * Returns an entry set of the map in the same order as they have been
+ * added.
+ *
+ * @return the entry set.
+ */
+ public final Set> entrySet() {
+ Set> result = new LinkedHashSet>();
+ if (baseMap != null) {
+ for (Entry entry : baseMap.entrySet()) {
+ String k = entry.getKey();
+ if (removedKeys.contains(k)) {
+ continue;
+ }
+ if (ownMap.containsKey(k)) {
+ continue;
+ }
+ result.add(entry);
+ }
+ }
+
+ result.addAll(ownMap.entrySet());
+ return result;
+ }
+
+ /**
+ * Returns the number of key-value mappings in this map.
+ *
+ * @return the number of key-value mappings in this map
+ */
+ public final int size() {
+ int baseSize = 0;
+ if (baseMap != null) {
+ for (Entry entry : baseMap.entrySet()) {
+ String k = entry.getKey();
+ if (removedKeys.contains(k)) {
+ continue;
+ }
+ if (ownMap.containsKey(k)) {
+ continue;
+ }
+ baseSize++;
+ }
+ }
+
+ return baseSize + ownMap.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 size() == 0;
+ }
+
+ /**
+ * Removes all entries from this map.
+ *
+ * The map becomes empty after this call returns.
+ */
+ public void clear() {
+ ownMap.clear();
+ removedKeys.clear();
+ if (baseMap != null) {
+ for (Entry entry : baseMap.entrySet()) {
+ removedKeys.add(entry.getKey());
+ }
+ }
+ }
+
+ /**
+ * Returns an unmodifiable copy of this map as a {@code Map}
+ * collection.
+ *
+ * @return unmodifiable copy
+ */
+ public Map toMap() {
+ TreeMap result = comparator == null
+ ? new TreeMap()
+ : new TreeMap(comparator);
+
+ for (Entry entry : entrySet()) {
+ result.put(entry.getKey(), entry.getValue());
+ }
+
+ return Collections.unmodifiableMap(result);
+ }
+
+ private String fixKey(final String key) {
+ if (comparator == null) {
+ return key;
+ }
+
+ for (String k : ownMap.keySet()) {
+ if (comparator.compare(k, key) == 0) {
+ return k;
+ }
+ }
+
+ // key was not found in the ownMap
+ // perhaps it is in the base one?
+ if (baseMap != null) {
+ for (Entry entry : baseMap.entrySet()) {
+ String k = entry.getKey();
+ if (comparator.compare(k, key) == 0) {
+ return k;
+ }
+ }
+ }
+
+ return key;
+ }
+
+ private String getImpl(final String fixedKey) {
+ if (removedKeys.contains(fixedKey)) {
+ return null;
+ }
+ String result = ownMap.get(fixedKey);
+ if (result != null) {
+ return result;
+ }
+ if (baseMap != null) {
+ return baseMap.getImpl(fixedKey);
+ }
+ return null;
+ }
+
+ 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);
+ }
+
+ public void putAll(Set> entrySet) {
+ for (Entry entry : entrySet) {
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ private static class Accessor extends EnvironmentMapAccessor {
+
+ public Accessor() {
+ }
+
+ @Override
+ public Map getModifiedVars(EnvironmentMap environmentMap) {
+ return Collections.unmodifiableMap(environmentMap.ownMap);
+ }
+
+ @Override
+ public EnvironmentMap createBasedOn(EnvironmentMap map) {
+ return new EnvironmentMap(map);
+ }
+
+ @Override
+ public EnvironmentMap createCasePreserving(char pathSeparator) {
+ Collator c = Collator.getInstance(Locale.US);
+ c.setStrength(Collator.PRIMARY);
+ return new EnvironmentMap(c, pathSeparator);
+ }
+
+ @Override
+ public EnvironmentMap createCaseSensitive(char pathSeparator) {
+ return new EnvironmentMap(null, pathSeparator);
+ }
+ }
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/api/NativeExecutionException.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/NativeExecutionException.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/NativeExecutionException.java
@@ -0,0 +1,87 @@
+/*
+ * 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.cnd.execution.api;
+
+import java.io.IOException;
+
+/**
+ * The root exception of all execution-related exceptions.
+ *
+ * This exception is thrown if any execution problem occurs.
+ *
+ * @author akrasny
+ */
+public class NativeExecutionException extends IOException {
+
+ 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/cnd.execution/src/org/netbeans/modules/cnd/execution/api/NativeProcessBuilder.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/NativeProcessBuilder.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/NativeProcessBuilder.java
@@ -0,0 +1,331 @@
+/*
+ * 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.cnd.execution.api;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+import org.netbeans.modules.cnd.execution.api.process.ProcessState.State;
+import org.netbeans.modules.cnd.execution.access.EnvironmentMapAccessor;
+import org.netbeans.modules.cnd.execution.access.NativeProcessBuilderFactory;
+import org.netbeans.modules.cnd.execution.access.NativeProcessParamsFactory;
+import org.netbeans.modules.cnd.execution.api.config.StateListenerConfiguration;
+import org.netbeans.modules.cnd.execution.api.config.StateListenerConfiguration.ProcessStateChangeEvent;
+import org.netbeans.modules.cnd.execution.api.config.StateListenerConfiguration.ProcessStateChangeListener;
+import org.netbeans.modules.cnd.execution.common.ConnectionsInfo;
+import org.netbeans.modules.cnd.execution.common.NativeProcess;
+import org.netbeans.modules.cnd.execution.common.ProcessStateChangeNotifier;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessCreator;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessParams;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfo;
+import org.netbeans.modules.cnd.execution.util.HostInfo;
+import org.netbeans.modules.dlight.spi.terminal.ShellConfiguration;
+import org.openide.util.Lookup;
+import org.openide.util.RequestProcessor;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ProxyLookup;
+
+/**
+ * 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, Lookup.Provider {
+
+ private final NativeProcessCreator creator;
+ private final Connection connection;
+ private final List listeners = new ArrayList();
+ private final EnvironmentMap environmentMap;
+ private final StateListenerConfiguration stateConfig = new StateListenerConfiguration(this);
+ private final ShellConfiguration shellConfig = new ShellConfiguration() {
+ @Override
+ public String getShell() {
+ return HostInfo.getFor(connection).getShell();
+ }
+ };
+
+ 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) {
+ this.creator = creator;
+ this.connection = connection;
+
+ EnvironmentMapAccessor mapAccess = EnvironmentMapAccessor.getDefault();
+ EnvironmentMap envMap = HostInfo.getEnvironmentMap(connection);
+ environmentMap = envMap == null ? mapAccess.createCaseSensitive(':') : mapAccess.createBasedOn(envMap);
+ }
+
+ /**
+ * 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.
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;
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return new ProxyLookup(Lookups.fixed(stateConfig, shellConfig), creator.getLookup());
+ }
+
+ /**
+ * 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 Process 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(),
+ EnvironmentMapAccessor.getDefault().getModifiedVars(environmentMap),
+ command,
+ shell,
+ shellScript,
+ redirectError,
+ wdir,
+ creator.getLookup());
+
+ 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/cnd.execution/src/org/netbeans/modules/cnd/execution/api/config/StateListenerConfiguration.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/config/StateListenerConfiguration.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/config/StateListenerConfiguration.java
@@ -0,0 +1,169 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.cnd.execution.api.config;
+
+import java.util.EventListener;
+import java.util.EventObject;
+import org.netbeans.modules.cnd.execution.api.NativeProcessBuilder;
+import org.netbeans.modules.cnd.execution.api.process.ProcessState;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public final class StateListenerConfiguration {
+
+ private final NativeProcessBuilder npb;
+
+ public StateListenerConfiguration(NativeProcessBuilder npb) {
+ this.npb = npb;
+ }
+
+
+ public void addProcessListener(ProcessStateChangeListener listener) {
+ this.npb.addProcessListener(listener);
+ }
+
+ public void removeProcessListener(ProcessStateChangeListener listener) {
+ this.npb.removeProcessListener(listener);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * ProcessStateChangeEvent is used to notify interested parties that state
+ * of the source's process has changed.
+ *
+ * @author akrasny
+ */
+ public static final class ProcessStateChangeEvent extends EventObject {
+
+ private static final long serialVersionUID = 1L;
+ private final ProcessState.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(Process process, ProcessState.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(Process process, ProcessState.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 ProcessState.State getState() {
+ return state;
+ }
+
+ /**
+ * Returns the source {@link Process} for this event.
+ *
+ * @return the event source
+ */
+ @Override
+ public Process getSource() {
+ return (Process) super.getSource();
+ }
+
+ /**
+ * Returns the timestamp of when this event occurred.
+ *
+ * @return this event's timestamp.
+ */
+ public long getEventNanoTime() {
+ return ts;
+ }
+ }
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/api/process/ProcessState.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/process/ProcessState.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/process/ProcessState.java
@@ -0,0 +1,107 @@
+/*
+ * 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.cnd.execution.api.process;
+
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public abstract class ProcessState {
+
+ private static ProcessState find(Process process) {
+ if (process instanceof Lookup.Provider) {
+ Lookup.Provider p = (Lookup.Provider) process;
+ return p.getLookup().lookup(ProcessState.class);
+ }
+ return null;
+ }
+
+ public static boolean isSupported(Process process) {
+ return find(process) != null;
+ }
+
+ public static State getState(Process process) {
+ ProcessState processState = find(process);
+ if (processState != null) {
+ return processState.getState();
+ }
+ return null;
+ }
+
+ protected abstract State getState();
+
+ /**
+ * Enumerates all possible states of a {@link Process}.
+ */
+ 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 is done, but exit status is not available yet.
+ */
+ FINISHING,
+ /**
+ * Native process exited.
+ */
+ FINISHED,
+ /**
+ * Native process submission failed due to some exception.
+ */
+ ERROR
+ }
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/api/process/package-info.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/process/package-info.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/api/process/package-info.java
@@ -0,0 +1,51 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-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]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+/**
+ * The API supporting enhanced functionality for
+ * a {@link java.lang.Process}. Could be moved to org.netbeans.api.extexecution.process
+ * in future.
+ */
+package org.netbeans.modules.cnd.execution.api.process;
+
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/common/Bundle.properties b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/Bundle.properties
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionListeners.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionListeners.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.ConnectionManager;
+import org.netbeans.modules.cnd.execution.api.ConnectionStateChangeEvent;
+import org.netbeans.modules.cnd.execution.api.ConnectionStateChangeEvent.State;
+import org.netbeans.modules.cnd.execution.api.ConnectionStateChangeListener;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionServiceLookup.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionServiceLookup.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionsInfo.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionsInfo.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionsInfo.java
@@ -0,0 +1,146 @@
+/*
+ * 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.cnd.execution.common;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.modules.cnd.execution.access.ConnectionAccessor;
+import org.netbeans.modules.cnd.execution.access.EnvironmentMapAccessor;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.EnvironmentMap;
+import org.netbeans.modules.cnd.execution.api.NativeExecutionException;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfo;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfoProvider;
+import org.netbeans.modules.cnd.execution.util.HostInfo;
+import org.netbeans.modules.cnd.execution.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) {
+ Map map = data.getEnvironmentMap();
+ if (map != null) {
+ info.env.putAll(data.getEnvironmentMap());
+ }
+
+ Map props = data.getProperties();
+ if (props != null) {
+ info.properties.putAll(props);
+ }
+ }
+ } catch (NativeExecutionException ex) {
+ }
+ }
+
+ setConnectionInfo(connection.getURI(), info);
+ }
+
+ private static final class ProxyInfo implements ConnectionInfo {
+
+ final Map env = new HashMap();
+ final Map properties = new HashMap();
+
+ @Override
+ public Map getEnvironmentMap() {
+ return env;
+ }
+
+ @Override
+ public Map getProperties() {
+ return properties;
+ }
+ }
+}
\ No newline at end of file
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionsPool.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionsPool.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.common;
+
+import java.net.URI;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionsRegistry.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ConnectionsRegistry.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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.cnd.execution.access.ConnectionAccessor;
+import org.netbeans.modules.cnd.execution.access.EnvironmentMapAccessor;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.EnvironmentMap;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfo;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/common/Connector.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/Connector.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.common;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+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.cnd.execution.access.ConnectionAccessor;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.NativeExecutionException;
+import org.netbeans.modules.cnd.execution.spi.AuthDataProvider;
+import org.netbeans.modules.cnd.execution.spi.ConnectionImplementation;
+import org.netbeans.modules.cnd.execution.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 IOException {
+ return connectImpl(uri, authDataProvider);
+ }
+
+ private static ConnectionImplementation connectImpl(final URI uri, final AuthDataProvider authDataProvider) throws IOException {
+ final AtomicReference resultRef = new AtomicReference();
+ final AtomicReference exRef = new AtomicReference();
+ final String msg = NbBundle.getMessage(Connector.class, "Connector.progress.connectTo", uri.getHost()); // 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();
+ }
+ }
+
+ IOException 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 (IOException ex) {
+ exRef.compareAndSet(null, ex);
+ } catch (InterruptedException ex) {
+ exRef.compareAndSet(null, new InterruptedIOException(uri.toString()));
+ break;
+ }
+ }
+
+ exRef.compareAndSet(null, new NativeExecutionException("Unsupported connection scheme: " + uri)); // NOI18N
+ return null;
+ }
+
+ @Override
+ public boolean cancel() {
+ exRef.compareAndSet(null, new InterruptedIOException(uri.toString()));
+ if (thread != null) {
+ thread.interrupt();
+ }
+ return true;
+ }
+ }
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/common/NativeProcess.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/NativeProcess.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/NativeProcess.java
@@ -0,0 +1,437 @@
+/*
+ * 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.cnd.execution.common;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.logging.Level;
+import org.netbeans.api.extexecution.process.ProcessCharset;
+import org.netbeans.api.extexecution.process.ProcessId;
+import org.netbeans.api.extexecution.process.ProcessSignal;
+import org.netbeans.modules.cnd.execution.api.process.ProcessState;
+import org.netbeans.modules.cnd.execution.api.process.ProcessState.State;
+import org.netbeans.modules.cnd.execution.ExecutionLogger;
+import org.netbeans.modules.cnd.execution.access.NativeProcessAccessor;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.NativeExecutionException;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessCreator;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessImplementation;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessParams;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.RequestProcessor;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ProxyLookup;
+
+/**
+ * An object that represents an external process.
+ *
+ * @author akrasny
+ */
+public final class NativeProcess extends Process implements Lookup.Provider {
+
+ 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 final Lookup fixedLookup;
+ private Lookup lookup;
+ 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());
+ }
+
+ public 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();
+ fixedLookup = Lookups.fixed(
+ new NativeProcessId(),
+ new NativeProcessCharset(),
+ new NativeProcessState(),
+ new NativeProcessSignal());
+ }
+
+ public NativeProcess start() throws NativeExecutionException {
+ try {
+ setState(State.STARTING);
+ processImpl = creator.createAndStart(params);
+
+ if (processImpl instanceof Lookup.Provider) {
+ Lookup.Provider provider = (Lookup.Provider) processImpl;
+ lookup = new ProxyLookup(fixedLookup, provider.getLookup());
+ } else {
+ lookup = fixedLookup;
+ }
+
+ 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 (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.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() {
+ killProcess();
+ }
+
+ /**
+ * 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
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return lookup;
+ }
+
+ 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 = null; // 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;
+ }
+
+ private class NativeProcessId extends ProcessId {
+
+ @Override
+ protected Integer getId() {
+ return NativeProcess.this.getPID();
+ }
+ }
+
+ private class NativeProcessState extends ProcessState {
+
+ @Override
+ protected State getState() {
+ return NativeProcess.this.getState();
+ }
+ }
+
+ private class NativeProcessCharset extends ProcessCharset {
+
+ @Override
+ protected Charset getInputCharset() {
+ return getProcessInputCharset(NativeProcess.this);
+ }
+
+ @Override
+ protected Charset getOutputCharset() {
+ return getProcessOutputCharset(NativeProcess.this);
+ }
+
+ @Override
+ protected Charset getErrorCharset() {
+ return getProcessOutputCharset(NativeProcess.this);
+ }
+ }
+
+ private class NativeProcessSignal extends ProcessSignal {
+
+ @Override
+ protected void signal(Signal signal) {
+ SignalUtils.signal(NativeProcess.this, SignalUtils.translate(signal));
+ }
+
+ @Override
+ protected void signalGroup(Signal signal) {
+ SignalUtils.signalGrp(NativeProcess.this, SignalUtils.translate(signal));
+ }
+ }
+
+ 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/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ProcessStateChangeNotifier.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/ProcessStateChangeNotifier.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.common;
+
+import org.netbeans.modules.cnd.execution.api.process.ProcessState.State;
+
+/**
+ *
+ * @author akrasny
+ */
+public interface ProcessStateChangeNotifier {
+
+ public void notifyProcessStateChange(final State newProcessState);
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/common/SignalUtils.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/SignalUtils.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/common/SignalUtils.java
@@ -0,0 +1,285 @@
+/*
+ * 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.cnd.execution.common;
+
+import java.net.URI;
+import java.util.EnumMap;
+import java.util.Map;
+import org.netbeans.api.extexecution.process.ProcessSignal;
+import org.netbeans.modules.cnd.execution.access.ConnectionAccessor;
+import org.netbeans.modules.cnd.execution.access.NativeProcessAccessor;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.ConnectionManager;
+import org.netbeans.modules.cnd.execution.spi.support.SignalSupport;
+import org.netbeans.modules.cnd.execution.spi.support.SignalSupportProvider;
+import org.netbeans.modules.cnd.execution.util.HostInfo;
+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);
+ }
+
+ private static Map translation;
+
+ public synchronized static Signal translate(ProcessSignal.Signal signal) {
+ if (translation == null) {
+ translation = new EnumMap(ProcessSignal.Signal.class);
+ for (Signal sig : Signal.values()) {
+ ProcessSignal.Signal api = sig.getApiSignal();
+ if (api != null) {
+ translation.put(api, sig);
+ }
+ }
+ }
+ return translation.get(signal);
+ }
+
+ /**
+ * Available signals
+ */
+ public enum Signal {
+
+ NULL(0, ProcessSignal.Signal.NULL),
+ SIGHUP(1, ProcessSignal.Signal.SIGHUP),
+ SIGINT(2, ProcessSignal.Signal.SIGINT),
+ SIGQUIT(3, ProcessSignal.Signal.SIGQUIT),
+ SIGILL(4, ProcessSignal.Signal.SIGILL),
+ SIGTRAP(5, ProcessSignal.Signal.SIGTRAP),
+ SIGABRT(6, ProcessSignal.Signal.SIGABRT),
+ SIGEMT(7, ProcessSignal.Signal.SIGEMT),
+ SIGFPE(8, ProcessSignal.Signal.SIGFPE),
+ SIGKILL(9, ProcessSignal.Signal.SIGKILL),
+ SIGBUS(10, ProcessSignal.Signal.SIGBUS),
+ SIGSEGV(11, ProcessSignal.Signal.SIGSEGV),
+ SIGSYS(12, ProcessSignal.Signal.SIGSYS),
+ SIGPIPE(13, ProcessSignal.Signal.SIGPIPE),
+ SIGALRM(14, ProcessSignal.Signal.SIGALRM),
+ SIGTERM(15, ProcessSignal.Signal.SIGTERM),
+ SIGUSR1(16, ProcessSignal.Signal.SIGUSR1),
+ SIGUSR2(17, ProcessSignal.Signal.SIGUSR2),
+ SIGCHLD(18, ProcessSignal.Signal.SIGCHLD),
+ SIGPWR(19, ProcessSignal.Signal.SIGPWR),
+ SIGWINCH(20, ProcessSignal.Signal.SIGWINCH),
+ SIGURG(21, ProcessSignal.Signal.SIGURG),
+ SIGPOLL(22, ProcessSignal.Signal.SIGPOLL),
+ SIGSTOP(23, ProcessSignal.Signal.SIGSTOP),
+ SIGTSTP(24, ProcessSignal.Signal.SIGTSTP),
+ SIGCONT(25, ProcessSignal.Signal.SIGCONT),
+ SIGTTIN(26, ProcessSignal.Signal.SIGTTIN),
+ SIGTTOU(27, ProcessSignal.Signal.SIGTTOU),
+ SIGVTALRM(28, ProcessSignal.Signal.SIGVTALRM),
+ SIGPROF(29, ProcessSignal.Signal.SIGPROF),
+ SIGXCPU(30, ProcessSignal.Signal.SIGXCPU),
+ SIGWAITING(32, ProcessSignal.Signal.SIGWAITING),
+ SIGLWP(33, ProcessSignal.Signal.SIGLWP),
+ SIGFREEZE(34, ProcessSignal.Signal.SIGFREEZE),
+ SIGTHAW(35, ProcessSignal.Signal.SIGTHAW),
+ SIGCANCEL(36, ProcessSignal.Signal.SIGCANCEL),
+ SIGLOST(37, ProcessSignal.Signal.SIGLOST),
+ SIGXRES(38, ProcessSignal.Signal.SIGXRES),
+ SIGJVM1(39, ProcessSignal.Signal.SIGJVM1);
+ private final int id;
+
+ private final ProcessSignal.Signal apiSignal;
+
+ private Signal(int id, ProcessSignal.Signal apiSignal) {
+ this.id = id;
+ this.apiSignal = apiSignal;
+ }
+
+ /**
+ * 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
+ }
+
+ ProcessSignal.Signal getApiSignal() {
+ return apiSignal;
+ }
+ }
+}
\ No newline at end of file
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/resources/Bundle.properties b/cnd.execution/src/org/netbeans/modules/cnd/execution/resources/Bundle.properties
new file mode 100755
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/resources/Bundle.properties
@@ -0,0 +1,2 @@
+OpenIDE-Module-Name=Native Execution API
+
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/AuthDataProvider.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/AuthDataProvider.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/AuthDataProvider.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.cnd.execution.spi;
+
+import java.net.URI;
+import org.netbeans.modules.cnd.execution.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
+ /**
+ * Common identifier used for requesting a User Interaction facility.
+ */
+ public static final String USER_INTERACTION = "userinteraction"; // 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/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/ConnectionImplementation.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/ConnectionImplementation.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/ConnectionImplementation.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.cnd.execution.spi;
+
+import java.net.URI;
+import org.netbeans.modules.cnd.execution.api.NativeExecutionException;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfoProvider;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/ConnectorImplementation.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/ConnectorImplementation.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/ConnectorImplementation.java
@@ -0,0 +1,93 @@
+/*
+ * 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.cnd.execution.spi;
+
+import java.io.IOException;
+import java.net.URI;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.ConnectionManager;
+import org.netbeans.modules.cnd.execution.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, IOException;
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/NativeProcessCreator.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/NativeProcessCreator.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/NativeProcessCreator.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.cnd.execution.spi;
+
+import org.netbeans.modules.cnd.execution.api.NativeExecutionException;
+import org.netbeans.modules.cnd.execution.api.NativeProcessBuilder;
+import org.openide.util.Lookup;
+
+/**
+ * An SPI interface for providing process creator implementation.
+ *
+ * @author akrasny
+ */
+public interface NativeProcessCreator extends Lookup.Provider {
+
+ /**
+ * 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/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/NativeProcessImplementation.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/NativeProcessImplementation.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/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.cnd.execution.spi;
+
+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/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/NativeProcessParams.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/NativeProcessParams.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/NativeProcessParams.java
@@ -0,0 +1,197 @@
+/*
+ * 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.cnd.execution.spi;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.netbeans.modules.cnd.execution.access.NativeProcessParamsFactory;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.NativeProcessBuilder;
+import org.netbeans.modules.cnd.execution.common.NativeProcess;
+import org.openide.util.Lookup;
+
+/**
+ * Parameters constructed by a {@link NativeProcessBuilder} to be used for
+ * {@link NativeProcess} creation.
+ *
+ *
This is an immutable object.
+ *
+ * @author akrasny
+ */
+public final class NativeProcessParams implements Lookup.Provider {
+
+ private final Connection connection;
+ private final Map connectionInfo;
+ 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 final Lookup lookup;
+
+ private NativeProcessParams(Connection connection, Map connectionInfo,
+ Map environmentMap,
+ List command, String shell, String shellScript,
+ boolean redirectError, String wdir, Lookup lookup) {
+ this.connection = connection;
+ this.connectionInfo = connectionInfo;
+ this.environment = environmentMap;
+ this.command = command;
+ this.shell = shell;
+ this.shellScript = shellScript;
+ this.redirectError = redirectError;
+ this.wdir = wdir;
+ this.lookup = lookup;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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;
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return lookup;
+ }
+
+
+ //
+ static {
+ NativeProcessParamsFactory.setDefault(new NativeProcessParamsFactoryImpl());
+ }
+
+ private static class NativeProcessParamsFactoryImpl extends NativeProcessParamsFactory {
+
+ @Override
+ public NativeProcessParams newNativeProcessParams(Connection connection,
+ Map connectionInfo, Map env,
+ List command, String shell, String shellScript,
+ boolean redirectError, String wdir, Lookup lookup) {
+ NativeProcessParams params = new NativeProcessParams(connection, connectionInfo, env,
+ command, shell, shellScript, redirectError, wdir, lookup);
+ return params;
+ }
+ }
+ //
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/URIIdentifier.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/URIIdentifier.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.spi;
+
+import java.net.URI;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/UserInteraction.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/UserInteraction.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/UserInteraction.java
@@ -0,0 +1,55 @@
+/*
+ * 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.cnd.execution.spi;
+
+import java.net.URI;
+
+/**
+ *
+ * @author Andrew
+ */
+public interface UserInteraction {
+
+ public boolean promptYesNo(URI uri, String message);
+
+ public void notify(URI uri, String message);
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/support/ConnectionInfo.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/support/ConnectionInfo.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.spi.support;
+
+import java.util.Map;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.EnvironmentMap;
+import org.netbeans.modules.cnd.execution.spi.ConnectionImplementation;
+import org.netbeans.modules.cnd.execution.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 Map getEnvironmentMap();
+
+ /**
+ * Returns a map of attributes to be associated with the connection.
+ *
+ * @return the map of connection attributes.
+ */
+ public Map getProperties();
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/support/ConnectionInfoProvider.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/support/ConnectionInfoProvider.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.spi.support;
+
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.NativeExecutionException;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/support/SignalSupport.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/support/SignalSupport.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.spi.support;
+
+import org.netbeans.modules.cnd.execution.common.NativeProcess;
+import org.netbeans.modules.cnd.execution.spi.ConnectionImplementation;
+import org.netbeans.modules.cnd.execution.common.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/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/support/SignalSupportProvider.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/spi/support/SignalSupportProvider.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.spi.support;
+
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/util/Computable.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/util/Computable.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.util;
+
+import org.netbeans.modules.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/util/HostInfo.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/util/HostInfo.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/util/HostInfo.java
@@ -0,0 +1,413 @@
+/*
+ * 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.cnd.execution.util;
+
+import java.net.URI;
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import org.netbeans.modules.cnd.execution.ExecutionLogger;
+import org.netbeans.modules.cnd.execution.access.EnvironmentMapAccessor;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.EnvironmentMap;
+import org.netbeans.modules.cnd.execution.common.ConnectionsInfo;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfo;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfoProvider;
+import org.openide.util.Exceptions;
+
+/**
+ * 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 {
+
+ public static final String UNKNOWN = "UNKNOWN"; // NOI18N
+ private final URI connectionURI;
+
+ private HostInfo(final URI connectionURI) {
+ this.connectionURI = connectionURI;
+ }
+
+ /**
+ * 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) {
+ return new HostInfo(connection.getURI());
+ }
+
+ public static EnvironmentMap getEnvironmentMap(Connection connection) {
+ ConnectionInfo cinfo = ConnectionsInfo.getConnectionInfo(connection.getURI());
+ if (cinfo == null) {
+ return null;
+ }
+
+ HostInfo hinfo = getFor(connection);
+ EnvironmentMap base;
+ EnvironmentMapAccessor access = EnvironmentMapAccessor.getDefault();
+ switch (hinfo.getOS().family) {
+ case MACOSX:
+ base = access.createCasePreserving(':');
+ break;
+ case WINDOWS:
+ base = access.createCasePreserving(';');
+ break;
+ default:
+ base = access.createCaseSensitive(':');
+ break;
+ }
+ base.putAll(cinfo.getEnvironmentMap().entrySet());
+ return base;
+ }
+
+ public String expandMacros(final String string) {
+ try {
+ return MacroExpander.expandMacros(string, getMacros());
+ } catch (ParseException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ return string;
+ }
+
+ /**
+ * Returns an OS object
+ *
+ * @return the OS object
+ */
+ public OS getOS() {
+ return new OS(
+ get("OSFAMILY", OSFamily.UNKNOWN), // NOI18N
+ get("OSNAME", UNKNOWN), // NOI18N
+ get("OSVERSION", UNKNOWN), // NOI18N
+ getBitness("BITNESS", Bitness._32)); // NOI18N
+ }
+
+ /**
+ * Returns a number of CPUs on the host.
+ *
+ * @return the number of CPUs on the host.
+ */
+ public int getCpuNum() {
+ return get("CPUNUM", 1); // NOI18N
+ }
+
+ /**
+ * Returns CpuFamily information.
+ *
+ * @return CpuFamily information.
+ */
+ public CpuFamily getCpuFamily() {
+ return get("CPUFAMILY", CpuFamily.UNKNOWN); // NOI18N
+ }
+
+ /**
+ * 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(getOS().family);
+ }
+
+ /**
+ * Tests weather this is a Unix-like system.
+ *
+ * @return true if OSFamily is one of LINUX, MACOSX or SOLARIS
+ */
+ public boolean isUnix() {
+ return getOS().family.isUnix();
+ }
+
+ /**
+ * Returns the login shell (as specified in /etc/passwd) of the connected
+ * user.
+ *
+ * @return the login shell
+ */
+ public String getShell() {
+ return get("SHELL", "/bin/sh"); // NOI18N
+ }
+
+ public String getTempDir() {
+ return get("TMPDIRBASE", "/var/tmp"); // 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;
+
+ public boolean isUnix() {
+ switch (this) {
+ case LINUX:
+ case MACOSX:
+ case SOLARIS:
+ return true;
+ case WINDOWS:
+ return false;
+ case UNKNOWN:
+ return false;
+ default:
+ throw new IllegalStateException("Unexpected OSFamily: " + this); //NOI18N
+ }
+ }
+
+ /**
+ * Returns CamelCase name of the family.
+ *
+ * Like: SunOS; Linux; Windows; MacOSX.
+ *
+ * @return CamelCase name
+ */
+ public String cname() {
+ switch (this) {
+ case LINUX:
+ return "Linux"; // NOI18N
+ case MACOSX:
+ return "MacOSX"; // NOI18N
+ case SOLARIS:
+ return "SunOS"; // NOI18N
+ case WINDOWS:
+ return "Windows"; // NOI18N
+ case UNKNOWN:
+ return "UNKNOWN"; // NOI18N
+ default:
+ throw new IllegalStateException("Unexpected OSFamily: " + this); //NOI18N
+ }
+ }
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ //
+ private Map getMacros() {
+ Map map = new HashMap();
+ String soext;
+ final OS os = getOS();
+ switch (os.family) {
+ case WINDOWS:
+ soext = "dll"; // NOI18N
+ break;
+ case MACOSX:
+ soext = "dylib"; // NOI18N
+ break;
+ case SOLARIS:
+ case LINUX:
+ case UNKNOWN:
+ soext = "so"; // NOI18N
+ break;
+ default:
+ throw new IllegalStateException("Unexpected OSFamily: " + os.family); //NOI18N
+ }
+
+ map.put("soext", soext); // NOI18N
+ map.put("osname", os.family.cname()); // NOI18N
+ map.put("isa", os.getBitness().toString()); // NOI18N
+ map.put("_isa", os.getBitness() == HostInfo.Bitness._64 ? "_64" : ""); // NOI18N
+ map.put("platform", getCpuFamily().name().toLowerCase()); // NOI18N
+
+ return map;
+ }
+
+ private String get(String key) {
+ ConnectionInfo info = ConnectionsInfo.getConnectionInfo(connectionURI);
+ if (info != null) {
+ return info.getProperties().get(key);
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private > T get(String name, T defaultValue) {
+ String val = get(name);
+ if (val != null) {
+ try {
+ T result = (T) Enum.valueOf(defaultValue.getClass(), val.toUpperCase());
+ return result;
+ } catch (Throwable ex) {
+ ExecutionLogger.getInstance().log(Level.WARNING,
+ "HostInfo: Invalid value for {0} - {1}", // NOI18N
+ new Object[]{name, val});
+ }
+ }
+ return defaultValue;
+ }
+
+ private Bitness getBitness(String name, Bitness defaultValue) {
+ String val = get(name);
+ if (val != null) {
+ if ("64".equals(val)) { // NOI18N
+ return Bitness._64;
+ }
+ if ("32".equals(val)) { // NOI18N
+ return Bitness._32;
+ }
+ ExecutionLogger.getInstance().log(Level.WARNING,
+ "HostInfo: Invalid value for Bitness - {0}", // NOI18N
+ val);
+ }
+ return defaultValue;
+ }
+
+ private String get(String name, String defaultValue) {
+ String val = get(name);
+ return val == null ? defaultValue : val;
+ }
+
+ private int get(String name, int defaultValue) {
+ String val = get(name);
+ if (val != null) {
+ try {
+ return Integer.parseInt(val);
+ } catch (NumberFormatException ex) {
+ ExecutionLogger.getInstance().log(Level.WARNING,
+ "HostInfo: Invalid value for {0} - {1}", // NOI18N
+ new Object[]{name, val});
+ }
+ }
+ return defaultValue;
+ }
+ //
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/util/MacroExpander.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/util/MacroExpander.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/util/ProcessUtils.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/util/ProcessUtils.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/util/ProcessUtils.java
@@ -0,0 +1,124 @@
+/*
+ * 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.cnd.execution.util;
+
+import org.netbeans.modules.cnd.execution.common.SignalUtils;
+import java.util.concurrent.TimeUnit;
+import org.netbeans.modules.cnd.execution.common.NativeProcess;
+import org.netbeans.modules.cnd.execution.common.SignalUtils.Signal;
+import org.openide.util.RequestProcessor;
+
+/**
+ * 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() {
+ }
+
+ /**
+ * 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 SIGTERM 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 Process 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) {
+ }
+
+ if (!(process instanceof NativeProcess)) {
+ return;
+ }
+
+ final NativeProcess nativeProcess = (NativeProcess) process;
+ try {
+ SignalUtils.signalGrp(nativeProcess, Signal.SIGTERM);
+ RP.schedule(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ process.exitValue();
+ // No exception means successful termination
+ return;
+ } catch (IllegalThreadStateException ex) {
+ }
+ try {
+ SignalUtils.signalGrp(nativeProcess, Signal.SIGKILL);
+ } catch (UnsupportedOperationException ex) {
+ // ignore
+ }
+ }
+ }, 5, TimeUnit.SECONDS);
+ } catch (UnsupportedOperationException ex) {
+ // ignore
+ }
+ }
+}
diff --git a/cnd.execution/src/org/netbeans/modules/cnd/execution/util/TasksCachedProcessor.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/util/TasksCachedProcessor.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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.cnd.execution.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/cnd.execution/src/org/netbeans/modules/cnd/execution/util/URIMatcher.java b/cnd.execution/src/org/netbeans/modules/cnd/execution/util/URIMatcher.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/src/org/netbeans/modules/cnd/execution/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.cnd.execution.util;
+
+import java.net.URI;
+import java.util.concurrent.atomic.AtomicReference;
+import org.netbeans.modules.cnd.execution.common.ConnectionServiceLookup;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/test/unit/data/goldenfiles/org/netbeans/modules/nativeexecution/util/MacroMapTest/testPut.pass b/cnd.execution/test/unit/data/goldenfiles/org/netbeans/modules/nativeexecution/util/MacroMapTest/testPut.pass
new file mode 100644
--- /dev/null
+++ b/cnd.execution/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/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/ConnectionManagerTest.java b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/ConnectionManagerTest.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/ConnectionManagerTest.java
@@ -0,0 +1,249 @@
+/*
+ * 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.cnd.execution.api;
+
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.ConnectionManager;
+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/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/ConnectionTest.java b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/ConnectionTest.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/ConnectionTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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.cnd.execution.api;
+
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.ConnectionManager;
+import org.netbeans.modules.cnd.execution.api.ConnectionStateChangeListener;
+import org.netbeans.modules.cnd.execution.api.ConnectionStateChangeEvent;
+import org.netbeans.modules.cnd.execution.api.NativeExecutionException;
+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.cnd.execution.util.HostInfo;
+import org.netbeans.modules.cnd.execution.util.HostInfo.CpuFamily;
+import org.netbeans.modules.cnd.execution.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/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/TestConnectionIdentifier.java b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/TestConnectionIdentifier.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/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.cnd.execution.api;
+
+import java.net.URI;
+import org.netbeans.modules.cnd.execution.spi.URIIdentifier;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author akrasny
+ */
+@ServiceProvider(service = org.netbeans.modules.cnd.execution.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/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/TestConnector.java b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/TestConnector.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/api/TestConnector.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.cnd.execution.api;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+import org.netbeans.modules.cnd.execution.spi.AuthDataProvider;
+import org.netbeans.modules.cnd.execution.spi.ConnectionImplementation;
+import org.netbeans.modules.cnd.execution.spi.ConnectorImplementation;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessCreator;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessImplementation;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessParams;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfo;
+import org.netbeans.modules.cnd.execution.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.cnd.execution.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 Map getEnvironmentMap() {
+ HashMap env = new HashMap();
+ 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;
+
+ @Override
+ public NativeProcessImplementation createAndStart(NativeProcessParams params) throws NativeExecutionException {
+ this.params = params;
+ throw new NativeExecutionException("Not supported");
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return Lookup.EMPTY;
+ }
+ }
+}
\ No newline at end of file
diff --git a/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/common/ConnectionsRegistryTest.java b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/common/ConnectionsRegistryTest.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/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.cnd.execution.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/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/util/EnvironmentMapTest.java b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/util/EnvironmentMapTest.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/util/EnvironmentMapTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.cnd.execution.util;
+
+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.cnd.execution.access.EnvironmentMapAccessor;
+import org.netbeans.modules.cnd.execution.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() {
+ EnvironmentMap map = EnvironmentMapAccessor.getDefault().createCasePreserving(';');
+ map.put("Path", "");
+ map.put("PATH", "${PATH};${UNKNOWN}");
+ map.appendPath("path", "");
+
+ map.dump(System.out);
+ assertEquals(1, map.size());
+ assertEquals(";${UNKNOWN};", map.get("path"));
+
+ String name = map.entrySet().iterator().next().getKey();
+
+ // First time case was exactly Path - it should be preserved
+ assertEquals("Path", name);
+
+
+ map = EnvironmentMapAccessor.getDefault().createCaseSensitive(':');
+ // map.setDictionary(special);
+ map.put("Path", "");
+ map.put("PATH", "${PATH}:${UNKNOWN}");
+ map.appendPath("path", "");
+ map.prependPath("path", "");
+
+ map.dump(System.out);
+ assertEquals(3, map.entrySet().size());
+ assertEquals(":", map.get("path"));
+ assertEquals("${PATH}:${UNKNOWN}", map.get("PATH"));
+ assertEquals("", map.get("Path"));
+ }
+}
diff --git a/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/util/HostInfoTest.java b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/util/HostInfoTest.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/util/HostInfoTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.cnd.execution.util;
+
+import static org.junit.Assert.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.concurrent.ExecutionException;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.netbeans.api.extexecution.ExecutionService;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.ConnectionManager;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @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());
+
+ File f = new File("/usr/bin/uname");
+ if (!f.canExecute()) {
+ f = new File("/bin/uname");
+ if (!f.canExecute()) {
+ fail("uname not found");
+ }
+ }
+ try {
+ org.netbeans.api.extexecution.ProcessBuilder pb = local.getProcessBuilder();
+ pb.setExecutable(f.getAbsolutePath());
+ pb.setArguments(Collections.singletonList("-a"));
+ StringWriter output = new StringWriter();
+ ExecutionService.newService(pb, output, null).run().get();
+ System.out.println(output.toString());
+ } catch (ExecutionException ex) {
+ Exceptions.printStackTrace(ex);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+
+ }
+}
diff --git a/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/util/MacroMapTest.java b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/util/MacroMapTest.java
new file mode 100644
--- /dev/null
+++ b/cnd.execution/test/unit/src/org/netbeans/modules/cnd/execution/util/MacroMapTest.java
@@ -0,0 +1,198 @@
+/*
+ * 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.cnd.execution.util;
+
+import org.netbeans.modules.cnd.execution.api.EnvironmentMap;
+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.netbeans.modules.cnd.execution.access.EnvironmentMapAccessor;
+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 EnvironmentMap.
+ */
+// @Test
+ public void _testPut() {
+ EnvironmentMap map;
+
+// map = EnvironmentMapAccessor.getDefault().createCaseSensitive(':');
+// map.put("A", "1");
+// map.put("C", "2");
+// map.put("B", "3");
+// map.dump(getRef());
+//
+// map = EnvironmentMapAccessor.getDefault().createCaseSensitive(':');
+// map.put("A", "1");
+// map.put("c", "2");
+// map.put("b", "3");
+// map.put("C", "4");
+// map.put("A", "5");
+// map.dump(getRef());
+//
+// map = EnvironmentMapAccessor.getDefault().createCasePreserving(':');
+// map.put("A", "1");
+// map.put("C", "2");
+// map.put("B", "3");
+// map.dump(getRef());
+//
+// map = EnvironmentMapAccessor.getDefault().createCasePreserving(':');
+// map.put("A", "1");
+// map.put("c", "2");
+// map.put("b", "3");
+// map.put("C", "4");
+// map.put("A", "5");
+// map.dump(getRef());
+//
+// map = EnvironmentMapAccessor.getDefault().createCasePreserving(':');
+// map.put("A", "1");
+// map.put("C", "2");
+// map.put("B", "3");
+// map.dump(getRef());
+//
+// map = EnvironmentMapAccessor.getDefault().createCasePreserving(':');
+// 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/cnd.makeproject/nbproject/project.xml b/cnd.makeproject/nbproject/project.xml
--- a/cnd.makeproject/nbproject/project.xml
+++ b/cnd.makeproject/nbproject/project.xml
@@ -67,6 +67,14 @@
1.9.2
+
+ org.netbeans.modules.cnd.execution
+
+
+
+ 1.0
+
+ org.netbeans.modules.cnd.source
@@ -133,6 +141,14 @@
+ org.netbeans.modules.execmerge
+
+
+
+ 1.0
+
+
+ org.netbeans.modules.extexecution
diff --git a/cnd.makeproject/src/org/netbeans/modules/cnd/makeproject/api/ProjectActionSupport.java b/cnd.makeproject/src/org/netbeans/modules/cnd/makeproject/api/ProjectActionSupport.java
--- a/cnd.makeproject/src/org/netbeans/modules/cnd/makeproject/api/ProjectActionSupport.java
+++ b/cnd.makeproject/src/org/netbeans/modules/cnd/makeproject/api/ProjectActionSupport.java
@@ -61,6 +61,7 @@
import java.util.prefs.Preferences;
import javax.swing.AbstractAction;
import javax.swing.Action;
+import org.netbeans.api.extexecution.ProcessBuilder;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.api.project.Project;
@@ -73,6 +74,7 @@
import org.netbeans.modules.cnd.api.remote.PathMap;
import org.netbeans.modules.cnd.api.remote.RemoteFileUtil;
import org.netbeans.modules.cnd.api.remote.RemoteSyncSupport;
+import org.netbeans.modules.cnd.execution.api.Connection;
import org.netbeans.modules.cnd.makeproject.MakeOptions;
import org.netbeans.modules.cnd.makeproject.api.BuildActionsProvider.BuildAction;
import org.netbeans.modules.cnd.makeproject.api.BuildActionsProvider.OutputStreamHandler;
@@ -92,6 +94,7 @@
import org.netbeans.modules.cnd.utils.CndUtils;
import org.netbeans.modules.cnd.utils.cache.CndFileUtils;
import org.netbeans.modules.dlight.api.terminal.TerminalSupport;
+import org.netbeans.modules.execmerge.ConnectionUtils;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
import org.netbeans.modules.nativeexecution.api.ExecutionListener;
import org.netbeans.modules.nativeexecution.api.execution.IOTabsController;
@@ -881,7 +884,9 @@
}
}
}
- TerminalSupport.openTerminal(getString("TargetExecutor.TermAction.tabTitle", projectName, env.getDisplayName()), env, dir); // NOI18N
+
+ TerminalSupport.openTerminal(getString("TargetExecutor.TermAction.tabTitle", projectName, env.getDisplayName()),
+ ConnectionUtils.ExecutionEnvironment2Connection(env), dir); // NOI18N
break;
}
}
diff --git a/cnd.remote.projectui/nbproject/project.xml b/cnd.remote.projectui/nbproject/project.xml
--- a/cnd.remote.projectui/nbproject/project.xml
+++ b/cnd.remote.projectui/nbproject/project.xml
@@ -67,6 +67,14 @@
+ org.netbeans.modules.cnd.execution
+
+
+
+ 1.0
+
+
+ org.netbeans.modules.cnd.makeproject
diff --git a/cnd.remote/nbproject/project.xml b/cnd.remote/nbproject/project.xml
--- a/cnd.remote/nbproject/project.xml
+++ b/cnd.remote/nbproject/project.xml
@@ -69,6 +69,14 @@
+ org.netbeans.modules.cnd.execution
+
+
+
+ 1.0
+
+
+ org.netbeans.modules.cnd.makeproject
@@ -126,6 +134,14 @@
+ org.netbeans.modules.execmerge
+
+
+
+ 1.0
+
+
+ org.netbeans.modules.extexecution
diff --git a/cnd.remote/src/org/netbeans/modules/remote/ui/OpenTerminalAction.java b/cnd.remote/src/org/netbeans/modules/remote/ui/OpenTerminalAction.java
--- a/cnd.remote/src/org/netbeans/modules/remote/ui/OpenTerminalAction.java
+++ b/cnd.remote/src/org/netbeans/modules/remote/ui/OpenTerminalAction.java
@@ -39,7 +39,6 @@
*
* Portions Copyrighted 2011 Sun Microsystems, Inc.
*/
-
package org.netbeans.modules.remote.ui;
import java.io.IOException;
@@ -48,6 +47,7 @@
import javax.swing.SwingUtilities;
import org.netbeans.modules.cnd.remote.mapper.RemotePathMap;
import org.netbeans.modules.dlight.api.terminal.TerminalSupport;
+import org.netbeans.modules.execmerge.ConnectionUtils;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
import org.netbeans.modules.nativeexecution.api.HostInfo;
import org.netbeans.modules.nativeexecution.api.util.ConnectionManager;
@@ -70,9 +70,10 @@
* @author Vladimir Voskresensky
*/
@ActionID(id = "org.netbeans.modules.remote.ui.OpenTerminalAction", category = "NativeRemote")
-@ActionRegistration(displayName = "OpenTerminalMenuItem")
+@ActionRegistration(displayName = "OpenTerminalMenuItem", lazy = false)
@ActionReference(path = "Remote/Host/Actions", name = "OpenTerminalAction", position = 700)
public class OpenTerminalAction extends SingleHostAction {
+
private JMenu remotePopupMenu;
private JMenuItem localPopupMenu;
@@ -88,7 +89,7 @@
Node[] activatedNodes = getActivatedNodes();
if (activatedNodes != null && activatedNodes.length == 1 && !isRemote(activatedNodes[0])) {
SystemAction.get(AddHome.class).performAction(env, node);
- }
+ }
}
@Override
@@ -175,7 +176,7 @@
@Override
public void run() {
- TerminalSupport.openTerminal(env.getDisplayName(), env, path);
+ TerminalSupport.openTerminal(env.getDisplayName(), ConnectionUtils.ExecutionEnvironment2Connection(env), path);
}
};
@@ -235,7 +236,6 @@
}
return null;
}
-
private static final class AddMirror extends AddPlace {
@@ -249,5 +249,4 @@
return remoteSyncRoot;
}
}
-
}
diff --git a/cnd.search/nbproject/project.xml b/cnd.search/nbproject/project.xml
--- a/cnd.search/nbproject/project.xml
+++ b/cnd.search/nbproject/project.xml
@@ -14,11 +14,19 @@
+ org.netbeans.modules.cnd.execution
+
+
+
+ 1.0
+
+
+ org.netbeans.modules.dlight.nativeexecution
- 1.14
+ 1.21
@@ -35,7 +43,7 @@
2
- 1.30
+ 1.37
diff --git a/cnd.search/src/org/netbeans/modules/cnd/search/SearchResult.java b/cnd.search/src/org/netbeans/modules/cnd/search/SearchResult.java
--- a/cnd.search/src/org/netbeans/modules/cnd/search/SearchResult.java
+++ b/cnd.search/src/org/netbeans/modules/cnd/search/SearchResult.java
@@ -41,7 +41,7 @@
*/
package org.netbeans.modules.cnd.search;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
+import org.netbeans.modules.cnd.execution.api.Connection;
import org.netbeans.modules.remote.spi.FileSystemProvider;
import org.openide.filesystems.FileObject;
@@ -51,11 +51,11 @@
*/
public final class SearchResult {
- public final ExecutionEnvironment env;
+ public final Connection connection;
public final MatchingFileData data;
- public SearchResult(ExecutionEnvironment env, MatchingFileData matchingFile) {
- this.env = env;
+ public SearchResult(Connection connection, MatchingFileData matchingFile) {
+ this.connection = connection;
this.data = matchingFile;
}
@@ -64,6 +64,6 @@
return null;
}
- return FileSystemProvider.getFileObject(env, data.getPath());
+ return FileSystemProvider.getFileObject(connection, data.getPath());
}
}
diff --git a/cnd.search/src/org/netbeans/modules/cnd/search/impl/SearchBrowseHostScope.java b/cnd.search/src/org/netbeans/modules/cnd/search/impl/SearchBrowseHostScope.java
--- a/cnd.search/src/org/netbeans/modules/cnd/search/impl/SearchBrowseHostScope.java
+++ b/cnd.search/src/org/netbeans/modules/cnd/search/impl/SearchBrowseHostScope.java
@@ -41,6 +41,7 @@
*/
package org.netbeans.modules.cnd.search.impl;
+import java.net.URI;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -50,8 +51,7 @@
import org.netbeans.api.search.provider.SearchInfoUtils;
import org.netbeans.api.search.provider.SearchListener;
import org.netbeans.modules.cnd.search.ui.DirectoryChooser;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
-import org.netbeans.modules.nativeexecution.api.util.ConnectionManager;
+import org.netbeans.modules.cnd.execution.api.ConnectionManager;
import org.netbeans.modules.remote.spi.FileSystemProvider;
import org.netbeans.spi.search.SearchInfoDefinition;
import org.netbeans.spi.search.SearchScopeDefinition;
@@ -64,144 +64,144 @@
* @author akrasny
*/
public final class SearchBrowseHostScope {
-
- private static FileObject root;
- private final ExecutionEnvironment env;
- private SearchScopeDefinition browseScope = new BrowseHostScopeDefinition();
- private SearchScopeDefinition lastScope = new LastSearchBrowseHostScope();
-
- public SearchBrowseHostScope(ExecutionEnvironment env) {
- this.env = env;
- }
-
- final class BrowseHostScopeDefinition extends SearchScopeDefinition {
-
- private final SearchInfo searchInfo;
-
- public BrowseHostScopeDefinition() {
- searchInfo = SearchInfoUtils.createForDefinition(new BrowseHostInfoDefinition());
- }
-
- @Override
- public String getTypeId() {
- return SearchBrowseHostScope.class.getName();
- }
-
- @Override
- public String getDisplayName() {
- return NbBundle.getMessage(SearchBrowseHostScope.class, "LBL_BrowseHostScopeDefinitionName", env.getDisplayName()); // NOI18N
- }
-
- @Override
- public boolean isApplicable() {
- return ConnectionManager.getInstance().isConnectedTo(env);
- }
-
- @Override
- public SearchInfo getSearchInfo() {
- return searchInfo;
- }
-
- @Override
- public int getPriority() {
- return 701;
- }
-
- @Override
- public void clean() {
- }
-
- @Override
- public void selected() {
- chooseRoots();
- notifyListeners();
- }
-
- private FileObject[] chooseRoots() {
- FileObject dir = DirectoryChooser.chooseDirectory(WindowManager.getDefault().getMainWindow(), env, null);
- if (dir != null) {
- root = dir;
- return new FileObject[]{root};
- }
- return new FileObject[0];
- }
-
- private class BrowseHostInfoDefinition extends SearchInfoDefinition {
-
- private SearchInfo delegate;
-
- @Override
- public boolean canSearch() {
- return true;
- }
-
- @Override
- public Iterator filesToSearch(SearchScopeOptions options, SearchListener listener, AtomicBoolean terminated) {
- return getDelegate().getFilesToSearch(options, listener, terminated).iterator();
- }
-
- @Override
- public List getSearchRoots() {
- return getDelegate().getSearchRoots();
- }
-
- private synchronized SearchInfo getDelegate() {
- if (delegate == null) {
- delegate = createDelegate();
- }
- return delegate;
- }
-
- private SearchInfo createDelegate() {
- FileObject[] fileObjects = chooseRoots();
- return SearchInfoUtils.createSearchInfoForRoots(fileObjects);
- }
- }
- }
-
- private class LastSearchBrowseHostScope extends SearchScopeDefinition {
-
- @Override
- public String getTypeId() {
- return SearchBrowseHostScope.class.getName();
- }
-
- @Override
- public String getDisplayName() {
- if (root != null) {
- return NbBundle.getMessage(SearchBrowseHostScope.class, "LBL_BrowseHostScopeBrowseName", // NOI18N
- root.getNameExt(),
- FileSystemProvider.getExecutionEnvironment(root).getDisplayName());
- } else {
- return NbBundle.getMessage(SearchBrowseHostScope.class, "LBL_NoSelection"); // NOI18N
- }
- }
-
- @Override
- public boolean isApplicable() {
- return root != null;
- }
-
- @Override
- public SearchInfo getSearchInfo() {
- return SearchInfoUtils.createSearchInfoForRoots(new FileObject[]{root});
- }
-
- @Override
- public int getPriority() {
- return 700;
- }
-
- @Override
- public void clean() {
- }
- }
-
- public SearchScopeDefinition getBrowseScope() {
- return browseScope;
- }
-
- public SearchScopeDefinition getLastScope() {
- return lastScope;
- }
+//
+// private static FileObject root;
+// private final URI uri;
+// private SearchScopeDefinition browseScope = new BrowseHostScopeDefinition();
+// private SearchScopeDefinition lastScope = new LastSearchBrowseHostScope();
+//
+// public SearchBrowseHostScope(URI uri) {
+// this.uri = uri;
+// }
+//
+// final class BrowseHostScopeDefinition extends SearchScopeDefinition {
+//
+// private final SearchInfo searchInfo;
+//
+// public BrowseHostScopeDefinition() {
+// searchInfo = SearchInfoUtils.createForDefinition(new BrowseHostInfoDefinition());
+// }
+//
+// @Override
+// public String getTypeId() {
+// return SearchBrowseHostScope.class.getName();
+// }
+//
+// @Override
+// public String getDisplayName() {
+// return NbBundle.getMessage(SearchBrowseHostScope.class, "LBL_BrowseHostScopeDefinitionName", uri); // NOI18N
+// }
+//
+// @Override
+// public boolean isApplicable() {
+// return ConnectionManager.getConnection(uri) != null;
+// }
+//
+// @Override
+// public SearchInfo getSearchInfo() {
+// return searchInfo;
+// }
+//
+// @Override
+// public int getPriority() {
+// return 701;
+// }
+//
+// @Override
+// public void clean() {
+// }
+//
+// @Override
+// public void selected() {
+// chooseRoots();
+// notifyListeners();
+// }
+//
+// private FileObject[] chooseRoots() {
+// FileObject dir = DirectoryChooser.chooseDirectory(WindowManager.getDefault().getMainWindow(), uri, null);
+// if (dir != null) {
+// root = dir;
+// return new FileObject[]{root};
+// }
+// return new FileObject[0];
+// }
+//
+// private class BrowseHostInfoDefinition extends SearchInfoDefinition {
+//
+// private SearchInfo delegate;
+//
+// @Override
+// public boolean canSearch() {
+// return true;
+// }
+//
+// @Override
+// public Iterator filesToSearch(SearchScopeOptions options, SearchListener listener, AtomicBoolean terminated) {
+// return getDelegate().getFilesToSearch(options, listener, terminated).iterator();
+// }
+//
+// @Override
+// public List getSearchRoots() {
+// return getDelegate().getSearchRoots();
+// }
+//
+// private synchronized SearchInfo getDelegate() {
+// if (delegate == null) {
+// delegate = createDelegate();
+// }
+// return delegate;
+// }
+//
+// private SearchInfo createDelegate() {
+// FileObject[] fileObjects = chooseRoots();
+// return SearchInfoUtils.createSearchInfoForRoots(fileObjects);
+// }
+// }
+// }
+//
+// private class LastSearchBrowseHostScope extends SearchScopeDefinition {
+//
+// @Override
+// public String getTypeId() {
+// return SearchBrowseHostScope.class.getName();
+// }
+//
+// @Override
+// public String getDisplayName() {
+// if (root != null) {
+// return NbBundle.getMessage(SearchBrowseHostScope.class, "LBL_BrowseHostScopeBrowseName", // NOI18N
+// root.getNameExt(),
+// FileSystemProvider.getExecutionEnvironment(root).getDisplayName());
+// } else {
+// return NbBundle.getMessage(SearchBrowseHostScope.class, "LBL_NoSelection"); // NOI18N
+// }
+// }
+//
+// @Override
+// public boolean isApplicable() {
+// return root != null;
+// }
+//
+// @Override
+// public SearchInfo getSearchInfo() {
+// return SearchInfoUtils.createSearchInfoForRoots(new FileObject[]{root});
+// }
+//
+// @Override
+// public int getPriority() {
+// return 700;
+// }
+//
+// @Override
+// public void clean() {
+// }
+// }
+//
+// public SearchScopeDefinition getBrowseScope() {
+// return browseScope;
+// }
+//
+// public SearchScopeDefinition getLastScope() {
+// return lastScope;
+// }
}
diff --git a/cnd.search/src/org/netbeans/modules/cnd/search/impl/spi/CNDSearchComposition.java b/cnd.search/src/org/netbeans/modules/cnd/search/impl/spi/CNDSearchComposition.java
--- a/cnd.search/src/org/netbeans/modules/cnd/search/impl/spi/CNDSearchComposition.java
+++ b/cnd.search/src/org/netbeans/modules/cnd/search/impl/spi/CNDSearchComposition.java
@@ -41,9 +41,13 @@
*/
package org.netbeans.modules.cnd.search.impl.spi;
-import java.io.BufferedReader;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.netbeans.api.extexecution.ExecutionService;
+import org.netbeans.api.extexecution.input.LineProcessor;
import org.netbeans.api.search.SearchRoot;
import org.netbeans.api.search.provider.SearchListener;
import org.netbeans.modules.cnd.search.MatchingFileData;
@@ -54,12 +58,8 @@
import org.netbeans.modules.cnd.search.ui.SearchResultNode;
import org.netbeans.modules.cnd.search.ui.SearchResultPropertySet;
import org.netbeans.modules.cnd.search.util.OutlineSupport;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
-import org.netbeans.modules.nativeexecution.api.NativeProcess;
-import org.netbeans.modules.nativeexecution.api.NativeProcessBuilder;
-import org.netbeans.modules.nativeexecution.api.util.ConnectionManager;
-import org.netbeans.modules.nativeexecution.api.util.HostInfoUtils;
-import org.netbeans.modules.nativeexecution.api.util.ProcessUtils;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.util.HostInfo;
import org.netbeans.modules.remote.spi.FileSystemProvider;
import org.netbeans.spi.search.provider.DefaultSearchResultsDisplayer;
import org.netbeans.spi.search.provider.SearchComposition;
@@ -69,9 +69,7 @@
import org.netbeans.spi.search.provider.SearchResultsDisplayer.NodeDisplayer;
import org.openide.explorer.view.OutlineView;
import org.openide.nodes.Node;
-import org.openide.util.Cancellable;
-import org.openide.util.RequestProcessor;
-import org.openide.util.RequestProcessor.Task;
+import org.openide.util.Exceptions;
/**
*
@@ -79,13 +77,12 @@
*/
public final class CNDSearchComposition extends SearchComposition {
- private static final RequestProcessor RP = new RequestProcessor(CNDSearchComposition.class.getName(), 2);
private final AtomicBoolean terminated = new AtomicBoolean(false);
private final SearchParams params;
private DefaultSearchResultsDisplayer displayer;
private final String title;
private final Presenter presenter;
- private Cancellable cancel;
+ private Future> task;
public CNDSearchComposition(String title, SearchProvider.Presenter presenter, SearchParams params) {
this.title = title;
@@ -109,9 +106,9 @@
@Override
public void terminate() {
if (terminated.compareAndSet(false, true)) {
- if (cancel != null) {
- cancel.cancel();
- cancel = null;
+ if (task != null) {
+ task.cancel(true);
+ task = null;
}
}
}
@@ -134,102 +131,75 @@
}
private void searchInRoot(SearchRoot root, final SearchListener listener) {
- if (isTerminated()) {
- return;
- }
-
- final ExecutionEnvironment env = FileSystemProvider.getExecutionEnvironment(root.getFileObject());
-
- if (!ConnectionManager.getInstance().isConnectedTo(env)) {
- return;
- }
-
- if (env.isRemote() && HostInfoUtils.isHostInfoAvailable(env)) {
+ final Connection connection = FileSystemProvider.getConnection(root.getFileObject());
+ if (!connection.isConnected()) {
return;
}
final Searcher find;
- try {
- if (HostInfoUtils.getHostInfo(env).getOSFamily().isUnix()) {
- find = new UnixFindBasedSearcher(root, params);
- } else {
- find = null;
- }
- } catch (Exception ex) {
- return;
+
+ if (HostInfo.getFor(connection).isUnix()) {
+ find = new UnixFindBasedSearcher(root, params);
+ } else {
+ find = null;
}
if (find == null) {
return;
}
- NativeProcessBuilder npb = NativeProcessBuilder.newProcessBuilder(env);
- npb.setExecutable(find.getCommand()).setArguments(find.getCommandArguments());
+ try {
+ final org.netbeans.api.extexecution.ProcessBuilder npb = connection.getProcessBuilder();
+ npb.setExecutable(find.getCommand());
+ npb.setArguments(Arrays.asList(find.getCommandArguments()));
+ task = ExecutionService.newService(npb, new LineProcessor() {
+ @Override
+ public void processLine(String line) {
+ if (isTerminated()) {
+ task.cancel(true);
+ }
+
+ MatchingFileData data = find.processOutputLine(line.toString().trim());
+
+ if (data != null) {
+ displayer.addMatchingObject(new SearchResult(connection, data));
+ }
+ }
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void close() {
+ }
+ }, new LineProcessor() {
+ @Override
+ public void processLine(String line) {
+ if (isTerminated()) {
+ task.cancel(true);
+ }
+
+ Throwable ex = new Throwable(line.toString());
+ listener.generalError(ex);
+ }
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void close() {
+ }
+ }, null).run();
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
try {
- final NativeProcess process = npb.call();
- final Runnable readOutputTask = new Runnable() {
-
- @Override
- public void run() {
- try {
- BufferedReader br = ProcessUtils.getReader(process.getInputStream(), env.isRemote());
- String line;
- while (!isTerminated() && (line = br.readLine()) != null) {
- MatchingFileData data = find.processOutputLine(line.trim());
-
- if (data != null) {
- displayer.addMatchingObject(new SearchResult(env, data));
- }
- }
- } catch (IOException ex) {
- if (!isTerminated()) {
- listener.generalError(ex);
- }
- }
- }
- };
-
- final Runnable readErrorTask = new Runnable() {
-
- @Override
- public void run() {
- try {
- BufferedReader br = ProcessUtils.getReader(process.getErrorStream(), env.isRemote());
- String line;
- while (!isTerminated() && (line = br.readLine()) != null) {
- Throwable ex = new Throwable(line);
- listener.generalError(ex);
- }
- } catch (IOException ex) {
- if (!isTerminated()) {
- listener.generalError(ex);
- }
- }
- }
- };
-
- final Task outTask = RP.post(readOutputTask);
- final Task errTask = RP.post(readErrorTask);
-
- cancel = new Cancellable() {
-
- @Override
- public boolean cancel() {
- process.destroy();
- outTask.cancel();
- errTask.cancel();
- outTask.waitFinished();
- errTask.waitFinished();
- return true;
- }
- };
-
- process.waitFor();
+ task.get();
} catch (InterruptedException ex) {
- // Exceptions.printStackTrace(ex);
- } catch (IOException ex) {
- listener.generalError(ex);
+ Exceptions.printStackTrace(ex);
+ } catch (ExecutionException ex) {
+ Exceptions.printStackTrace(ex);
}
}
diff --git a/cnd.search/src/org/netbeans/modules/cnd/search/ui/CNDSearchPanel.java b/cnd.search/src/org/netbeans/modules/cnd/search/ui/CNDSearchPanel.java
--- a/cnd.search/src/org/netbeans/modules/cnd/search/ui/CNDSearchPanel.java
+++ b/cnd.search/src/org/netbeans/modules/cnd/search/ui/CNDSearchPanel.java
@@ -55,9 +55,6 @@
import org.netbeans.api.search.ui.FileNameController;
import org.netbeans.api.search.ui.ScopeController;
import org.netbeans.api.search.ui.SearchPatternController;
-import org.netbeans.modules.cnd.search.impl.SearchBrowseHostScope;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
-import org.netbeans.modules.nativeexecution.api.util.ConnectionManager;
import org.netbeans.spi.search.SearchScopeDefinition;
import org.openide.util.ChangeSupport;
import org.openide.util.NbBundle;
@@ -222,13 +219,14 @@
private SearchScopeDefinition[] getAdditionalSearchScopes() {
List result = new ArrayList();
- List recentConnections = ConnectionManager.getInstance().getRecentConnections();
-
- for (ExecutionEnvironment env : recentConnections) {
- SearchBrowseHostScope scope = new SearchBrowseHostScope(env);
- result.add(scope.getBrowseScope());
- result.add(scope.getLastScope());
- }
+// ConnectionManager.
+// List recentConnections = ConnectionManager.getInstance().getRecentConnections();
+//
+// for (ExecutionEnvironment env : recentConnections) {
+// SearchBrowseHostScope scope = new SearchBrowseHostScope(env);
+// result.add(scope.getBrowseScope());
+// result.add(scope.getLastScope());
+// }
return result.toArray(new SearchScopeDefinition[result.size()]);
}
diff --git a/cnd.search/src/org/netbeans/modules/cnd/search/ui/DirectoryChooser.java b/cnd.search/src/org/netbeans/modules/cnd/search/ui/DirectoryChooser.java
--- a/cnd.search/src/org/netbeans/modules/cnd/search/ui/DirectoryChooser.java
+++ b/cnd.search/src/org/netbeans/modules/cnd/search/ui/DirectoryChooser.java
@@ -50,7 +50,7 @@
import java.io.File;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
+import org.netbeans.modules.cnd.execution.api.Connection;
import org.netbeans.modules.remote.api.ui.FileChooserBuilder;
import org.netbeans.modules.remote.spi.FileSystemProvider;
import org.openide.DialogDescriptor;
@@ -71,12 +71,12 @@
private FileObject validatedFileObject = null;
private Dialog dialog;
- public static FileObject chooseDirectory(Frame window, ExecutionEnvironment env, String initPath) {
- DirectoryChooser chooser = new DirectoryChooser(env, initPath);
+ public static FileObject chooseDirectory(Frame window, Connection connection, String initPath) {
+ DirectoryChooser chooser = new DirectoryChooser(connection, initPath);
boolean cancelled = false;
DialogDescriptor dd = new DialogDescriptor(chooser,
- NbBundle.getMessage(DirectoryChooser.class, "DirectoryChooser.title", env.getDisplayName()), // NOI18N
+ NbBundle.getMessage(DirectoryChooser.class, "DirectoryChooser.title", connection.toString()), // NOI18N
true,
new Object[]{chooser.selectButton, DialogDescriptor.CANCEL_OPTION},
chooser.selectButton, DialogDescriptor.DEFAULT_ALIGN, null, null, true);
@@ -96,11 +96,11 @@
/**
* Creates new form SearchRootChooser
*/
- private DirectoryChooser(ExecutionEnvironment env, String path) {
+ private DirectoryChooser(Connection connection, String path) {
initComponents();
selectButton = new JButton();
Mnemonics.setLocalizedText(selectButton, NbBundle.getMessage(DirectoryChooser.class, "DirectoryChooser.ok_button.text")); // NOI18N
- FileChooserBuilder fcBuilder = new FileChooserBuilder(env);
+ FileChooserBuilder fcBuilder = new FileChooserBuilder(connection);
chooser = fcBuilder.createFileChooser();
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
diff --git a/cnd.search/src/org/netbeans/modules/cnd/search/ui/SearchResultNode.java b/cnd.search/src/org/netbeans/modules/cnd/search/ui/SearchResultNode.java
--- a/cnd.search/src/org/netbeans/modules/cnd/search/ui/SearchResultNode.java
+++ b/cnd.search/src/org/netbeans/modules/cnd/search/ui/SearchResultNode.java
@@ -97,8 +97,8 @@
public Image getIcon(int type) {
Object dobRefProp = getValue(DOB_REF_PROP);
if (dobRefProp instanceof WeakReference) {
- WeakReference dobRef = (WeakReference)dobRefProp;
- DataObject dob = dobRef.get();
+ WeakReference> dobRef = (WeakReference>)dobRefProp;
+ DataObject dob = (DataObject) dobRef.get();
if (dob != null) {
return dob.getNodeDelegate().getIcon(type);
}
diff --git a/cnd.toolchain/nbproject/project.xml b/cnd.toolchain/nbproject/project.xml
--- a/cnd.toolchain/nbproject/project.xml
+++ b/cnd.toolchain/nbproject/project.xml
@@ -91,6 +91,14 @@
+ org.netbeans.modules.cnd.execution
+
+
+
+ 1.0
+
+
+ org.netbeans.modules.options.api
diff --git a/dlight.nativeexecution/external/binaries-list b/dlight.nativeexecution/external/binaries-list
--- a/dlight.nativeexecution/external/binaries-list
+++ b/dlight.nativeexecution/external/binaries-list
@@ -1,2 +1,2 @@
-886018BFD299115709FB351D28D9C1F5A2C6F5FD exechlp-1.0.zip
+7AA7A8C9DA31FCB920B0613EC8C49229801FB6C6 exechlp-1.1.zip
diff --git a/dlight.nativeexecution/external/exechlp-1.0-license.txt b/dlight.nativeexecution/external/exechlp-1.0-license.txt
deleted file mode 100644
--- a/dlight.nativeexecution/external/exechlp-1.0-license.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-Name: exechlp
-Version: 1.0
-Description: binaries that used by dlight.nativeexecution module
-License: TBD
-OSR: -
-Origin: -
-Files: exechlp-1.0.zip contains killall process_start pty pty_open sigqueue stat unbuffer.so for different platforms
-Source: -
-Comment: needed for dlight.nativeexecution module to provide system-dependent services
-
-process_start, pty, pty_open - used for dealing with pseude terminals
-sigqueue, killall - sending signals to processes
-stat - getting detailed file information
-unbuffer.so - used when unbuffering is required
-
-Use of exechlp version 1.0 is governed by the terms of the license below:
-
-TBD
-
diff --git a/dlight.nativeexecution/external/exechlp-1.1-license.txt b/dlight.nativeexecution/external/exechlp-1.1-license.txt
new file mode 100644
--- /dev/null
+++ b/dlight.nativeexecution/external/exechlp-1.1-license.txt
@@ -0,0 +1,19 @@
+Name: exechlp
+Version: 1.1
+Description: binaries that used by dlight.nativeexecution module
+License: TBD
+OSR: -
+Origin: -
+Files: exechlp-1.1.zip contains killall process_start pty pty_open sigqueue stat unbuffer.so for different platforms
+Source: -
+Comment: needed for dlight.nativeexecution module to provide system-dependent services
+
+process_start, pty, pty_open - used for dealing with pseude terminals
+sigqueue, killall - sending signals to processes
+stat - getting detailed file information
+unbuffer.so - used when unbuffering is required
+
+Use of exechlp version 1.1 is governed by the terms of the license below:
+
+TBD
+
diff --git a/dlight.nativeexecution/nbproject/project.properties b/dlight.nativeexecution/nbproject/project.properties
--- a/dlight.nativeexecution/nbproject/project.properties
+++ b/dlight.nativeexecution/nbproject/project.properties
@@ -21,72 +21,72 @@
**/RegisterDerbyTest.class,\
**/TerminalConfigurationProviderTest.class
-release.external/exechlp-1.0.zip!/Linux-x86/process_start = bin/nativeexecution/Linux-x86/process_start
-release.external/exechlp-1.0.zip!/Linux-x86/pty = bin/nativeexecution/Linux-x86/pty
-release.external/exechlp-1.0.zip!/Linux-x86/pty_open = bin/nativeexecution/Linux-x86/pty_open
-release.external/exechlp-1.0.zip!/Linux-x86/sigqueue = bin/nativeexecution/Linux-x86/sigqueue
-release.external/exechlp-1.0.zip!/Linux-x86/stat = bin/nativeexecution/Linux-x86/stat
-release.external/exechlp-1.0.zip!/Linux-x86/unbuffer.so = bin/nativeexecution/Linux-x86/unbuffer.so
-release.external/exechlp-1.0.zip!/Linux-x86/killall = bin/nativeexecution/Linux-x86/killall
-release.external/exechlp-1.0.zip!/Linux-x86_64/process_start = bin/nativeexecution/Linux-x86_64/process_start
-release.external/exechlp-1.0.zip!/Linux-x86_64/pty = bin/nativeexecution/Linux-x86_64/pty
-release.external/exechlp-1.0.zip!/Linux-x86_64/pty_open = bin/nativeexecution/Linux-x86_64/pty_open
-release.external/exechlp-1.0.zip!/Linux-x86_64/sigqueue = bin/nativeexecution/Linux-x86_64/sigqueue
-release.external/exechlp-1.0.zip!/Linux-x86_64/stat = bin/nativeexecution/Linux-x86_64/stat
-release.external/exechlp-1.0.zip!/Linux-x86_64/unbuffer.so = bin/nativeexecution/Linux-x86_64/unbuffer.so
-release.external/exechlp-1.0.zip!/Linux-x86_64/killall = bin/nativeexecution/Linux-x86_64/killall
-release.external/exechlp-1.0.zip!/Windows-x86/process_start = bin/nativeexecution/Windows-x86/process_start
-release.external/exechlp-1.0.zip!/Windows-x86/pty = bin/nativeexecution/Windows-x86/pty
-release.external/exechlp-1.0.zip!/Windows-x86/pty_open = bin/nativeexecution/Windows-x86/pty_open
-release.external/exechlp-1.0.zip!/Windows-x86/sigqueue = bin/nativeexecution/Windows-x86/sigqueue
-release.external/exechlp-1.0.zip!/Windows-x86/unbuffer.dll = bin/nativeexecution/Windows-x86/unbuffer.dll
-release.external/exechlp-1.0.zip!/Windows-x86/killall = bin/nativeexecution/Windows-x86/killall
-release.external/exechlp-1.0.zip!/Windows-x86_64/process_start = bin/nativeexecution/Windows-x86_64/process_start
-release.external/exechlp-1.0.zip!/Windows-x86_64/pty = bin/nativeexecution/Windows-x86_64/pty
-release.external/exechlp-1.0.zip!/Windows-x86_64/pty_open = bin/nativeexecution/Windows-x86_64/pty_open
-release.external/exechlp-1.0.zip!/Windows-x86_64/sigqueue = bin/nativeexecution/Windows-x86_64/sigqueue
-release.external/exechlp-1.0.zip!/Windows-x86_64/killall = bin/nativeexecution/Windows-x86_64/killall
-release.external/exechlp-1.0.zip!/MacOSX-x86/process_start = bin/nativeexecution/MacOSX-x86/process_start
-release.external/exechlp-1.0.zip!/MacOSX-x86/pty = bin/nativeexecution/MacOSX-x86/pty
-release.external/exechlp-1.0.zip!/MacOSX-x86/pty_open = bin/nativeexecution/MacOSX-x86/pty_open
-release.external/exechlp-1.0.zip!/MacOSX-x86/stat = bin/nativeexecution/MacOSX-x86/stat
-release.external/exechlp-1.0.zip!/MacOSX-x86/unbuffer.dylib = bin/nativeexecution/MacOSX-x86/unbuffer.dylib
-release.external/exechlp-1.0.zip!/MacOSX-x86/killall = bin/nativeexecution/MacOSX-x86/killall
-release.external/exechlp-1.0.zip!/MacOSX-x86_64/process_start = bin/nativeexecution/MacOSX-x86_64/process_start
-release.external/exechlp-1.0.zip!/MacOSX-x86_64/pty = bin/nativeexecution/MacOSX-x86_64/pty
-release.external/exechlp-1.0.zip!/MacOSX-x86_64/pty_open = bin/nativeexecution/MacOSX-x86_64/pty_open
-release.external/exechlp-1.0.zip!/MacOSX-x86_64/stat = bin/nativeexecution/MacOSX-x86_64/stat
-release.external/exechlp-1.0.zip!/MacOSX-x86_64/unbuffer.dylib = bin/nativeexecution/MacOSX-x86_64/unbuffer.dylib
-release.external/exechlp-1.0.zip!/MacOSX-x86_64/killall = bin/nativeexecution/MacOSX-x86_64/killall
-release.external/exechlp-1.0.zip!/SunOS-sparc/privp = bin/nativeexecution/SunOS-sparc/privp
-release.external/exechlp-1.0.zip!/SunOS-sparc/process_start = bin/nativeexecution/SunOS-sparc/process_start
-release.external/exechlp-1.0.zip!/SunOS-sparc/pty = bin/nativeexecution/SunOS-sparc/pty
-release.external/exechlp-1.0.zip!/SunOS-sparc/pty_open = bin/nativeexecution/SunOS-sparc/pty_open
-release.external/exechlp-1.0.zip!/SunOS-sparc/sigqueue = bin/nativeexecution/SunOS-sparc/sigqueue
-release.external/exechlp-1.0.zip!/SunOS-sparc/stat = bin/nativeexecution/SunOS-sparc/stat
-release.external/exechlp-1.0.zip!/SunOS-sparc/unbuffer.so = bin/nativeexecution/SunOS-sparc/unbuffer.so
-release.external/exechlp-1.0.zip!/SunOS-sparc/killall = bin/nativeexecution/SunOS-sparc/killall
-release.external/exechlp-1.0.zip!/SunOS-sparc_64/privp = bin/nativeexecution/SunOS-sparc_64/privp
-release.external/exechlp-1.0.zip!/SunOS-sparc_64/process_start = bin/nativeexecution/SunOS-sparc_64/process_start
-release.external/exechlp-1.0.zip!/SunOS-sparc_64/pty = bin/nativeexecution/SunOS-sparc_64/pty
-release.external/exechlp-1.0.zip!/SunOS-sparc_64/pty_open = bin/nativeexecution/SunOS-sparc_64/pty_open
-release.external/exechlp-1.0.zip!/SunOS-sparc_64/sigqueue = bin/nativeexecution/SunOS-sparc_64/sigqueue
-release.external/exechlp-1.0.zip!/SunOS-sparc_64/stat = bin/nativeexecution/SunOS-sparc_64/stat
-release.external/exechlp-1.0.zip!/SunOS-sparc_64/unbuffer.so = bin/nativeexecution/SunOS-sparc_64/unbuffer.so
-release.external/exechlp-1.0.zip!/SunOS-sparc_64/killall = bin/nativeexecution/SunOS-sparc_64/killall
-release.external/exechlp-1.0.zip!/SunOS-x86/privp = bin/nativeexecution/SunOS-x86/privp
-release.external/exechlp-1.0.zip!/SunOS-x86/process_start = bin/nativeexecution/SunOS-x86/process_start
-release.external/exechlp-1.0.zip!/SunOS-x86/pty = bin/nativeexecution/SunOS-x86/pty
-release.external/exechlp-1.0.zip!/SunOS-x86/pty_open = bin/nativeexecution/SunOS-x86/pty_open
-release.external/exechlp-1.0.zip!/SunOS-x86/sigqueue = bin/nativeexecution/SunOS-x86/sigqueue
-release.external/exechlp-1.0.zip!/SunOS-x86/stat = bin/nativeexecution/SunOS-x86/stat
-release.external/exechlp-1.0.zip!/SunOS-x86/unbuffer.so = bin/nativeexecution/SunOS-x86/unbuffer.so
-release.external/exechlp-1.0.zip!/SunOS-x86/killall = bin/nativeexecution/SunOS-x86/killall
-release.external/exechlp-1.0.zip!/SunOS-x86_64/process_start = bin/nativeexecution/SunOS-x86_64/process_start
-release.external/exechlp-1.0.zip!/SunOS-x86_64/pty = bin/nativeexecution/SunOS-x86_64/pty
-release.external/exechlp-1.0.zip!/SunOS-x86_64/pty_open = bin/nativeexecution/SunOS-x86_64/pty_open
-release.external/exechlp-1.0.zip!/SunOS-x86_64/sigqueue = bin/nativeexecution/SunOS-x86_64/sigqueue
-release.external/exechlp-1.0.zip!/SunOS-x86_64/stat = bin/nativeexecution/SunOS-x86_64/stat
-release.external/exechlp-1.0.zip!/SunOS-x86_64/unbuffer.so = bin/nativeexecution/SunOS-x86_64/unbuffer.so
-release.external/exechlp-1.0.zip!/SunOS-x86_64/killall = bin/nativeexecution/SunOS-x86_64/killall
+release.external/exechlp-1.1.zip!/Linux-x86/process_start = bin/nativeexecution/Linux-x86/process_start
+release.external/exechlp-1.1.zip!/Linux-x86/pty = bin/nativeexecution/Linux-x86/pty
+release.external/exechlp-1.1.zip!/Linux-x86/pty_open = bin/nativeexecution/Linux-x86/pty_open
+release.external/exechlp-1.1.zip!/Linux-x86/sigqueue = bin/nativeexecution/Linux-x86/sigqueue
+release.external/exechlp-1.1.zip!/Linux-x86/stat = bin/nativeexecution/Linux-x86/stat
+release.external/exechlp-1.1.zip!/Linux-x86/unbuffer.so = bin/nativeexecution/Linux-x86/unbuffer.so
+release.external/exechlp-1.1.zip!/Linux-x86/killall = bin/nativeexecution/Linux-x86/killall
+release.external/exechlp-1.1.zip!/Linux-x86_64/process_start = bin/nativeexecution/Linux-x86_64/process_start
+release.external/exechlp-1.1.zip!/Linux-x86_64/pty = bin/nativeexecution/Linux-x86_64/pty
+release.external/exechlp-1.1.zip!/Linux-x86_64/pty_open = bin/nativeexecution/Linux-x86_64/pty_open
+release.external/exechlp-1.1.zip!/Linux-x86_64/sigqueue = bin/nativeexecution/Linux-x86_64/sigqueue
+release.external/exechlp-1.1.zip!/Linux-x86_64/stat = bin/nativeexecution/Linux-x86_64/stat
+release.external/exechlp-1.1.zip!/Linux-x86_64/unbuffer.so = bin/nativeexecution/Linux-x86_64/unbuffer.so
+release.external/exechlp-1.1.zip!/Linux-x86_64/killall = bin/nativeexecution/Linux-x86_64/killall
+release.external/exechlp-1.1.zip!/Windows-x86/process_start = bin/nativeexecution/Windows-x86/process_start
+release.external/exechlp-1.1.zip!/Windows-x86/pty = bin/nativeexecution/Windows-x86/pty
+release.external/exechlp-1.1.zip!/Windows-x86/pty_open = bin/nativeexecution/Windows-x86/pty_open
+release.external/exechlp-1.1.zip!/Windows-x86/sigqueue = bin/nativeexecution/Windows-x86/sigqueue
+release.external/exechlp-1.1.zip!/Windows-x86/unbuffer.dll = bin/nativeexecution/Windows-x86/unbuffer.dll
+release.external/exechlp-1.1.zip!/Windows-x86/killall = bin/nativeexecution/Windows-x86/killall
+release.external/exechlp-1.1.zip!/Windows-x86_64/process_start = bin/nativeexecution/Windows-x86_64/process_start
+release.external/exechlp-1.1.zip!/Windows-x86_64/pty = bin/nativeexecution/Windows-x86_64/pty
+release.external/exechlp-1.1.zip!/Windows-x86_64/pty_open = bin/nativeexecution/Windows-x86_64/pty_open
+release.external/exechlp-1.1.zip!/Windows-x86_64/sigqueue = bin/nativeexecution/Windows-x86_64/sigqueue
+release.external/exechlp-1.1.zip!/Windows-x86_64/killall = bin/nativeexecution/Windows-x86_64/killall
+release.external/exechlp-1.1.zip!/MacOSX-x86/process_start = bin/nativeexecution/MacOSX-x86/process_start
+release.external/exechlp-1.1.zip!/MacOSX-x86/pty = bin/nativeexecution/MacOSX-x86/pty
+release.external/exechlp-1.1.zip!/MacOSX-x86/pty_open = bin/nativeexecution/MacOSX-x86/pty_open
+release.external/exechlp-1.1.zip!/MacOSX-x86/stat = bin/nativeexecution/MacOSX-x86/stat
+release.external/exechlp-1.1.zip!/MacOSX-x86/unbuffer.dylib = bin/nativeexecution/MacOSX-x86/unbuffer.dylib
+release.external/exechlp-1.1.zip!/MacOSX-x86/killall = bin/nativeexecution/MacOSX-x86/killall
+release.external/exechlp-1.1.zip!/MacOSX-x86_64/process_start = bin/nativeexecution/MacOSX-x86_64/process_start
+release.external/exechlp-1.1.zip!/MacOSX-x86_64/pty = bin/nativeexecution/MacOSX-x86_64/pty
+release.external/exechlp-1.1.zip!/MacOSX-x86_64/pty_open = bin/nativeexecution/MacOSX-x86_64/pty_open
+release.external/exechlp-1.1.zip!/MacOSX-x86_64/stat = bin/nativeexecution/MacOSX-x86_64/stat
+release.external/exechlp-1.1.zip!/MacOSX-x86_64/unbuffer.dylib = bin/nativeexecution/MacOSX-x86_64/unbuffer.dylib
+release.external/exechlp-1.1.zip!/MacOSX-x86_64/killall = bin/nativeexecution/MacOSX-x86_64/killall
+release.external/exechlp-1.1.zip!/SunOS-sparc/privp = bin/nativeexecution/SunOS-sparc/privp
+release.external/exechlp-1.1.zip!/SunOS-sparc/process_start = bin/nativeexecution/SunOS-sparc/process_start
+release.external/exechlp-1.1.zip!/SunOS-sparc/pty = bin/nativeexecution/SunOS-sparc/pty
+release.external/exechlp-1.1.zip!/SunOS-sparc/pty_open = bin/nativeexecution/SunOS-sparc/pty_open
+release.external/exechlp-1.1.zip!/SunOS-sparc/sigqueue = bin/nativeexecution/SunOS-sparc/sigqueue
+release.external/exechlp-1.1.zip!/SunOS-sparc/stat = bin/nativeexecution/SunOS-sparc/stat
+release.external/exechlp-1.1.zip!/SunOS-sparc/unbuffer.so = bin/nativeexecution/SunOS-sparc/unbuffer.so
+release.external/exechlp-1.1.zip!/SunOS-sparc/killall = bin/nativeexecution/SunOS-sparc/killall
+release.external/exechlp-1.1.zip!/SunOS-sparc_64/privp = bin/nativeexecution/SunOS-sparc_64/privp
+release.external/exechlp-1.1.zip!/SunOS-sparc_64/process_start = bin/nativeexecution/SunOS-sparc_64/process_start
+release.external/exechlp-1.1.zip!/SunOS-sparc_64/pty = bin/nativeexecution/SunOS-sparc_64/pty
+release.external/exechlp-1.1.zip!/SunOS-sparc_64/pty_open = bin/nativeexecution/SunOS-sparc_64/pty_open
+release.external/exechlp-1.1.zip!/SunOS-sparc_64/sigqueue = bin/nativeexecution/SunOS-sparc_64/sigqueue
+release.external/exechlp-1.1.zip!/SunOS-sparc_64/stat = bin/nativeexecution/SunOS-sparc_64/stat
+release.external/exechlp-1.1.zip!/SunOS-sparc_64/unbuffer.so = bin/nativeexecution/SunOS-sparc_64/unbuffer.so
+release.external/exechlp-1.1.zip!/SunOS-sparc_64/killall = bin/nativeexecution/SunOS-sparc_64/killall
+release.external/exechlp-1.1.zip!/SunOS-x86/privp = bin/nativeexecution/SunOS-x86/privp
+release.external/exechlp-1.1.zip!/SunOS-x86/process_start = bin/nativeexecution/SunOS-x86/process_start
+release.external/exechlp-1.1.zip!/SunOS-x86/pty = bin/nativeexecution/SunOS-x86/pty
+release.external/exechlp-1.1.zip!/SunOS-x86/pty_open = bin/nativeexecution/SunOS-x86/pty_open
+release.external/exechlp-1.1.zip!/SunOS-x86/sigqueue = bin/nativeexecution/SunOS-x86/sigqueue
+release.external/exechlp-1.1.zip!/SunOS-x86/stat = bin/nativeexecution/SunOS-x86/stat
+release.external/exechlp-1.1.zip!/SunOS-x86/unbuffer.so = bin/nativeexecution/SunOS-x86/unbuffer.so
+release.external/exechlp-1.1.zip!/SunOS-x86/killall = bin/nativeexecution/SunOS-x86/killall
+release.external/exechlp-1.1.zip!/SunOS-x86_64/process_start = bin/nativeexecution/SunOS-x86_64/process_start
+release.external/exechlp-1.1.zip!/SunOS-x86_64/pty = bin/nativeexecution/SunOS-x86_64/pty
+release.external/exechlp-1.1.zip!/SunOS-x86_64/pty_open = bin/nativeexecution/SunOS-x86_64/pty_open
+release.external/exechlp-1.1.zip!/SunOS-x86_64/sigqueue = bin/nativeexecution/SunOS-x86_64/sigqueue
+release.external/exechlp-1.1.zip!/SunOS-x86_64/stat = bin/nativeexecution/SunOS-x86_64/stat
+release.external/exechlp-1.1.zip!/SunOS-x86_64/unbuffer.so = bin/nativeexecution/SunOS-x86_64/unbuffer.so
+release.external/exechlp-1.1.zip!/SunOS-x86_64/killall = bin/nativeexecution/SunOS-x86_64/killall
diff --git a/dlight.nativeexecution/nbproject/project.xml b/dlight.nativeexecution/nbproject/project.xml
--- a/dlight.nativeexecution/nbproject/project.xml
+++ b/dlight.nativeexecution/nbproject/project.xml
@@ -54,7 +54,7 @@
2
- 1.13
+ 1.37
@@ -276,6 +276,8 @@
org.netbeans.modules.dlight.uncoverorg.netbeans.modules.dlight.utilorg.netbeans.modules.dlight.webstack
+ org.netbeans.modules.execmerge
+ org.netbeans.modules.nativeexecution.implorg.netbeans.nativeexecution.terminalorg.netbeans.modules.nativeexecution.apiorg.netbeans.modules.nativeexecution.api.execution
diff --git a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/AbstractNativeProcess.java b/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/AbstractNativeProcess.java
--- a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/AbstractNativeProcess.java
+++ b/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/AbstractNativeProcess.java
@@ -47,6 +47,7 @@
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
+import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.Callable;
@@ -59,6 +60,9 @@
import java.util.logging.Level;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
+import org.netbeans.api.extexecution.process.ProcessCharset;
+import org.netbeans.api.extexecution.process.ProcessId;
+import org.netbeans.api.extexecution.process.ProcessSignal;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
import org.netbeans.modules.nativeexecution.api.HostInfo;
import org.netbeans.modules.nativeexecution.api.NativeProcess;
@@ -77,8 +81,9 @@
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
+import org.openide.util.lookup.Lookups;
-public abstract class AbstractNativeProcess extends NativeProcess implements ExProcessInfoProvider {
+public abstract class AbstractNativeProcess extends NativeProcess implements ExProcessInfoProvider, Lookup.Provider {
protected final static java.util.logging.Logger LOG = Logger.getInstance();
private final static Integer PID_TIMEOUT =
@@ -96,6 +101,59 @@
// Immutable listeners list.
private final Collection listeners;
private final Object stateLock;
+
+ private final ProcessId processId = new ProcessId() {
+ @Override
+ protected Integer getId() {
+ try {
+ return getPID();
+ } catch (IOException ex) {
+ LOG.log(Level.INFO, null, ex);
+ }
+ return null;
+ }
+ };
+ private final ProcessCharset processCharset = new ProcessCharset() {
+
+ @Override
+ protected Charset getInputCharset() {
+ return info.getCharset();
+ }
+
+ @Override
+ protected Charset getOutputCharset() {
+ return info.getCharset();
+ }
+
+ @Override
+ protected Charset getErrorCharset() {
+ return info.getCharset();
+ }
+
+ };
+ private final ProcessSignal processSignal = new ProcessSignal() {
+
+ @Override
+ protected void signal(ProcessSignal.Signal signal) throws IOException {
+ try {
+ SignalSupport.signalProcess(execEnv, getPID(),
+ SignalSupport.translate(signal));
+ } catch (UnsupportedOperationException ex) {
+ throw new IOException(ex);
+ }
+ }
+
+ @Override
+ protected void signalGroup(ProcessSignal.Signal signal) throws IOException {
+ try {
+ SignalSupport.signalProcessGroup(execEnv, getPID(),
+ SignalSupport.translate(signal));
+ } catch (UnsupportedOperationException ex) {
+ throw new IOException(ex);
+ }
+ }
+ };
+
private volatile State state;
private volatile int pid = 0;
private volatile boolean isInterrupted;
@@ -142,6 +200,11 @@
listeners = info.getListenersSnapshot();
}
+ @Override
+ public final Lookup getLookup() {
+ return Lookups.fixed(processId, processCharset, processSignal);
+ }
+
public final NativeProcess createAndStart() {
try {
if (hostInfo == null) {
diff --git a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Signal.java b/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Signal.java
--- a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Signal.java
+++ b/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Signal.java
@@ -41,6 +41,8 @@
*/
package org.netbeans.modules.nativeexecution.api.util;
+import org.netbeans.api.extexecution.process.ProcessSignal;
+
/**
*
* @author ak119685
@@ -48,54 +50,58 @@
public enum Signal {
// IDs are taken from signal_iso.h on Solaris
- NULL(0),
- SIGHUP(1),
- SIGINT(2),
- SIGQUIT(3),
- SIGILL(4),
- SIGTRAP(5),
- SIGIOT(6),
- SIGABRT(6),
- SIGEMT(7),
- SIGFPE(8),
- SIGKILL(9),
- SIGBUS(10),
- SIGSEGV(11),
- SIGSYS(12),
- SIGPIPE(13),
- SIGALRM(14),
- SIGTERM(15),
- SIGUSR1(16),
- SIGUSR2(17),
- SIGCLD(18),
- SIGCHLD(18),
- SIGPWR(19),
- SIGWINCH(20),
- SIGURG(21),
- SIGPOLL(22),
- SIGIO(22),
- SIGSTOP(23),
- SIGTSTP(24),
- SIGCONT(25),
- SIGTTIN(26),
- SIGTTOU(27),
- SIGVTALRM(28),
- SIGPROF(29),
- SIGXCPU(30),
- SIGXFSZ(31),
- SIGWAITING(32),
- SIGLWP(33),
- SIGFREEZE(34),
- SIGTHAW(35),
- SIGCANCEL(36),
- SIGLOST(37),
- SIGXRES(38),
- SIGJVM1(39),
- SIGJVM2(40);
+ NULL(0, ProcessSignal.Signal.NULL),
+ SIGHUP(1, ProcessSignal.Signal.SIGHUP),
+ SIGINT(2, ProcessSignal.Signal.SIGINT),
+ SIGQUIT(3, ProcessSignal.Signal.SIGQUIT),
+ SIGILL(4, ProcessSignal.Signal.SIGILL),
+ SIGTRAP(5, ProcessSignal.Signal.SIGTRAP),
+ SIGIOT(6, null),
+ SIGABRT(6, ProcessSignal.Signal.SIGABRT),
+ SIGEMT(7, ProcessSignal.Signal.SIGEMT),
+ SIGFPE(8, ProcessSignal.Signal.SIGFPE),
+ SIGKILL(9, ProcessSignal.Signal.SIGKILL),
+ SIGBUS(10, ProcessSignal.Signal.SIGBUS),
+ SIGSEGV(11, ProcessSignal.Signal.SIGSEGV),
+ SIGSYS(12, ProcessSignal.Signal.SIGSYS),
+ SIGPIPE(13, ProcessSignal.Signal.SIGPIPE),
+ SIGALRM(14, ProcessSignal.Signal.SIGALRM),
+ SIGTERM(15, ProcessSignal.Signal.SIGTERM),
+ SIGUSR1(16, ProcessSignal.Signal.SIGUSR1),
+ SIGUSR2(17, ProcessSignal.Signal.SIGUSR2),
+ SIGCLD(18, null),
+ SIGCHLD(18, ProcessSignal.Signal.SIGCHLD),
+ SIGPWR(19, ProcessSignal.Signal.SIGPWR),
+ SIGWINCH(20, ProcessSignal.Signal.SIGWINCH),
+ SIGURG(21, ProcessSignal.Signal.SIGURG),
+ SIGPOLL(22, ProcessSignal.Signal.SIGPOLL),
+ SIGIO(22, null),
+ SIGSTOP(23, ProcessSignal.Signal.SIGSTOP),
+ SIGTSTP(24, ProcessSignal.Signal.SIGTSTP),
+ SIGCONT(25, ProcessSignal.Signal.SIGCONT),
+ SIGTTIN(26, ProcessSignal.Signal.SIGTTIN),
+ SIGTTOU(27, ProcessSignal.Signal.SIGTTOU),
+ SIGVTALRM(28, ProcessSignal.Signal.SIGVTALRM),
+ SIGPROF(29, ProcessSignal.Signal.SIGPROF),
+ SIGXCPU(30, ProcessSignal.Signal.SIGXCPU),
+ SIGXFSZ(31, null),
+ SIGWAITING(32, ProcessSignal.Signal.SIGWAITING),
+ SIGLWP(33, ProcessSignal.Signal.SIGLWP),
+ SIGFREEZE(34, ProcessSignal.Signal.SIGFREEZE),
+ SIGTHAW(35, ProcessSignal.Signal.SIGTHAW),
+ SIGCANCEL(36, ProcessSignal.Signal.SIGCANCEL),
+ SIGLOST(37, ProcessSignal.Signal.SIGLOST),
+ SIGXRES(38, ProcessSignal.Signal.SIGXRES),
+ SIGJVM1(39, ProcessSignal.Signal.SIGJVM1),
+ SIGJVM2(40, null);
+
private final int id;
- private Signal(int id) {
+ private final ProcessSignal.Signal apiSignal;
+
+ private Signal(int id, ProcessSignal.Signal apiSignal) {
this.id = id;
+ this.apiSignal = apiSignal;
}
/*
@@ -107,4 +113,8 @@
int getID() {
return id;
}
+
+ public ProcessSignal.Signal getApiSignal() {
+ return apiSignal;
+ }
}
diff --git a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/signals/SignalSupport.java b/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/signals/SignalSupport.java
--- a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/signals/SignalSupport.java
+++ b/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/signals/SignalSupport.java
@@ -42,6 +42,9 @@
package org.netbeans.modules.nativeexecution.signals;
import java.util.Collection;
+import java.util.EnumMap;
+import java.util.Map;
+import org.netbeans.api.extexecution.process.ProcessSignal;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
import org.netbeans.modules.nativeexecution.api.util.Signal;
import org.openide.util.Lookup;
@@ -140,4 +143,19 @@
return result;
}
+
+ private static Map translation;
+
+ public synchronized static Signal translate(ProcessSignal.Signal signal) {
+ if (translation == null) {
+ translation = new EnumMap(ProcessSignal.Signal.class);
+ for (Signal sig : Signal.values()) {
+ ProcessSignal.Signal api = sig.getApiSignal();
+ if (api != null) {
+ translation.put(api, sig);
+ }
+ }
+ }
+ return translation.get(signal);
+ }
}
diff --git a/dlight.nativeexecution/tools/pty/Makefile b/dlight.nativeexecution/tools/pty/Makefile
--- a/dlight.nativeexecution/tools/pty/Makefile
+++ b/dlight.nativeexecution/tools/pty/Makefile
@@ -17,6 +17,7 @@
$(ROOT_DIR)/src/options.c \
$(ROOT_DIR)/src/pty_fork.c \
$(ROOT_DIR)/src/pty.c \
+ $(ROOT_DIR)/src/stty.c \
$(ROOT_DIR)/src/util.c
SRC_DIRS=\
@@ -30,7 +31,6 @@
EXEC=$(DIST_DIR)/$(PNAME)
-
CF_COMMON = --std=c99 -s -O2
CF_Linux-x86 = $(CF_COMMON) -DLINUX -D_GNU_SOURCE -D_XOPEN_SOURCE=700 -m32
CF_Linux-x86_64 = $(CF_COMMON) -DLINUX -D_GNU_SOURCE -D_XOPEN_SOURCE=700 -m64
@@ -40,8 +40,8 @@
CF_SunOS-sparc_64 = $(CF_COMMON) -DSOLARIS -D__EXTENSIONS__ -m64
CF_SunOS-x86 = $(CF_COMMON) -DSOLARIS -D__EXTENSIONS__ -m32
CF_SunOS-x86_64 = $(CF_COMMON) -DSOLARIS -D__EXTENSIONS__ -m64
-CF_Windows-x86 = $(CF_COMMON) -DWINDOWS -m32
-CF_Windows-x86_64 = $(CF_COMMON) -DWINDOWS -m32
+CF_Windows-x86 = $(CF_COMMON) -DWINDOWS -m32 --std=gnu99
+CF_Windows-x86_64 = $(CF_COMMON) -DWINDOWS -m32 --std=gnu99
LF_Windows-x86 = --static-libgcc
LF_Windows-x86_64 = --static-libgcc
diff --git a/dlight.nativeexecution/tools/pty/src/options.c b/dlight.nativeexecution/tools/pty/src/options.c
--- a/dlight.nativeexecution/tools/pty/src/options.c
+++ b/dlight.nativeexecution/tools/pty/src/options.c
@@ -35,6 +35,9 @@
}
opts->envfile = argv[idx];
return argc; // pretend that everything is parsed ...
+ } else if (strcmp(argv[idx], "--resize") == 0) {
+ opts->resize = 1;
+ nopt += 1;
} else if (strcmp(argv[idx], "--") == 0) {
idx++;
nopt += 2;
diff --git a/dlight.nativeexecution/tools/pty/src/options.h b/dlight.nativeexecution/tools/pty/src/options.h
--- a/dlight.nativeexecution/tools/pty/src/options.h
+++ b/dlight.nativeexecution/tools/pty/src/options.h
@@ -20,6 +20,7 @@
int set_erase_key;
int redirect_error;
int waitSignal;
+ int resize;
char *pty;
char *wdir;
const char *envfile;
diff --git a/dlight.nativeexecution/tools/pty/src/pty.c b/dlight.nativeexecution/tools/pty/src/pty.c
--- a/dlight.nativeexecution/tools/pty/src/pty.c
+++ b/dlight.nativeexecution/tools/pty/src/pty.c
@@ -79,9 +79,10 @@
// --dumpenv record current environment in a specified file
// --report record process' and exit status information into
// specified file
+ // --resize send TIOCSWINSZ to a terminal with the specified sizes
err_quit("\n\n"
- "usage: %s [-e] [--no-pty] [-w] [-p pts_name] [--set-erase-key]\n"
+ "usage: %s\t[-e] [--no-pty] [-w] [-p pts_name] [--set-erase-key]\n"
"\t\t[--readenv env_file] [[--env NAME=VALUE] ...] [--dir dir]\n"
"\t\t[--redirect-error] [--report report_file] program [ arg ... ]\n\n"
"\t-e\t\t turn echoing off\n"
@@ -92,9 +93,12 @@
"\t--dir\t\t change working directory for starting process\n"
"\t--redirect-error redirect stderror to stdout for starting process (makes sense if --no-pty only)\n"
"\t--report\t record process' and exit status information into specified file\n\n"
- "usage: %s --dumpenv env_file\n"
- "\t--dumpenv\t dump environment to a file\n"
- , progname, progname);
+ "usage: %s\t--dumpenv env_file\n"
+ "\t--dumpenv\t dump environment to a file\n\n"
+ "usage: %s\t--resize -p pts_name cols,rows,xpixels,ypixels\n"
+ "\t--resize\t send TIOCSWINSZ to a terminal with the specified sizes\n"
+ "\t\t\t Zero or not specified size means no change\n"
+ , progname, progname, progname);
exit(-1);
}
@@ -107,6 +111,10 @@
dup2(STDOUT_FILENO, STDERR_FILENO);
}
+ if (params.resize) {
+ return stty_winsz(params.pty, argv[0]);
+ }
+
if (params.nopty == 0) {
if (params.pty != NULL) {
pid = pty_fork1(params.pty);
diff --git a/dlight.nativeexecution/tools/pty/src/pty.h b/dlight.nativeexecution/tools/pty/src/pty.h
--- a/dlight.nativeexecution/tools/pty/src/pty.h
+++ b/dlight.nativeexecution/tools/pty/src/pty.h
@@ -10,6 +10,7 @@
#include "error.h"
#include "util.h"
#include "options.h"
+#include "stty.h"
#include
#include
#include
diff --git a/dlight.nativeexecution/tools/pty/src/stty.c b/dlight.nativeexecution/tools/pty/src/stty.c
new file mode 100644
--- /dev/null
+++ b/dlight.nativeexecution/tools/pty/src/stty.c
@@ -0,0 +1,58 @@
+#include "stty.h"
+#include "error.h"
+#include
+#include
+#include
+#include
+
+#if defined (__CYGWIN__) || defined (LINUX)
+#include
+#endif
+
+#if defined (__CYGWIN__)
+#include
+#else
+#include
+#endif
+
+int stty_winsz(const char* pts, const char* sz) {
+ if (pts == NULL) {
+ err_quit("pts must be specified when --resize is used");
+ }
+ char* sizes = strdup(sz);
+ if (sizes == (char *) NULL) {
+ err_sys("strdup error");
+ }
+ char *t;
+ char *lasts;
+ struct winsize wsize, orig;
+
+ int pty_fd;
+ if ((pty_fd = open(pts, O_RDWR)) == -1) {
+ err_sys("ERROR cannot open pty \"%s\" -- %s\n", pts, strerror(errno));
+ }
+
+ if (!isatty(pty_fd)) {
+ err_quit("Not a terminal: %s\n", pts);
+ }
+
+ ioctl(pty_fd, TIOCGWINSZ, &orig);
+
+ t = strtok_r(sizes, ",", &lasts);
+ wsize.ws_col = t == NULL ? orig.ws_col : atoi(t);
+ if (wsize.ws_col == 0) wsize.ws_col = orig.ws_col;
+
+ t = strtok_r(NULL, ",", &lasts);
+ wsize.ws_row = t == NULL ? orig.ws_row : atoi(t);
+ if (wsize.ws_row == 0) wsize.ws_row = orig.ws_row;
+
+ t = strtok_r(NULL, ",", &lasts);
+ wsize.ws_xpixel = t == NULL ? orig.ws_xpixel : atoi(t);
+ if (wsize.ws_xpixel == 0) wsize.ws_xpixel = orig.ws_xpixel;
+
+ t = strtok_r(NULL, ",", &lasts);
+ wsize.ws_ypixel = t == NULL ? orig.ws_ypixel : atoi(t);
+ if (wsize.ws_ypixel == 0) wsize.ws_ypixel = orig.ws_ypixel;
+
+ return ioctl(pty_fd, TIOCSWINSZ, &wsize);
+}
diff --git a/dlight.nativeexecution/tools/pty/src/stty.h b/dlight.nativeexecution/tools/pty/src/stty.h
new file mode 100644
--- /dev/null
+++ b/dlight.nativeexecution/tools/pty/src/stty.h
@@ -0,0 +1,20 @@
+/*
+ * File: stty.h
+ * Author: akrasny
+ */
+
+#ifndef STTY_H
+#define STTY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int stty_winsz(const char*, const char*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STTY_H */
+
diff --git a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fileoperations/spi/FileOperationsProvider.java b/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fileoperations/spi/FileOperationsProvider.java
--- a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fileoperations/spi/FileOperationsProvider.java
+++ b/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fileoperations/spi/FileOperationsProvider.java
@@ -49,6 +49,7 @@
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import org.netbeans.api.extexecution.Environment;
import org.netbeans.api.extexecution.ProcessBuilder;
import org.netbeans.modules.dlight.libs.common.PathUtilities;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
@@ -62,8 +63,11 @@
import org.netbeans.modules.remote.impl.fs.RemoteFileSystem;
import org.netbeans.modules.remote.impl.fs.RemoteFileSystemManager;
import org.netbeans.modules.remote.impl.fs.RemoteFileUrlMapper;
+import org.netbeans.spi.extexecution.EnvironmentFactory;
+import org.netbeans.spi.extexecution.EnvironmentImplementation;
import org.netbeans.spi.extexecution.ProcessBuilderFactory;
-import org.netbeans.spi.extexecution.ProcessBuilderImplementation;
+import org.netbeans.spi.extexecution.ProcessBuilderImplementation2;
+import org.netbeans.spi.extexecution.ProcessParameters;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileSystem;
import org.openide.util.Lookup;
@@ -378,7 +382,7 @@
}
protected ProcessBuilder createProcessBuilder(FileProxyO file) {
- return ProcessBuilderFactory.createProcessBuilder(new ProcessBuilderImplementationImpl(env), "RFS Process Builder"); // NOI18N
+ return ProcessBuilderFactory.createProcessBuilder(new ProcessBuilderImplementationImpl2(env), "RFS Process Builder"); // NOI18N
}
protected void refreshFor(FileProxyO ... files) {
@@ -462,23 +466,33 @@
return defaultProvider;
}
- private static final class ProcessBuilderImplementationImpl implements ProcessBuilderImplementation {
+ private static final class ProcessBuilderImplementationImpl2 implements ProcessBuilderImplementation2 {
private final ExecutionEnvironment env;
- private ProcessBuilderImplementationImpl(ExecutionEnvironment env) {
+ private final NativeProcessBuilder pb;
+ private final Environment environment;
+ private ProcessBuilderImplementationImpl2(ExecutionEnvironment env) {
this.env = env;
+ this.pb = NativeProcessBuilder.newProcessBuilder(env);
+ this.environment = EnvironmentFactory.createEnvironment(
+ new EnvironmentImplementationImpl(pb.getEnvironment()));
}
@Override
- public Process createProcess(String executable, String workingDirectory, List arguments, List paths, Map environment, boolean redirectErrorStream) throws IOException {
- NativeProcessBuilder pb = NativeProcessBuilder.newProcessBuilder(env);
- pb.setExecutable(executable).setWorkingDirectory(workingDirectory).setArguments(arguments.toArray(new String[arguments.size()]));
- MacroMap mm = MacroMap.forExecEnv(env);
- mm.putAll(environment);
- pb.getEnvironment().putAll(mm);
- for(String path : paths) {
- pb.getEnvironment().appendPathVariable("PATH", path); // NOI18N
- }
- if (redirectErrorStream) {
+ public Environment getEnvironment() {
+ return this.environment;
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return Lookup.EMPTY;
+ }
+
+ @Override
+ public Process createProcess(ProcessParameters parameters) throws IOException {
+ pb.setExecutable(parameters.getExecutable())
+ .setWorkingDirectory(parameters.getWorkingDirectory())
+ .setArguments(parameters.getArguments().toArray(new String[parameters.getArguments().size()]));
+ if (parameters.isRedirectErrorStream()) {
pb.redirectError();
}
return pb.call();
@@ -489,6 +503,43 @@
return env.getDisplayName();
}
}
+
+ private static final class EnvironmentImplementationImpl implements EnvironmentImplementation {
+ private final MacroMap mm;
+ public EnvironmentImplementationImpl(MacroMap mm) {
+ this.mm = mm;
+ }
+
+ @Override
+ public String getVariable(String name) {
+ return mm.get(name);
+ }
+
+ @Override
+ public void appendPath(String name, String value) {
+ mm.appendPathVariable(name, value);
+ }
+
+ @Override
+ public void prependPath(String name, String value) {
+ mm.prependPathVariable(name, value);
+ }
+
+ @Override
+ public void setVariable(String name, String value) {
+ mm.put(name, value);
+ }
+
+ @Override
+ public void removeVariable(String name) {
+ mm.remove(name);
+ }
+
+ @Override
+ public Map values() {
+ return mm.toMap();
+ }
+ }
public interface FileProxyO {
diff --git a/dlight.remote/manifest.mf b/dlight.remote/manifest.mf
--- a/dlight.remote/manifest.mf
+++ b/dlight.remote/manifest.mf
@@ -3,5 +3,5 @@
OpenIDE-Module: org.netbeans.modules.dlight.remote
OpenIDE-Module-Implementation-Version: 1
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/remote/resources/Bundle.properties
-OpenIDE-Module-Needs: org.netbeans.modules.dlight.remote.spi.RemoteProviderToken
+OpenIDE-Module-Needs: org.netbeans.modules.dlight.remote.spi.RemoteProviderToken, ConnectionService.localhost, ConnectionService.ssh
OpenIDE-Module-Recommends: org.netbeans.modules.remotefs.versioning
diff --git a/dlight.remote/nbproject/project.xml b/dlight.remote/nbproject/project.xml
--- a/dlight.remote/nbproject/project.xml
+++ b/dlight.remote/nbproject/project.xml
@@ -15,6 +15,14 @@
+ org.netbeans.modules.cnd.execution
+
+
+
+ 1.0
+
+
+ org.netbeans.modules.dlight.libs.common
@@ -31,6 +39,14 @@
+ org.netbeans.modules.execmerge
+
+
+
+ 1.0
+
+
+ org.openide.awt
diff --git a/dlight.remote/src/org/netbeans/modules/remote/api/ui/FileChooserBuilder.java b/dlight.remote/src/org/netbeans/modules/remote/api/ui/FileChooserBuilder.java
--- a/dlight.remote/src/org/netbeans/modules/remote/api/ui/FileChooserBuilder.java
+++ b/dlight.remote/src/org/netbeans/modules/remote/api/ui/FileChooserBuilder.java
@@ -63,6 +63,7 @@
import javax.swing.filechooser.FileSystemView;
import javax.swing.filechooser.FileView;
import javax.swing.plaf.FileChooserUI;
+import org.netbeans.modules.cnd.execution.api.Connection;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory;
import org.netbeans.modules.remote.spi.FileSystemProvider;
@@ -95,7 +96,9 @@
public abstract void setCurrentDirectory(FileObject dir);
+
public abstract FileObject getSelectedFileObject();
+
public abstract FileObject[] getSelectedFileObjects();
@Override
@@ -139,10 +142,17 @@
private static final String readOnlyKey = "FileChooser.readOnly"; // NOI18N
private final ExecutionEnvironment env;
+ private final Connection connection;
private Preferences forModule;
public FileChooserBuilder(ExecutionEnvironment env) {
this.env = env;
+ this.connection = null;
+ }
+
+ public FileChooserBuilder(Connection connection) {
+ this.connection = connection;
+ this.env = null;
}
public JFileChooserEx createFileChooser(Callable selectedPath) {
@@ -291,6 +301,7 @@
private static class RemoteFileChooserImpl extends JFileChooserEx
implements PropertyChangeListener {
+
private final Preferences forModule;
private final ExecutionEnvironment env;
@@ -411,7 +422,7 @@
String path = getSelectedFile().getAbsolutePath();
if (forModule != null) {
String envID = ExecutionEnvironmentFactory.toUniqueID(env);
- forModule.put("FileChooserPath"+envID, path); // NOI18N
+ forModule.put("FileChooserPath" + envID, path); // NOI18N
}
}
}
@@ -420,6 +431,7 @@
}
private static class CustomFileView extends FileView {
+
final FileSystemView view;
public CustomFileView(FileSystemView view) {
diff --git a/dlight.remote/src/org/netbeans/modules/remote/spi/FileSystemProvider.java b/dlight.remote/src/org/netbeans/modules/remote/spi/FileSystemProvider.java
--- a/dlight.remote/src/org/netbeans/modules/remote/spi/FileSystemProvider.java
+++ b/dlight.remote/src/org/netbeans/modules/remote/spi/FileSystemProvider.java
@@ -45,10 +45,13 @@
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
+import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.logging.Level;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.execmerge.ConnectionUtils;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory;
import org.netbeans.modules.remote.support.RemoteLogger;
@@ -84,6 +87,7 @@
return getFileSystem(env, "/"); //NOI18N
}
+ @Deprecated
public static ExecutionEnvironment getExecutionEnvironment(FileSystem fileSystem) {
for (FileSystemProviderImplementation provider : ALL_PROVIDERS) {
if (provider.isMine(fileSystem)) {
@@ -93,6 +97,7 @@
return ExecutionEnvironmentFactory.getLocal();
}
+ @Deprecated
public static ExecutionEnvironment getExecutionEnvironment(FileObject fileObject) {
try {
return getExecutionEnvironment(fileObject.getFileSystem());
@@ -102,6 +107,14 @@
return ExecutionEnvironmentFactory.getLocal();
}
+ public static Connection getConnection(FileObject fileObject) {
+ return ConnectionUtils.ExecutionEnvironment2Connection(getExecutionEnvironment(fileObject));
+ }
+
+ public static Connection getConnection(FileSystem fileSystem) {
+ return ConnectionUtils.ExecutionEnvironment2Connection(getExecutionEnvironment(fileSystem));
+ }
+
public static FileSystem getFileSystem(ExecutionEnvironment env, String root) {
for (FileSystemProviderImplementation provider : ALL_PROVIDERS) {
if (provider.isMine(env)) {
@@ -190,6 +203,18 @@
return FileUtil.toFileObject(FileUtil.normalizeFile(new File(absPath)));
}
+ public static FileObject getFileObject(Connection connection, String absPath) {
+ return getFileObject(Connection2ExecutionEnvironment(connection), absPath);
+ }
+
+ private static ExecutionEnvironment Connection2ExecutionEnvironment(Connection connection) {
+ URI uri = connection.getURI();
+ if ("localhost".equals(uri.getScheme())) { // NOI18N
+ return ExecutionEnvironmentFactory.getLocal();
+ }
+ return ExecutionEnvironmentFactory.createNew(uri.getUserInfo(), uri.getHost());
+ }
+
public static FileObject getCanonicalFileObject(FileObject fileObject) throws IOException {
for (FileSystemProviderImplementation provider : ALL_PROVIDERS) {
if (provider.isMine(fileObject)) {
diff --git a/dlight.terminal/manifest.mf b/dlight.terminal/manifest.mf
--- a/dlight.terminal/manifest.mf
+++ b/dlight.terminal/manifest.mf
@@ -4,4 +4,5 @@
OpenIDE-Module-Implementation-Version: 1
OpenIDE-Module-Layer: org/netbeans/modules/dlight/terminal/layer.xml
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/dlight/terminal/Bundle.properties
+OpenIDE-Module-Recommends: org.netbeans.modules.dlight.spi.terminal.ConnectionProvider
diff --git a/dlight.terminal/nbproject/project.xml b/dlight.terminal/nbproject/project.xml
--- a/dlight.terminal/nbproject/project.xml
+++ b/dlight.terminal/nbproject/project.xml
@@ -23,11 +23,29 @@
- org.netbeans.modules.dlight.nativeexecution
+ org.netbeans.modules.autoupdate.ui
- 1.10.3
+ 1.35
+
+
+
+ org.netbeans.modules.extexecution
+
+
+
+ 2
+ 1.37
+
+
+
+ org.netbeans.modules.options.api
+
+
+
+ 1
+ 1.32
@@ -105,9 +123,12 @@
com.sun.tools.ide.analysis.discovercom.sun.tools.ide.analysis.previsecom.sun.tools.ide.analysis.tha
+ org.netbeans.modules.cnd.executionorg.netbeans.modules.cnd.makeprojectorg.netbeans.modules.cnd.remote
+ org.netbeans.modules.nativeexecution.implorg.netbeans.modules.dlight.api.terminal
+ org.netbeans.modules.dlight.spi.terminal
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/api/terminal/ProcessTerminal.java b/dlight.terminal/src/org/netbeans/modules/dlight/api/terminal/ProcessTerminal.java
new file mode 100644
--- /dev/null
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/api/terminal/ProcessTerminal.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.dlight.api.terminal;
+
+import java.awt.Dimension;
+import java.util.concurrent.atomic.AtomicReference;
+import org.openide.util.Lookup;
+import org.openide.util.RequestProcessor;
+import org.openide.util.RequestProcessor.Task;
+
+/**
+ *
+ * @author akrasny
+ */
+public abstract class ProcessTerminal {
+
+ private static final RequestProcessor RP = new RequestProcessor("ProcessTerminal resize", 1); // NOI18N
+ private final AtomicReference sizeRef = new AtomicReference();
+ private final AtomicReference pixelSizeRef = new AtomicReference();
+ private final Task resizeTask = RP.create(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (resizeTask) {
+ ttyResized(sizeRef.get(), pixelSizeRef.get());
+ }
+ }
+ }, true);
+
+ private static ProcessTerminal find(Process process) {
+ if (process instanceof Lookup.Provider) {
+ Lookup.Provider p = (Lookup.Provider) process;
+ return p.getLookup().lookup(ProcessTerminal.class);
+ }
+ return null;
+ }
+
+ public static boolean isSupported(Process process) {
+ return find(process) != null;
+ }
+
+ public static void ttyResized(Process process, Dimension size, Dimension pixelSize) {
+ ProcessTerminal termInfo = find(process);
+ if (termInfo != null) {
+ synchronized (termInfo.resizeTask) {
+ termInfo.sizeRef.set(size);
+ termInfo.pixelSizeRef.set(pixelSize);
+ }
+ termInfo.resizeTask.schedule(500);
+ }
+ }
+
+ protected abstract void ttyResized(Dimension size, Dimension pixelSize);
+}
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/api/terminal/TerminalSupport.java b/dlight.terminal/src/org/netbeans/modules/dlight/api/terminal/TerminalSupport.java
--- a/dlight.terminal/src/org/netbeans/modules/dlight/api/terminal/TerminalSupport.java
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/api/terminal/TerminalSupport.java
@@ -46,7 +46,6 @@
import javax.swing.Action;
import org.netbeans.modules.dlight.terminal.action.TerminalSupportImpl;
import org.netbeans.modules.dlight.terminal.ui.TerminalContainerTopComponent;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
import org.openide.windows.IOContainer;
/**
@@ -63,8 +62,8 @@
* @param ioContainer
* @param env
*/
- public static void openTerminal(IOContainer ioContainer, String termTitle, ExecutionEnvironment env) {
- TerminalSupportImpl.openTerminalImpl(ioContainer, termTitle, env, null, false);
+ public static void openTerminal(IOContainer ioContainer, String termTitle, org.netbeans.api.extexecution.ProcessBuilder.Provider provider) {
+ TerminalSupportImpl.openTerminalImpl(ioContainer, termTitle, provider, null, false);
}
/**
@@ -72,15 +71,15 @@
* @param ioContainer
* @param env
*/
- public static void openTerminal(IOContainer ioContainer, String termTitle, ExecutionEnvironment env, String dir) {
- TerminalSupportImpl.openTerminalImpl(ioContainer, termTitle, env, dir, false);
+ public static void openTerminal(IOContainer ioContainer, String termTitle, org.netbeans.api.extexecution.ProcessBuilder.Provider provider, String dir) {
+ TerminalSupportImpl.openTerminalImpl(ioContainer, termTitle, provider, dir, false);
}
/**
* opens terminal tab in default terminals container and change dir into specified directory
* @param env
*/
- public static void openTerminal(String termTitle, ExecutionEnvironment env, String dir) {
+ public static void openTerminal(String termTitle, org.netbeans.api.extexecution.ProcessBuilder.Provider provider, String dir) {
final TerminalContainerTopComponent instance = TerminalContainerTopComponent.findInstance();
Object prev = instance.getClientProperty(TerminalContainerTopComponent.AUTO_OPEN_LOCAL_PROPERTY);
instance.putClientProperty(TerminalContainerTopComponent.AUTO_OPEN_LOCAL_PROPERTY, Boolean.FALSE);
@@ -88,7 +87,7 @@
instance.open();
instance.requestActive();
IOContainer ioContainer = instance.getIOContainer();
- TerminalSupportImpl.openTerminalImpl(ioContainer, termTitle, env, dir, false);
+ TerminalSupportImpl.openTerminalImpl(ioContainer, termTitle, provider, dir, false);
} finally {
instance.putClientProperty(TerminalContainerTopComponent.AUTO_OPEN_LOCAL_PROPERTY, prev);
}
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/spi/terminal/ConnectionProvider.java b/dlight.terminal/src/org/netbeans/modules/dlight/spi/terminal/ConnectionProvider.java
new file mode 100644
--- /dev/null
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/spi/terminal/ConnectionProvider.java
@@ -0,0 +1,57 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.dlight.spi.terminal;
+
+import java.io.IOException;
+import java.net.URI;
+import org.netbeans.api.extexecution.ProcessBuilder;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public interface ConnectionProvider {
+
+ ProcessBuilder.Provider getConnection(URI uri) throws IOException;
+
+ URI getLocal();
+}
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/spi/terminal/ShellConfiguration.java b/dlight.terminal/src/org/netbeans/modules/dlight/spi/terminal/ShellConfiguration.java
new file mode 100644
--- /dev/null
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/spi/terminal/ShellConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.dlight.spi.terminal;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public interface ShellConfiguration {
+
+ String getShell();
+
+}
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/spi/terminal/TerminalConfiguration.java b/dlight.terminal/src/org/netbeans/modules/dlight/spi/terminal/TerminalConfiguration.java
new file mode 100644
--- /dev/null
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/spi/terminal/TerminalConfiguration.java
@@ -0,0 +1,58 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.dlight.spi.terminal;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public interface TerminalConfiguration {
+
+ boolean isTerminalMode();
+
+ void setTerminalMode(boolean terminalMode);
+
+ String getEmulation();
+
+ void setEmulation(String emulation);
+
+}
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/Bundle.properties b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/Bundle.properties
--- a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/Bundle.properties
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/Bundle.properties
@@ -1,7 +1,6 @@
CTL_LocalTerminal=Terminal
CTL_RemoteTerminalAction=Remote Terminal
RemoteConnectionTitle=SSH Connection
-TerminalAction.FailedToStart.text=Failed to start terminal: {0}
RemoteTerminalShortDescr=Create New Remote Terminal Tab
LocalTerminalShortDescr=Create New Local Terminal Tab
CTL_ShowTerminalAction=T&erminal
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/LocalTerminalAction.java b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/LocalTerminalAction.java
--- a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/LocalTerminalAction.java
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/LocalTerminalAction.java
@@ -41,13 +41,14 @@
*/
package org.netbeans.modules.dlight.terminal.action;
+import java.net.URI;
+import org.netbeans.modules.dlight.spi.terminal.ConnectionProvider;
import org.netbeans.modules.dlight.terminal.ui.TerminalContainerTopComponent;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.util.ImageUtilities;
+import org.openide.util.Lookup;
import org.openide.util.NbBundle;
/**
@@ -55,7 +56,7 @@
* @author Vladimir Voskresensky
*/
@ActionID(id = "LocalTerminalAction", category = "Window")
-@ActionRegistration(iconInMenu = true, displayName = "#CTL_LocalTerminal", iconBase = "org/netbeans/modules/dlight/terminal/action/local_term.png")
+@ActionRegistration(iconInMenu = true, lazy = false, displayName = "#CTL_LocalTerminal", iconBase = "org/netbeans/modules/dlight/terminal/action/local_term.png")
@ActionReference(path = TerminalAction.TERMINAL_ACTIONS_PATH, name = "org-netbeans-modules-dlight-terminal-action-LocalTerminalAction", position = 100)
public final class LocalTerminalAction extends TerminalAction {
@@ -65,7 +66,7 @@
}
@Override
- protected ExecutionEnvironment getEnvironment() {
- return ExecutionEnvironmentFactory.getLocal();
+ protected URI getConnectionURI() {
+ return Lookup.getDefault().lookup(ConnectionProvider.class).getLocal();
}
}
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/RemoteTerminalAction.java b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/RemoteTerminalAction.java
--- a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/RemoteTerminalAction.java
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/RemoteTerminalAction.java
@@ -42,14 +42,16 @@
package org.netbeans.modules.dlight.terminal.action;
import java.awt.Dialog;
+import java.net.URI;
+import org.netbeans.modules.dlight.spi.terminal.ConnectionProvider;
import org.netbeans.modules.dlight.terminal.ui.RemoteInfoDialog;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.util.ImageUtilities;
+import org.openide.util.Lookup;
import org.openide.util.NbBundle;
/**
@@ -57,7 +59,7 @@
* @author Vladimir Voskresensky
*/
@ActionID(id = "RemoteTerminalAction", category = "Window")
-@ActionRegistration(iconInMenu = true, displayName = "#CTL_RemoteTerminalAction", iconBase = "org/netbeans/modules/dlight/terminal/action/remote_term.png")
+@ActionRegistration(iconInMenu = true, lazy = false, displayName = "#CTL_RemoteTerminalAction", iconBase = "org/netbeans/modules/dlight/terminal/action/remote_term.png")
@ActionReference(path = TerminalAction.TERMINAL_ACTIONS_PATH, name = "org-netbeans-modules-dlight-terminal-action-RemoteTerminalAction", position = 200)
public final class RemoteTerminalAction extends TerminalAction {
@@ -70,7 +72,7 @@
}
@Override
- protected ExecutionEnvironment getEnvironment() {
+ protected URI getConnectionURI() {
String title = NbBundle.getMessage(RemoteTerminalAction.class, "RemoteConnectionTitle");
cfgPanel.init();
DialogDescriptor dd = new DialogDescriptor(cfgPanel, title, // NOI18N
@@ -78,7 +80,7 @@
DialogDescriptor.OK_OPTION, null);
Dialog cfgDialog = DialogDisplayer.getDefault().createDialog(dd);
-
+
try {
cfgDialog.setVisible(true);
} catch (Throwable th) {
@@ -94,7 +96,6 @@
return null;
}
- final ExecutionEnvironment env = cfgPanel.getExecutionEnvironment();
- return env;
+ return cfgPanel.getConnectionURI();
}
}
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/ShowTerminalAction.java b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/ShowTerminalAction.java
--- a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/ShowTerminalAction.java
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/ShowTerminalAction.java
@@ -59,6 +59,9 @@
public class ShowTerminalAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
+ if (!TerminalAction.checkInstalled()) {
+ return;
+ }
final TerminalContainerTopComponent instance = TerminalContainerTopComponent.findInstance();
instance.open();
instance.requestActive();
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/TerminalAction.java b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/TerminalAction.java
--- a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/TerminalAction.java
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/TerminalAction.java
@@ -43,11 +43,22 @@
import java.awt.Component;
import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.NoRouteToHostException;
+import java.net.URI;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
+import org.netbeans.modules.autoupdate.ui.api.PluginManager;
+import org.netbeans.modules.dlight.spi.terminal.ConnectionProvider;
import org.netbeans.modules.dlight.terminal.ui.TerminalContainerTopComponent;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
import org.openide.util.actions.Presenter;
import org.openide.windows.IOContainer;
import org.openide.windows.IOProvider;
@@ -60,6 +71,8 @@
public static final String TERMINAL_ACTIONS_PATH = "Terminal/Actions"; // NOI18N
+ private static final String NATIVE_EXECUTION = "org.netbeans.modules.cnd.execution"; // NOI18N
+
public TerminalAction(String name, String descr, ImageIcon icon) {
putValue(Action.NAME, name);
putValue(Action.SMALL_ICON, icon);
@@ -67,17 +80,50 @@
}
@Override
+ @Messages({
+ "# {0} - host",
+ "UnreachableHostError=Host {0} cannot be reached. Please verify proxy settings."
+ })
public void actionPerformed(final ActionEvent e) {
+ if (!checkInstalled()) {
+ return;
+ }
+
final TerminalContainerTopComponent instance = TerminalContainerTopComponent.findInstance();
instance.open();
instance.requestActive();
final IOContainer ioContainer = instance.getIOContainer();
final IOProvider term = IOProvider.get("Terminal"); // NOI18N
- if (term != null) {
- final ExecutionEnvironment env = getEnvironment();
- if (env != null) {
- TerminalSupportImpl.openTerminalImpl(ioContainer, env.getDisplayName(), env, null, TerminalContainerTopComponent.SILENT_MODE_COMMAND.equals(e.getActionCommand()));
- }
+ assert term != null;
+
+ boolean silentMode = TerminalContainerTopComponent.SILENT_MODE_COMMAND.equals(e.getActionCommand());
+
+ final URI connectionURI = getConnectionURI();
+ if (connectionURI == null) {
+ return;
+ }
+
+ try {
+ ConnectionProvider provider = Lookup.getDefault().lookup(ConnectionProvider.class);
+
+ // XXX disable action when lookup empty
+ final org.netbeans.api.extexecution.ProcessBuilder.Provider pbp =
+ provider.getConnection(connectionURI);
+
+ TerminalSupportImpl.openTerminalImpl(
+ ioContainer,
+ null,
+ pbp,
+ null, /* dir */
+ silentMode);
+ } catch (InterruptedIOException ex) {
+ return;
+ } catch (NoRouteToHostException ex) {
+ DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
+ Bundle.UnreachableHostError(connectionURI.getHost()),
+ NotifyDescriptor.ERROR_MESSAGE));
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
}
}
@@ -86,5 +132,22 @@
return TerminalSupportImpl.getToolbarPresenter(this);
}
- protected abstract ExecutionEnvironment getEnvironment();
+ protected abstract URI getConnectionURI();
+
+ @NbBundle.Messages({
+ "module install_title=Native Execution API installation",
+ "module_install_question=Terminal requires Native Execution API support. Do you want to install it now?",
+ "native_execution=Native Execution API"
+ })
+ public static boolean checkInstalled() {
+ if (Lookup.getDefault().lookup(ConnectionProvider.class) != null) {
+ return true;
+ }
+ NotifyDescriptor d = new NotifyDescriptor.Confirmation(Bundle.module_install_question(),
+ Bundle.module_install_title(), NotifyDescriptor.YES_NO_OPTION);
+ if (DialogDisplayer.getDefault().notify(d) == NotifyDescriptor.YES_OPTION) {
+ return null == PluginManager.installSingle(NATIVE_EXECUTION, Bundle.native_execution());
+ }
+ return false;
+ }
}
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/TerminalSupportImpl.java b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/TerminalSupportImpl.java
--- a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/TerminalSupportImpl.java
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/action/TerminalSupportImpl.java
@@ -39,44 +39,27 @@
*
* Portions Copyrighted 2011 Sun Microsystems, Inc.
*/
-
package org.netbeans.modules.dlight.terminal.action;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
+import java.net.ConnectException;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
-import org.netbeans.modules.nativeexecution.api.HostInfo;
-import org.netbeans.modules.nativeexecution.api.NativeProcess;
-import org.netbeans.modules.nativeexecution.api.NativeProcessBuilder;
-import org.netbeans.modules.nativeexecution.api.execution.NativeExecutionDescriptor;
-import org.netbeans.modules.nativeexecution.api.execution.NativeExecutionService;
-import org.netbeans.modules.nativeexecution.api.pty.PtySupport;
-import org.netbeans.modules.nativeexecution.api.util.ConnectionManager;
-import org.netbeans.modules.nativeexecution.api.util.ConnectionManager.CancellationException;
-import org.netbeans.modules.nativeexecution.api.util.HostInfoUtils;
+import org.netbeans.modules.dlight.api.terminal.ProcessTerminal;
+import org.netbeans.modules.dlight.spi.terminal.ShellConfiguration;
+import org.netbeans.modules.dlight.spi.terminal.TerminalConfiguration;
+import org.netbeans.modules.terminal.api.IOEmulation;
import org.netbeans.modules.terminal.api.IONotifier;
+import org.netbeans.modules.terminal.api.IOResizable;
+import org.netbeans.modules.terminal.api.IOTerm;
import org.netbeans.modules.terminal.api.IOVisibility;
-import org.openide.DialogDisplayer;
-import org.openide.NotifyDescriptor;
import org.openide.util.Exceptions;
import org.openide.util.ImageUtilities;
-import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
-import org.openide.util.WeakListeners;
import org.openide.windows.IOContainer;
import org.openide.windows.IOProvider;
import org.openide.windows.InputOutput;
@@ -86,11 +69,13 @@
* @author Vladimir Voskresensky
*/
public final class TerminalSupportImpl {
+
private static final RequestProcessor RP = new RequestProcessor("Terminal Action RP", 100); // NOI18N
private TerminalSupportImpl() {
+ super();
}
-
+
public static Component getToolbarPresenter(Action action) {
JButton button = new JButton(action);
button.setBorderPainted(false);
@@ -107,163 +92,83 @@
button.setDisabledIcon(ImageUtilities.createDisabledIcon((Icon) icon));
return button;
}
-
- public static void openTerminalImpl(final IOContainer ioContainer, final String tabTitle, final ExecutionEnvironment env, final String dir, final boolean silentMode) {
+
+ public static void openTerminalImpl(final IOContainer ioContainer, final String title,
+ final org.netbeans.api.extexecution.ProcessBuilder.Provider provider, final String dir, final boolean silentMode) {
+
final IOProvider term = IOProvider.get("Terminal"); // NOI18N
- if (term != null) {
- final AtomicBoolean destroyed = new AtomicBoolean(false);
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- if (SwingUtilities.isEventDispatchThread()) {
- ioContainer.requestActive();
- } else {
- doWork();
- }
- }
-
- private void doWork() {
- if (!ConnectionManager.getInstance().isConnectedTo(env)) {
- try {
- ConnectionManager.getInstance().connectTo(env);
- } catch (IOException ex) {
- if (!destroyed.get()) {
- String error = ex.getCause() == null ? ex.getMessage() : ex.getCause().getMessage();
- String msg = NbBundle.getMessage(TerminalSupportImpl.class, "TerminalAction.FailedToStart.text", error); // NOI18N
- DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(msg, NotifyDescriptor.ERROR_MESSAGE));
- }
- return;
- } catch (CancellationException ex) {
- return;
- }
- }
-
- final HostInfo hostInfo;
- try {
- hostInfo = HostInfoUtils.getHostInfo(env);
- boolean isSupported = PtySupport.isSupportedFor(env);
- if (!isSupported) {
- if (!silentMode) {
- String message;
-
- if (hostInfo.getOSFamily() == HostInfo.OSFamily.WINDOWS) {
- message = NbBundle.getMessage(TerminalSupportImpl.class, "LocalTerminalNotSupported.error.nocygwin"); // NOI18N
- } else {
- message = NbBundle.getMessage(TerminalSupportImpl.class, "LocalTerminalNotSupported.error"); // NOI18N
- }
-
- NotifyDescriptor nd = new NotifyDescriptor.Message(message, NotifyDescriptor.INFORMATION_MESSAGE);
- DialogDisplayer.getDefault().notify(nd);
- }
- return;
- }
- } catch (IOException ex) {
- Exceptions.printStackTrace(ex);
- return;
- } catch (CancellationException ex) {
- Exceptions.printStackTrace(ex);
- return;
- }
-
- final AtomicReference ioRef = new AtomicReference();
- try {
- ioRef.set(term.getIO(tabTitle, null, ioContainer));
-
- NativeProcessBuilder npb = NativeProcessBuilder.newProcessBuilder(env);
- npb.addNativeProcessListener(new NativeProcessListener(ioRef.get(), destroyed));
-
- String shell = hostInfo.getLoginShell();
- if (dir != null) {
- npb.setWorkingDirectory(dir);
- }
-// npb.setWorkingDirectory("${HOME}");
- npb.setExecutable(shell);
- NativeExecutionDescriptor descr;
- descr = new NativeExecutionDescriptor().controllable(true).frontWindow(true).inputVisible(true).inputOutput(ioRef.get());
- descr.postExecution(new Runnable() {
-
- @Override
- public void run() {
- ioRef.get().closeInputOutput();
- }
- });
- NativeExecutionService es = NativeExecutionService.newService(npb, descr, "Terminal Emulator"); // NOI18N
- Future result = es.run();
- // ask terminal to become active
- SwingUtilities.invokeLater(this);
-
- try {
- // if terminal can not be started then ExecutionException should be thrown
- // wait one second to see if terminal can not be started. otherwise it's OK to exit by TimeOut
- result.get(1, TimeUnit.SECONDS);
- } catch (TimeoutException ex) {
- // we should be there
- } catch (InterruptedException ex) {
- Exceptions.printStackTrace(ex);
- } catch (ExecutionException ex) {
- if (!destroyed.get()) {
- String error = ex.getCause() == null ? ex.getMessage() : ex.getCause().getMessage();
- String msg = NbBundle.getMessage(TerminalSupportImpl.class, "TerminalAction.FailedToStart.text", error); // NOI18N
- DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(msg, NotifyDescriptor.ERROR_MESSAGE));
- }
- }
- } catch (java.util.concurrent.CancellationException ex) { // VK: don't quite understand who can throw it?
- Exceptions.printStackTrace(ex);
- reportInIO(ioRef.get(), ex);
- }
- }
-
- private void reportInIO(InputOutput io, Exception ex) {
- if (io != null && ex != null) {
- io.getErr().print(ex.getLocalizedMessage());
- }
- }
- };
- RP.post(runnable);
- }
- }
-
- private final static class NativeProcessListener implements ChangeListener, PropertyChangeListener {
-
- private final AtomicReference processRef;
- private final AtomicBoolean destroyed;
-
- public NativeProcessListener(InputOutput io, AtomicBoolean destroyed) {
- assert destroyed != null;
- this.destroyed = destroyed;
- this.processRef = new AtomicReference();
- IONotifier.addPropertyChangeListener(io, WeakListeners.propertyChange(NativeProcessListener.this, io));
+ if (term == null) {
+ return;
}
- @Override
- public void stateChanged(ChangeEvent e) {
- NativeProcess process = processRef.get();
- if (process == null && e.getSource() instanceof NativeProcess) {
- processRef.compareAndSet(null, (NativeProcess) e.getSource());
+ try {
+ org.netbeans.api.extexecution.ProcessBuilder pb;
+ try {
+ pb = provider.getProcessBuilder();
+ } catch (ConnectException ex) {
+ return;
}
- }
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- if (IOVisibility.PROP_VISIBILITY.equals(evt.getPropertyName()) && Boolean.FALSE.equals(evt.getNewValue())) {
- if (destroyed.compareAndSet(false, true)) {
- // term is closing => destroy process
- final NativeProcess proc = processRef.get();
- if (proc != null) {
+ final InputOutput termIO = term.getIO(title != null ? title : pb.getDescription(),
+ null, ioContainer);
+
+ ShellConfiguration shellConfiguration = pb.getLookup().lookup(ShellConfiguration.class);
+ if (shellConfiguration == null) {
+ throw new IllegalStateException("No shell provided by the builder: " + pb.getDescription());
+ }
+ pb.setExecutable(shellConfiguration.getShell());
+ TerminalConfiguration tcc = pb.getLookup().lookup(TerminalConfiguration.class);
+
+ if (tcc != null) {
+ tcc.setTerminalMode(true);
+ tcc.setEmulation(IOEmulation.getEmulation(termIO));
+ }
+
+ if (dir != null) {
+ pb.setWorkingDirectory(dir);
+ }
+
+ final Process shell = pb.call();
+
+ IOTerm.connect(termIO, shell.getOutputStream(), shell.getInputStream(), shell.getErrorStream());
+ IONotifier.addPropertyChangeListener(termIO, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (IOVisibility.PROP_VISIBILITY.equals(evt.getPropertyName()) && Boolean.FALSE.equals(evt.getNewValue())) {
RP.submit(new Runnable() {
-
@Override
public void run() {
try {
- proc.destroy();
+ shell.destroy();
} catch (Throwable th) {
}
}
});
+ } else if (IOResizable.PROP_SIZE.equals(evt.getPropertyName())) {
+ IOResizable.Size size = (IOResizable.Size) evt.getNewValue();
+ ProcessTerminal.ttyResized(shell, size.cells, size.pixels);
}
}
- }
+ });
+
+ ioContainer.requestActive();
+ termIO.select();
+
+ RP.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ shell.waitFor();
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ } finally {
+ termIO.closeInputOutput();
+ }
+ }
+ });
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
}
}
}
diff --git a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/ui/RemoteInfoDialog.java b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/ui/RemoteInfoDialog.java
--- a/dlight.terminal/src/org/netbeans/modules/dlight/terminal/ui/RemoteInfoDialog.java
+++ b/dlight.terminal/src/org/netbeans/modules/dlight/terminal/ui/RemoteInfoDialog.java
@@ -49,14 +49,14 @@
import java.awt.Component;
import java.awt.Toolkit;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.prefs.Preferences;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.text.JTextComponent;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
-import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory;
-import org.netbeans.modules.nativeexecution.api.util.ConnectionManager;
+import org.openide.util.Exceptions;
import org.openide.util.NbPreferences;
/**
@@ -233,10 +233,10 @@
private javax.swing.JTextField userField;
// End of variables declaration//GEN-END:variables
- private ExecutionEnvironment last;
- public ExecutionEnvironment getExecutionEnvironment() {
+ private URI last;
+ public URI getConnectionURI() {
if (btnKnownHosts.isSelected()) {
- last = (ExecutionEnvironment) cbKnownHosts.getSelectedItem();
+ last = (URI) cbKnownHosts.getSelectedItem();
} else {
if (userField.getText().isEmpty() || hostField.getText().isEmpty()) {
return null;
@@ -250,19 +250,22 @@
} catch (NumberFormatException ex) {
}
}
-
- last = ExecutionEnvironmentFactory.createNew(userField.getText(), hostField.getText(), port);
+ try {
+ last = new URI("ssh://" + userField.getText() + '@' + hostField.getText() + ':' + port);
+ } catch (URISyntaxException ex) {
+ Exceptions.printStackTrace(ex);
+ }
}
Preferences prefs = NbPreferences.forModule(RemoteInfoDialog.class);
- prefs.put(LAST_SELECTED_HOST, ExecutionEnvironmentFactory.toUniqueID(last));
+ prefs.put(LAST_SELECTED_HOST, last.toString());
return last;
}
private void fillHosts() {
- cbKnownHosts.removeAllItems();
- for (ExecutionEnvironment ee : ConnectionManager.getInstance().getRecentConnections()) {
- cbKnownHosts.addItem(ee);
- }
+ cbKnownHosts.removeAllItems();
+// for (ExecutionEnvironment ee : ConnectionManager.getInstance().getRecentConnections()) {
+// cbKnownHosts.addItem(ee);
+// }
boolean hasKnown = cbKnownHosts.getItemCount() > 0;
btnKnownHosts.setEnabled(hasKnown);
if (hasKnown) {
@@ -289,7 +292,11 @@
Preferences prefs = NbPreferences.forModule(RemoteInfoDialog.class);
String eeID = prefs.get(LAST_SELECTED_HOST, "");
if (!eeID.isEmpty()) {
- last = ExecutionEnvironmentFactory.fromUniqueID(eeID);
+ try {
+ last = new URI(eeID);
+ } catch (URISyntaxException ex) {
+ Exceptions.printStackTrace(ex);
+ }
}
}
fillHosts();
diff --git a/execmerge/build.xml b/execmerge/build.xml
new file mode 100644
--- /dev/null
+++ b/execmerge/build.xml
@@ -0,0 +1,5 @@
+
+
+ Builds, tests, and runs the project org.netbeans.modules.execmerge
+
+
diff --git a/execmerge/manifest.mf b/execmerge/manifest.mf
new file mode 100644
--- /dev/null
+++ b/execmerge/manifest.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+OpenIDE-Module: org.netbeans.modules.execmerge
+OpenIDE-Module-Implementation-Version: 1
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/execmerge/resources/Bundle.properties
+AutoUpdate-Show-In-Client: false
diff --git a/execmerge/nbproject/project.properties b/execmerge/nbproject/project.properties
new file mode 100644
--- /dev/null
+++ b/execmerge/nbproject/project.properties
@@ -0,0 +1,3 @@
+javac.source=1.6
+javac.compilerargs=-Xlint -Xlint:-serial
+spec.version.base=1.0
diff --git a/execmerge/nbproject/project.xml b/execmerge/nbproject/project.xml
new file mode 100644
--- /dev/null
+++ b/execmerge/nbproject/project.xml
@@ -0,0 +1,38 @@
+
+
+ org.netbeans.modules.apisupport.project
+
+
+ org.netbeans.modules.execmerge
+
+
+ org.netbeans.modules.cnd.execution
+
+
+
+ 1.0
+
+
+
+ org.netbeans.modules.dlight.nativeexecution
+
+
+
+ 1.26
+
+
+
+ org.openide.util
+
+
+
+ 8.28
+
+
+
+
+ org.netbeans.modules.execmerge
+
+
+
+
diff --git a/execmerge/src/org/netbeans/modules/execmerge/ConnectionUtils.java b/execmerge/src/org/netbeans/modules/execmerge/ConnectionUtils.java
new file mode 100644
--- /dev/null
+++ b/execmerge/src/org/netbeans/modules/execmerge/ConnectionUtils.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.execmerge;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.ConnectionManager;
+import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author akrasny
+ */
+public final class ConnectionUtils {
+
+ private ConnectionUtils() {
+ }
+
+ public static Connection ExecutionEnvironment2Connection(ExecutionEnvironment env) {
+ if (env.isLocal()) {
+ return ConnectionManager.getLocalConnection();
+ }
+
+ try {
+ URI uri = new URI("ssh://" + env.getUser() + "@" + env.getHost()); // NOI18N
+ return ConnectionManager.connect(uri);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ } catch (URISyntaxException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+
+ return ConnectionManager.getLocalConnection();
+ }
+
+}
diff --git a/execmerge/src/org/netbeans/modules/execmerge/resources/Bundle.properties b/execmerge/src/org/netbeans/modules/execmerge/resources/Bundle.properties
new file mode 100644
--- /dev/null
+++ b/execmerge/src/org/netbeans/modules/execmerge/resources/Bundle.properties
@@ -0,0 +1,1 @@
+OpenIDE-Module-Name=Temp Module for Execution Merge
diff --git a/extexecution/apichanges.xml b/extexecution/apichanges.xml
--- a/extexecution/apichanges.xml
+++ b/extexecution/apichanges.xml
@@ -104,6 +104,7 @@
External Execution APIExternal Execution Input APIExternal Execution Input Printing API
+ External Execution Process APIExternal Execution Startup Arguments APIExternal Execution SPIExternal Execution Process Destroy SPI
@@ -115,7 +116,50 @@
-
+
+ Enhance API and SPI to make it usable as a proxy to native execution
+
+
+
+
+
+
+ There is new SPI for ProcessBuilder named
+ ProcessBuilderImplementation2 which now implements
+ Lookup.Provider to be extensible and provides
+ a separate Environment object represented by
+ the EnvironmentImplementation in the SPI.
+ The ProcessBuilder itself allows access to those
+ new features via getLookup() and
+ getEnvironment() methods and it now also
+ implements Lookup.Provider. The utility class
+ ProcessParameters wraps up the parameters passed
+ to the SPI for process creation. Instances of
+ Environment API are created via
+ EnvironmentFactory support class.
+
+
+ There are also new classes extending a Process
+ functionality named ProcessCharset,
+ ProcessId and ProcessSignal allowing
+ client to get the charset, to get ID and to send signal to
+ a process. This might not be always supported and the support
+ may be pre-checked.
+
+ The support API/SPI
+
+ allows enhancement of process with additional data such as ID, character set
+ and ability to send signals. Client can later easily check the feature is
+ supported and perform the query or action.
+
+
The SPI
allows different implementations of process builder.
@@ -170,8 +177,17 @@
+ The process returned by default or custom builders may support additional
+ features. To do so the process must be a Lookup.Provider and put
+ the implementation of the feature to lookup. The possible extensions are
+ located in org.netbeans.api.extexecution.process
+ package. The client then use static methods on respective classes in order
+ to use the extended functionality.
+
- No known platform dependencies. In future there could be need for native code
- in order to terminate the whole process tree created by execution of external
- process.
+ No known platform dependencies. The platform dependent way of process
+ termination is in a separate implementation module.
diff --git a/extexecution/nbproject/project.xml b/extexecution/nbproject/project.xml
--- a/extexecution/nbproject/project.xml
+++ b/extexecution/nbproject/project.xml
@@ -88,6 +88,7 @@
org.netbeans.api.extexecutionorg.netbeans.api.extexecution.print
+ org.netbeans.api.extexecution.processorg.netbeans.api.extexecution.inputorg.netbeans.api.extexecution.startuporg.netbeans.spi.extexecution
diff --git a/extexecution/src/org/netbeans/api/extexecution/Environment.java b/extexecution/src/org/netbeans/api/extexecution/Environment.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/api/extexecution/Environment.java
@@ -0,0 +1,156 @@
+/*
+ * 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.api.extexecution;
+
+import java.util.Map;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.modules.extexecution.EnvironmentAccessor;
+import org.netbeans.spi.extexecution.EnvironmentImplementation;
+import org.openide.util.Parameters;
+
+/**
+ * The class that provides an access to environment variables.
+ *
+ * @see ProcessBuilder#getEnvironment()
+ * @see EnvironmentImplementation
+ * @author Petr Hejl
+ * @since 1.37
+ */
+public final class Environment {
+
+ private final EnvironmentImplementation implementation;
+
+ static {
+ EnvironmentAccessor.setDefault(new EnvironmentAccessor() {
+
+ @Override
+ public Environment createEnvironment(EnvironmentImplementation impl) {
+ return new Environment(impl);
+ }
+ });
+ }
+
+ private Environment(EnvironmentImplementation implementation) {
+ this.implementation = implementation;
+ }
+
+ /**
+ * Returns the value of the variable or null.
+ *
+ * @param name the name of the variable
+ * @return the value of the variable or null
+ */
+ @CheckForNull
+ public String getVariable(@NonNull String name) {
+ Parameters.notNull("name", name);
+
+ return implementation.getVariable(name);
+ }
+
+ /**
+ * Appends a path to a path-like variable. The proper path separator is used
+ * to separate the new value.
+ *
+ * @param name the name of the variable such as for example
+ * PATH or LD_LIBRARY_PATH
+ * @param value the value (path to append)
+ */
+ public void appendPath(@NonNull String name, @NonNull String value) {
+ Parameters.notNull("name", name);
+ Parameters.notNull("value", value);
+
+ implementation.appendPath(name, value);
+ }
+
+ /**
+ * Prepends a path to a path-like variable. The proper path separator is used
+ * to separate the new value.
+ *
+ * @param name the name of the variable such as for example
+ * PATH or LD_LIBRARY_PATH
+ * @param value the value (path to prepend)
+ */
+ public void prependPath(@NonNull String name, @NonNull String value) {
+ Parameters.notNull("name", name);
+ Parameters.notNull("value", value);
+
+ implementation.prependPath(name, value);
+ }
+
+ /**
+ * Sets a value for a variable with the given name.
+ *
+ * @param name the name of the variable
+ * @param value the value
+ */
+ public void setVariable(@NonNull String name, @NonNull String value) {
+ Parameters.notNull("name", name);
+ Parameters.notNull("value", value);
+
+ implementation.setVariable(name, value);
+ }
+
+ /**
+ * Removes a variable with the given name. The subsequent call to
+ * {@link #getVariable(java.lang.String)} with the same argument will return
+ * null.
+ *
+ * @param name the name of the variable
+ */
+ public void removeVariable(@NonNull String name) {
+ Parameters.notNull("name", name);
+
+ implementation.removeVariable(name);
+ }
+
+ /**
+ * Returns all variable names and associated values as a {@link Map}.
+ * Changes to the map are not propagated back to the {@link Environment}.
+ *
+ * @return all variable names and associated values
+ */
+ @NonNull
+ public Map values() {
+ return implementation.values();
+ }
+}
diff --git a/extexecution/src/org/netbeans/api/extexecution/ExecutionService.java b/extexecution/src/org/netbeans/api/extexecution/ExecutionService.java
--- a/extexecution/src/org/netbeans/api/extexecution/ExecutionService.java
+++ b/extexecution/src/org/netbeans/api/extexecution/ExecutionService.java
@@ -52,6 +52,7 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
+import java.io.Writer;
import java.nio.charset.Charset;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -66,10 +67,12 @@
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.modules.extexecution.ProcessInputStream;
@@ -79,7 +82,9 @@
import org.netbeans.api.extexecution.input.InputProcessors;
import org.netbeans.api.extexecution.input.InputReaderTask;
import org.netbeans.api.extexecution.input.InputReaders;
+import org.netbeans.api.extexecution.input.LineProcessor;
import org.netbeans.api.extexecution.input.LineProcessors;
+import org.netbeans.api.extexecution.process.ProcessCharset;
import org.openide.util.Cancellable;
import org.openide.util.Mutex;
import org.openide.util.NbBundle;
@@ -91,20 +96,20 @@
* Execution service provides the facility to execute the process while
* displaying the output and handling the input.
*
- * It will execute the program with an associated I/O window, with stop and
- * restart buttons. It will also obey various descriptor properties such as
- * whether or not to show a progress bar.
+ * It will execute the program with an associated I/O window, possibly with
+ * stop and restart buttons. It will also obey various descriptor properties
+ * such as whether or not to show a progress bar.
*
* All processes launched by this class are terminated on VM exit (if
* these are not finished or terminated earlier).
*
- * Note that once service is run for the first time, subsequents runs can be
+ * Note that once service is run for the first time, subsequent runs can be
* invoked by the user (rerun button) if it is allowed to do so
* ({@link ExecutionDescriptor#isControllable()}).
*
*
*
* @author Petr Hejl
@@ -130,6 +143,21 @@
private static final ExecutorService EXECUTOR_SERVICE = new RequestProcessor(ExecutionService.class.getName(), Integer.MAX_VALUE);
+ private static final InputProcessor NULL_PROCESSOR = new InputProcessor() {
+
+ @Override
+ public void processInput(char[] chars) throws IOException {
+ }
+
+ @Override
+ public void reset() throws IOException {
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+ };
+
static {
// rerun accessor
RerunAction.Accessor.setDefault(new RerunAction.Accessor() {
@@ -156,16 +184,25 @@
});
}
- private final Callable processCreator;
+ private final Callable extends Process> processCreator;
private final ExecutionDescriptor descriptor;
private final String originalDisplayName;
- private ExecutionService(Callable processCreator, String displayName, ExecutionDescriptor descriptor) {
+ private final Reader processInput;
+
+ private final boolean rerunAllowed;
+
+ private final AtomicInteger runCount = new AtomicInteger();
+
+ private ExecutionService(Callable extends Process> processCreator, String displayName,
+ ExecutionDescriptor descriptor, Reader processInput, boolean rerunAllowed) {
this.processCreator = processCreator;
this.originalDisplayName = displayName;
this.descriptor = descriptor;
+ this.processInput = processInput;
+ this.rerunAllowed = rerunAllowed;
}
/**
@@ -178,24 +215,130 @@
* @return new execution service
*/
@NonNull
- public static ExecutionService newService(@NonNull Callable processCreator,
+ public static ExecutionService newService(@NonNull Callable extends Process> processCreator,
@NonNull ExecutionDescriptor descriptor, @NonNull String displayName) {
- return new ExecutionService(processCreator, displayName, descriptor);
+ return new ExecutionService(processCreator, displayName, descriptor, null, true);
+ }
+
+ /**
+ * Creates new execution service. Service will wrap up the processes
+ * created by processCreator and will manage them. The service
+ * may not be run more than once otherwise {@link IllegalStateException}
+ * is thrown on {@link #run()}. No UI will be displayed.
+ *
+ * Passed processInput will be implicitly closed when the execution (invoked by
+ * {@link #run()}) is finished. The client should not use the reader passed
+ * as argument anymore or the reader should be designed thread safe.
+ *
+ * @param processCreator callable returning the process to wrap up
+ * @param outputProcessor processor processing lines of standard output;
+ * may be null
+ * @param errorProcessor processor processing lines of standard error
+ * output; may be null
+ * @param processorInput reader providing input for standard input of
+ * the created process. Once passed it either should not be
+ * used anymore or it should be designed to be thread safe.
+ * May be null.
+ * @return new execution service
+ * @since 1.37
+ */
+ @NonNull
+ public static ExecutionService newService(@NonNull Callable extends Process> processCreator,
+ @NullAllowed final LineProcessor outputProcessor, @NullAllowed final LineProcessor errorProcessor,
+ @NullAllowed final Reader processorInput) {
+ ExecutionDescriptor descriptor = new ExecutionDescriptor()
+ .inputOutput(InputOutput.NULL);
+
+ if (outputProcessor != null) {
+ descriptor = descriptor.outProcessorFactory(new InputProcessorFactory() {
+ @Override
+ public InputProcessor newInputProcessor(InputProcessor defaultProcessor) {
+ return InputProcessors.bridge(outputProcessor);
+ }
+ });
+ }
+ if (errorProcessor != null) {
+ descriptor = descriptor.errProcessorFactory(new InputProcessorFactory() {
+ @Override
+ public InputProcessor newInputProcessor(InputProcessor defaultProcessor) {
+ return InputProcessors.bridge(errorProcessor);
+ }
+ });
+ }
+
+ return new ExecutionService(processCreator, null, descriptor, processorInput, false);
+ }
+
+ /**
+ * Creates new execution service. Service will wrap up the processes
+ * created by processCreator and will manage them. The service
+ * may not be run more than once otherwise {@link IllegalStateException}
+ * is thrown on {@link #run()}. No UI will be displayed.
+ *
+ * Passed inputWriter and errorWriter will be implicitly closed when the
+ * execution (invoked by {@link #run()}) is finished. The client either
+ * should not use the passed writers anymore or these should be designed
+ * to be thread safe.
+ *
+ * @param processCreator callable returning the process to wrap up
+ * @param outputWriter where to write standard output of the process. Once
+ * passed it either should not be used anymore or it should
+ * be designed to be thread safe. May be null.
+ * @param errorWriter where to write standard error output of the process.
+ * Once passed it either should not be used anymore or it should
+ * be designed to be thread safe. May be null.
+ * @return new execution service
+ * @since 1.37
+ */
+ public static ExecutionService newService(@NonNull Callable extends Process> processCreator,
+ @NullAllowed final Writer outputWriter, @NullAllowed final Writer errorWriter) {
+ ExecutionDescriptor descriptor = new ExecutionDescriptor()
+ .inputOutput(InputOutput.NULL);
+
+ if (outputWriter != null) {
+ descriptor = descriptor.outProcessorFactory(new InputProcessorFactory() {
+ @Override
+ public InputProcessor newInputProcessor(InputProcessor defaultProcessor) {
+ return InputProcessors.copying(outputWriter);
+ }
+ });
+ }
+ if (errorWriter != null) {
+ descriptor = descriptor.errProcessorFactory(new InputProcessorFactory() {
+ @Override
+ public InputProcessor newInputProcessor(InputProcessor defaultProcessor) {
+ return InputProcessors.copying(errorWriter);
+ }
+ });
+ }
+
+ return new ExecutionService(processCreator, null, descriptor, null, false);
}
/**
* Runs the process described by this service. The call does not block
* and the task is represented by the returned value. Integer returned
* as a result of the {@link Future} is exit code of the process.
+ * The ability to call this method multiple times depends on a way
+ * in which the service has been created. Only service created by
+ * {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.ExecutionDescriptor, java.lang.String)}
+ * may be run more than once.
*
* The output tabs are reused (if caller does not use the custom one,
- * see {@link ExecutionDescriptor#getInputOutput()}) - the tab to reuse
- * (if any) is selected by having the same name and same buttons
- * (control and option). If there is no output tab to reuse new one
- * is opened.
+ * see {@link ExecutionDescriptor#getInputOutput()} or if it is not being
+ * run without output tab, see {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.input.LineProcessor, org.netbeans.api.extexecution.input.LineProcessor, java.io.Reader)})
+ * - the tab to reuse (if any) is selected by having the same name
+ * and same buttons (control and option). If there is no output tab to
+ * reuse new one is opened.
*
- * This method can be invoked multiple times returning the different and
- * unrelated {@link Future}s. On each call Callable<Process>
+ * If the service has been created by {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.input.LineProcessor, org.netbeans.api.extexecution.input.LineProcessor, java.io.Reader)}
+ * this method may be called only once. Subsequent calls will cause an
+ * {@link IllegalStateException} to be thrown.
+ * If the service has been created by {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.ExecutionDescriptor, java.lang.String)}
+ * this method can be invoked multiple times returning the different and
+ * unrelated {@link Future}s.
+ *
+ * On each call Callable<Process>
* passed to {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.ExecutionDescriptor, java.lang.String)}
* is invoked in order to create the process. If the process creation fails
* (throwing an exception) returned Future will throw
@@ -213,6 +356,10 @@
}
private Future run(InputOutput required) {
+ if (!rerunAllowed && runCount.incrementAndGet() > 1) {
+ throw new IllegalStateException("Run invoked multimple times");
+ }
+
final InputOutputManager.InputOutputData ioData = getInputOutput(required);
final String displayName = ioData.getDisplayName();
@@ -220,9 +367,16 @@
final ProgressHandle handle = createProgressHandle(ioData.getInputOutput(), displayName, cancellable);
final InputOutput io = ioData.getInputOutput();
- final OutputWriter out = io.getOut();
- final OutputWriter err = io.getErr();
- final Reader in = io.getIn();
+ assert processInput == null || io == InputOutput.NULL;
+
+ final Reader in;
+ if (processInput != null) {
+ in = processInput;
+ } else if (descriptor.isInputVisible() && io != InputOutput.NULL) {
+ in = io.getIn();
+ } else {
+ in = null;
+ }
final CountDownLatch finishedLatch = new CountDownLatch(1);
@@ -267,23 +421,37 @@
outStream = new ProcessInputStream(process, process.getInputStream());
errStream = new ProcessInputStream(process, process.getErrorStream());
- executor = Executors.newFixedThreadPool(descriptor.isInputVisible() ? 3 : 2);
+ executor = Executors.newFixedThreadPool(in != null ? 3 : 2);
Charset charset = descriptor.getCharset();
+ Charset inputCharset = charset;
+ Charset outputCharset = charset;
+ Charset errorCharset = charset;
if (charset == null) {
- charset = Charset.defaultCharset();
+ inputCharset = ProcessCharset.getInputCharset(process);
+ outputCharset = ProcessCharset.getOutputCharset(process);
+ errorCharset = ProcessCharset.getErrorCharset(process);
+ }
+ if (inputCharset == null) {
+ inputCharset = Charset.defaultCharset();
+ }
+ if (outputCharset == null) {
+ outputCharset = Charset.defaultCharset();
+ }
+ if (errorCharset == null) {
+ errorCharset = Charset.defaultCharset();
}
tasks.add(InputReaderTask.newDrainingTask(
- InputReaders.forStream(new BufferedInputStream(outStream), charset),
- createOutProcessor(out)));
+ InputReaders.forStream(new BufferedInputStream(outStream), outputCharset),
+ createOutProcessor(io)));
tasks.add(InputReaderTask.newDrainingTask(
- InputReaders.forStream(new BufferedInputStream(errStream), charset),
- createErrProcessor(err)));
- if (descriptor.isInputVisible()) {
+ InputReaders.forStream(new BufferedInputStream(errStream), errorCharset),
+ createErrProcessor(io)));
+ if (in != null) {
tasks.add(InputReaderTask.newTask(
InputReaders.forReader(in),
- createInProcessor(process.getOutputStream())));
+ createInProcessor(process.getOutputStream(), inputCharset)));
}
for (InputReaderTask task : tasks) {
executor.submit(task);
@@ -568,15 +736,20 @@
Mutex.EVENT.readAccess(ui);
}
- private InputProcessor createOutProcessor(OutputWriter writer) {
- LineConvertorFactory convertorFactory = descriptor.getOutConvertorFactory();
+ private InputProcessor createOutProcessor(InputOutput io) {
InputProcessor outProcessor = null;
- if (descriptor.isOutLineBased()) {
- outProcessor = InputProcessors.bridge(LineProcessors.printing(writer,
- convertorFactory != null ? convertorFactory.newLineConvertor() : null, true));
+ if (io != InputOutput.NULL) {
+ LineConvertorFactory convertorFactory = descriptor.getOutConvertorFactory();
+ OutputWriter writer = io.getOut();
+ if (descriptor.isOutLineBased()) {
+ outProcessor = InputProcessors.bridge(LineProcessors.printing(writer,
+ convertorFactory != null ? convertorFactory.newLineConvertor() : null, true));
+ } else {
+ outProcessor = InputProcessors.printing(writer,
+ convertorFactory != null ? convertorFactory.newLineConvertor() : null, true);
+ }
} else {
- outProcessor = InputProcessors.printing(writer,
- convertorFactory != null ? convertorFactory.newLineConvertor() : null, true);
+ outProcessor = NULL_PROCESSOR;
}
InputProcessorFactory descriptorOutFactory = descriptor.getOutProcessorFactory();
@@ -587,15 +760,20 @@
return outProcessor;
}
- private InputProcessor createErrProcessor(OutputWriter writer) {
- LineConvertorFactory convertorFactory = descriptor.getErrConvertorFactory();
+ private InputProcessor createErrProcessor(InputOutput io) {
InputProcessor errProcessor = null;
- if (descriptor.isErrLineBased()) {
- errProcessor = InputProcessors.bridge(LineProcessors.printing(writer,
- convertorFactory != null ? convertorFactory.newLineConvertor() : null, false));
+ if (io != InputOutput.NULL) {
+ LineConvertorFactory convertorFactory = descriptor.getErrConvertorFactory();
+ OutputWriter writer = io.getErr();
+ if (descriptor.isErrLineBased()) {
+ errProcessor = InputProcessors.bridge(LineProcessors.printing(writer,
+ convertorFactory != null ? convertorFactory.newLineConvertor() : null, false));
+ } else {
+ errProcessor = InputProcessors.printing(writer,
+ convertorFactory != null ? convertorFactory.newLineConvertor() : null, false);
+ }
} else {
- errProcessor = InputProcessors.printing(writer,
- convertorFactory != null ? convertorFactory.newLineConvertor() : null, false);
+ errProcessor = NULL_PROCESSOR;
}
InputProcessorFactory descriptorErrFactory = descriptor.getErrProcessorFactory();
@@ -606,8 +784,8 @@
return errProcessor;
}
- private InputProcessor createInProcessor(OutputStream os) {
- return InputProcessors.copying(new OutputStreamWriter(os));
+ private InputProcessor createInProcessor(OutputStream os, Charset charset) {
+ return InputProcessors.copying(new OutputStreamWriter(os, charset));
}
private static class ProgressCancellable implements Cancellable {
diff --git a/extexecution/src/org/netbeans/api/extexecution/ExternalProcessBuilder.java b/extexecution/src/org/netbeans/api/extexecution/ExternalProcessBuilder.java
--- a/extexecution/src/org/netbeans/api/extexecution/ExternalProcessBuilder.java
+++ b/extexecution/src/org/netbeans/api/extexecution/ExternalProcessBuilder.java
@@ -100,6 +100,8 @@
private final Map envVariables = new HashMap();
+ private final boolean emptySystemVariables;
+
/**
* Creates the new builder that will create the process by running
* given executable. Arguments must not be part of the string.
@@ -117,6 +119,7 @@
this.arguments.addAll(builder.arguments);
this.paths.addAll(builder.paths);
this.envVariables.putAll(builder.envVariables);
+ this.emptySystemVariables = builder.emptySystemVariables;
}
/**
@@ -286,7 +289,13 @@
}
Map pbEnv = pb.environment();
- Map env = buildEnvironment(pbEnv);
+ Map env;
+ if (emptySystemVariables) {
+ pbEnv.clear();
+ env = new HashMap();
+ } else {
+ env = buildEnvironment(pbEnv);
+ }
pbEnv.putAll(env);
String uuid = UUID.randomUUID().toString();
pbEnv.put(WrapperProcess.KEY_UUID, uuid);
@@ -297,6 +306,11 @@
return wp;
}
+ ExternalProcessBuilder emptySystemVariables(boolean emptySystemVariables) {
+ BuilderData builder = new BuilderData(this);
+ return new ExternalProcessBuilder(builder.emptySystemVariables(emptySystemVariables));
+ }
+
/**
* Logs the given pb using the given level.
*
@@ -331,18 +345,7 @@
// Find PATH environment variable - on Windows it can be some other
// case and we should use whatever it has.
- String pathName = "PATH"; // NOI18N
-
- if (Utilities.isWindows()) {
- pathName = "Path"; // NOI18N
-
- for (String key : ret.keySet()) {
- if ("PATH".equals(key.toUpperCase(Locale.ENGLISH))) { // NOI18N
- pathName = key;
- break;
- }
- }
- }
+ String pathName = getPathName(original);
// TODO use StringBuilder
String currentPath = ret.get(pathName);
@@ -362,6 +365,7 @@
return ret;
}
+
// package level for unit testing
List buildArguments() {
if (!Utilities.isWindows()) {
@@ -378,6 +382,44 @@
return result;
}
+ static void putPath(File path, String pathName, boolean prepend, Map current) {
+ String currentPath = current.get(pathName);
+
+ if (currentPath == null) {
+ currentPath = "";
+ }
+
+ if (prepend) {
+ currentPath = path.getAbsolutePath().replace(" ", "\\ ") //NOI18N
+ + File.pathSeparator + currentPath;
+ } else {
+ currentPath = currentPath + File.pathSeparator
+ + path.getAbsolutePath().replace(" ", "\\ "); //NOI18N
+ }
+
+ if (!"".equals(currentPath.trim())) {
+ current.put(pathName, currentPath);
+ }
+ }
+
+ static String getPathName(Map systemEnv) {
+ // Find PATH environment variable - on Windows it can be some other
+ // case and we should use whatever it has.
+ String pathName = "PATH"; // NOI18N
+
+ if (Utilities.isWindows()) {
+ pathName = "Path"; // NOI18N
+
+ for (String keySystem : systemEnv.keySet()) {
+ if ("PATH".equals(keySystem.toUpperCase(Locale.ENGLISH))) { // NOI18N
+ pathName = keySystem;
+ break;
+ }
+ }
+ }
+ return pathName;
+ }
+
private static String escapeString(String s) {
if (s.length() == 0) {
return "\"\""; // NOI18N
@@ -475,6 +517,8 @@
private Map envVariables = new HashMap();
+ private boolean emptySystemVariables;
+
public BuilderData(String executable) {
this.executable = executable;
}
@@ -486,6 +530,7 @@
this.arguments.addAll(builder.arguments);
this.paths.addAll(builder.paths);
this.envVariables.putAll(builder.envVariables);
+ this.emptySystemVariables = builder.emptySystemVariables;
}
public BuilderData workingDirectory(File workingDirectory) {
@@ -521,6 +566,11 @@
envVariables.put(name, value);
return this;
}
+
+ public BuilderData emptySystemVariables(boolean emptySystemVariables) {
+ this.emptySystemVariables = emptySystemVariables;
+ return this;
+ }
}
diff --git a/extexecution/src/org/netbeans/api/extexecution/ProcessBuilder.java b/extexecution/src/org/netbeans/api/extexecution/ProcessBuilder.java
--- a/extexecution/src/org/netbeans/api/extexecution/ProcessBuilder.java
+++ b/extexecution/src/org/netbeans/api/extexecution/ProcessBuilder.java
@@ -46,12 +46,19 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Callable;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.modules.extexecution.ProcessBuilderAccessor;
+import org.netbeans.modules.extexecution.ProcessParametersAccessor;
+import org.netbeans.spi.extexecution.EnvironmentFactory;
+import org.netbeans.spi.extexecution.EnvironmentImplementation;
import org.netbeans.spi.extexecution.ProcessBuilderImplementation;
+import org.netbeans.spi.extexecution.ProcessBuilderImplementation2;
+import org.netbeans.spi.extexecution.ProcessParameters;
+import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.Parameters;
import org.openide.util.UserQuestionException;
@@ -68,35 +75,49 @@
* for creating the local machine OS processes.
*
* Thread safety of this class depends on thread safety of
- * the {@link ProcessBuilderImplementation} the class is using. If it is thread
+ * the implementation class.
+ *
+ * If the {@link ProcessBuilderImplementation} is used and it is thread
* safe (if possible the implementation should be even stateless) this class
* is thread safe as well.
+ *
+ * If the {@link ProcessBuilderImplementation2} is used and it is (including
+ * {@link EnvironmentImplementation}) thread safe and does not have any mutable
+ * configuration accessible via {@link ProcessBuilderImplementation2#getLookup()}
+ * it is thread safe as well. Otherwise it is not thread safe.
+ *
+ * The synchronization mechanism use in this object is the {@link ProcessBuilderImplementation}
+ * or {@link ProcessBuilderImplementation2} object monitor.
*
* @author Petr Hejl
* @since 1.28
*/
-public final class ProcessBuilder implements Callable {
+public final class ProcessBuilder implements Callable, Lookup.Provider {
private final ProcessBuilderImplementation implementation;
+ private final ProcessBuilderImplementation2 implementation2;
+
+ private final Object lock;
+
private final String description;
- /**GuardedBy("this")*/
+ /**GuardedBy("lock")*/
private String executable;
- /**GuardedBy("this")*/
+ /**GuardedBy("lock")*/
private String workingDirectory;
- /**GuardedBy("this")*/
+ /**GuardedBy("lock")*/
private List arguments = new ArrayList();
- /**GuardedBy("this")*/
+ /**GuardedBy("lock")*/
private List paths = new ArrayList();
- /**GuardedBy("this")*/
+ /**GuardedBy("lock")*/
private Map envVariables = new HashMap();
- /**GuardedBy("this")*/
+ /**GuardedBy("lock")*/
private boolean redirectErrorStream;
static {
@@ -106,12 +127,32 @@
public ProcessBuilder createProcessBuilder(ProcessBuilderImplementation impl, String description) {
return new ProcessBuilder(impl, description);
}
+
+ @Override
+ public ProcessBuilder createProcessBuilder(ProcessBuilderImplementation2 impl, String description) {
+ return new ProcessBuilder(impl, description);
+ }
});
}
private ProcessBuilder(ProcessBuilderImplementation implementation, String description) {
+ this(implementation, null, description);
+ }
+
+ private ProcessBuilder(ProcessBuilderImplementation2 implementation2, String description) {
+ this(null, implementation2, description);
+ }
+
+ private ProcessBuilder(ProcessBuilderImplementation implementation, ProcessBuilderImplementation2 implementation2, String description) {
+ assert implementation == null || implementation2 == null;
this.implementation = implementation;
+ this.implementation2 = implementation2;
this.description = description;
+ if (implementation != null) {
+ lock = implementation;
+ } else {
+ lock = implementation2;
+ }
}
/**
@@ -122,7 +163,7 @@
* machine
*/
public static ProcessBuilder getLocal() {
- return new ProcessBuilder(new LocalProcessFactory(),
+ return new ProcessBuilder(new LocalProcessBuilder(),
NbBundle.getMessage(ProcessBuilder.class, "LocalProcessBuilder"));
}
@@ -146,7 +187,7 @@
public void setExecutable(@NonNull String executable) {
Parameters.notNull("executable", executable);
- synchronized (this) {
+ synchronized (lock) {
this.executable = executable;
}
}
@@ -158,7 +199,7 @@
* @param workingDirectory the working directory of the process
*/
public void setWorkingDirectory(@NullAllowed String workingDirectory) {
- synchronized (this) {
+ synchronized (lock) {
this.workingDirectory = workingDirectory;
}
}
@@ -172,7 +213,7 @@
public void setArguments(@NonNull List arguments) {
Parameters.notNull("arguments", arguments);
- synchronized (this) {
+ synchronized (lock) {
this.arguments.clear();
this.arguments.addAll(arguments);
}
@@ -184,11 +225,20 @@
* exception of PATH possibly configured by {@link #setPaths(java.util.List)}.
*
* @param envVariables the environment variables for the process
+ * @deprecated use {@link Environment#setVariable(java.lang.String, java.lang.String)}
+ * on object received by {@link #getEnvironment()} call
*/
public void setEnvironmentVariables(@NonNull Map envVariables) {
Parameters.notNull("envVariables", envVariables);
- synchronized (this) {
+ if (implementation2 != null) {
+ for (Map.Entry entry : envVariables.entrySet()) {
+ implementation2.getEnvironment().setVariable(entry.getKey(), entry.getValue());
+ }
+ return;
+ }
+
+ synchronized (lock) {
this.envVariables.clear();
this.envVariables.putAll(envVariables);
}
@@ -196,15 +246,32 @@
/**
* Sets the additional paths to be included in PATH environment
- * variable for the process.
+ * variable for the process. The paths are prepended to the PATH variable
+ * one by one as specified in the list so in fact the last path in
+ * the list will be the first one in the PATH variable.
+ *
+ * This method is semi-deprecated. If {@link #getEnvironment()} is not
+ * null this call adds paths one by one by call to
+ * {@link Environment#prependPath(java.lang.String, java.lang.String)}
+ * on returned object.
*
* @param paths the additional paths to be included in PATH
* environment variable
+ * @deprecated use {@link Environment#prependPath(java.lang.String, java.lang.String)}
+ * on object received by {@link #getEnvironment()} call, with
+ * the first argument being PATH
*/
public void setPaths(@NonNull List paths) {
Parameters.notNull("paths", paths);
- synchronized (this) {
+ if (implementation2 != null) {
+ for (String path : paths) {
+ implementation2.getEnvironment().prependPath("PATH", path); // NOI18N
+ }
+ return;
+ }
+
+ synchronized (lock) {
this.paths.clear();
this.paths.addAll(paths);
}
@@ -218,12 +285,86 @@
* @param redirectErrorStream the error stream redirection
*/
public void setRedirectErrorStream(boolean redirectErrorStream) {
- synchronized (this) {
+ synchronized (lock) {
this.redirectErrorStream = redirectErrorStream;
}
}
/**
+ * Returns the object for environment variables manipulation.
+ *
+ * @return the object for environment variables manipulation
+ * @since 1.37
+ */
+ @NonNull
+ public Environment getEnvironment() {
+ if (implementation2 != null) {
+ return implementation2.getEnvironment();
+ }
+ return EnvironmentFactory.createEnvironment(new EnvironmentImplementation() {
+
+ @Override
+ public void prependPath(String name, String value) {
+ if (!name.equalsIgnoreCase("PATH")) { // NOI18N
+ throw new UnsupportedOperationException("The deprecated implementation "
+ + implementation.getClass().getName() + "does not support this method for a non PATH variable.");
+ }
+ synchronized (lock) {
+ paths.add(0, value);
+ }
+ }
+
+ @Override
+ public void setVariable(String name, String value) {
+ synchronized (lock) {
+ envVariables.put(name, value);
+ }
+ }
+
+ @Override
+ public String getVariable(String name) {
+ throw new UnsupportedOperationException("The deprecated implementation "
+ + implementation.getClass().getName() + "does not support this method.");
+ }
+
+ @Override
+ public void appendPath(String name, String value) {
+ throw new UnsupportedOperationException("The deprecated implementation "
+ + implementation.getClass().getName() + "does not support this method.");
+ }
+
+ @Override
+ public void removeVariable(String name) {
+ throw new UnsupportedOperationException("The deprecated implementation "
+ + implementation.getClass().getName() + "does not support this method.");
+ }
+
+ @Override
+ public Map values() {
+ throw new UnsupportedOperationException("The deprecated implementation "
+ + implementation.getClass().getName() + "does not support this method.");
+ }
+ });
+ }
+
+ /**
+ * Returns the associated {@link Lookup}. Extension point provided by
+ * {@link ProcessBuilderImplementation2}.
+ *
+ * @return the associated {@link Lookup}.
+ * @see ProcessBuilderImplementation2#getLookup()
+ * @since 1.37
+ */
+ @Override
+ public Lookup getLookup() {
+ if (implementation2 != null) {
+ return implementation2.getLookup();
+ }
+ return Lookup.EMPTY;
+ }
+
+
+ /**
* Creates the new {@link Process} based on the properties configured
* in this builder.
*
@@ -232,7 +373,7 @@
*
* Since version 1.35 implementors of this method are advised to throw
* a {@link UserQuestionException} in case the execution cannot be
- * performed and requires additional user confirmation, or configuration.
+ * performed and requires additional user confirmation, or configuration.
* Callers of this method may check for this exception and handle it
* appropriately.
*
@@ -248,52 +389,168 @@
@NonNull
@Override
public Process call() throws IOException {
- String currentExecutable = null;
- String currentWorkingDirectory = null;
+ String currentExecutable;
+ String currentWorkingDirectory;
List currentArguments = new ArrayList();
List currentPaths = new ArrayList();
- Map currentEnvVariables = new HashMap();
- boolean currentRedirectErrorStream = false;
+ Map currentVariables = new HashMap();
+ boolean currentRedirectErrorStream;
- synchronized (this) {
+ synchronized (lock) {
currentExecutable = executable;
currentWorkingDirectory = workingDirectory;
currentArguments.addAll(arguments);
currentPaths.addAll(paths);
- currentEnvVariables.putAll(envVariables);
currentRedirectErrorStream = redirectErrorStream;
+ if (implementation2 != null) {
+ currentVariables.putAll(getEnvironment().values());
+ } else {
+ currentVariables.putAll(envVariables);
+ }
}
if (currentExecutable == null) {
throw new IllegalStateException("The executable has not been configured");
}
+ if (implementation2 != null) {
+ ProcessParameters params = ProcessParametersAccessor.getDefault().createProcessParameters(
+ currentExecutable, currentWorkingDirectory, currentArguments,
+ currentRedirectErrorStream, currentVariables);
+ return implementation2.createProcess(params);
+ }
+
return implementation.createProcess(currentExecutable, currentWorkingDirectory, currentArguments,
- currentPaths, currentEnvVariables, currentRedirectErrorStream);
+ currentPaths, currentVariables, currentRedirectErrorStream);
}
- private static class LocalProcessFactory implements ProcessBuilderImplementation {
+ /**
+ * Marks an object from which it is possible to get a {@link ProcessBuilder}.
+ *
+ * @since 1.37
+ */
+ public static interface Provider {
+
+ /**
+ * Returns the {@link ProcessBuilder} for the object.
+ *
+ * @return the {@link ProcessBuilder} for the object
+ * @throws IOException if there was a problem with the provision
+ */
+ ProcessBuilder getProcessBuilder() throws IOException;
+
+ }
+
+ private static class LocalProcessBuilder implements ProcessBuilderImplementation2 {
+
+ private final Environment environment = EnvironmentFactory.createEnvironment(
+ new LocalEnvironment(this, System.getenv()));
@Override
- public Process createProcess(String executable, String workingDirectory, List arguments,
- List paths, Map environment, boolean redirectErrorStream) throws IOException {
+ public Environment getEnvironment() {
+ return environment;
+ }
- ExternalProcessBuilder builder = new ExternalProcessBuilder(executable);
- if (workingDirectory != null) {
- builder = builder.workingDirectory(new File(workingDirectory));
+ @Override
+ public Lookup getLookup() {
+ return Lookup.EMPTY;
+ }
+
+ @Override
+ public Process createProcess(ProcessParameters parameters) throws IOException {
+ ExternalProcessBuilder builder = new ExternalProcessBuilder(parameters.getExecutable());
+ String workingDir = parameters.getWorkingDirectory();
+ if (workingDir != null) {
+ builder = builder.workingDirectory(new File(workingDir));
}
- for (String argument : arguments) {
+ for (String argument : parameters.getArguments()) {
builder = builder.addArgument(argument);
}
- for (String path : paths) {
- builder = builder.prependPath(new File(path));
- }
- for (Map.Entry entry : environment.entrySet()) {
+ builder = builder.redirectErrorStream(parameters.isRedirectErrorStream());
+
+ builder = builder.emptySystemVariables(true);
+ for (Map.Entry entry : parameters.getEnvironmentVariables().entrySet()) {
builder = builder.addEnvironmentVariable(entry.getKey(), entry.getValue());
}
- builder = builder.redirectErrorStream(redirectErrorStream);
return builder.call();
}
}
+
+ private static class LocalEnvironment implements EnvironmentImplementation {
+
+ private final LocalProcessBuilder builder;
+
+ private final Map systemEnvironment;
+
+ private final String pathName;
+
+ public LocalEnvironment(LocalProcessBuilder builder, Map systemEnvironment) {
+ this.builder = builder;
+ this.systemEnvironment = new HashMap(systemEnvironment);
+ this.pathName = ExternalProcessBuilder.getPathName(systemEnvironment);
+ }
+
+ @Override
+ public String getVariable(String name) {
+ synchronized (builder) {
+ if ("PATH".equals(name.toUpperCase(Locale.ENGLISH))) { // NOI18N
+ return systemEnvironment.get(pathName);
+ } else {
+ return systemEnvironment.get(name);
+ }
+ }
+ }
+
+ @Override
+ public void appendPath(String name, String value) {
+ putPath(name, value, false);
+ }
+
+ @Override
+ public void prependPath(String name, String value) {
+ putPath(name, value, true);
+ }
+
+ @Override
+ public void setVariable(String name, String value) {
+ synchronized (builder) {
+ if ("PATH".equals(name.toUpperCase(Locale.ENGLISH))) { // NOI18N
+ systemEnvironment.put(pathName, value);
+ } else {
+ systemEnvironment.put(name, value);
+ }
+ }
+ }
+
+ @Override
+ public void removeVariable(String name) {
+ synchronized (builder) {
+ if ("PATH".equals(name.toUpperCase(Locale.ENGLISH))) { // NOI18N
+ systemEnvironment.remove(pathName);
+ } else {
+ systemEnvironment.remove(name);
+ }
+ }
+ }
+
+ @Override
+ public Map values() {
+ synchronized (builder) {
+ return new HashMap(systemEnvironment);
+ }
+ }
+
+ private void putPath(String name, String value, boolean prepend) {
+ synchronized (builder) {
+ if ("PATH".equals(name.toUpperCase(Locale.ENGLISH))) { // NOI18N
+ ExternalProcessBuilder.putPath(new File(value), pathName,
+ prepend, systemEnvironment);
+ } else {
+ ExternalProcessBuilder.putPath(new File(value), name,
+ prepend, systemEnvironment);
+ }
+ }
+ }
+ }
}
diff --git a/extexecution/src/org/netbeans/api/extexecution/input/InputReaders.java b/extexecution/src/org/netbeans/api/extexecution/input/InputReaders.java
--- a/extexecution/src/org/netbeans/api/extexecution/input/InputReaders.java
+++ b/extexecution/src/org/netbeans/api/extexecution/input/InputReaders.java
@@ -46,6 +46,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.io.StringReader;
import java.nio.charset.Charset;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NonNull;
@@ -82,6 +83,12 @@
*/
@NonNull
public static InputReader forReader(@NonNull Reader reader) {
+ if (reader instanceof StringReader) {
+ // unfortunatelly the string reader is always
+ // ready (isReady() returns true) which I would consider a bug
+ // when end of string is reached
+ return new DefaultInputReader(reader, false);
+ }
return new DefaultInputReader(reader, true);
}
diff --git a/extexecution/src/org/netbeans/api/extexecution/process/ProcessCharset.java b/extexecution/src/org/netbeans/api/extexecution/process/ProcessCharset.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/api/extexecution/process/ProcessCharset.java
@@ -0,0 +1,169 @@
+/*
+ * 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.api.extexecution.process;
+
+import java.nio.charset.Charset;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.openide.util.Lookup;
+import org.openide.util.Parameters;
+
+/**
+ * This class allows client to get input and output charset of
+ * the {@link Process}. Though the process charsets might not be always
+ * supported.
+ *
+ * If the {@link Process} implementation wants to support charsets it has to
+ * implement {@link Lookup.Provider} and there has to be instance of this class
+ * in the returned {@link Lookup}. The functionality itself is implemented in
+ * methods {@link #getInputCharset()} and {@link #getOutputCharset()}.
+ *
+ * @author Petr Hejl
+ * @since 1.37
+ */
+public abstract class ProcessCharset {
+
+ private static ProcessCharset find(Process process) {
+ if (process instanceof Lookup.Provider) {
+ Lookup.Provider p = (Lookup.Provider) process;
+ return p.getLookup().lookup(ProcessCharset.class);
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the getting of charsets of the {@link Process} is supported.
+ * If the return value is false methods
+ * {@link #getInputCharset(java.lang.Process)} and {@link #getOutputCharset(java.lang.Process)}
+ * will return null for sure.
+ *
+ * @param process the process to check
+ * @return true if process charsets can be received false
+ * otherwise
+ */
+ public static boolean isSupported(@NonNull Process process) {
+ Parameters.notNull("process", process);
+
+ return find(process) != null;
+ }
+
+ /**
+ * Returns the input charset of the process if supported. In case it is not
+ * supported or the process can't determine the charset null is
+ * returned.
+ *
+ * @param process the process
+ * @return the input charset of the process or null
+ */
+ @CheckForNull
+ public static Charset getInputCharset(@NonNull Process process) {
+ Parameters.notNull("process", process);
+
+ ProcessCharset processCharset = find(process);
+ if (processCharset != null) {
+ return processCharset.getInputCharset();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the output charset of the process if supported. In case it is not
+ * supported or the process can't determine the charset null is
+ * returned.
+ *
+ * @param process the process
+ * @return the output charset of the process or null
+ */
+ @CheckForNull
+ public static Charset getOutputCharset(@NonNull Process process) {
+ Parameters.notNull("process", process);
+
+ ProcessCharset processCharset = find(process);
+ if (processCharset != null) {
+ return processCharset.getOutputCharset();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the error output charset of the process if supported. In case it
+ * is not supported or the process can't determine the charset null
+ * is returned.
+ *
+ * @param process the process
+ * @return the error output charset of the process or null
+ */
+ @CheckForNull
+ public static Charset getErrorCharset(@NonNull Process process) {
+ Parameters.notNull("process", process);
+
+ ProcessCharset processCharset = find(process);
+ if (processCharset != null) {
+ return processCharset.getErrorCharset();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the input charset of a process or null.
+ *
+ * @return input charset of a process or null
+ */
+ @CheckForNull
+ protected abstract Charset getInputCharset();
+
+ /**
+ * Returns the output charset of a process or null.
+ *
+ * @return output charset of a process or null
+ */
+ @CheckForNull
+ protected abstract Charset getOutputCharset();
+
+ /**
+ * Returns the error output charset of a process or null.
+ *
+ * @return error output charset of a process or null
+ */
+ @CheckForNull
+ protected abstract Charset getErrorCharset();
+}
diff --git a/extexecution/src/org/netbeans/api/extexecution/process/ProcessId.java b/extexecution/src/org/netbeans/api/extexecution/process/ProcessId.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/api/extexecution/process/ProcessId.java
@@ -0,0 +1,111 @@
+/*
+ * 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.api.extexecution.process;
+
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.openide.util.Lookup;
+import org.openide.util.Parameters;
+
+/**
+ * This class allows client to request ID of the {@link Process}. Though
+ * the process ID might not be always supported.
+ *
+ * If the {@link Process} implementation wants to support the ID it has to
+ * implement {@link Lookup.Provider} and there has to be instance of this class
+ * in the returned {@link Lookup}. The functionality itself is implemented in
+ * method {@link #getId()}.
+ *
+ * @author Petr Hejl
+ * @since 1.37
+ */
+public abstract class ProcessId {
+
+ private static ProcessId find(Process process) {
+ if (process instanceof Lookup.Provider) {
+ Lookup.Provider p = (Lookup.Provider) process;
+ return p.getLookup().lookup(ProcessId.class);
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the getting of the ID of the {@link Process} is supported.
+ * If the return value is false the {@link #getId(java.lang.Process)}
+ * will return null for sure.
+ *
+ * @param process the process to check
+ * @return true if the ID can be received false
+ * otherwise
+ */
+ public static boolean isSupported(@NonNull Process process) {
+ Parameters.notNull("process", process);
+
+ return find(process) != null;
+ }
+
+ /**
+ * Returns the ID of the process if supported. In case it is not supported
+ * or the process can't determine its ID null is returned.
+ *
+ * @param process the process
+ * @return the process ID or null
+ */
+ @CheckForNull
+ public static Integer getId(@NonNull Process process) {
+ Parameters.notNull("process", process);
+
+ ProcessId processId = find(process);
+ if (processId != null) {
+ return processId.getId();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the ID of a process or null.
+ *
+ * @return ID of a process or null
+ */
+ @CheckForNull
+ protected abstract Integer getId();
+}
diff --git a/extexecution/src/org/netbeans/api/extexecution/process/ProcessSignal.java b/extexecution/src/org/netbeans/api/extexecution/process/ProcessSignal.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/api/extexecution/process/ProcessSignal.java
@@ -0,0 +1,181 @@
+/*
+ * 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.api.extexecution.process;
+
+import java.io.IOException;
+import org.netbeans.api.annotations.common.NonNull;
+import org.openide.util.Lookup;
+import org.openide.util.Parameters;
+
+/**
+ * This class allows client send a signal to the {@link Process} or to whole
+ * its group. Though signal sending might not be always supported.
+ *
+ * If the {@link Process} implementation wants to support the signal sending
+ * it has to implement {@link Lookup.Provider} and there has to be instance
+ * of this class in the returned {@link Lookup}. The functionality itself is
+ * implemented in methods {@link #signal(org.netbeans.api.extexecution.process.ProcessSignal.Signal)}
+ * and {@link #signalGroup(org.netbeans.api.extexecution.process.ProcessSignal.Signal)}.
+ *
+ * @author Petr Hejl
+ * @since 1.37
+ */
+public abstract class ProcessSignal {
+
+ private static ProcessSignal find(Process process) {
+ if (process instanceof Lookup.Provider) {
+ Lookup.Provider p = (Lookup.Provider) process;
+ return p.getLookup().lookup(ProcessSignal.class);
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the signal sending is supported for the {@link Process}.
+ * If the return value is false the signal operations are
+ * effectively noops.
+ *
+ * @param process the process to check
+ * @return true if the signals can be send false
+ * otherwise
+ */
+ public static boolean isSupported(@NonNull Process process) {
+ Parameters.notNull("process", process);
+
+ return find(process) != null;
+ }
+
+ /**
+ * Sends a signal to the process. If the signal sending is not supported
+ * this is effectively noop.
+ *
+ * @param process the process where to send signal
+ * @param signal the signal to send
+ * @throws IOException if problem with signal sending occurs
+ */
+ public static void signal(@NonNull Process process, @NonNull Signal signal) throws IOException {
+ Parameters.notNull("process", process);
+ Parameters.notNull("signal", signal);
+
+ ProcessSignal processSignal = find(process);
+ if (processSignal != null) {
+ processSignal.signal(signal);
+ }
+ }
+
+ /**
+ * Sends a signal to the group the process belongs to. If the signal sending
+ * is not supported this is effectively noop.
+ *
+ * @param process the process marking the group where to send signal
+ * @param signal the signal to send
+ * @throws IOException if problem with signal sending occurs
+ */
+ public static void signalGroup(@NonNull Process process, @NonNull Signal signal) throws IOException {
+ Parameters.notNull("process", process);
+ Parameters.notNull("signal", signal);
+
+ ProcessSignal processSignal = find(process);
+ if (processSignal != null) {
+ processSignal.signalGroup(signal);
+ }
+ }
+
+ /**
+ * Sends a given signal to the process.
+ *
+ * @param signal the signal to send
+ * @throws IOException if problem with signal sending occurs
+ */
+ protected abstract void signal(@NonNull Signal signal) throws IOException;
+
+ /**
+ * Sends a given signal to the group the process belongs to.
+ *
+ * @param signal the signal to send
+ * @throws IOException if problem with signal sending occurs
+ */
+ protected abstract void signalGroup(@NonNull Signal signal) throws IOException;
+
+ public enum Signal {
+
+ NULL,
+ SIGHUP,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGEMT,
+ SIGFPE,
+ SIGKILL,
+ SIGBUS,
+ SIGSEGV,
+ SIGSYS,
+ SIGPIPE,
+ SIGALRM,
+ SIGTERM,
+ SIGUSR1,
+ SIGUSR2,
+ SIGCHLD,
+ SIGPWR,
+ SIGWINCH,
+ SIGURG,
+ SIGPOLL,
+ SIGSTOP,
+ SIGTSTP,
+ SIGCONT,
+ SIGTTIN,
+ SIGTTOU,
+ SIGVTALRM,
+ SIGPROF,
+ SIGXCPU,
+ SIGWAITING,
+ SIGLWP,
+ SIGFREEZE,
+ SIGTHAW,
+ SIGCANCEL,
+ SIGLOST,
+ SIGXRES,
+ SIGJVM1;
+ }
+}
diff --git a/extexecution/src/org/netbeans/api/extexecution/process/package-info.java b/extexecution/src/org/netbeans/api/extexecution/process/package-info.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/api/extexecution/process/package-info.java
@@ -0,0 +1,50 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-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]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+/**
+ * The API supporting enhanced functionality for
+ * a {@link java.lang.Process}.
+ */
+package org.netbeans.api.extexecution.process;
+
diff --git a/extexecution/src/org/netbeans/modules/extexecution/EnvironmentAccessor.java b/extexecution/src/org/netbeans/modules/extexecution/EnvironmentAccessor.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/modules/extexecution/EnvironmentAccessor.java
@@ -0,0 +1,81 @@
+/*
+ * 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.extexecution;
+
+import org.netbeans.api.extexecution.Environment;
+import org.netbeans.spi.extexecution.EnvironmentImplementation;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public abstract class EnvironmentAccessor {
+
+ private static volatile EnvironmentAccessor DEFAULT;
+
+ public static EnvironmentAccessor getDefault() {
+ EnvironmentAccessor a = DEFAULT;
+ if (a != null) {
+ return a;
+ }
+
+ // invokes static initializer of Environment.class
+ // that will assign value to the DEFAULT field above
+ Class c = Environment.class;
+ try {
+ Class.forName(c.getName(), true, c.getClassLoader());
+ } catch (ClassNotFoundException ex) {
+ assert false : ex;
+ }
+ return DEFAULT;
+ }
+
+ public static void setDefault(EnvironmentAccessor accessor) {
+ if (DEFAULT != null) {
+ throw new IllegalStateException();
+ }
+
+ DEFAULT = accessor;
+ }
+
+ public abstract Environment createEnvironment(EnvironmentImplementation impl);
+}
diff --git a/extexecution/src/org/netbeans/modules/extexecution/ProcessBuilderAccessor.java b/extexecution/src/org/netbeans/modules/extexecution/ProcessBuilderAccessor.java
--- a/extexecution/src/org/netbeans/modules/extexecution/ProcessBuilderAccessor.java
+++ b/extexecution/src/org/netbeans/modules/extexecution/ProcessBuilderAccessor.java
@@ -42,6 +42,7 @@
package org.netbeans.modules.extexecution;
import org.netbeans.spi.extexecution.ProcessBuilderImplementation;
+import org.netbeans.spi.extexecution.ProcessBuilderImplementation2;
/**
*
@@ -78,4 +79,7 @@
public abstract org.netbeans.api.extexecution.ProcessBuilder createProcessBuilder(
ProcessBuilderImplementation impl, String description);
+
+ public abstract org.netbeans.api.extexecution.ProcessBuilder createProcessBuilder(
+ ProcessBuilderImplementation2 impl, String description);
}
diff --git a/extexecution/src/org/netbeans/modules/extexecution/ProcessParametersAccessor.java b/extexecution/src/org/netbeans/modules/extexecution/ProcessParametersAccessor.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/modules/extexecution/ProcessParametersAccessor.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.extexecution;
+
+import java.util.List;
+import java.util.Map;
+import org.netbeans.spi.extexecution.ProcessParameters;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public abstract class ProcessParametersAccessor {
+
+ private static volatile ProcessParametersAccessor DEFAULT;
+
+ public static ProcessParametersAccessor getDefault() {
+ ProcessParametersAccessor a = DEFAULT;
+ if (a != null) {
+ return a;
+ }
+
+ // invokes static initializer of ProcessParameters.class
+ // that will assign value to the DEFAULT field above
+ Class c = ProcessParameters.class;
+ try {
+ Class.forName(c.getName(), true, c.getClassLoader());
+ } catch (ClassNotFoundException ex) {
+ assert false : ex;
+ }
+ return DEFAULT;
+ }
+
+ public static void setDefault(ProcessParametersAccessor accessor) {
+ if (DEFAULT != null) {
+ throw new IllegalStateException();
+ }
+
+ DEFAULT = accessor;
+ }
+
+ public abstract ProcessParameters createProcessParameters(String executable,
+ String workingDirectory, List arguments, boolean redirectErrorStream,
+ Map environmentVariables);
+}
diff --git a/extexecution/src/org/netbeans/spi/extexecution/EnvironmentFactory.java b/extexecution/src/org/netbeans/spi/extexecution/EnvironmentFactory.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/spi/extexecution/EnvironmentFactory.java
@@ -0,0 +1,69 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 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 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.spi.extexecution;
+
+import org.netbeans.api.extexecution.Environment;
+import org.netbeans.modules.extexecution.EnvironmentAccessor;
+
+/**
+ * The factory allowing SPI implementors of {@link EnvironmentImplementation}
+ * to create its API instances {@link Environment}.
+ *
+ * @author Petr Hejl
+ * @since 1.37
+ */
+public class EnvironmentFactory {
+
+ private EnvironmentFactory() {
+ super();
+ }
+
+ /**
+ * Creates the instance of {@link Environment} from its SPI representation.
+ *
+ * @param impl SPI representation
+ * @return the API instance
+ */
+ public static Environment createEnvironment(EnvironmentImplementation impl) {
+ return EnvironmentAccessor.getDefault().createEnvironment(impl);
+ }
+}
diff --git a/extexecution/src/org/netbeans/spi/extexecution/EnvironmentImplementation.java b/extexecution/src/org/netbeans/spi/extexecution/EnvironmentImplementation.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/spi/extexecution/EnvironmentImplementation.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.spi.extexecution;
+
+import java.util.Map;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.extexecution.Environment;
+
+/**
+ * The interface representing the implementation
+ * of {@link org.netbeans.api.extexecution.Environment}.
+ *
+ * @see Environment
+ * @author Petr Hejl
+ * @since 1.37
+ */
+public interface EnvironmentImplementation {
+
+ /**
+ * Returns the value of the variable or null.
+ *
+ * @param name the name of the variable
+ * @return the value of the variable or null
+ */
+ @CheckForNull
+ String getVariable(@NonNull String name);
+
+ /**
+ * Appends a path to a path-like variable. The proper path separator should
+ * be used to separate the new value.
+ *
+ * @param name the name of the variable such as for example
+ * PATH or LD_LIBRARY_PATH
+ * @param value the value (path to append)
+ */
+ void appendPath(@NonNull String name, @NonNull String value);
+
+ /**
+ * Prepends a path to a path-like variable. The proper path separator should
+ * be used to separate the new value.
+ *
+ * @param name the name of the variable such as for example
+ * PATH or LD_LIBRARY_PATH
+ * @param value the value (path to prepend)
+ */
+ void prependPath(@NonNull String name, @NonNull String value);
+
+ /**
+ * Sets a value for a variable with the given name.
+ *
+ * @param name the name of the variable
+ * @param value the value
+ */
+ void setVariable(@NonNull String name, @NonNull String value);
+
+ /**
+ * Removes a variable with the given name. The subsequent call to
+ * {@link #getVariable(java.lang.String)} with the same argument should
+ * return null.
+ *
+ * @param name the name of the variable
+ */
+ void removeVariable(@NonNull String name);
+
+ /**
+ * Returns all variable names and associated values as a {@link Map}.
+ * Changes to the map must not be propagated back to the {@link Environment}.
+ *
+ * @return all variable names and associated values
+ */
+ @NonNull
+ Map values();
+
+}
diff --git a/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderFactory.java b/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderFactory.java
--- a/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderFactory.java
+++ b/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderFactory.java
@@ -63,9 +63,24 @@
* @param impl SPI representation
* @param description human readable description of the builder
* @return the API instance
+ * @deprecated use {@link #createProcessBuilder(org.netbeans.spi.extexecution.ProcessBuilderImplementation2, java.lang.String)}
*/
public static org.netbeans.api.extexecution.ProcessBuilder createProcessBuilder(
ProcessBuilderImplementation impl, String description) {
return ProcessBuilderAccessor.getDefault().createProcessBuilder(impl, description);
}
+
+ /**
+ * Creates the instance of {@link org.netbeans.api.extexecution.ProcessBuilder}
+ * from its SPI representation.
+ *
+ * @param impl SPI representation
+ * @param description human readable description of the builder
+ * @return the API instance
+ * @since 1.37
+ */
+ public static org.netbeans.api.extexecution.ProcessBuilder createProcessBuilder(
+ ProcessBuilderImplementation2 impl, String description) {
+ return ProcessBuilderAccessor.getDefault().createProcessBuilder(impl, description);
+ }
}
diff --git a/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderImplementation.java b/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderImplementation.java
--- a/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderImplementation.java
+++ b/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderImplementation.java
@@ -62,6 +62,7 @@
* @see org.netbeans.api.extexecution.ProcessBuilder
* @author Petr Hejl
* @since 1.28
+ * @deprecated use {@link ProcessBuilderImplementation2}
*/
public interface ProcessBuilderImplementation {
@@ -80,7 +81,7 @@
* the process should be redirected to standard output stream
* @return a process created with specified parameters and environment
* configuration
- * @throws IOException IOException if the process could not be created
+ * @throws IOException if the process could not be created
* @throws UserQuestionException in case there is a need to interact with
* user, don't be afraid to throw a subclass of
* {@link UserQuestionException} with overriden {@link UserQuestionException#confirmed()}
diff --git a/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderImplementation2.java b/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderImplementation2.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/spi/extexecution/ProcessBuilderImplementation2.java
@@ -0,0 +1,93 @@
+/*
+ * 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.spi.extexecution;
+
+import java.io.IOException;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.extexecution.Environment;
+import org.openide.util.Lookup;
+
+/**
+ * The interface representing the implementation
+ * of {@link org.netbeans.api.extexecution.ProcessBuilder}.
+ *
+ * @see org.netbeans.api.extexecution.ProcessBuilder
+ * @author Petr Hejl
+ * @since 1.37
+ */
+public interface ProcessBuilderImplementation2 extends Lookup.Provider {
+
+ /**
+ * Returns the object for environment variables manipulation.
+ *
+ * @return the object for environment variables manipulation
+ */
+ @NonNull
+ Environment getEnvironment();
+
+ /**
+ * Provides an extension point to the implementors. One may enhance the
+ * functionality of {@link org.netbeans.api.extexecution.ProcessBuilder}
+ * by this as the content of this {@link Lookup} is included in
+ * {@link org.netbeans.api.extexecution.ProcessBuilder#getLookup()}
+ *
+ * @return a lookup providing an extension point
+ */
+ @Override
+ Lookup getLookup();
+
+ /**
+ * Creates a process using the specified parameters.
+ *
+ * The environment variables stored in parameters are acquired by call to
+ * {@link Environment#values()}. So if the implementation does not aim to be
+ * or can't thread safe it may check or use the {@link Environment}
+ * directly.
+ *
+ * @param parameters the instance describing the process parameters
+ * @return a process created with specified parameters
+ * @throws IOException if the process could not be created
+ */
+ @NonNull
+ Process createProcess(@NonNull ProcessParameters parameters) throws IOException;
+
+}
diff --git a/extexecution/src/org/netbeans/spi/extexecution/ProcessParameters.java b/extexecution/src/org/netbeans/spi/extexecution/ProcessParameters.java
new file mode 100644
--- /dev/null
+++ b/extexecution/src/org/netbeans/spi/extexecution/ProcessParameters.java
@@ -0,0 +1,142 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.spi.extexecution;
+
+import java.util.List;
+import java.util.Map;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.modules.extexecution.ProcessParametersAccessor;
+
+/**
+ * The parameters configured for process creation.
+ *
+ * @see ProcessBuilderImplementation2
+ * @author Petr Hejl
+ * @since 1.37
+ */
+public final class ProcessParameters {
+
+ private final String executable;
+
+ private final String workingDirectory;
+
+ private final List arguments;
+
+ private final boolean redirectErrorStream;
+
+ private final Map environmentVariables;
+
+ static {
+ ProcessParametersAccessor.setDefault(new ProcessParametersAccessor() {
+
+ @Override
+ public ProcessParameters createProcessParameters(String executable, String workingDirectory,
+ List arguments, boolean redirectErrorStream, Map environmentVariables) {
+ return new ProcessParameters(executable, workingDirectory, arguments,
+ redirectErrorStream, environmentVariables);
+ }
+ });
+ }
+
+ private ProcessParameters(String executable, String workingDirectory, List arguments,
+ boolean redirectErrorStream, Map environmentVariables) {
+ this.executable = executable;
+ this.workingDirectory = workingDirectory;
+ this.arguments = arguments;
+ this.redirectErrorStream = redirectErrorStream;
+ this.environmentVariables = environmentVariables;
+ }
+
+ /**
+ * Returns the configured executable.
+ *
+ * @return the configured executable
+ */
+ @NonNull
+ public String getExecutable() {
+ return executable;
+ }
+
+ /**
+ * Returns the configured working directory or null in case it
+ * was not configured.
+ *
+ * @return the configured working directory or null in case it
+ * was not configured
+ */
+ @CheckForNull
+ public String getWorkingDirectory() {
+ return workingDirectory;
+ }
+
+ /**
+ * Returns the arguments configured for the process.
+ *
+ * @return the arguments configured for the process
+ */
+ @NonNull
+ public List getArguments() {
+ return arguments;
+ }
+
+ /**
+ * Returns true if standard error stream should be redirected
+ * to standard output stream.
+ *
+ * @return true if standard error stream should be redirected
+ * to standard output stream
+ */
+ public boolean isRedirectErrorStream() {
+ return redirectErrorStream;
+ }
+
+ /**
+ * Returns the environment variables configured for the process.
+ *
+ * @return the environment variables configured for the process
+ */
+ @NonNull
+ public Map getEnvironmentVariables() {
+ return environmentVariables;
+ }
+}
diff --git a/extexecution/test/unit/src/org/netbeans/api/extexecution/ExecutionServiceTest.java b/extexecution/test/unit/src/org/netbeans/api/extexecution/ExecutionServiceTest.java
--- a/extexecution/test/unit/src/org/netbeans/api/extexecution/ExecutionServiceTest.java
+++ b/extexecution/test/unit/src/org/netbeans/api/extexecution/ExecutionServiceTest.java
@@ -42,11 +42,14 @@
package org.netbeans.api.extexecution;
+import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.util.LinkedList;
@@ -358,7 +361,7 @@
final String[] lines = new String[] {"Process line \u1234", "Process line \u1235", "Process line \u1236"};
TestInputStream is = new TestInputStream(TestInputUtils.prepareInputStream(lines, "\n", charset, true));
- TestProcess process = new TestProcess(0, is);
+ TestProcess process = new TestProcess(0, is, null);
is.setProcess(process);
TestCallable callable = new TestCallable();
@@ -536,6 +539,123 @@
assertFalse(val.get());
}
+ public void testWriterService() throws InterruptedException, ExecutionException {
+ TestProcess process = new TestProcess(0,
+ new ByteArrayInputStream("testing input".getBytes()),
+ new ByteArrayInputStream("testing error".getBytes()));
+ TestCallable callable = new TestCallable();
+ callable.addProcess(process);
+
+ StringWriter in = new StringWriter();
+ StringWriter err = new StringWriter();
+ ExecutionService service = ExecutionService.newService(callable, in, err);
+ Future task = service.run();
+ assertNotNull(task);
+
+ process.waitStarted();
+
+ process.destroy();
+ process.waitFor();
+ assertTrue(process.isFinished());
+
+ assertEquals(0, task.get().intValue());
+ assertEquals("testing input", in.toString());
+ assertEquals("testing error", err.toString());
+ }
+
+ public void testWriterServiceOnce() throws InterruptedException, ExecutionException {
+ TestProcess process = new TestProcess(0,
+ new ByteArrayInputStream(new byte[0]), null);
+ TestCallable callable = new TestCallable();
+ callable.addProcess(process);
+
+ ExecutionService service = ExecutionService.newService(callable,
+ (Writer) null, (Writer) null);
+ Future task = service.run();
+ assertNotNull(task);
+
+ process.waitStarted();
+
+ process.destroy();
+ process.waitFor();
+ assertTrue(process.isFinished());
+
+ assertEquals(0, task.get().intValue());
+
+ try {
+ service.run();
+ fail("Multiple run should fail with ISE");
+ } catch (IllegalStateException ex) {
+ // expected
+ }
+ }
+
+ public void testLineService() throws InterruptedException, ExecutionException {
+ final String[] linesIn = new String[] {"Process line 1", "Process line 2", "Process line 3"};
+ final String[] linesErr = new String[] {"Error line 1", "Error line 2", "Error line 3"};
+
+ TestInputStream in = new TestInputStream(
+ TestInputUtils.prepareInputStream(linesIn, "\n", Charset.defaultCharset(), true));
+ TestInputStream err = new TestInputStream(
+ TestInputUtils.prepareInputStream(linesErr, "\n", Charset.defaultCharset(), true));
+ TestProcess process = new TestProcess(0, in, err);
+ TestCallable callable = new TestCallable();
+ callable.addProcess(process);
+
+ TestLineProcessor inProcessor = new TestLineProcessor(false);
+ TestLineProcessor errProcessor = new TestLineProcessor(false);
+ ExecutionService service = ExecutionService.newService(callable,
+ inProcessor, errProcessor, null);
+ Future task = service.run();
+ assertNotNull(task);
+
+ process.waitStarted();
+
+ process.destroy();
+ process.waitFor();
+ assertTrue(process.isFinished());
+
+ assertEquals(0, task.get().intValue());
+
+ List processed = inProcessor.getLinesProcessed();
+ assertEquals(linesIn.length, processed.size());
+ for (int i = 0; i < linesIn.length; i++) {
+ assertEquals(linesIn[i], processed.get(i));
+ }
+ processed = errProcessor.getLinesProcessed();
+ assertEquals(linesErr.length, processed.size());
+ for (int i = 0; i < linesErr.length; i++) {
+ assertEquals(linesErr[i], processed.get(i));
+ }
+ }
+
+ public void testLineServiceOnce() throws InterruptedException, ExecutionException {
+ TestProcess process = new TestProcess(0,
+ new ByteArrayInputStream(new byte[0]), null);
+ TestCallable callable = new TestCallable();
+ callable.addProcess(process);
+
+ ExecutionService service = ExecutionService.newService(callable,
+ null, null, null);
+ Future task = service.run();
+ assertNotNull(task);
+
+ process.waitStarted();
+
+ process.destroy();
+ process.waitFor();
+ assertTrue(process.isFinished());
+
+ assertEquals(0, task.get().intValue());
+
+ try {
+ service.run();
+ fail("Multiple run should fail with ISE");
+ } catch (IllegalStateException ex) {
+ // expected
+ }
+ }
+
private static InputOutputManager.InputOutputData getInputOutput(String name,
boolean actions, String optionsPath) {
@@ -579,6 +699,8 @@
private final InputStream is;
+ private final InputStream err;
+
private boolean finished;
private boolean started;
@@ -586,12 +708,13 @@
public TestProcess(int returnValue) {
this(returnValue, TestInputUtils.prepareInputStream(
new String[] {"Process line 1", "Process line 2", "Process line 3"}, "\n",
- Charset.defaultCharset(), true));
+ Charset.defaultCharset(), true), null);
}
- public TestProcess(int returnValue, InputStream is) {
+ public TestProcess(int returnValue, InputStream is, InputStream err) {
this.returnValue = returnValue;
this.is = is;
+ this.err = err;
}
public void start() {
@@ -637,6 +760,9 @@
@Override
public InputStream getErrorStream() {
+ if (err != null) {
+ return err;
+ }
return new InputStream() {
@Override
public int read() throws IOException {
diff --git a/extexecution/test/unit/src/org/netbeans/api/extexecution/ProcessBuilderTest.java b/extexecution/test/unit/src/org/netbeans/api/extexecution/ProcessBuilderTest.java
--- a/extexecution/test/unit/src/org/netbeans/api/extexecution/ProcessBuilderTest.java
+++ b/extexecution/test/unit/src/org/netbeans/api/extexecution/ProcessBuilderTest.java
@@ -48,8 +48,13 @@
import java.util.List;
import java.util.Map;
import org.netbeans.junit.NbTestCase;
+import org.netbeans.spi.extexecution.EnvironmentFactory;
+import org.netbeans.spi.extexecution.EnvironmentImplementation;
import org.netbeans.spi.extexecution.ProcessBuilderFactory;
import org.netbeans.spi.extexecution.ProcessBuilderImplementation;
+import org.netbeans.spi.extexecution.ProcessBuilderImplementation2;
+import org.netbeans.spi.extexecution.ProcessParameters;
+import org.openide.util.Lookup;
/**
*
@@ -166,7 +171,7 @@
assertEquals("test2", testBuilder.getPaths().get(0));
}
- public void testEnvironment() throws IOException {
+ public void testEnvironmentVariables() throws IOException {
TestProcessBuilder testBuilder = new TestProcessBuilder();
ProcessBuilder builder = ProcessBuilderFactory.createProcessBuilder(testBuilder, "Test builder");
builder.setExecutable("ls");
@@ -201,6 +206,136 @@
assertEquals("value2", testBuilder.getEnvironment().get("key2"));
}
+ public void testEnvironment() throws IOException {
+ TestProcessBuilder2 testBuilder = new TestProcessBuilder2();
+ ProcessBuilder builder = ProcessBuilderFactory.createProcessBuilder(testBuilder, "Test builder");
+ builder.setExecutable("ls");
+
+ builder.getEnvironment().setVariable("key1", "value1");
+ builder.getEnvironment().setVariable("key2", "value2");
+
+ assertEquals("value1", testBuilder.getEnvironment().getVariable("key1"));
+ assertEquals("value2", testBuilder.getEnvironment().getVariable("key2"));
+
+ builder.call();
+ assertEquals(2, testBuilder.getParameters().getEnvironmentVariables().size());
+ assertEquals("value1", testBuilder.getParameters().getEnvironmentVariables().get("key1"));
+ assertEquals("value2", testBuilder.getParameters().getEnvironmentVariables().get("key2"));
+
+ builder.getEnvironment().prependPath("PATH", "/test1");
+ builder.getEnvironment().prependPath("PATH", "/test2");
+
+ builder.call();
+ assertEquals(3, testBuilder.getParameters().getEnvironmentVariables().size());
+ assertEquals("/test2:/test1",
+ testBuilder.getParameters().getEnvironmentVariables().get("PATH"));
+
+ builder.getEnvironment().appendPath("PATH", "/test3");
+
+ builder.call();
+ assertEquals(3, testBuilder.getParameters().getEnvironmentVariables().size());
+ assertEquals("/test2:/test1:/test3",
+ testBuilder.getParameters().getEnvironmentVariables().get("PATH"));
+
+ builder.getEnvironment().removeVariable("PATH");
+ assertNull(builder.getEnvironment().getVariable("PATH"));
+
+ builder.call();
+ assertEquals(2, testBuilder.getParameters().getEnvironmentVariables().size());
+ assertNull(testBuilder.getParameters().getEnvironmentVariables().get("PATH"));
+ }
+
+ public void testFallbackEnvironment() throws IOException {
+ TestProcessBuilder testBuilder = new TestProcessBuilder();
+ ProcessBuilder builder = ProcessBuilderFactory.createProcessBuilder(testBuilder, "Test builder");
+ builder.setExecutable("ls");
+
+ builder.getEnvironment().setVariable("key1", "value1");
+ builder.getEnvironment().setVariable("key2", "value2");
+
+ builder.call();
+ assertEquals(2, testBuilder.getEnvironment().size());
+ assertEquals("value1", testBuilder.getEnvironment().get("key1"));
+ assertEquals("value2", testBuilder.getEnvironment().get("key2"));
+
+ builder.getEnvironment().prependPath("PATH", "/test1");
+ builder.getEnvironment().prependPath("Path", "/test2");
+
+ builder.call();
+ assertEquals(2, testBuilder.getPaths().size());
+ assertEquals("/test2", testBuilder.getPaths().get(0));
+ assertEquals("/test1", testBuilder.getPaths().get(1));
+
+ try {
+ builder.getEnvironment().prependPath("LD_LIBRARY_PATH", "/test");
+ fail("Prepend of unknown path does not throw exception");
+ } catch (UnsupportedOperationException ex) {
+ // expected
+ }
+
+ try {
+ builder.getEnvironment().appendPath("PATH", "/test");
+ fail("Append of any path does not throw exception");
+ } catch (UnsupportedOperationException ex) {
+ // expected
+ }
+
+ try {
+ builder.getEnvironment().getVariable("PATH");
+ fail("getVariable() does not throw exception");
+ } catch (UnsupportedOperationException ex) {
+ // expected
+ }
+
+ try {
+ builder.getEnvironment().removeVariable("PATH");
+ fail("removeVariable() does not throw exception");
+ } catch (UnsupportedOperationException ex) {
+ // expected
+ }
+
+ try {
+ builder.getEnvironment().values();
+ fail("values() does not throw exception");
+ } catch (UnsupportedOperationException ex) {
+ // expected
+ }
+ }
+
+ public void testFallbackEnvironmentCombined() throws IOException {
+ TestProcessBuilder testBuilder = new TestProcessBuilder();
+ ProcessBuilder builder = ProcessBuilderFactory.createProcessBuilder(testBuilder, "Test builder");
+ builder.setExecutable("ls");
+
+ builder.getEnvironment().setVariable("key1", "value1");
+ builder.getEnvironment().setVariable("key2", "value2");
+
+ builder.call();
+ assertEquals(2, testBuilder.getEnvironment().size());
+ assertEquals("value1", testBuilder.getEnvironment().get("key1"));
+ assertEquals("value2", testBuilder.getEnvironment().get("key2"));
+
+ builder.setEnvironmentVariables(Collections.singletonMap("key3", "value3"));
+
+ builder.call();
+ assertEquals(1, testBuilder.getEnvironment().size());
+ assertEquals("value3", testBuilder.getEnvironment().get("key3"));
+
+ builder.getEnvironment().prependPath("PATH", "/test1");
+ builder.getEnvironment().prependPath("Path", "/test2");
+
+ builder.call();
+ assertEquals(2, testBuilder.getPaths().size());
+ assertEquals("/test2", testBuilder.getPaths().get(0));
+ assertEquals("/test1", testBuilder.getPaths().get(1));
+
+ builder.setPaths(Collections.singletonList("/test3"));
+
+ builder.call();
+ assertEquals(1, testBuilder.getPaths().size());
+ assertEquals("/test3", testBuilder.getPaths().get(0));
+ }
+
public void testRedirectErrorStream() throws IOException {
TestProcessBuilder testBuilder = new TestProcessBuilder();
ProcessBuilder builder = ProcessBuilderFactory.createProcessBuilder(testBuilder, "Test builder");
@@ -216,7 +351,7 @@
assertTrue(testBuilder.isRedirectErrorStream());
}
- private class TestProcessBuilder implements ProcessBuilderImplementation {
+ private static class TestProcessBuilder implements ProcessBuilderImplementation {
private String executable;
@@ -267,6 +402,80 @@
public String getWorkingDirectory() {
return workingDirectory;
}
+ }
+ private static class TestProcessBuilder2 implements ProcessBuilderImplementation2 {
+
+ private final Environment environment = EnvironmentFactory.createEnvironment(new TestEnvironment());
+
+ private ProcessParameters parameters;
+
+ @Override
+ public Environment getEnvironment() {
+ return environment;
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return Lookup.EMPTY;
+ }
+
+ @Override
+ public Process createProcess(ProcessParameters parameters) throws IOException {
+ this.parameters = parameters;
+
+ return null;
+ }
+
+ public ProcessParameters getParameters() {
+ return parameters;
+ }
+ }
+
+ private static class TestEnvironment implements EnvironmentImplementation {
+
+ private final Map values = new HashMap();
+
+ @Override
+ public String getVariable(String name) {
+ return values.get(name);
+ }
+
+ @Override
+ public void appendPath(String name, String value) {
+ String orig = values.get(name);
+ if (orig == null || orig.isEmpty()) {
+ values.put(name, value);
+ } else {
+ // intentionally hardcoded for tests
+ values.put(name, orig + ":" + value);
+ }
+ }
+
+ @Override
+ public void prependPath(String name, String value) {
+ String orig = values.get(name);
+ if (orig == null || orig.isEmpty()) {
+ values.put(name, value);
+ } else {
+ // intentionally hardcoded for tests
+ values.put(name, value + ":" + orig);
+ }
+ }
+
+ @Override
+ public void setVariable(String name, String value) {
+ values.put(name, value);
+ }
+
+ @Override
+ public void removeVariable(String name) {
+ values.remove(name);
+ }
+
+ @Override
+ public Map values() {
+ return new HashMap(values);
+ }
}
}
diff --git a/extexecution/test/unit/src/org/netbeans/api/extexecution/input/InputReadersReaderTest.java b/extexecution/test/unit/src/org/netbeans/api/extexecution/input/InputReadersReaderTest.java
--- a/extexecution/test/unit/src/org/netbeans/api/extexecution/input/InputReadersReaderTest.java
+++ b/extexecution/test/unit/src/org/netbeans/api/extexecution/input/InputReadersReaderTest.java
@@ -47,6 +47,7 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.Arrays;
import org.netbeans.junit.NbTestCase;
@@ -85,4 +86,22 @@
assertTrue(Arrays.equals(TEST_CHARS, processor.getCharsProcessed()));
}
+
+ public void testReadStringReader() throws IOException {
+ Reader reader = new StringReader(new String(TEST_CHARS));
+ InputReader inputReader = InputReaders.forReader(reader);
+ TestInputProcessor processor = new TestInputProcessor(false);
+
+ int read = 0;
+ int retries = 0;
+ while (read < TEST_CHARS.length && retries < MAX_RETRIES) {
+ read += inputReader.readInput(processor);
+ retries++;
+ }
+
+ assertEquals(read, TEST_CHARS.length);
+ assertEquals(0, processor.getResetCount());
+
+ assertTrue(Arrays.equals(TEST_CHARS, processor.getCharsProcessed()));
+ }
}
diff --git a/extexecution/test/unit/src/org/netbeans/api/extexecution/process/ProcessCharsetTest.java b/extexecution/test/unit/src/org/netbeans/api/extexecution/process/ProcessCharsetTest.java
new file mode 100644
--- /dev/null
+++ b/extexecution/test/unit/src/org/netbeans/api/extexecution/process/ProcessCharsetTest.java
@@ -0,0 +1,91 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.extexecution.process;
+
+import java.nio.charset.Charset;
+import org.netbeans.junit.NbTestCase;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public class ProcessCharsetTest extends NbTestCase {
+
+ public ProcessCharsetTest(String name) {
+ super(name);
+ }
+
+ public void testProcessCharset() {
+ assertFalse(ProcessCharset.isSupported(new TestProcess(Lookup.EMPTY)));
+
+ assertNull(ProcessCharset.getOutputCharset(new TestProcess(Lookup.EMPTY)));
+ assertNull(ProcessCharset.getInputCharset(new TestProcess(Lookup.EMPTY)));
+ assertNull(ProcessCharset.getErrorCharset(new TestProcess(Lookup.EMPTY)));
+
+ TestProcessCharset charset = new TestProcessCharset();
+ TestProcess process = new TestProcess(Lookups.fixed(charset));
+ assertTrue(ProcessCharset.isSupported(process));
+ assertEquals(charset.getOutputCharset(), ProcessCharset.getOutputCharset(process));
+ assertEquals(charset.getInputCharset(), ProcessCharset.getInputCharset(process));
+ assertEquals(charset.getErrorCharset(), ProcessCharset.getErrorCharset(process));
+ }
+
+ private static class TestProcessCharset extends ProcessCharset {
+
+ @Override
+ protected Charset getInputCharset() {
+ return Charset.forName("US-ASCII");
+ }
+
+ @Override
+ protected Charset getOutputCharset() {
+ return Charset.forName("ISO-8859-1");
+ }
+
+ @Override
+ protected Charset getErrorCharset() {
+ return Charset.forName("UTF-8");
+ }
+ }
+}
diff --git a/extexecution/test/unit/src/org/netbeans/api/extexecution/process/ProcessIdTest.java b/extexecution/test/unit/src/org/netbeans/api/extexecution/process/ProcessIdTest.java
new file mode 100644
--- /dev/null
+++ b/extexecution/test/unit/src/org/netbeans/api/extexecution/process/ProcessIdTest.java
@@ -0,0 +1,76 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.extexecution.process;
+
+import org.netbeans.junit.NbTestCase;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public class ProcessIdTest extends NbTestCase {
+
+ public ProcessIdTest(String name) {
+ super(name);
+ }
+
+ public void testProcessId() {
+ assertFalse(ProcessId.isSupported(new TestProcess(Lookup.EMPTY)));
+
+ assertNull(ProcessId.getId(new TestProcess(Lookup.EMPTY)));
+
+ TestProcessId id = new TestProcessId();
+ TestProcess process = new TestProcess(Lookups.fixed(id));
+ assertTrue(ProcessId.isSupported(process));
+ assertEquals(id.getId(), ProcessId.getId(process));
+ }
+
+ private static class TestProcessId extends ProcessId {
+
+ @Override
+ protected Integer getId() {
+ return 1;
+ }
+ }
+}
diff --git a/extexecution/test/unit/src/org/netbeans/api/extexecution/process/ProcessSignalTest.java b/extexecution/test/unit/src/org/netbeans/api/extexecution/process/ProcessSignalTest.java
new file mode 100644
--- /dev/null
+++ b/extexecution/test/unit/src/org/netbeans/api/extexecution/process/ProcessSignalTest.java
@@ -0,0 +1,116 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.extexecution.process;
+
+import java.io.IOException;
+import org.netbeans.junit.NbTestCase;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public class ProcessSignalTest extends NbTestCase {
+
+ public ProcessSignalTest(String name) {
+ super(name);
+ }
+
+ public void testProcessSignal() throws IOException {
+ assertFalse(ProcessSignal.isSupported(new TestProcess(Lookup.EMPTY)));
+
+ TestProcessSignal signal = new TestProcessSignal();
+ TestProcess process = new TestProcess(Lookups.fixed(signal));
+ assertTrue(ProcessSignal.isSupported(process));
+
+ ProcessSignal.signal(process, ProcessSignal.Signal.SIGALRM);
+ ProcessSignal.signalGroup(process, ProcessSignal.Signal.SIGCANCEL);
+
+ assertEquals(ProcessSignal.Signal.SIGALRM, signal.getSignal());
+ assertEquals(ProcessSignal.Signal.SIGCANCEL, signal.getGroupSignal());
+
+ try {
+ ProcessSignal.signal(process, ProcessSignal.Signal.NULL);
+ fail("No exception propagated");
+ } catch (IOException ex) {
+ // expected
+ }
+ try {
+ ProcessSignal.signalGroup(process, ProcessSignal.Signal.NULL);
+ fail("No exception propagated");
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+
+ private static class TestProcessSignal extends ProcessSignal {
+
+ private Signal signal;
+
+ private Signal groupSignal;
+
+ @Override
+ protected void signal(Signal signal) throws IOException {
+ if (this.signal != null) {
+ throw new IOException("Test");
+ }
+ this.signal = signal;
+ }
+
+ @Override
+ protected void signalGroup(Signal signal) throws IOException {
+ if (this.groupSignal != null) {
+ throw new IOException("Test");
+ }
+ this.groupSignal = signal;
+ }
+
+ public Signal getSignal() {
+ return signal;
+ }
+
+ public Signal getGroupSignal() {
+ return groupSignal;
+ }
+ }
+}
diff --git a/extexecution/test/unit/src/org/netbeans/api/extexecution/process/TestProcess.java b/extexecution/test/unit/src/org/netbeans/api/extexecution/process/TestProcess.java
new file mode 100644
--- /dev/null
+++ b/extexecution/test/unit/src/org/netbeans/api/extexecution/process/TestProcess.java
@@ -0,0 +1,94 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.extexecution.process;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public class TestProcess extends Process implements Lookup.Provider {
+
+ private final Lookup lookup;
+
+ public TestProcess(Lookup lookup) {
+ this.lookup = lookup;
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return lookup;
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public InputStream getErrorStream() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public int waitFor() throws InterruptedException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public int exitValue() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void destroy() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+}
diff --git a/extexecution/test/unit/src/org/netbeans/spi/extexecution/ProcessParametersTest.java b/extexecution/test/unit/src/org/netbeans/spi/extexecution/ProcessParametersTest.java
new file mode 100644
--- /dev/null
+++ b/extexecution/test/unit/src/org/netbeans/spi/extexecution/ProcessParametersTest.java
@@ -0,0 +1,79 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.spi.extexecution;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.extexecution.ProcessParametersAccessor;
+
+/**
+ *
+ * @author Petr Hejl
+ */
+public class ProcessParametersTest extends NbTestCase {
+
+ public ProcessParametersTest(String name) {
+ super(name);
+ }
+
+ public void testParameters() {
+ Map variables = new HashMap();
+ variables.put("key1", "value1");
+ variables.put("key2", "value2");
+
+ ProcessParameters params = ProcessParametersAccessor.getDefault().createProcessParameters(
+ "ls", "/home", Collections.singletonList("argument"), true, variables);
+
+ assertEquals("ls", params.getExecutable());
+ assertEquals("/home", params.getWorkingDirectory());
+ assertTrue(params.isRedirectErrorStream());
+
+ assertEquals(1, params.getArguments().size());
+ assertEquals("argument", params.getArguments().get(0));
+
+ assertEquals(2, params.getEnvironmentVariables().size());
+ assertEquals("value1", params.getEnvironmentVariables().get("key1"));
+ assertEquals("value2", params.getEnvironmentVariables().get("key2"));
+ }
+}
diff --git a/j2ee.weblogic9/nbproject/project.xml b/j2ee.weblogic9/nbproject/project.xml
--- a/j2ee.weblogic9/nbproject/project.xml
+++ b/j2ee.weblogic9/nbproject/project.xml
@@ -105,7 +105,7 @@
2
- 1.13
+ 1.37
diff --git a/j2ee.weblogic9/src/org/netbeans/modules/j2ee/weblogic9/deploy/CommandBasedDeployer.java b/j2ee.weblogic9/src/org/netbeans/modules/j2ee/weblogic9/deploy/CommandBasedDeployer.java
--- a/j2ee.weblogic9/src/org/netbeans/modules/j2ee/weblogic9/deploy/CommandBasedDeployer.java
+++ b/j2ee.weblogic9/src/org/netbeans/modules/j2ee/weblogic9/deploy/CommandBasedDeployer.java
@@ -66,12 +66,10 @@
import javax.enterprise.deploy.spi.Target;
import javax.enterprise.deploy.spi.TargetModuleID;
import javax.enterprise.deploy.spi.status.ProgressObject;
-import org.netbeans.api.extexecution.ExecutionDescriptor;
import org.netbeans.api.extexecution.ExecutionService;
import org.netbeans.api.extexecution.ExternalProcessBuilder;
-import org.netbeans.api.extexecution.input.InputProcessor;
-import org.netbeans.api.extexecution.input.InputProcessors;
import org.netbeans.api.extexecution.input.LineProcessor;
+import org.netbeans.api.extexecution.input.LineProcessors;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.platform.JavaPlatformManager;
import org.netbeans.modules.j2ee.dd.api.application.Application;
@@ -88,14 +86,12 @@
import org.netbeans.modules.j2ee.weblogic9.config.WLMessageDestination;
import org.netbeans.modules.j2ee.weblogic9.dd.model.WebApplicationModel;
import org.netbeans.modules.j2ee.weblogic9.ui.FailedAuthenticationSupport;
-import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.JarFileSystem;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.util.Utilities;
-import org.openide.windows.InputOutput;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -110,8 +106,6 @@
private static final RequestProcessor URL_WAIT_RP = new RequestProcessor("Weblogic URL Wait", 10); // NOI18N
- private static final boolean SHOW_CONSOLE = Boolean.getBoolean(CommandBasedDeployer.class.getName() + ".showConsole");;
-
public CommandBasedDeployer(WLDeploymentManager deploymentManager) {
super(deploymentManager);
}
@@ -668,19 +662,25 @@
builder = builder.addArgument(param);
}
- ExecutionDescriptor descriptor = new ExecutionDescriptor().inputVisible(true).outLineBased(true);
- if (processor != null) {
- descriptor = descriptor.outProcessorFactory(new ExecutionDescriptor.InputProcessorFactory() {
+ LineProcessor realProcessor = processor;
+ if (LOGGER.isLoggable(Level.FINE)) {
+ realProcessor = LineProcessors.proxy(processor, new LineProcessor() {
- public InputProcessor newInputProcessor(InputProcessor defaultProcessor) {
- return InputProcessors.proxy(defaultProcessor, InputProcessors.bridge(processor));
+ @Override
+ public void processLine(String line) {
+ LOGGER.log(Level.FINE, line);
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void close() {
}
});
}
- if (!SHOW_CONSOLE) {
- descriptor = descriptor.inputOutput(InputOutput.NULL);
- }
- return ExecutionService.newService(builder, descriptor, "weblogic.Deployer " + command);
+ return ExecutionService.newService(builder, realProcessor, null, null);
}
private String getClassPath() {
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
@@ -88,6 +88,7 @@
org.netbeans.modules.masterfs.macosxorg.netbeans.modules.masterfs.solarisorg.netbeans.modules.masterfs.windows
+ org.netbeans.modules.nativeexecution.implorg.netbeans.modules.python.qshellcom.sun.jnacom.sun.jna.ptr
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,115 @@
+
+
+ org.netbeans.modules.apisupport.project
+
+
+ org.netbeans.modules.nativeexecution.impl
+
+
+ com.jcraft.jsch
+
+
+
+ 0.1.43
+
+
+
+ org.netbeans.libs.jna
+
+
+
+ 1
+ 1.4
+
+
+
+ org.netbeans.modules.cnd.execution
+
+
+
+
+
+
+
+
+ org.netbeans.modules.dlight.nativeexecution
+
+
+
+ 1.26
+
+
+
+ org.netbeans.modules.dlight.terminal
+
+
+
+ 1.14
+
+
+
+ org.netbeans.modules.extexecution
+
+
+
+ 2
+ 1.37
+
+
+
+ org.openide.modules
+
+
+
+ 7.35
+
+
+
+ org.openide.util
+
+
+
+ 8.24
+
+
+
+ org.openide.util.lookup
+
+
+
+ 8.15
+
+
+
+
+
+ unit
+
+ org.netbeans.bootstrap
+
+
+
+ org.netbeans.core.startup
+
+
+
+ org.netbeans.insane
+
+
+
+ org.netbeans.libs.junit4
+
+
+
+ org.netbeans.modules.nbjunit
+
+
+
+
+
+
+
+
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,198 @@
+/*
+ * 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.cnd.execution.api.NativeExecutionException;
+import org.netbeans.modules.cnd.execution.spi.NativeProcessImplementation;
+import org.netbeans.modules.cnd.execution.spi.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
+ }
+
+ 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/HelperUtility.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/common/HelperUtility.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/common/HelperUtility.java
@@ -0,0 +1,169 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.common;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.MissingResourceException;
+import java.util.logging.Level;
+import org.netbeans.modules.cnd.execution.ExecutionLogger;
+import org.netbeans.modules.cnd.execution.access.ConnectionAccessor;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.nativeexecution.impl.util.FileOperationsSupport;
+import org.netbeans.modules.cnd.execution.util.HostInfo;
+import org.openide.modules.InstalledFileLocator;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @author ak119685
+ */
+public class HelperUtility {
+
+ protected static final ExecutionLogger log = ExecutionLogger.getInstance();
+ private final HashMap cache = new HashMap();
+ private final String pattern;
+ protected final String codeNameBase;
+
+ public HelperUtility(String searchPattern) {
+ this("org.netbeans.modules.nativeexecution.impl.common", searchPattern); // NOI18N
+ }
+
+ public HelperUtility(String codeNameBase, String searchPattern) {
+ this.codeNameBase = codeNameBase;
+ pattern = searchPattern;
+ }
+
+ /**
+ *
+ * @param connection
+ * @return the ready-to-use remote path for the utility
+ * @throws IOException
+ */
+ public final String getPath(final Connection connection) throws IOException {
+ return getPath(connection, null);
+ }
+
+ private String getPath(final Connection connection, final HostInfo hostInfo) throws IOException {
+ if (!connection.isConnected()) {
+ throw new IllegalStateException("Connection " + // NOI18N
+ connection.getURI() + " is broken"); // NOI18N
+ }
+
+ String result;
+
+ synchronized (cache) {
+ result = cache.get(connection.getURI());
+
+ if (result == null) {
+ ConnectionAccessor access = ConnectionAccessor.getDefault();
+ Lookup lookup = access.getConnectionLookup(connection);
+ FileOperationsSupport fos = lookup.lookup(FileOperationsSupport.class);
+ if (fos == null) {
+ log.log(Level.WARNING,
+ "FileOperationsSupport is not provided for {0}",
+ connection.getURI()); // NOI18N
+ return null;
+ }
+
+ final HostInfo info = (hostInfo == null)
+ ? HostInfo.getFor(connection)
+ : hostInfo;
+
+ if (!isSupported(info)) {
+ log.log(Level.INFO, "Utility {0} is not supported for {1}",
+ new Object[]{pattern, connection.getURI()}); // NOI18N
+ return null;
+ }
+
+ try {
+ File localFile = getLocalFileFor(info);
+
+ // Construct destination: {tmpbase}/{hash}/{name}
+
+ // hash - a string unique to pair:
+ // local file location and connection
+ String key = localFile.getAbsolutePath().concat(connection.getURI().toString());
+ String hash = Integer.toString(key.hashCode()).replace('-', '0');
+
+
+ String fileName = localFile.getName();
+ String dstFile = info.getTempDir() + '/' + hash + '/' + fileName;
+
+ result = fos.uploadFile(localFile, dstFile, 0700);
+
+ cache.put(connection.getURI(), result);
+ } catch (MissingResourceException ex) {
+ return null;
+ } catch (IOException ex) {
+ throw ex;
+ } catch (Exception ex) {
+ if (ex.getCause() instanceof IOException) {
+ throw (IOException) ex.getCause();
+ }
+ throw new IOException(ex);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ protected File getLocalFileFor(final HostInfo info) throws MissingResourceException {
+ String path = info.expandMacros(pattern);
+
+ InstalledFileLocator fl = InstalledFileLocator.getDefault();
+ File file = fl.locate(path, codeNameBase, false);
+
+ if (file == null || !file.exists()) {
+ throw new MissingResourceException(path, null, null); //NOI18N
+ }
+
+ return file;
+ }
+
+ protected boolean isSupported(HostInfo hostInfo) {
+ return true;
+ }
+}
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,198 @@
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import org.netbeans.api.extexecution.ExecutionService;
+import org.netbeans.api.extexecution.input.LineProcessor;
+import org.netbeans.modules.cnd.execution.api.Connection;
+import org.netbeans.modules.cnd.execution.api.NativeExecutionException;
+import org.netbeans.modules.cnd.execution.api.NativeProcessBuilder;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfo;
+import org.netbeans.modules.cnd.execution.spi.support.ConnectionInfoProvider;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Andrew
+ */
+public final class ShellBasedConnectionInfoProvider implements ConnectionInfoProvider {
+ @Override
+ public ConnectionInfo getConnectionInfo(Connection connection) throws NativeExecutionException {
+ NativeProcessBuilder npb = connection.newNativeProcessBuilder();
+ npb.setShellScript("/bin/sh", "/bin/sh -s"); // NOI18N
+ final Map env = new HashMap();
+ final Map info = new HashMap();
+
+ // FIXME change this to piped/proxy reader/writer
+ StringBuilder sb = new StringBuilder();
+ sb.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));
+ try {
+ String line;
+ while ((line = br.readLine()) != null) {
+ sb.append(line).append('\n');
+ }
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ } finally {
+ try {
+ br.close();
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ Reader processInput = new StringReader(sb.toString());
+ try {
+ ExecutionService.newService(npb, new LineProcessor() {
+
+ 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(String 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:
+ info.put(name, value);
+ break;
+ }
+ }
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void close() {
+ }
+ }, null, processInput).run().get();
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ throw new NativeExecutionException(ex);
+ } catch (ExecutionException ex) {
+ throw new NativeExecutionException(ex);
+ }
+
+ return new ConnectionInfo() {
+
+ @Override
+ public Map getEnvironmentMap() {
+ return env;
+ }
+
+ @Override
+ public Map getProperties() {
+ return info;
+ }
+ };
+ }
+
+ /**
+ * @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.
+
+MSG_PasswordInteractive={0} {1}
+JSchPasswordPromptPanel.pwdField.text=jPasswordField1
diff --git a/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchChannelsSupport.java b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchChannelsSupport.java
new file mode 100644
--- /dev/null
+++ b/nativeexecution.impl/src/org/netbeans/modules/nativeexecution/impl/jsch/JSchChannelsSupport.java
@@ -0,0 +1,349 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 2010 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.nativeexecution.impl.jsch;
+
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.UserInfo;
+import java.io.InterruptedIOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+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.cnd.execution.ExecutionLogger;
+import org.netbeans.modules.cnd.execution.api.ConnectionException;
+import org.netbeans.modules.cnd.execution.spi.AuthDataProvider;
+import org.netbeans.modules.cnd.execution.spi.UserInteraction;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author ak119685
+ */
+public final class JSchChannelsSupport {
+
+ 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 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 UserInfo userInfo;
+ 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 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();
+
+ static {
+ Set> data = new HashSet>(System.getProperties().entrySet());
+
+ for (Entry