You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by kr...@apache.org on 2010/04/01 13:20:53 UTC

svn commit: r929929 [1/2] - in /camel/trunk/components/camel-exec: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/camel/ src/main/java/org/apache/camel/component/ src/main/java/org/apache/camel/co...

Author: krasserm
Date: Thu Apr  1 11:20:51 2010
New Revision: 929929

URL: http://svn.apache.org/viewvc?rev=929929&view=rev
Log:
https://issues.apache.org/activemq/browse/CAMEL-2549

Added:
    camel/trunk/components/camel-exec/   (with props)
    camel/trunk/components/camel-exec/pom.xml
    camel/trunk/components/camel-exec/src/
    camel/trunk/components/camel-exec/src/main/
    camel/trunk/components/camel-exec/src/main/java/
    camel/trunk/components/camel-exec/src/main/java/org/
    camel/trunk/components/camel-exec/src/main/java/org/apache/
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecBinding.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommand.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommandExecutor.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecComponent.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecEndpoint.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecProducer.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResult.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResultConverter.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecBinding.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java
    camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/ExecParseUtils.java
    camel/trunk/components/camel-exec/src/main/resources/
    camel/trunk/components/camel-exec/src/main/resources/META-INF/
    camel/trunk/components/camel-exec/src/main/resources/META-INF/LICENSE.txt
    camel/trunk/components/camel-exec/src/main/resources/META-INF/NOTICE.txt
    camel/trunk/components/camel-exec/src/main/resources/META-INF/services/
    camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/
    camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/
    camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/
    camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/TypeConverter
    camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/component/
    camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/component/exec
    camel/trunk/components/camel-exec/src/test/
    camel/trunk/components/camel-exec/src/test/java/
    camel/trunk/components/camel-exec/src/test/java/org/
    camel/trunk/components/camel-exec/src/test/java/org/apache/
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecEndpointTest.java
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecJavaProcessTest.java
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecOutFileTest.java
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecProducerTest.java
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecScriptTest.java
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecTestUtils.java
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecutableJavaProgram.java
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ExecCommandExecutorMock.java
    camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ExecParseUtilsTest.java
    camel/trunk/components/camel-exec/src/test/resources/
    camel/trunk/components/camel-exec/src/test/resources/exec-test-script.bat
    camel/trunk/components/camel-exec/src/test/resources/exec-test-script.sh
    camel/trunk/components/camel-exec/src/test/resources/log4j.properties
    camel/trunk/components/camel-exec/src/test/resources/org/
    camel/trunk/components/camel-exec/src/test/resources/org/apache/
    camel/trunk/components/camel-exec/src/test/resources/org/apache/camel/
    camel/trunk/components/camel-exec/src/test/resources/org/apache/camel/component/
    camel/trunk/components/camel-exec/src/test/resources/org/apache/camel/component/exec/
    camel/trunk/components/camel-exec/src/test/resources/org/apache/camel/component/exec/ExecEndpointTest-context.xml
    camel/trunk/components/camel-exec/src/test/resources/org/apache/camel/component/exec/ExecScriptTest-context.xml
    camel/trunk/components/camel-exec/src/test/resources/org/apache/camel/component/exec/exec-mock-executor-context.xml

Propchange: camel/trunk/components/camel-exec/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Apr  1 11:20:51 2010
@@ -0,0 +1,9 @@
+.project
+.checkstyle
+.pmd
+.classpath
+target
+.settings
+eclipse-classes
+*.i??
+classes

Added: camel/trunk/components/camel-exec/pom.xml
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/pom.xml?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/pom.xml (added)
+++ camel/trunk/components/camel-exec/pom.xml Thu Apr  1 11:20:51 2010
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+  <!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements. See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version
+    2.0 (the "License"); you may not use this file except in compliance
+    with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+    applicable law or agreed to in writing, software distributed under
+    the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
+    OR CONDITIONS OF ANY KIND, either express or implied. See the
+    License for the specific language governing permissions and
+    limitations under the License.
+  -->
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-parent</artifactId>
+    <version>2.3-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-exec</artifactId>
+  <packaging>bundle</packaging>
+  <name>Camel :: Exec</name>
+  <description>Camel support for system command execution</description>
+
+  <properties>
+    <!--
+      TODO: move the versions to section dependencyManagement of the parent pom,
+      and then remove the versions underneath
+    -->
+    <commons-exec-version>1.0.1</commons-exec-version>
+    <commons-io-version>1.4</commons-io-version>
+    <commons-lang-version>2.5</commons-lang-version>
+    <camel.osgi.export.pkg>org.apache.camel.component.exec.*</camel.osgi.export.pkg>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-exec</artifactId>
+      <version>${commons-exec-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>${commons-io-version}</version>
+    </dependency>
+     <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>${commons-lang-version}</version>
+    </dependency>
+
+    <!-- test scope -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecBinding.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecBinding.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecBinding.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecBinding.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.exec.impl.ExecParseUtils;
+
+/**
+ * Represents the binding of input and output types of a
+ * {@link ExecCommandExecutor} to an {@link Exchange}. The input of the executor
+ * is an {@link ExecCommand} and the output is an {@link ExecResult}.
+ */
+public interface ExecBinding {
+    /**
+     * The header value overrides the executable of the command, configured in
+     * the exec endpoint URI. As executable is considered the remaining of the
+     * {@link ExecEndpoint} URI; <br>
+     * <br>
+     * e.g. in the URI <i> <code>exec:"C:/Program Files/jdk/java.exe"</code>
+     * </i>, <code>"C:/Program Files/jdk/java.exe"<code> is the executable, escaped by the " character.
+     */
+    String EXEC_COMMAND_EXECUTABLE = "CamelExecCommandExecutable";
+    /**
+     * The header value overrides the existing command arguments in the
+     * {@link ExecEndpoint} URI. The arguments may be one or many
+     * whitespace-separated tokens, and can be quoted with <code>"</code>, or with
+     * <code>""</code>.
+     * 
+     * @see {@link #EXEC_COMMAND_EXECUTABLE}
+     * @see ExecParseUtils#splitToWhiteSpaceSeparatedTokens(String)
+     */
+    String EXEC_COMMAND_ARGS = "CamelExecCommandArgs";
+
+    /**
+     * Specifies the file name of a file, created by the executable, that should
+     * be considered as output of the executable, e.g. a log file.
+     * 
+     * @see ExecResultConverter#toInputStream(ExecResult)
+     */
+    String EXEC_COMMAND_OUT_FILE = "CamelExecCommandOutFile";
+
+    /**
+     * Sets the working directory of the {@link #EXEC_COMMAND_EXECUTABLE}. The
+     * header value overrides any existing command in the endpoint URI. If this
+     * is not configured, the working directory of the current process will be
+     * used.
+     */
+    String EXEC_COMMAND_WORKING_DIR = "CamelExecCommandWorkingDir";
+    /**
+     * Specifies the amount of time, in milliseconds, after which the process of
+     * the executable should be terminated.
+     */
+    String EXEC_COMMAND_TIMEOUT = "CamelExecCommandTimeout";
+
+    /**
+     * The value of this header is a String with the standard output stream of
+     * the executable.
+     */
+    String EXEC_STDOUT = "CamelExecStdout";
+    /**
+     * The value of this header is a String with the standard error stream of
+     * the executable.
+     */
+    String EXEC_STDERR = "CamelExecStderr";
+
+    /**
+     * The value of this header is the exit value that is returned, after the
+     * execution. By convention a non-zero status exit value indicates abnormal
+     * termination. <br>
+     * <b>Note that the exit value is OS dependent.</b>
+     */
+    String EXEC_EXIT_VALUE = "CamelExecExitValue";
+
+    /**
+     * Creates a {@link ExecCommand} from the headers in the
+     * <code>exchange</code> and the settings of the <code>endpoint</code>.
+     * 
+     * @param exchange a Camel {@link Exchange}
+     * @param endpoint an {@link ExecEndpoint} instance
+     * @return an {@link ExecCommand} object
+     * @see ExecCommandExecutor
+     */
+    ExecCommand readInput(Exchange exchange, ExecEndpoint endpoint);
+
+    /**
+     * Populates the exchange form the {@link ExecResult}.
+     * 
+     * @param exchange a Camel {@link Exchange}, in which to write the
+     *            <code>result</code>
+     * @param result the result of a command execution
+     * @see ExecCommandExecutor
+     */
+    void writeOutput(Exchange exchange, ExecResult result);
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommand.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommand.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommand.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommand.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,109 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.apache.camel.util.ObjectHelper.notNull;
+
+/**
+ * Value object that describes the command to be executed.
+ */
+public class ExecCommand implements Serializable {
+
+    private static final long serialVersionUID = 1755094616849607573L;
+
+    /**
+     * @see ExecBinding#EXEC_COMMAND_EXECUTABLE
+     */
+    private String executable;
+
+    /**
+     * @see ExecBinding#EXEC_COMMAND_ARGS
+     */
+    private List<String> args;
+
+    /**
+     * @see ExecBinding#EXEC_COMMAND_WORKING_DIR
+     */
+    private String workingDir;
+
+    /**
+     * @see ExecBinding#EXEC_COMMAND_TIMEOUT
+     */
+    private long timeout;
+
+    /**
+     * @see ExecBinding#EXEC_COMMAND_OUT_FILE
+     */
+    private File outFile;
+    /**
+     * The input of the executable
+     */
+    private InputStream input;
+
+    public ExecCommand(String executable, List<String> args, String workingDir, Long timeout, InputStream input, File outFile) {
+        notNull(executable, "command executable");
+        this.executable = executable;
+        this.args = unmodifiableOrEmptyList(args);
+        this.workingDir = workingDir;
+        this.timeout = timeout;
+        this.input = input;
+        this.outFile = outFile;
+    }
+
+    public List<String> getArgs() {
+        return args;
+    }
+
+    public String getExecutable() {
+        return executable;
+    }
+
+    public InputStream getInput() {
+        return input;
+    }
+
+    public File getOutFile() {
+        return outFile;
+    }
+
+    public long getTimeout() {
+        return timeout;
+    }
+
+    public String getWorkingDir() {
+        return workingDir;
+    }
+
+    @Override
+    public String toString() {
+        String dirToPrint = workingDir == null ? "null" : workingDir;
+        String outFileToPrint = outFile == null ? "null" : outFile.getPath();
+        return "ExecCommand [args=" + args + ", executable=" + executable + ", timeout=" + timeout + ", outFile=" + outFileToPrint + ", workingDir=" + dirToPrint + "]";
+    }
+
+    private <T> List<T> unmodifiableOrEmptyList(List<T> list) {
+        return Collections.unmodifiableList(list == null ? new ArrayList<T>() : list);
+    }
+
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommandExecutor.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommandExecutor.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommandExecutor.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecCommandExecutor.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import java.io.IOException;
+
+import org.apache.commons.exec.ExecuteException;
+
+/**
+ * Executes {@link ExecCommand} instances.
+ */
+public interface ExecCommandExecutor {
+
+    /**
+     * Executes the <code>command</code> and returns its exit value
+     * 
+     * @param execCommand The command object, that describes the executable
+     *            application
+     * @throws ExecuteException if the execution failed
+     * @throws IOException if there is an invalid path in the working directory,
+     *             or if the absolute path of the command executable is invalid,
+     *             or if the executable does not exist
+     */
+    ExecResult execute(ExecCommand execCommand) throws ExecException, IOException;
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecComponent.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecComponent.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecComponent.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecComponent.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import java.util.Map;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.impl.DefaultComponent;
+
+/**
+ * Represents the component that manages {@link ExecEndpoint}. With the
+ * component it is possible to execute an system command.
+ */
+public class ExecComponent extends DefaultComponent {
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        ExecEndpoint endpoint = new ExecEndpoint(uri, this);
+        setProperties(endpoint, parameters);
+        endpoint.setExecutable(remaining);
+        return endpoint;
+    }
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecEndpoint.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecEndpoint.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecEndpoint.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecEndpoint.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,201 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.exec.impl.DefaultExecBinding;
+import org.apache.camel.component.exec.impl.DefaultExecCommandExecutor;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * The endpoint utilizes an {@link ExecCommandExecutor} to execute a system
+ * command when it receives message exchanges.
+ * 
+ * @see Endpoint
+ * @see ExecBinding
+ * @see ExecCommandExecutor
+ * @see ExecCommand
+ * @see ExecResult
+ */
+public class ExecEndpoint extends DefaultEndpoint {
+
+    /**
+     * Indicates that no {@link #timeout} is used.
+     */
+    public static final long NO_TIMEOUT = Long.MAX_VALUE;
+
+    private String executable;
+
+    private String args;
+
+    private String workingDir;
+
+    private long timeout;
+
+    private String outFile;
+
+    private ExecCommandExecutor commandExecutor;
+
+    private ExecBinding binding;
+
+    public ExecEndpoint(String uri, ExecComponent component) {
+        super(uri, component);
+        this.timeout = NO_TIMEOUT;
+        this.binding = new DefaultExecBinding();
+        this.commandExecutor = new DefaultExecCommandExecutor();
+    }
+
+    public Producer createProducer() throws Exception {
+        return new ExecProducer(this);
+    }
+
+    public Consumer createConsumer(Processor processor) throws Exception {
+        throw new UnsupportedOperationException("Consumer not supported for ExecEndpoint!");
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+    /**
+     * @return the executable to be executed; that is the remaining part of the
+     *         endpoint URI
+     * @see ExecBinding#EXEC_COMMAND_EXECUTABLE
+     */
+    public String getExecutable() {
+        return executable;
+    }
+
+    /**
+     * Sets the executable to be executed
+     * 
+     * @param executable must not be empty or <code>null</code>
+     */
+    public void setExecutable(String executable) {
+        ObjectHelper.notEmpty(executable, "executable");
+        this.executable = executable;
+    }
+
+    /**
+     * @return the arguments of the executable application, as configured from
+     *         the endpoint URI
+     * @see ExecBinding#EXEC_COMMAND_ARGS
+     */
+    public String getArgs() {
+        return args;
+    }
+
+    /**
+     * Sets the arguments of the executable application
+     * 
+     * @param args Returns <code>null</code> value if no arguments are
+     *            configured in the endpoint URI
+     */
+    public void setArgs(String args) {
+        this.args = args;
+    }
+
+    /**
+     * @return the working directory of the executable, or <code>null</code>
+     * @see ExecBinding#EXEC_COMMAND_WORKING_DIR
+     */
+    public String getWorkingDir() {
+        return workingDir;
+    }
+
+    /**
+     * Sets the working directory of the executable application
+     * 
+     * @param dir the working directory of the executable. <code>null</code>
+     *            values indicates that the current working directory will be
+     *            used.
+     */
+    public void setWorkingDir(String dir) {
+        this.workingDir = dir;
+    }
+
+    /**
+     * @return The returned value is always a positive <code>long</code>. The
+     *         default value is {@link ExecEndpoint#NO_TIMEOUT}
+     * @see ExecBinding#EXEC_COMMAND_TIMEOUT
+     */
+    public long getTimeout() {
+        return timeout;
+    }
+
+    /**
+     * Sets the timeout.
+     * 
+     * @param timeout The <code>timeout</code> must be a positive long
+     * @see ExecBinding#EXEC_COMMAND_TIMEOUT
+     */
+    public void setTimeout(long timeout) {
+        if (timeout <= 0) {
+            throw new IllegalArgumentException("The timeout must be a positive long!");
+        }
+        this.timeout = timeout;
+    }
+
+    /**
+     * @return <code>null</code> if no out file is set, otherwise returns the
+     *         value of the outFile
+     * @see ExecBinding#EXEC_COMMAND_OUT_FILE
+     */
+    public String getOutFile() {
+        return outFile;
+    }
+
+    /**
+     * @param outFile a not-empty file path
+     * @see ExecBinding#EXEC_COMMAND_OUT_FILE
+     */
+    public void setOutFile(String outFile) {
+        ObjectHelper.notEmpty(outFile, "outFile");
+        this.outFile = outFile;
+    }
+
+    /**
+     * @return The command executor used to execute commands. Defaults to
+     *         {@link DefaultExecCommandExecutror}
+     */
+    public ExecCommandExecutor getCommandExecutor() {
+        return commandExecutor;
+    }
+
+    /**
+     * Sets a custom executor to execute commands.
+     * 
+     * @param commandExecutor a not-null instance of {@link ExecCommandExecutor}
+     */
+    public void setCommandExecutor(ExecCommandExecutor commandExecutor) {
+        ObjectHelper.notNull(commandExecutor, "commandExecutor");
+        this.commandExecutor = commandExecutor;
+    }
+
+    public ExecBinding getBinding() {
+        return binding;
+    }
+
+    public void setBinding(ExecBinding binding) {
+        ObjectHelper.notNull(binding, "binding");
+        this.binding = binding;
+    }
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import org.apache.camel.RuntimeCamelException;
+
+/**
+ * Exception thrown when there is an execution failure.
+ */
+public class ExecException extends RuntimeCamelException {
+
+    private static final long serialVersionUID = 7808703605527644487L;
+
+    public ExecException() {
+    }
+
+    public ExecException(String message) {
+        super(message);
+    }
+
+    public ExecException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public ExecException(Throwable cause) {
+        super(cause);
+    }
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecProducer.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecProducer.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecProducer.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecProducer.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultProducer;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Exec producer
+ * 
+ * @see {link Producer}
+ */
+public class ExecProducer extends DefaultProducer {
+
+    private final Log log;
+
+    private final ExecEndpoint endpoint;
+
+    public ExecProducer(ExecEndpoint endpoint) {
+        super(endpoint);
+        this.endpoint = endpoint;
+        this.log = LogFactory.getLog(ExecProducer.class);
+    }
+
+    public void process(Exchange exchange) throws Exception {
+        ExecCommand execCommand = getBinding().readInput(exchange, endpoint);
+
+        if (log.isInfoEnabled()) {
+            log.info("Executing " + execCommand);
+        }
+        ExecResult result = endpoint.getCommandExecutor().execute(execCommand);
+        ObjectHelper.notNull(result, "The command executor must return a not-null result");
+        log(result);
+        getBinding().writeOutput(exchange, result);
+    }
+
+    private ExecBinding getBinding() {
+        return endpoint.getBinding();
+    }
+
+    private void log(ExecResult result) {
+        String executable = result.getCommand().getExecutable();
+        // 0 means no error, by convention
+        if (result.getExitValue() != 0) {
+            if (log.isErrorEnabled()) {
+                log.error(new StringBuilder(executable).append(" exit value: ").append(result.getExitValue()));
+                log.error(new StringBuilder(executable).append(" stderr: ").append(result.getStderr()));
+            }
+        }
+        if (log.isDebugEnabled()) {
+            log.debug(new StringBuilder(executable).append(" stdout: ").append(result.getStdout()));
+        }
+
+    }
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResult.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResult.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResult.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResult.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.Serializable;
+
+/**
+ * Represents the result of the execution of an {@link ExecCommand}
+ */
+public class ExecResult implements Serializable {
+
+    private static final long serialVersionUID = -2238558080056724637L;
+
+    private final ExecCommand command;
+
+    private int exitValue;
+
+    private InputStream stdout;
+
+    private InputStream stderr;
+
+    public ExecResult(ExecCommand command) {
+        this.command = command;
+        this.stdout = new ByteArrayInputStream(new byte[0]);
+        this.stderr = new ByteArrayInputStream(new byte[0]);
+    }
+
+    /**
+     * @return The command, that produced this result
+     */
+    public ExecCommand getCommand() {
+        return command;
+    }
+
+    /**
+     * @return The exit value of the command executable
+     */
+    public int getExitValue() {
+        return exitValue;
+    }
+
+    public void setExitValue(int exitValue) {
+        this.exitValue = exitValue;
+    }
+
+    /**
+     * @return The stdout of the command executable
+     */
+    public InputStream getStdout() {
+        return stdout;
+    }
+
+    public void setStdout(InputStream stdout) {
+        this.stdout = stdout;
+    }
+
+    /**
+     * @return The stderr of the command executable
+     */
+    public InputStream getStderr() {
+        return stderr;
+    }
+
+    public void setStderr(InputStream stderr) {
+        this.stderr = stderr;
+    }
+
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResultConverter.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResultConverter.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResultConverter.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResultConverter.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import org.w3c.dom.Document;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Default converters for {@link ExecResult}. For details how to extend the
+ * converters check out <a
+ * href="http://camel.apache.org/type-converter.html">the Camel docs for type
+ * converters.</a>
+ */
+@Converter
+public final class ExecResultConverter {
+
+    private static final Log LOG = LogFactory.getLog(ExecResultConverter.class);
+
+    private ExecResultConverter() {
+    }
+
+    @Converter
+    public static InputStream convertToInputStream(ExecResult result) throws FileNotFoundException {
+        return toInputStream(result);
+    }
+
+    @Converter
+    public static String convertToString(ExecResult result, Exchange exchange) throws FileNotFoundException {
+        return convertTo(String.class, exchange, result);
+    }
+
+    @Converter
+    public static Document convertToDocument(ExecResult result, Exchange exchange) throws FileNotFoundException {
+        return convertTo(Document.class, exchange, result);
+    }
+
+    @Converter
+    public static byte[] convertToByteArray(ExecResult result, Exchange exchange) throws FileNotFoundException {
+        return convertTo(byte[].class, exchange, result);
+    }
+
+    /**
+     * Converts <code>ExecResult</code> to the type <code>T</code>.
+     * 
+     * @param <T> The type to convert to
+     * @param type Class instance of the type to which to convert
+     * @param exchange a Camel exchange. If exchange is <code>null</code>, no
+     *            conversion will be made
+     * @param result
+     * @return the converted {@link ExecResult}
+     * @throws FileNotFoundException if theres is a file in the execResult, and
+     *             the file can not be found
+     */
+    public static <T> T convertTo(Class<T> type, Exchange exchange, ExecResult result) throws FileNotFoundException {
+        if (exchange != null) {
+            return (T)exchange.getContext().getTypeConverter().convertTo(type, exchange, toInputStream(result));
+        } else {
+            // should revert to fallback converter if we don't have an exchange
+            return null;
+        }
+    }
+
+    /**
+     * If the ExecResult contains out file,
+     * <code>InputStream<code> with the output of the <code>execResult</code>.
+     * If there is {@link ExecCommand#getOutFile()}, its content is preferred to
+     * {@link ExecResult#getStdout()}
+     * 
+     * @param execResult ExecResult object.
+     * @return InputStream object
+     * @throws FileNotFoundException if the {@link ExecResult#getOutFile()} is
+     *             not <code>null</code>, but can not be found
+     */
+    public static InputStream toInputStream(ExecResult execResult) throws FileNotFoundException {
+        if (execResult == null) {
+            LOG.error("Unable to convert a null exec result!");
+            return null;
+        }
+        InputStream resultVal = execResult.getStdout();
+        // prefer generic file conversion
+        if (execResult.getCommand().getOutFile() != null) {
+            resultVal = new FileInputStream(execResult.getCommand().getOutFile());
+        }
+        return resultVal;
+    }
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecBinding.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecBinding.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecBinding.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecBinding.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,93 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec.impl;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.exec.ExecBinding;
+import org.apache.camel.component.exec.ExecCommand;
+import org.apache.camel.component.exec.ExecEndpoint;
+import org.apache.camel.component.exec.ExecResult;
+import org.apache.camel.util.ObjectHelper;
+
+import static org.apache.camel.component.exec.impl.ExecParseUtils.splitToWhiteSpaceSeparatedTokens;
+
+/**
+ * Default implementation of {@link ExecBinding}.
+ * 
+ * @see DefaultExecBinding#writeOutputInMessage(Message, ExecResult)
+ */
+public class DefaultExecBinding implements ExecBinding {
+
+    public ExecCommand readInput(Exchange exchange, ExecEndpoint endpoint) {
+        ObjectHelper.notNull(exchange, "exchange");
+        ObjectHelper.notNull(endpoint, "endpoint");
+
+        String cmd = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_EXECUTABLE, endpoint.getExecutable(), String.class);
+        String args = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_ARGS, endpoint.getArgs(), String.class);
+        String dir = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_WORKING_DIR, endpoint.getWorkingDir(), String.class);
+        long timeout = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_TIMEOUT, endpoint.getTimeout(), Long.class);
+        String outFilePath = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_OUT_FILE, endpoint.getOutFile(), String.class);
+        InputStream input = exchange.getIn().getBody(InputStream.class);
+
+        List<String> argsList = splitToWhiteSpaceSeparatedTokens(args);
+        File outFile = outFilePath == null ? null : new File(outFilePath);
+        return new ExecCommand(cmd, argsList, dir, timeout, input, outFile);
+    }
+
+    public void writeOutput(Exchange exchange, ExecResult result) {
+        ObjectHelper.notNull(exchange, "exchange");
+        ObjectHelper.notNull(result, "result");
+
+        if (exchange.getPattern().isOutCapable()) {
+            writeOutputInMessage(exchange.getOut(), result);
+            exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders());
+        } else {
+            writeOutputInMessage(exchange.getIn(), result);
+        }
+    }
+
+    /**
+     * Write the {@link ExecResult} in the message body. Write the stderr and
+     * the exit value for convenience in the message headers. <br>
+     * The stdout and/or resultFile should be accessible using a converter or
+     * using the result object directly.
+     * 
+     * @param message a Camel message
+     * @param result an {@link ExecResult} instance
+     */
+    protected void writeOutputInMessage(Message message, ExecResult result) {
+        message.setHeader(EXEC_STDERR, result.getStderr());
+        message.setHeader(EXEC_EXIT_VALUE, result.getExitValue());
+        message.setBody(result);
+    }
+
+    /**
+     * Gets and removes the <code> <code>headerName</code> header form the input
+     * <code>message</code> (the header will not be propagated)
+     */
+    protected <T> T getAndRemoveHeader(Message message, String headerName, T defaultValue, Class<T> headerType) {
+        T h = message.getHeader(headerName, defaultValue, headerType);
+        message.removeHeader(headerName);
+        return h;
+    }
+
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.camel.component.exec.ExecCommand;
+import org.apache.camel.component.exec.ExecCommandExecutor;
+import org.apache.camel.component.exec.ExecEndpoint;
+import org.apache.camel.component.exec.ExecException;
+import org.apache.camel.component.exec.ExecResult;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.exec.CommandLine;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.ExecuteException;
+import org.apache.commons.exec.ExecuteWatchdog;
+import org.apache.commons.exec.PumpStreamHandler;
+import org.apache.commons.exec.ShutdownHookProcessDestroyer;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Executes the command utilizing the <a
+ * href="http://commons.apache.org/exec/">Apache Commmons exec library</a>. Adds
+ * a shutdown hook for every executed process.
+ */
+public class DefaultExecCommandExecutor implements ExecCommandExecutor {
+
+    private static final Log LOG = LogFactory.getLog(DefaultExecCommandExecutor.class);
+
+    public ExecResult execute(ExecCommand command) {
+        ObjectHelper.notNull(command, "command");
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+
+        ExecResult result = new ExecResult(command);
+
+        DefaultExecutor executor = prepareDefaultExecutor(command);
+        // handle error and output of the process and write them to the given
+        // out stream
+        PumpStreamHandler handler = new PumpStreamHandler(out, err, command.getInput());
+        executor.setStreamHandler(handler);
+
+        CommandLine cl = toCommandLine(command);
+
+        try {
+            int exitValue = executor.execute(cl);
+
+            result.setExitValue(exitValue);
+            result.setStdout(new ByteArrayInputStream(out.toByteArray()));
+            result.setStderr(new ByteArrayInputStream(err.toByteArray()));
+            return result;
+
+        } catch (ExecuteException ee) {
+            LOG.error("ExecuteExeption while executing " + command.toString());
+            throw new ExecException("Failed to execute command " + command, ee);
+        } catch (IOException ioe) {
+            // invalid working dir
+            LOG.error("IOException while executing " + command.toString());
+            throw new ExecException("Unable to execute command " + command, ioe);
+        } finally {
+            // the inputStream must be closed after the execution
+            IOUtils.closeQuietly(command.getInput());
+        }
+    }
+
+    protected DefaultExecutor prepareDefaultExecutor(ExecCommand execCommand) {
+        DefaultExecutor executor = new DefaultExecutor();
+        executor.setExitValues(null);
+
+        if (execCommand.getWorkingDir() != null) {
+            executor.setWorkingDirectory(new File(execCommand.getWorkingDir()).getAbsoluteFile());
+        }
+        if (execCommand.getTimeout() != ExecEndpoint.NO_TIMEOUT) {
+            executor.setWatchdog(new ExecuteWatchdog(execCommand.getTimeout()));
+        }
+        executor.setProcessDestroyer(new ShutdownHookProcessDestroyer());
+        return executor;
+    }
+
+    /**
+     * Transforms an exec command to a {@link CommandLine}
+     * 
+     * @param execCommand
+     * @return a {@link CommandLine} object
+     */
+    protected CommandLine toCommandLine(ExecCommand execCommand) {
+        CommandLine cl = new CommandLine(execCommand.getExecutable());
+        List<String> args = execCommand.getArgs();
+        for (String arg : args) {
+            // do not handle quoting here, it is already quoted
+            cl.addArgument(arg, false);
+        }
+        return cl;
+    }
+}

Added: camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/ExecParseUtils.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/ExecParseUtils.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/ExecParseUtils.java (added)
+++ camel/trunk/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/ExecParseUtils.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,115 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Utility class for parsing, used by the Camel Exec component.
+ */
+public final class ExecParseUtils {
+
+    public static final String WHITESPACE = " ";
+
+    public static final String QUOTE_CHAR = "\"";
+
+    private ExecParseUtils() {
+    }
+
+    /**
+     * Splits the input line string by {@link #WHITESPACE}. Supports quoting the
+     * white-spaces with a {@link #QUOTE_CHAR}. A quote itself can also be
+     * quoted with another #{@link #QUOTE_CHAR}. More than two quotes in a
+     * sequence is not allowed<br>
+     * E.g. The string
+     * <code>"arg 1"  arg2<code> will return the tokens <code>arg 1</code>,
+     * <code>arg2</code><br>
+     * The string
+     * <code>""arg 1""  "arg2" arg 3<code> will return the tokens <code>"arg 1"</code>
+     * , <code>arg2</code>,<code>arg</code> and <code>3</code> <br>
+     * 
+     * @param input
+     * @return a list of {@link #WHITESPACE} separated tokens
+     */
+    public static List<String> splitToWhiteSpaceSeparatedTokens(String input) {
+        if (input == null) {
+            return new ArrayList<String>();
+        }
+        StringTokenizer tokenizer = new StringTokenizer(input.trim(), QUOTE_CHAR + WHITESPACE, true);
+        List<String> args = new ArrayList<String>();
+
+        StringBuilder quotedText = new StringBuilder();
+
+        while (tokenizer.hasMoreTokens()) {
+            String token = tokenizer.nextToken();
+            if (QUOTE_CHAR.equals(token)) {
+                // if we have a quote, add the next tokens to the quoted text
+                // until the quoting has finished
+                quotedText.append(QUOTE_CHAR);
+                String buffer = quotedText.toString();
+                if (isSingleQuoted(buffer) || isDoubleQuoted(buffer)) {
+                    args.add(buffer.substring(1, buffer.length() - 1));
+                    quotedText = new StringBuilder();
+                }
+            } else if (WHITESPACE.equals(token)) {
+                // a white space, if in quote, add the white space, otherwise
+                // skip it
+                if (quotedText.length() > 0) {
+                    quotedText.append(WHITESPACE);
+                }
+            } else {
+                if (quotedText.length() > 0) {
+                    quotedText.append(token);
+                } else {
+                    args.add(token);
+                }
+            }
+        }
+        if (quotedText.length() > 0) {
+            throw new IllegalArgumentException("Invalid quoting found in args " + quotedText);
+        }
+        return args;
+    }
+
+    /**
+     * Tests if the input is enclosed within {@link #QUOTE_CHAR} characters
+     * 
+     * @param input a not null String
+     * @return
+     */
+    protected static boolean isSingleQuoted(String input) {
+        if (input == null || input.trim().length() == 0) {
+            return false;
+        }
+        return input.matches("(^" + QUOTE_CHAR + "{1}([^" + QUOTE_CHAR + "]+)" + QUOTE_CHAR + "{1})");
+    }
+
+    /**
+     * Tests if the input is enclosed within a double-{@link #QUOTE_CHAR} string
+     * 
+     * @param input a not null String
+     * @return true if the regular expression is matched
+     */
+    protected static boolean isDoubleQuoted(String input) {
+        if (input == null || input.trim().length() == 0) {
+            return false;
+        }
+        return input.matches("(^" + QUOTE_CHAR + "{2}([^" + QUOTE_CHAR + "]+)" + QUOTE_CHAR + "{2})");
+    }
+}

Added: camel/trunk/components/camel-exec/src/main/resources/META-INF/LICENSE.txt
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/resources/META-INF/LICENSE.txt?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/resources/META-INF/LICENSE.txt (added)
+++ camel/trunk/components/camel-exec/src/main/resources/META-INF/LICENSE.txt Thu Apr  1 11:20:51 2010
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+

Added: camel/trunk/components/camel-exec/src/main/resources/META-INF/NOTICE.txt
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/resources/META-INF/NOTICE.txt?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/resources/META-INF/NOTICE.txt (added)
+++ camel/trunk/components/camel-exec/src/main/resources/META-INF/NOTICE.txt Thu Apr  1 11:20:51 2010
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.

Added: camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/TypeConverter
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/TypeConverter?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/TypeConverter (added)
+++ camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/TypeConverter Thu Apr  1 11:20:51 2010
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.camel.component.exec

Added: camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/component/exec
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/component/exec?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/component/exec (added)
+++ camel/trunk/components/camel-exec/src/main/resources/META-INF/services/org/apache/camel/component/exec Thu Apr  1 11:20:51 2010
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class=org.apache.camel.component.exec.ExecComponent

Added: camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecEndpointTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecEndpointTest.java?rev=929929&view=auto
==============================================================================
--- camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecEndpointTest.java (added)
+++ camel/trunk/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecEndpointTest.java Thu Apr  1 11:20:51 2010
@@ -0,0 +1,209 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.exec;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+
+import static org.apache.camel.component.exec.ExecEndpoint.NO_TIMEOUT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test the configuration of {@link ExecEndpoint}
+ */
+@ContextConfiguration
+public class ExecEndpointTest extends AbstractJUnit4SpringContextTests {
+
+    @Autowired
+    private CamelContext camelContext;
+
+    @Autowired
+    private ExecBinding customBinding;
+
+    @Autowired
+    private ExecCommandExecutor customExecutor;
+
+    private Component component;
+
+    @Before
+    public void setUp() throws Exception {
+        component = camelContext.getComponent("exec");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testValidComponentDescriptor() {
+        assertNotNull("The Camel Exec component can not be resolved", component);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointDefaultConf() throws Exception {
+        ExecEndpoint e = createExecEndpoint("exec:test");
+        assertTrue("The Camel Exec component must create instances of " + ExecEndpoint.class.getSimpleName(), e instanceof ExecEndpoint);
+        assertNull(e.getArgs());
+        assertNull(e.getWorkingDir());
+        assertNull(e.getOutFile());
+
+        assertEquals(NO_TIMEOUT, e.getTimeout());
+        assertEquals("test", e.getExecutable());
+        assertNotNull(e.getCommandExecutor());
+        assertNotNull(e.getBinding());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointDefaultNoTimeout() throws Exception {
+        ExecEndpoint e = createExecEndpoint("exec:test");
+        assertEquals(ExecEndpoint.NO_TIMEOUT, e.getTimeout());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointCustomBinding() throws Exception {
+        ExecEndpoint e = createExecEndpoint("exec:test?binding=#customBinding");
+        assertSame("Expected is the custom customBinding reference from the application context", customBinding, e.getBinding());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointCustomCommandExecutor() throws Exception {
+        ExecEndpoint e = createExecEndpoint("exec:test?commandExecutor=#customExecutor");
+        assertSame("Expected is the custom customExecutor reference from the application context", customExecutor, e.getCommandExecutor());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointWithArgs() throws Exception {
+        String args = "arg1 arg2 arg3";
+        ExecEndpoint e = createExecEndpoint("exec:test?args=" + args);
+        assertEquals(args, e.getArgs());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointWithArgs2() throws Exception {
+        String args = "arg1 \"arg2 \" arg3";
+        ExecEndpoint e = createExecEndpoint("exec:test?args=" + args);
+        assertEquals(args, e.getArgs());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointWithTimeout() throws Exception {
+        long timeout = 1999999L;
+        ExecEndpoint e = createExecEndpoint("exec:test?timeout=" + timeout);
+        assertEquals(timeout, e.getTimeout());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointWithOutFile() throws Exception {
+        String outFile = "output.txt";
+        ExecEndpoint e = createExecEndpoint("exec:test?outFile=" + outFile);
+        assertEquals(outFile, e.getOutFile());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointWithWorkingDir() throws Exception {
+        String workingDir = "/workingdir";
+        ExecEndpoint e = createExecEndpoint("exec:test?workingDir=" + workingDir);
+        assertEquals(workingDir, e.getWorkingDir());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointEscapedWorkingDir() throws Exception {
+        String cmd = "temp.exe";
+        String dir = "\"c:/program files/wokr/temp\"";
+        String uri = "exec:" + cmd + "?workingDir=" + dir;
+
+        ExecEndpoint endpoint = createExecEndpoint(uri);
+        assertEquals(cmd, endpoint.getExecutable());
+        assertNull(endpoint.getArgs());
+        assertNotNull(endpoint.getCommandExecutor());
+
+        assertEquals(dir, endpoint.getWorkingDir());
+
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointEscapedCommand() throws Exception {
+        String executable = "\"C:/Program Files/test/text.exe\"";
+        String uri = "exec:" + executable;
+
+        ExecEndpoint endpoint = createExecEndpoint(uri);
+
+        assertNull(endpoint.getArgs());
+        assertNull(endpoint.getWorkingDir());
+        assertNotNull(endpoint.getCommandExecutor());
+
+        assertEquals(executable, endpoint.getExecutable());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointComposite() throws Exception {
+        String workingDir = "/workingdir";
+        String argsEscaped = "arg1 arg2 \"arg 3\"";
+        long timeout = 10000L;
+
+        ExecEndpoint e = createExecEndpoint("exec:executable.exe?workingDir=" + workingDir + "&timeout=" + timeout + "&args=" + argsEscaped);
+        assertEquals(workingDir, e.getWorkingDir());
+        assertEquals(argsEscaped, e.getArgs());
+        assertEquals(timeout, e.getTimeout());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testCreateEndpointComposite2() throws Exception {
+        String workingDir = "/workingdir";
+        String outFile = "target/outfile.xml";
+        long timeout = 10000;
+        StringBuilder builder = new StringBuilder();
+        builder.append("exec:executable.exe").append("?workingDir=" + workingDir).append("&timeout=" + timeout);
+        builder.append("&outFile=" + outFile);
+        builder.append("&commandExecutor=#customExecutor&binding=#customBinding");
+
+        ExecEndpoint e = createExecEndpoint(builder.toString());
+        assertEquals(workingDir, e.getWorkingDir());
+        assertEquals(timeout, e.getTimeout());
+        assertEquals(outFile, e.getOutFile());
+        assertSame(customBinding, e.getBinding());
+        assertSame(customExecutor, e.getCommandExecutor());
+    }
+
+    private ExecEndpoint createExecEndpoint(String uri) throws Exception {
+        logger.debug("Using Exec endpoint URI " + uri);
+        return (ExecEndpoint)component.createEndpoint(uri);
+
+    }
+}