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 transient 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            return toWriter(file, false, IOHelper.getCharsetName(null, true));
134        }
135        
136        @Converter
137        public static BufferedWriter toWriter(File file, Exchange exchange) throws IOException {
138            return toWriter(file, false, IOHelper.getCharsetName(exchange));
139        }
140    
141        public static BufferedWriter toWriter(File file, boolean append, String charset) throws IOException {
142            FileOutputStream os = new FileOutputStream(file, append);
143            return IOHelper.buffered(new EncodingFileWriter(os, charset));
144        }
145    
146        /**
147         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
148         */
149        @Deprecated
150        public static Reader toReader(InputStream in) throws IOException {
151            return toReader(in, null);
152        }
153    
154        @Converter
155        public static Reader toReader(InputStream in, Exchange exchange) throws IOException {
156            return IOHelper.buffered(new InputStreamReader(in, IOHelper.getCharsetName(exchange)));
157        }
158    
159        /**
160         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
161         */
162        @Deprecated
163        public static Writer toWriter(OutputStream out) throws IOException {
164            return toWriter(out, null);
165        }
166        
167        @Converter
168        public static Writer toWriter(OutputStream out, Exchange exchange) throws IOException {
169            return IOHelper.buffered(new OutputStreamWriter(out, IOHelper.getCharsetName(exchange)));
170        }
171    
172        @Converter
173        public static StringReader toReader(String text) {
174            // no buffering required as the complete string input is already passed
175            // over as a whole
176            return new StringReader(text);
177        }
178    
179        /**
180         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
181         */
182        @Deprecated
183        public static InputStream toInputStream(String text) throws IOException {
184            return toInputStream(text, null);
185        }
186        
187        @Converter
188        public static InputStream toInputStream(String text, Exchange exchange) throws IOException {
189            return toInputStream(text.getBytes(IOHelper.getCharsetName(exchange)));
190        }
191        
192        @Converter
193        public static InputStream toInputStream(StringBuffer buffer, Exchange exchange) throws IOException {
194            return toInputStream(buffer.toString(), exchange);
195        }
196        
197        @Converter
198        public static InputStream toInputStream(StringBuilder builder, Exchange exchange) throws IOException {
199            return toInputStream(builder.toString(), exchange);
200        }
201        
202        /**
203         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
204         */
205        @Deprecated
206        public static InputStream toInputStream(BufferedReader buffer) throws IOException {
207            return toInputStream(buffer, null);
208        }
209        
210        @Converter
211        public static InputStream toInputStream(BufferedReader buffer, Exchange exchange) throws IOException {
212            return toInputStream(toString(buffer), exchange);
213        }
214    
215        /**
216         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
217         */
218        @Deprecated
219        public static String toString(byte[] data) throws IOException {
220            return toString(data, null);
221        }
222        
223        @Converter
224        public static String toString(byte[] data, Exchange exchange) throws IOException {
225            return new String(data, IOHelper.getCharsetName(exchange));
226        }
227    
228        /**
229         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
230         */
231        @Deprecated
232        public static String toString(File file) throws IOException {
233            return toString(file, null);
234        }
235        
236        @Converter
237        public static String toString(File file, Exchange exchange) throws IOException {
238            return toString(toReader(file, exchange));
239        }
240    
241        @Converter
242        public static byte[] toByteArray(File file) throws IOException {
243            InputStream is = toInputStream(file);
244            try {
245                return toBytes(is);
246            } finally {
247                IOHelper.close(is, "file", LOG);
248            }
249        }
250        
251        /**
252         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
253         */
254        @Deprecated
255        public static byte[] toByteArray(Reader reader) throws IOException {
256            return toByteArray(reader, null);
257        }
258        
259        @Converter
260        public static byte[] toByteArray(Reader reader, Exchange exchange) throws IOException {
261            return toByteArray(IOHelper.buffered(reader), exchange);
262        }
263    
264        /**
265         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
266         */
267        @Deprecated
268        public static String toString(URL url) throws IOException {
269            return toString(url, null);
270        }
271    
272        @Converter
273        public static String toString(URL url, Exchange exchange) throws IOException {
274            InputStream is = toInputStream(url);
275            try {
276                return toString(is, exchange);
277            } finally {
278                IOHelper.close(is, "url", LOG);
279            }
280        }
281    
282        @Converter
283        public static String toString(Reader reader) throws IOException {
284            return toString(IOHelper.buffered(reader));
285        }
286    
287        @Converter
288        public static String toString(BufferedReader reader) throws IOException {
289            if (reader == null) {
290                return null;
291            }
292    
293            StringBuilder sb = new StringBuilder(1024);
294            char[] buf = new char[1024];
295            try {
296                int len;
297                // read until we reach then end which is the -1 marker
298                while ((len = reader.read(buf)) != -1) {
299                    sb.append(buf, 0, len);
300                }
301            } finally {
302                IOHelper.close(reader, "reader", LOG);
303            }
304    
305            return sb.toString();
306        }
307        
308        /**
309         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
310         */
311        @Deprecated
312        public static byte[] toByteArray(BufferedReader reader) throws IOException {
313            return toByteArray(reader, null);
314        }
315        
316        @Converter
317        public static byte[] toByteArray(BufferedReader reader, Exchange exchange) throws IOException {
318            String s = toString(reader);
319            return toByteArray(s, exchange);
320        }
321    
322        /**
323         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
324         */
325        @Deprecated
326        public static byte[] toByteArray(String value) throws IOException {
327            return toByteArray(value, null);
328        }
329    
330        @Converter
331        public static byte[] toByteArray(String value, Exchange exchange) throws IOException {
332            return value != null ? value.getBytes(IOHelper.getCharsetName(exchange)) : null;
333        }
334    
335        /**
336         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
337         */
338        @Deprecated
339        public static String toString(InputStream in) throws IOException {
340            return toString(in, null);
341        }
342    
343        @Converter
344        public static String toString(InputStream in, Exchange exchange) throws IOException {
345            return toString(toReader(in, exchange));
346        }
347    
348        @Converter
349        public static InputStream toInputStream(byte[] data) {
350            // no buffering required as the complete byte input is already passed
351            // over as a whole
352            return new ByteArrayInputStream(data);
353        }
354    
355        @Converter
356        public static ObjectOutput toObjectOutput(OutputStream stream) throws IOException {
357            if (stream instanceof ObjectOutput) {
358                return (ObjectOutput) stream;
359            } else {
360                return new ObjectOutputStream(IOHelper.buffered(stream));
361            }
362        }
363    
364        @Converter
365        public static ObjectInput toObjectInput(final InputStream stream, final Exchange exchange) throws IOException {
366            if (stream instanceof ObjectInput) {
367                return (ObjectInput) stream;
368            } else {
369                return new ObjectInputStream(IOHelper.buffered(stream)) {
370                    @Override
371                    protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
372                        // need to let Camel be able to resolve class using ClassResolver SPI, to let class loading
373                        // work in OSGi and other containers
374                        Class<?>  answer = null;
375                        String name = objectStreamClass.getName();
376                        if (exchange != null) {
377                            LOG.trace("Loading class {} using Camel ClassResolver", name);
378                            answer = exchange.getContext().getClassResolver().resolveClass(name);
379                        }
380                        if (answer == null) {
381                            LOG.trace("Loading class {} using JDK default implementation", name);
382                            answer = super.resolveClass(objectStreamClass);
383                        }
384                        return answer;
385                    }
386                };
387            }
388        }
389    
390        @Converter
391        public static byte[] toBytes(InputStream stream) throws IOException {
392            ByteArrayOutputStream bos = new ByteArrayOutputStream();
393            IOHelper.copy(IOHelper.buffered(stream), bos);
394    
395            // no need to close the ByteArrayOutputStream as it's close()
396            // implementation is noop
397            return bos.toByteArray();
398        }
399    
400        @Converter
401        public static byte[] toByteArray(ByteArrayOutputStream os) {
402            return os.toByteArray();
403        }
404    
405        /**
406         * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters.
407         */
408        @Deprecated
409        public static String toString(ByteArrayOutputStream os) throws IOException {
410            return toString(os, null);
411        }
412    
413        @Converter
414        public static String toString(ByteArrayOutputStream os, Exchange exchange) throws IOException {
415            return os.toString(IOHelper.getCharsetName(exchange));
416        }
417    
418        @Converter
419        public static InputStream toInputStream(ByteArrayOutputStream os) {
420            // no buffering required as the complete byte array input is already
421            // passed over as a whole
422            return new ByteArrayInputStream(os.toByteArray());
423        }
424    
425        /**
426         * Gets the charset name if set as property {@link Exchange#CHARSET_NAME}.
427         *
428         * @param exchange  the exchange
429         * @param useDefault should we fallback and use JVM default charset if no property existed?
430         * @return the charset, or <tt>null</tt> if no found
431         */
432        @Deprecated
433        public static String getCharsetName(Exchange exchange, boolean useDefault) {
434            return IOHelper.getCharsetName(exchange, useDefault);
435        }
436        
437        @Deprecated
438        public static String getCharsetName(Exchange exchange) {
439            return getCharsetName(exchange, true);
440        }
441    
442        /**
443         * Encoding-aware file reader. 
444         */
445        private static class EncodingFileReader extends InputStreamReader {
446    
447            private final FileInputStream in;
448    
449            /**
450             * @param in file to read
451             * @param charset character set to use
452             */
453            public EncodingFileReader(FileInputStream in, String charset)
454                throws FileNotFoundException, UnsupportedEncodingException {
455                super(in, charset);
456                this.in = in;
457            }
458    
459            @Override
460            public void close() throws IOException {
461                try {
462                    super.close();
463                } finally {
464                    in.close();
465                }
466            }
467        }
468        
469        /**
470         * Encoding-aware file writer. 
471         */
472        private static class EncodingFileWriter extends OutputStreamWriter {
473    
474            private final FileOutputStream out;
475    
476            /**
477             * @param out file to write
478             * @param charset character set to use
479             */
480            public EncodingFileWriter(FileOutputStream out, String charset)
481                throws FileNotFoundException, UnsupportedEncodingException {
482                super(out, charset);
483                this.out = out;
484            }
485    
486            @Override
487            public void close() throws IOException {
488                try {
489                    super.close();
490                } finally {
491                    out.close();
492                }
493            }
494        }
495        
496        /**
497         * This method will take off the quotes and double quotes of the charset
498         */
499        @Deprecated
500        public static String normalizeCharset(String charset) {
501            return IOHelper.normalizeCharset(charset);
502        }
503        
504        @Deprecated
505        public static void validateCharset(String charset) throws UnsupportedCharsetException {
506            IOHelper.validateCharset(charset);
507        }
508        
509    }