001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.component.exec;
018
019 import java.io.ByteArrayInputStream;
020 import java.io.FileInputStream;
021 import java.io.FileNotFoundException;
022 import java.io.IOException;
023 import java.io.InputStream;
024
025 import org.w3c.dom.Document;
026
027 import org.apache.camel.Converter;
028 import org.apache.camel.Exchange;
029 import org.apache.commons.io.IOUtils;
030 import org.slf4j.Logger;
031 import org.slf4j.LoggerFactory;
032
033 /**
034 * Default converters for {@link ExecResult}. For details how to extend the
035 * converters check out <a
036 * href="http://camel.apache.org/type-converter.html">the Camel docs for type
037 * converters.</a>
038 */
039 @Converter
040 public final class ExecResultConverter {
041
042 private static final Logger LOG = LoggerFactory.getLogger(ExecResultConverter.class);
043
044 private ExecResultConverter() {
045 }
046
047 @Converter
048 public static InputStream convertToInputStream(ExecResult result) throws FileNotFoundException {
049 return toInputStream(result);
050 }
051
052 @Converter
053 public static byte[] convertToByteArray(ExecResult result, Exchange exchange) throws FileNotFoundException, IOException {
054 InputStream stream = toInputStream(result);
055 try {
056 return IOUtils.toByteArray(stream);
057 } finally {
058 IOUtils.closeQuietly(stream);
059 }
060 }
061
062 @Converter
063 public static String convertToString(ExecResult result, Exchange exchange) throws FileNotFoundException {
064 return convertTo(String.class, exchange, result);
065 }
066
067 @Converter
068 public static Document convertToDocument(ExecResult result, Exchange exchange) throws FileNotFoundException {
069 return convertTo(Document.class, exchange, result);
070 }
071
072 /**
073 * Converts <code>ExecResult</code> to the type <code>T</code>.
074 *
075 * @param <T> The type to convert to
076 * @param type Class instance of the type to which to convert
077 * @param exchange a Camel exchange. If exchange is <code>null</code>, no
078 * conversion will be made
079 * @param result the exec result
080 * @return the converted {@link ExecResult}
081 * @throws FileNotFoundException if there is a file in the execResult, and
082 * the file can not be found
083 */
084 @SuppressWarnings("unchecked")
085 public static <T> T convertTo(Class<T> type, Exchange exchange, ExecResult result) throws FileNotFoundException {
086 InputStream is = toInputStream(result);
087 if (is != null) {
088 return exchange.getContext().getTypeConverter().convertTo(type, exchange, is);
089 } else {
090 // use Void to indicate we cannot convert it
091 // (prevents Camel from using a fallback converter which may convert a String from the instance name)
092 return (T) Void.TYPE;
093 }
094 }
095
096 /**
097 * Returns <code>InputStream</code> object with the <i>output</i> of the
098 * executable. If there is {@link ExecCommand#getOutFile()}, its content is
099 * preferred to {@link ExecResult#getStdout()}. If no out file is set, and
100 * the stdout of the exec result is <code>null</code> returns the stderr of
101 * the exec result. <br>
102 * If the output stream is of type <code>ByteArrayInputStream</code>, its
103 * <code>reset()</code> method is called.
104 *
105 * @param execResult ExecResult object to convert to InputStream.
106 * @return InputStream object with the <i>output</i> of the executable.
107 * Returns <code>null</code> if both {@link ExecResult#getStdout()}
108 * and {@link ExecResult#getStderr()} are <code>null</code> , or if
109 * the <code>execResult</code> is <code>null</code>.
110 * @throws FileNotFoundException if the {@link ExecCommand#getOutFile()} can
111 * not be opened. In this case the out file must have had a not
112 * <code>null</code> value
113 */
114 public static InputStream toInputStream(ExecResult execResult) throws FileNotFoundException {
115 if (execResult == null) {
116 LOG.warn("Received a null ExecResult instance to convert!");
117 return null;
118 }
119 // prefer the out file for output
120 InputStream result;
121 if (execResult.getCommand().getOutFile() != null) {
122 result = new FileInputStream(execResult.getCommand().getOutFile());
123 } else {
124 // if the stdout is null, return the stderr.
125 if (execResult.getStdout() == null && execResult.getCommand().isUseStderrOnEmptyStdout()) {
126 LOG.warn("ExecResult has no stdout, will fallback to use stderr.");
127 result = execResult.getStderr();
128 } else {
129 result = execResult.getStdout() != null ? execResult.getStdout() : null;
130 }
131 }
132 // reset the stream if it was already read.
133 resetIfByteArrayInputStream(result);
134 return result;
135 }
136
137 /**
138 * Resets the stream, only if it's a ByteArrayInputStream.
139 */
140 private static void resetIfByteArrayInputStream(InputStream stream) {
141 if (stream != null && stream instanceof ByteArrayInputStream) {
142 try {
143 stream.reset();
144 } catch (IOException ioe) {
145 LOG.error("Unable to reset the stream ", ioe);
146 }
147 }
148 }
149 }