/** * 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); } } } }