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 public static <T> T convertTo(Class<T> type, Exchange exchange, ExecResult result) throws FileNotFoundException { 085 InputStream is = toInputStream(result); 086 if (is != null) { 087 return exchange.getContext().getTypeConverter().convertTo(type, exchange, is); 088 } else { 089 // use Void to indicate we cannot convert it 090 // (prevents Camel from using a fallback converter which may convert a String from the instance name) 091 return (T) Void.TYPE; 092 } 093 } 094 095 /** 096 * Returns <code>InputStream</code> object with the <i>output</i> of the 097 * executable. If there is {@link ExecCommand#getOutFile()}, its content is 098 * preferred to {@link ExecResult#getStdout()}. If no out file is set, and 099 * the stdout of the exec result is <code>null</code> returns the stderr of 100 * the exec result. <br> 101 * If the output stream is of type <code>ByteArrayInputStream</code>, its 102 * <code>reset()</code> method is called. 103 * 104 * @param execResult ExecResult object to convert to InputStream. 105 * @return InputStream object with the <i>output</i> of the executable. 106 * Returns <code>null</code> if both {@link ExecResult#getStdout()} 107 * and {@link ExecResult#getStderr()} are <code>null</code> , or if 108 * the <code>execResult</code> is <code>null</code>. 109 * @throws FileNotFoundException if the {@link ExecCommand#getOutFile()} can 110 * not be opened. In this case the out file must have had a not 111 * <code>null</code> value 112 */ 113 public static InputStream toInputStream(ExecResult execResult) throws FileNotFoundException { 114 if (execResult == null) { 115 LOG.warn("Received a null ExecResult instance to convert!"); 116 return null; 117 } 118 // prefer the out file for output 119 InputStream result; 120 if (execResult.getCommand().getOutFile() != null) { 121 result = new FileInputStream(execResult.getCommand().getOutFile()); 122 } else { 123 // if the stdout is null, return the stderr. 124 if (execResult.getStdout() == null && execResult.getCommand().isUseStderrOnEmptyStdout()) { 125 LOG.warn("ExecResult has no stdout, will fallback to use stderr."); 126 result = execResult.getStderr(); 127 } else { 128 result = execResult.getStdout() != null ? execResult.getStdout() : null; 129 } 130 } 131 // reset the stream if it was already read. 132 resetIfByteArrayInputStream(result); 133 return result; 134 } 135 136 /** 137 * Resets the stream, only if it's a ByteArrayInputStream. 138 */ 139 private static void resetIfByteArrayInputStream(InputStream stream) { 140 if (stream != null && stream instanceof ByteArrayInputStream) { 141 try { 142 stream.reset(); 143 } catch (IOException ioe) { 144 LOG.error("Unable to reset the stream ", ioe); 145 } 146 } 147 } 148 }