camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From davscl...@apache.org
Subject [1/2] camel git commit: CAMEL-9225: camel-exec - Enrich exception with stdout/stderr. Thanks to Timo Bruckner for the patch.
Date Tue, 27 Oct 2015 08:35:04 GMT
Repository: camel
Updated Branches:
  refs/heads/master b6c2e1dd2 -> 678252004


CAMEL-9225: camel-exec - Enrich exception with stdout/stderr. Thanks to Timo Bruckner for
the patch.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/534b4a8e
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/534b4a8e
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/534b4a8e

Branch: refs/heads/master
Commit: 534b4a8ef3b89b35bd266c7c779f7fbd4b3ce03a
Parents: b6c2e1d
Author: Claus Ibsen <davsclaus@apache.org>
Authored: Tue Oct 27 09:35:17 2015 +0100
Committer: Claus Ibsen <davsclaus@apache.org>
Committed: Tue Oct 27 09:35:17 2015 +0100

----------------------------------------------------------------------
 .../camel/component/exec/ExecException.java     | 30 +++++--
 .../exec/impl/DefaultExecCommandExecutor.java   | 53 ++++++-----
 .../component/exec/ExecJavaProcessTest.java     | 92 +++++++++++++++++---
 .../ProvokeExceptionExecCommandExecutor.java    | 46 ++++++++++
 4 files changed, 176 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/534b4a8e/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java
----------------------------------------------------------------------
diff --git a/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java
b/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java
index d32a38b..afc762a 100644
--- a/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java
+++ b/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecException.java
@@ -16,27 +16,43 @@
  */
 package org.apache.camel.component.exec;
 
+import java.io.InputStream;
 import org.apache.camel.RuntimeCamelException;
 
 /**
  * Exception thrown when there is an execution failure.
  */
 public class ExecException extends RuntimeCamelException {
+    
+    private final int exitValue;
+    private final InputStream stdout;
+    private final InputStream stderr;
 
     private static final long serialVersionUID = 7808703605527644487L;
 
-    public ExecException() {
-    }
-
-    public ExecException(String message) {
+    public ExecException(String message, final InputStream stdout, final InputStream stderr,
final int exitValue) {
         super(message);
+        this.exitValue = exitValue;
+        this.stderr = stderr;
+        this.stdout = stdout;
     }
 
-    public ExecException(String message, Throwable cause) {
+    public ExecException(String message, final InputStream stdout, final InputStream stderr,
final int exitValue, Throwable cause) {
         super(message, cause);
+        this.exitValue = exitValue;
+        this.stderr = stderr;
+        this.stdout = stdout;
+    }
+
+    public int getExitValue() {
+        return exitValue;
+    }
+
+    public InputStream getStdout() {
+        return stdout;
     }
 
-    public ExecException(Throwable cause) {
-        super(cause);
+    public InputStream getStderr() {
+        return stderr;
     }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/534b4a8e/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java
----------------------------------------------------------------------
diff --git a/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java
b/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java
index b2ed60e..3cbce5b 100644
--- a/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java
+++ b/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecCommandExecutor.java
@@ -1,18 +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
+ * 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
+ * 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.
+ * 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;
 
@@ -51,6 +51,7 @@ public class DefaultExecCommandExecutor implements ExecCommandExecutor {
 
     private static final Logger LOG = LoggerFactory.getLogger(DefaultExecCommandExecutor.class);
 
+    @Override
     public ExecResult execute(ExecCommand command) {
         notNull(command, "command");
 
@@ -76,30 +77,34 @@ public class DefaultExecCommandExecutor implements ExecCommandExecutor
{
 
         } catch (ExecuteException ee) {
             LOG.error("ExecException while executing command: " + command.toString() + "
- " + ee.getMessage());
-            throw new ExecException("Failed to execute command " + command, ee);
+
+            InputStream stdout = out.size() == 0 ? null : new ByteArrayInputStream(out.toByteArray());
+            InputStream stderr = err.size() == 0 ? null : new ByteArrayInputStream(err.toByteArray());
+
+            throw new ExecException("Failed to execute command " + command, stdout, stderr,
ee.getExitValue(), ee);
+
         } catch (IOException ioe) {
+
+            InputStream stdout = out.size() == 0 ? null : new ByteArrayInputStream(out.toByteArray());
+            InputStream stderr = err.size() == 0 ? null : new ByteArrayInputStream(err.toByteArray());
+
+            int exitValue = 0; // use 0 as exit value as the executor didn't return the value
+            if (executor instanceof ExecDefaultExecutor) {
+                // get the exit value from the executor as it captures this to work around
the common-exec bug
+                exitValue = ((ExecDefaultExecutor) executor).getExitValue();
+            }
+
             // workaround to ignore if the stream was already closes due some race condition
in commons-exec
             String msg = ioe.getMessage();
             if (msg != null && "stream closed".equals(msg.toLowerCase(Locale.ENGLISH)))
{
                 LOG.debug("Ignoring Stream closed IOException", ioe);
-                // if the size is zero, we have no output, so construct the result
-                // with null (required by ExecResult)
-                InputStream stdout = out.size() == 0 ? null : new ByteArrayInputStream(out.toByteArray());
-                InputStream stderr = err.size() == 0 ? null : new ByteArrayInputStream(err.toByteArray());
-
-                // use 0 as exit value as the executor didn't return the value
-                int exitValue = 0;
-                if (executor instanceof ExecDefaultExecutor) {
-                    // get the exit value from the executor as it captures this to work around
the common-exec bug
-                    exitValue = ((ExecDefaultExecutor) executor).getExitValue();
-                }
 
                 ExecResult result = new ExecResult(command, stdout, stderr, exitValue);
                 return result;
             }
             // invalid working dir
             LOG.error("IOException while executing command: " + command.toString() + " -
" + ioe.getMessage());
-            throw new ExecException("Unable to execute command " + command, ioe);
+            throw new ExecException("Unable to execute command " + command, stdout, stderr,
exitValue, ioe);
         } finally {
             // the inputStream must be closed after the execution
             IOUtils.closeQuietly(command.getInput());
@@ -123,7 +128,7 @@ public class DefaultExecCommandExecutor implements ExecCommandExecutor
{
     /**
      * Transforms an {@link ExecCommand} to a {@link CommandLine}. No quoting fo
      * the arguments is used.
-     * 
+     *
      * @param execCommand a not-null <code>ExecCommand</code> instance.
      * @return a {@link CommandLine} object.
      */

http://git-wip-us.apache.org/repos/asf/camel/blob/534b4a8e/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecJavaProcessTest.java
----------------------------------------------------------------------
diff --git a/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecJavaProcessTest.java
b/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecJavaProcessTest.java
index d77e661..224f38a 100644
--- a/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecJavaProcessTest.java
+++ b/components/camel-exec/src/test/java/org/apache/camel/component/exec/ExecJavaProcessTest.java
@@ -1,18 +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
+ * 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
+ * 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.
+ * 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;
 
@@ -25,6 +25,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.Produce;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.AdviceWithRouteBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.converter.IOConverter;
@@ -49,7 +50,11 @@ import static org.apache.camel.component.exec.ExecutableJavaProgram.PRINT_IN_STD
 import static org.apache.camel.component.exec.ExecutableJavaProgram.READ_INPUT_LINES_AND_PRINT_THEM;
 import static org.apache.camel.component.exec.ExecutableJavaProgram.SLEEP_WITH_TIMEOUT;
 import static org.apache.camel.component.exec.ExecutableJavaProgram.THREADS;
+import org.apache.camel.component.exec.impl.ProvokeExceptionExecCommandExecutor;
+import org.apache.camel.impl.JndiRegistry;
 import static org.apache.commons.io.IOUtils.LINE_SEPARATOR;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 /**
  * Tests the functionality of the {@link ExecComponent}, executing<br>
@@ -58,7 +63,7 @@ import static org.apache.commons.io.IOUtils.LINE_SEPARATOR;
  * is set.</b> This is a more credible assumption, than assuming that java is in
  * the path, because the Maven scripts build the path to java with the JAVA_HOME
  * environment variable.
- * 
+ *
  * @see {@link ExecutableJavaProgram}
  */
 public class ExecJavaProcessTest extends CamelTestSupport {
@@ -70,6 +75,18 @@ public class ExecJavaProcessTest extends CamelTestSupport {
 
     @EndpointInject(uri = "mock:output")
     MockEndpoint output;
+    
+    /**
+     * Create JndiRegistry and bind custom {@link org.apache.camel.component.exec.ExecCommandExecutor}
+     * @return 
+     * @throws java.lang.Exception
+     */
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry registry = super.createRegistry();
+        registry.bind("executorMock", new ProvokeExceptionExecCommandExecutor());
+        return registry;
+    } 
 
     @Test
     public void testExecJavaProcessExitCode0() throws Exception {
@@ -123,7 +140,7 @@ public class ExecJavaProcessTest extends CamelTestSupport {
         // the second conversion should not need a reset, this is handled
         // in the type converter.
         String out2 = e.getIn().getBody(String.class);
-        
+
         output.assertIsSatisfied();
         assertEquals(PRINT_IN_STDOUT, out1);
         assertEquals(out1, out2);
@@ -348,12 +365,46 @@ public class ExecJavaProcessTest extends CamelTestSupport {
         assertEquals(expected, IOUtils.toString(inBody.getStdout()));
     }
 
+    /**
+     * Test for thrown {@link ExecException} and access stderr and exitValue
+     * of thrown Exception
+     */
+    @Test
+    public void testExecJavaProcessWithThrownExecException() throws Exception {
+        //add CustomExecutor
+        context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder()
{
+            @Override
+            public void configure() throws Exception {
+                weaveByToString(".*java.*").replace().to("exec:java?commandExecutor=#executorMock");
+            }
+        });
+
+        output.setExpectedMessageCount(0);
+        Exchange out = sendFailExchange(EXIT_WITH_VALUE_0, NO_TIMEOUT);
+        assertEquals(ExecException.class, out.getException().getClass());
+
+        //test if exitValue and stderr are accessible through thrown ExecException
+        ExecException ee = (ExecException) out.getException();
+        assertNotNull(ee.getExitValue());
+        assertNotNull(ee.getStderr());
+
+        output.assertIsSatisfied();
+    }
+
     protected Exchange sendExchange(final Object commandArgument, final long timeout) {
-        return sendExchange(commandArgument, timeout, "testBody", false);
+        return sendExchange(commandArgument, buildArgs(commandArgument), timeout, "testBody",
false);
+
+    }
+
+    protected Exchange sendFailExchange(final Object commandArgument, final long timeout)
{
+        return sendExchange(commandArgument, buildFailArgs(commandArgument), timeout, "testBody",
false);
     }
 
     protected Exchange sendExchange(final Object commandArgument, final long timeout, final
String body, final boolean useStderrOnEmptyStdout) {
-        final List<String> args = buildArgs(commandArgument);
+        return sendExchange(commandArgument, buildArgs(commandArgument), timeout, body, useStderrOnEmptyStdout);
+    }
+
+    protected Exchange sendExchange(final Object commandArgument, final List<String>
args, final long timeout, final String body, final boolean useStderrOnEmptyStdout) {
         final String javaAbsolutePath = buildJavaExecutablePath();
 
         return producerTemplate.send(new Processor() {
@@ -379,6 +430,19 @@ public class ExecJavaProcessTest extends CamelTestSupport {
         return args;
     }
 
+    /**
+     * Build arguments for execution which will result in error
+     */
+    List<String> buildFailArgs(Object commandArgument) {
+        String classpath = System.getProperty("java.class.path");
+        List<String> args = new ArrayList<String>();
+        args.add("-failArg");
+        args.add(classpath);
+        args.add(EXECUTABLE_PROGRAM_ARG);
+        args.add(commandArgument.toString());
+        return args;
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {

http://git-wip-us.apache.org/repos/asf/camel/blob/534b4a8e/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ProvokeExceptionExecCommandExecutor.java
----------------------------------------------------------------------
diff --git a/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ProvokeExceptionExecCommandExecutor.java
b/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ProvokeExceptionExecCommandExecutor.java
new file mode 100644
index 0000000..8bdeb08
--- /dev/null
+++ b/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ProvokeExceptionExecCommandExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * 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.
+ */
+package org.apache.camel.component.exec.impl;
+
+import org.apache.camel.component.exec.ExecCommand;
+import org.apache.camel.component.exec.ExecDefaultExecutor;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.ShutdownHookProcessDestroyer;
+
+/**
+ * Mock of {@link ExecCommandExecutor} which provokes to throw an
+ * {@link org.apache.camel.component.exec.ExecException}
+ */
+public class ProvokeExceptionExecCommandExecutor extends DefaultExecCommandExecutor {
+
+    @Override
+    protected DefaultExecutor prepareDefaultExecutor(ExecCommand execCommand) {
+        DefaultExecutor executor = new DefaultExecutorMock();
+        executor.setExitValues(null);
+        executor.setProcessDestroyer(new ShutdownHookProcessDestroyer());
+
+        return executor;
+    }
+
+    public class DefaultExecutorMock extends ExecDefaultExecutor {
+
+        @Override
+        public boolean isFailure(int exitValue) {
+            //provoke ExecuteException
+            return true;
+        }
+    }
+}
\ No newline at end of file


Mime
View raw message