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 */ 017package org.apache.camel.component.file; 018 019import java.io.BufferedReader; 020import java.io.File; 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.Reader; 024import java.io.Serializable; 025 026import org.apache.camel.Converter; 027import org.apache.camel.Exchange; 028import org.apache.camel.FallbackConverter; 029import org.apache.camel.NoTypeConversionAvailableException; 030import org.apache.camel.TypeConverter; 031import org.apache.camel.converter.IOConverter; 032import org.apache.camel.spi.TypeConverterRegistry; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036/** 037 * A set of converter methods for working with generic file types 038 */ 039@Converter 040public final class GenericFileConverter { 041 042 private static final Logger LOG = LoggerFactory.getLogger(GenericFileConverter.class); 043 044 private GenericFileConverter() { 045 // Helper Class 046 } 047 048 @FallbackConverter 049 public static Object convertTo(Class<?> type, Exchange exchange, Object value, TypeConverterRegistry registry) 050 throws IOException, NoTypeConversionAvailableException { 051 052 // use a fallback type converter so we can convert the embedded body if the value is GenericFile 053 if (GenericFile.class.isAssignableFrom(value.getClass())) { 054 055 GenericFile<?> file = (GenericFile<?>) value; 056 Class<?> from = file.getBody().getClass(); 057 058 // maybe from is already the type we want 059 if (from.isAssignableFrom(type)) { 060 return file.getBody(); 061 } 062 063 // no then try to lookup a type converter 064 TypeConverter tc = registry.lookup(type, from); 065 if (tc != null) { 066 Object body = file.getBody(); 067 // if its a file and we have a charset then use a reader to ensure we read the content using the given charset 068 // this is a bit complicated, but a file consumer can be configured with an explicit charset, which means 069 // we should read the file content with that given charset, and ignore any other charset properties 070 071 // if the desired type is InputStream or Reader we can use the optimized methods 072 if (Reader.class.isAssignableFrom(type)) { 073 Reader reader = genericFileToReader(file, exchange); 074 if (reader != null) { 075 return reader; 076 } 077 } 078 if (InputStream.class.isAssignableFrom(type)) { 079 InputStream is = genericFileToInputStream(file, exchange); 080 if (is != null) { 081 return is; 082 } 083 } 084 085 // okay if the file has a charset configured then we must try to load the file using that charset 086 // which mean we have to use the Reader first, and then convert from there 087 if (body instanceof File && file.getCharset() != null) { 088 Reader reader = genericFileToReader(file, exchange); 089 // we dont want a reader back, so use the type converter registry to find a suitable converter 090 TypeConverter readerTc = registry.lookup(type, Reader.class); 091 if (readerTc != null) { 092 // use the reader based type converter 093 return readerTc.convertTo(type, exchange, reader); 094 } 095 } 096 // fallback and use the type suitable type converter 097 return tc.convertTo(type, exchange, body); 098 } 099 } 100 101 return null; 102 } 103 104 @Converter 105 public static InputStream genericFileToInputStream(GenericFile<?> file, Exchange exchange) throws IOException, NoTypeConversionAvailableException { 106 if (file.getFile() instanceof File) { 107 // prefer to use a file input stream if its a java.io.File 108 File f = (File) file.getFile(); 109 // the file must exists 110 if (f.exists()) { 111 // read the file using the specified charset 112 String charset = file.getCharset(); 113 if (charset != null) { 114 LOG.debug("Read file {} with charset {}", f, file.getCharset()); 115 } else { 116 LOG.debug("Read file {} (no charset)", f); 117 } 118 return IOConverter.toInputStream(f, charset); 119 } 120 } 121 if (exchange != null) { 122 // otherwise ensure the body is loaded as we want the input stream of the body 123 file.getBinding().loadContent(exchange, file); 124 return exchange.getContext().getTypeConverter().convertTo(InputStream.class, exchange, file.getBody()); 125 } else { 126 // should revert to fallback converter if we don't have an exchange 127 return null; 128 } 129 } 130 131 @Converter 132 public static String genericFileToString(GenericFile<?> file, Exchange exchange) throws IOException, NoTypeConversionAvailableException { 133 // use reader first as it supports the file charset 134 BufferedReader reader = genericFileToReader(file, exchange); 135 if (reader != null) { 136 return IOConverter.toString(reader); 137 } 138 if (exchange != null) { 139 // otherwise ensure the body is loaded as we want the content of the body 140 file.getBinding().loadContent(exchange, file); 141 return exchange.getContext().getTypeConverter().convertTo(String.class, exchange, file.getBody()); 142 } else { 143 // should revert to fallback converter if we don't have an exchange 144 return null; 145 } 146 } 147 148 @Converter 149 public static Serializable genericFileToSerializable(GenericFile<?> file, Exchange exchange) throws IOException, NoTypeConversionAvailableException { 150 if (exchange != null) { 151 // load the file using input stream 152 InputStream is = genericFileToInputStream(file, exchange); 153 if (is != null) { 154 // need to double convert to convert correctly 155 byte[] data = exchange.getContext().getTypeConverter().convertTo(byte[].class, exchange, is); 156 if (data != null) { 157 return exchange.getContext().getTypeConverter().convertTo(Serializable.class, exchange, data); 158 } 159 } 160 } 161 // should revert to fallback converter if we don't have an exchange 162 return null; 163 } 164 165 private static BufferedReader genericFileToReader(GenericFile<?> file, Exchange exchange) throws IOException, NoTypeConversionAvailableException { 166 if (file.getFile() instanceof File) { 167 // prefer to use a file input stream if its a java.io.File 168 File f = (File) file.getFile(); 169 // the file must exists 170 if (!f.exists()) { 171 return null; 172 } 173 // and use the charset if the file was explicit configured with a charset 174 String charset = file.getCharset(); 175 if (charset != null) { 176 LOG.debug("Read file {} with charset {}", f, file.getCharset()); 177 return IOConverter.toReader(f, charset); 178 } else { 179 LOG.debug("Read file {} (no charset)", f); 180 return IOConverter.toReader(f, exchange); 181 } 182 } 183 return null; 184 } 185}