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.apache.commons.logging.Log; 031 import org.apache.commons.logging.LogFactory; 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 Log LOG = LogFactory.getLog(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 }