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.file;
018
019 import java.io.BufferedReader;
020 import java.io.File;
021 import java.io.IOException;
022 import java.io.InputStream;
023 import java.io.Reader;
024 import java.io.Serializable;
025
026 import org.apache.camel.Converter;
027 import org.apache.camel.Exchange;
028 import org.apache.camel.FallbackConverter;
029 import org.apache.camel.NoTypeConversionAvailableException;
030 import org.apache.camel.TypeConverter;
031 import org.apache.camel.converter.IOConverter;
032 import org.apache.camel.spi.TypeConverterRegistry;
033 import org.slf4j.Logger;
034 import org.slf4j.LoggerFactory;
035
036 /**
037 * A set of converter methods for working with generic file types
038 */
039 @Converter
040 public 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 return exchange.getContext().getTypeConverter().convertTo(Serializable.class, exchange, is);
155 }
156 }
157 // should revert to fallback converter if we don't have an exchange
158 return null;
159 }
160
161 private static BufferedReader genericFileToReader(GenericFile<?> file, Exchange exchange) throws IOException, NoTypeConversionAvailableException {
162 if (file.getFile() instanceof File) {
163 // prefer to use a file input stream if its a java.io.File
164 File f = (File) file.getFile();
165 // the file must exists
166 if (!f.exists()) {
167 return null;
168 }
169 // and use the charset if the file was explicit configured with a charset
170 String charset = file.getCharset();
171 if (charset != null) {
172 LOG.debug("Read file {} with charset {}", f, file.getCharset());
173 return IOConverter.toReader(f, charset);
174 } else {
175 LOG.debug("Read file {} (no charset)", f);
176 return IOConverter.toReader(f, exchange);
177 }
178 }
179 return null;
180 }
181 }