/**
* 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.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import org.w3c.dom.Document;
import org.apache.camel.Converter;
import org.apache.camel.Exchange;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 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 Logger LOG = LoggerFactory.getLogger(ExecResultConverter.class);
private ExecResultConverter() {
}
@Converter
public static InputStream convertToInputStream(ExecResult result) throws FileNotFoundException {
return toInputStream(result);
}
@Converter
public static byte[] convertToByteArray(ExecResult result, Exchange exchange) throws FileNotFoundException, IOException {
InputStream stream = toInputStream(result);
try {
return IOUtils.toByteArray(stream);
} finally {
IOUtils.closeQuietly(stream);
}
}
@Converter
public static String convertToString(ExecResult result, Exchange exchange) throws FileNotFoundException {
// special for string, as we want an empty string if no output from stdin / stderr
InputStream is = toInputStream(result);
if (is != null) {
return exchange.getContext().getTypeConverter().convertTo(String.class, exchange, is);
} else {
// no stdin/stdout, so return an empty string
return "";
}
}
@Converter
public static Document convertToDocument(ExecResult result, Exchange exchange) throws FileNotFoundException {
return convertTo(Document.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 the exec result
* @return the converted {@link ExecResult}
* @throws FileNotFoundException if there is a file in the execResult, and
* the file can not be found
*/
@SuppressWarnings("unchecked")
private static <T> T convertTo(Class<T> type, Exchange exchange, ExecResult result) throws FileNotFoundException {
InputStream is = toInputStream(result);
if (is != null) {
return exchange.getContext().getTypeConverter().convertTo(type, exchange, is);
} else {
// use Void to indicate we cannot convert it
// (prevents Camel from using a fallback converter which may convert a String from the instance name)
return (T) Void.TYPE;
}
}
/**
* Returns <code>InputStream</code> object with the <i>output</i> of the
* executable. If there is {@link ExecCommand#getOutFile()}, its content is
* preferred to {@link ExecResult#getStdout()}. If no out file is set, and
* the stdout of the exec result is <code>null</code> returns the stderr of
* the exec result. <br>
* If the output stream is of type <code>ByteArrayInputStream</code>, its
* <code>reset()</code> method is called.
*
* @param execResult ExecResult object to convert to InputStream.
* @return InputStream object with the <i>output</i> of the executable.
* Returns <code>null</code> if both {@link ExecResult#getStdout()}
* and {@link ExecResult#getStderr()} are <code>null</code> , or if
* the <code>execResult</code> is <code>null</code>.
* @throws FileNotFoundException if the {@link ExecCommand#getOutFile()} can
* not be opened. In this case the out file must have had a not
* <code>null</code> value
*/
private static InputStream toInputStream(ExecResult execResult) throws FileNotFoundException {
if (execResult == null) {
LOG.warn("Received a null ExecResult instance to convert!");
return null;
}
// prefer the out file for output
InputStream result;
if (execResult.getCommand().getOutFile() != null) {
result = new FileInputStream(execResult.getCommand().getOutFile());
} else {
// if the stdout is null, return the stderr.
if (execResult.getStdout() == null && execResult.getCommand().isUseStderrOnEmptyStdout()) {
LOG.warn("ExecResult has no stdout, will fallback to use stderr.");
result = execResult.getStderr();
} else {
result = execResult.getStdout() != null ? execResult.getStdout() : null;
}
}
// reset the stream if it was already read.
resetIfByteArrayInputStream(result);
return result;
}
/**
* Resets the stream, only if it's a ByteArrayInputStream.
*/
private static void resetIfByteArrayInputStream(InputStream stream) {
if (stream != null && stream instanceof ByteArrayInputStream) {
try {
stream.reset();
} catch (IOException ioe) {
LOG.error("Unable to reset the stream ", ioe);
}
}
}
}