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.converter;
018    
019    import java.io.BufferedReader;
020    import java.io.BufferedWriter;
021    import java.io.ByteArrayInputStream;
022    import java.io.ByteArrayOutputStream;
023    import java.io.File;
024    import java.io.FileInputStream;
025    import java.io.FileNotFoundException;
026    import java.io.FileOutputStream;
027    import java.io.IOException;
028    import java.io.InputStream;
029    import java.io.InputStreamReader;
030    import java.io.ObjectInput;
031    import java.io.ObjectInputStream;
032    import java.io.ObjectOutput;
033    import java.io.ObjectOutputStream;
034    import java.io.ObjectStreamClass;
035    import java.io.OutputStream;
036    import java.io.OutputStreamWriter;
037    import java.io.Reader;
038    import java.io.StringReader;
039    import java.io.UnsupportedEncodingException;
040    import java.io.Writer;
041    import java.net.URL;
042    import java.nio.charset.UnsupportedCharsetException;
043    
044    import org.apache.camel.Converter;
045    import org.apache.camel.Exchange;
046    import org.apache.camel.util.IOHelper;
047    import org.slf4j.Logger;
048    import org.slf4j.LoggerFactory;
049    
050    /**
051     * Some core java.io based <a
052     * href="http://camel.apache.org/type-converter.html">Type Converters</a>
053     *
054     * @version 
055     */
056    @Converter
057    public final class IOConverter {
058        private static final Logger LOG = LoggerFactory.getLogger(IOConverter.class);
059    
060        /**
061         * Utility classes should not have a public constructor.
062         */
063        private IOConverter() {
064        }
065    
066        @Converter
067        public static InputStream toInputStream(URL url) throws IOException {
068            return IOHelper.buffered(url.openStream());
069        }
070    
071        @Converter
072        public static InputStream toInputStream(File file) throws IOException {
073            return IOHelper.buffered(new FileInputStream(file));
074        }
075    
076        public static InputStream toInputStream(File file, String charset) throws IOException {
077            if (charset != null) {
078                final BufferedReader reader = toReader(file, charset);
079                return new InputStream() {
080                    @Override
081                    public int read() throws IOException {
082                        return reader.read();
083                    }
084                    
085                    @Override
086                    public void close() throws IOException {
087                        reader.close();
088                    }
089                    
090                    @Override
091                    public void reset() throws IOException {
092                        reader.reset();
093                    }
094                };
095            } else {
096                return IOHelper.buffered(new FileInputStream(file));
097            }
098        }
099    
100        /**
101         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
102         */
103        @Deprecated
104        public static BufferedReader toReader(File file) throws IOException {
105            return toReader(file, (String) null);
106        }
107    
108        @Converter
109        public static BufferedReader toReader(File file, Exchange exchange) throws IOException {
110            return toReader(file, IOHelper.getCharsetName(exchange));
111        }
112    
113        public static BufferedReader toReader(File file, String charset) throws IOException {
114            FileInputStream in = new FileInputStream(file);
115            return IOHelper.buffered(new EncodingFileReader(in, charset));
116        }
117    
118        @Converter
119        public static File toFile(String name) throws FileNotFoundException {
120            return new File(name);
121        }
122    
123        @Converter
124        public static OutputStream toOutputStream(File file) throws FileNotFoundException {
125            return IOHelper.buffered(new FileOutputStream(file));
126        }
127    
128        /**
129         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
130         */
131        @Deprecated
132        public static BufferedWriter toWriter(File file) throws IOException {
133            FileOutputStream os = new FileOutputStream(file, false);
134            return toWriter(os, IOHelper.getCharsetName(null, true));
135        }
136        
137        @Converter
138        public static BufferedWriter toWriter(File file, Exchange exchange) throws IOException {
139            FileOutputStream os = new FileOutputStream(file, false);
140            return toWriter(os, IOHelper.getCharsetName(exchange));
141        }
142    
143        public static BufferedWriter toWriter(File file, boolean append, String charset) throws IOException {
144            return toWriter(new FileOutputStream(file, append), charset);
145        }
146    
147        public static BufferedWriter toWriter(FileOutputStream os, String charset) throws IOException {
148            return IOHelper.buffered(new EncodingFileWriter(os, charset));
149        }
150    
151        /**
152         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
153         */
154        @Deprecated
155        public static Reader toReader(InputStream in) throws IOException {
156            return toReader(in, null);
157        }
158    
159        @Converter
160        public static Reader toReader(InputStream in, Exchange exchange) throws IOException {
161            return IOHelper.buffered(new InputStreamReader(in, IOHelper.getCharsetName(exchange)));
162        }
163    
164        /**
165         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
166         */
167        @Deprecated
168        public static Writer toWriter(OutputStream out) throws IOException {
169            return toWriter(out, null);
170        }
171        
172        @Converter
173        public static Writer toWriter(OutputStream out, Exchange exchange) throws IOException {
174            return IOHelper.buffered(new OutputStreamWriter(out, IOHelper.getCharsetName(exchange)));
175        }
176    
177        @Converter
178        public static StringReader toReader(String text) {
179            // no buffering required as the complete string input is already passed
180            // over as a whole
181            return new StringReader(text);
182        }
183    
184        /**
185         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
186         */
187        @Deprecated
188        public static InputStream toInputStream(String text) throws IOException {
189            return toInputStream(text, null);
190        }
191        
192        @Converter
193        public static InputStream toInputStream(String text, Exchange exchange) throws IOException {
194            return toInputStream(text.getBytes(IOHelper.getCharsetName(exchange)));
195        }
196        
197        @Converter
198        public static InputStream toInputStream(StringBuffer buffer, Exchange exchange) throws IOException {
199            return toInputStream(buffer.toString(), exchange);
200        }
201        
202        @Converter
203        public static InputStream toInputStream(StringBuilder builder, Exchange exchange) throws IOException {
204            return toInputStream(builder.toString(), exchange);
205        }
206        
207        /**
208         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
209         */
210        @Deprecated
211        public static InputStream toInputStream(BufferedReader buffer) throws IOException {
212            return toInputStream(buffer, null);
213        }
214        
215        @Converter
216        public static InputStream toInputStream(BufferedReader buffer, Exchange exchange) throws IOException {
217            return toInputStream(toString(buffer), exchange);
218        }
219    
220        /**
221         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
222         */
223        @Deprecated
224        public static String toString(byte[] data) throws IOException {
225            return toString(data, null);
226        }
227        
228        @Converter
229        public static String toString(byte[] data, Exchange exchange) throws IOException {
230            return new String(data, IOHelper.getCharsetName(exchange));
231        }
232    
233        /**
234         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
235         */
236        @Deprecated
237        public static String toString(File file) throws IOException {
238            return toString(file, null);
239        }
240        
241        @Converter
242        public static String toString(File file, Exchange exchange) throws IOException {
243            return toString(toReader(file, exchange));
244        }
245    
246        @Converter
247        public static byte[] toByteArray(File file) throws IOException {
248            InputStream is = toInputStream(file);
249            try {
250                return toBytes(is);
251            } finally {
252                IOHelper.close(is, "file", LOG);
253            }
254        }
255        
256        /**
257         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
258         */
259        @Deprecated
260        public static byte[] toByteArray(Reader reader) throws IOException {
261            return toByteArray(reader, null);
262        }
263        
264        @Converter
265        public static byte[] toByteArray(Reader reader, Exchange exchange) throws IOException {
266            return toByteArray(IOHelper.buffered(reader), exchange);
267        }
268    
269        /**
270         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
271         */
272        @Deprecated
273        public static String toString(URL url) throws IOException {
274            return toString(url, null);
275        }
276    
277        @Converter
278        public static String toString(URL url, Exchange exchange) throws IOException {
279            InputStream is = toInputStream(url);
280            try {
281                return toString(is, exchange);
282            } finally {
283                IOHelper.close(is, "url", LOG);
284            }
285        }
286    
287        @Converter
288        public static String toString(Reader reader) throws IOException {
289            return toString(IOHelper.buffered(reader));
290        }
291    
292        @Converter
293        public static String toString(BufferedReader reader) throws IOException {
294            if (reader == null) {
295                return null;
296            }
297    
298            StringBuilder sb = new StringBuilder(1024);
299            char[] buf = new char[1024];
300            try {
301                int len;
302                // read until we reach then end which is the -1 marker
303                while ((len = reader.read(buf)) != -1) {
304                    sb.append(buf, 0, len);
305                }
306            } finally {
307                IOHelper.close(reader, "reader", LOG);
308            }
309    
310            return sb.toString();
311        }
312        
313        /**
314         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
315         */
316        @Deprecated
317        public static byte[] toByteArray(BufferedReader reader) throws IOException {
318            return toByteArray(reader, null);
319        }
320        
321        @Converter
322        public static byte[] toByteArray(BufferedReader reader, Exchange exchange) throws IOException {
323            String s = toString(reader);
324            return toByteArray(s, exchange);
325        }
326    
327        /**
328         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
329         */
330        @Deprecated
331        public static byte[] toByteArray(String value) throws IOException {
332            return toByteArray(value, null);
333        }
334    
335        @Converter
336        public static byte[] toByteArray(String value, Exchange exchange) throws IOException {
337            return value != null ? value.getBytes(IOHelper.getCharsetName(exchange)) : null;
338        }
339    
340        /**
341         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
342         */
343        @Deprecated
344        public static String toString(InputStream in) throws IOException {
345            return toString(in, null);
346        }
347    
348        @Converter
349        public static String toString(InputStream in, Exchange exchange) throws IOException {
350            return toString(toReader(in, exchange));
351        }
352    
353        @Converter
354        public static InputStream toInputStream(byte[] data) {
355            // no buffering required as the complete byte input is already passed
356            // over as a whole
357            return new ByteArrayInputStream(data);
358        }
359    
360        @Converter
361        public static ObjectOutput toObjectOutput(OutputStream stream) throws IOException {
362            if (stream instanceof ObjectOutput) {
363                return (ObjectOutput) stream;
364            } else {
365                return new ObjectOutputStream(IOHelper.buffered(stream));
366            }
367        }
368    
369        @Converter
370        public static ObjectInput toObjectInput(final InputStream stream, final Exchange exchange) throws IOException {
371            if (stream instanceof ObjectInput) {
372                return (ObjectInput) stream;
373            } else {
374                return new ObjectInputStream(IOHelper.buffered(stream)) {
375                    @Override
376                    protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
377                        // need to let Camel be able to resolve class using ClassResolver SPI, to let class loading
378                        // work in OSGi and other containers
379                        Class<?>  answer = null;
380                        String name = objectStreamClass.getName();
381                        if (exchange != null) {
382                            LOG.trace("Loading class {} using Camel ClassResolver", name);
383                            answer = exchange.getContext().getClassResolver().resolveClass(name);
384                        }
385                        if (answer == null) {
386                            LOG.trace("Loading class {} using JDK default implementation", name);
387                            answer = super.resolveClass(objectStreamClass);
388                        }
389                        return answer;
390                    }
391                };
392            }
393        }
394    
395        @Converter
396        public static byte[] toBytes(InputStream stream) throws IOException {
397            ByteArrayOutputStream bos = new ByteArrayOutputStream();
398            IOHelper.copy(IOHelper.buffered(stream), bos);
399    
400            // no need to close the ByteArrayOutputStream as it's close()
401            // implementation is noop
402            return bos.toByteArray();
403        }
404    
405        @Converter
406        public static byte[] toByteArray(ByteArrayOutputStream os) {
407            return os.toByteArray();
408        }
409    
410        /**
411         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
412         */
413        @Deprecated
414        public static String toString(ByteArrayOutputStream os) throws IOException {
415            return toString(os, null);
416        }
417    
418        @Converter
419        public static String toString(ByteArrayOutputStream os, Exchange exchange) throws IOException {
420            return os.toString(IOHelper.getCharsetName(exchange));
421        }
422    
423        @Converter
424        public static InputStream toInputStream(ByteArrayOutputStream os) {
425            // no buffering required as the complete byte array input is already
426            // passed over as a whole
427            return new ByteArrayInputStream(os.toByteArray());
428        }
429    
430        /**
431         * Gets the charset name if set as header or property {@link Exchange#CHARSET_NAME}.
432         *
433         * @param exchange  the exchange
434         * @param useDefault should we fallback and use JVM default charset if no property existed?
435         * @return the charset, or <tt>null</tt> if no found
436         */
437        @Deprecated
438        public static String getCharsetName(Exchange exchange, boolean useDefault) {
439            return IOHelper.getCharsetName(exchange, useDefault);
440        }
441        
442        @Deprecated
443        public static String getCharsetName(Exchange exchange) {
444            return getCharsetName(exchange, true);
445        }
446    
447        /**
448         * Encoding-aware file reader. 
449         */
450        private static class EncodingFileReader extends InputStreamReader {
451    
452            private final FileInputStream in;
453    
454            /**
455             * @param in file to read
456             * @param charset character set to use
457             */
458            public EncodingFileReader(FileInputStream in, String charset)
459                throws FileNotFoundException, UnsupportedEncodingException {
460                super(in, charset);
461                this.in = in;
462            }
463    
464            @Override
465            public void close() throws IOException {
466                try {
467                    super.close();
468                } finally {
469                    in.close();
470                }
471            }
472        }
473        
474        /**
475         * Encoding-aware file writer. 
476         */
477        private static class EncodingFileWriter extends OutputStreamWriter {
478    
479            private final FileOutputStream out;
480    
481            /**
482             * @param out file to write
483             * @param charset character set to use
484             */
485            public EncodingFileWriter(FileOutputStream out, String charset)
486                throws FileNotFoundException, UnsupportedEncodingException {
487                super(out, charset);
488                this.out = out;
489            }
490    
491            @Override
492            public void close() throws IOException {
493                try {
494                    super.close();
495                } finally {
496                    out.close();
497                }
498            }
499        }
500        
501        /**
502         * This method will take off the quotes and double quotes of the charset
503         */
504        @Deprecated
505        public static String normalizeCharset(String charset) {
506            return IOHelper.normalizeCharset(charset);
507        }
508        
509        @Deprecated
510        public static void validateCharset(String charset) throws UnsupportedCharsetException {
511            IOHelper.validateCharset(charset);
512        }
513        
514    }