1//
2//  ========================================================================
3//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4//  ------------------------------------------------------------------------
5//  All rights reserved. This program and the accompanying materials
6//  are made available under the terms of the Eclipse Public License v1.0
7//  and Apache License v2.0 which accompanies this distribution.
8//
9//      The Eclipse Public License is available at
10//      http://www.eclipse.org/legal/epl-v10.html
11//
12//      The Apache License v2.0 is available at
13//      http://www.opensource.org/licenses/apache2.0.php
14//
15//  You may elect to redistribute this code under either of these licenses.
16//  ========================================================================
17//
18
19package org.eclipse.jetty.util;
20import java.io.ByteArrayOutputStream;
21import java.io.Closeable;
22import java.io.File;
23import java.io.FileInputStream;
24import java.io.FileOutputStream;
25import java.io.IOException;
26import java.io.InputStream;
27import java.io.InputStreamReader;
28import java.io.OutputStream;
29import java.io.PrintWriter;
30import java.io.Reader;
31import java.io.StringWriter;
32import java.io.Writer;
33
34import org.eclipse.jetty.util.log.Log;
35import org.eclipse.jetty.util.log.Logger;
36import org.eclipse.jetty.util.thread.QueuedThreadPool;
37
38/* ======================================================================== */
39/** IO Utilities.
40 * Provides stream handling utilities in
41 * singleton Threadpool implementation accessed by static members.
42 */
43public class IO
44{
45    private static final Logger LOG = Log.getLogger(IO.class);
46
47    /* ------------------------------------------------------------------- */
48    public final static String
49        CRLF      = "\015\012";
50
51    /* ------------------------------------------------------------------- */
52    public final static byte[]
53        CRLF_BYTES    = {(byte)'\015',(byte)'\012'};
54
55    /* ------------------------------------------------------------------- */
56    public static int bufferSize = 64*1024;
57
58    /* ------------------------------------------------------------------- */
59    // TODO get rid of this singleton!
60    private static class Singleton {
61        static final QueuedThreadPool __pool=new QueuedThreadPool();
62        static
63        {
64            try{__pool.start();}
65            catch(Exception e){LOG.warn(e); System.exit(1);}
66        }
67    }
68
69    /* ------------------------------------------------------------------- */
70    static class Job implements Runnable
71    {
72        InputStream in;
73        OutputStream out;
74        Reader read;
75        Writer write;
76
77        Job(InputStream in,OutputStream out)
78        {
79            this.in=in;
80            this.out=out;
81            this.read=null;
82            this.write=null;
83        }
84        Job(Reader read,Writer write)
85        {
86            this.in=null;
87            this.out=null;
88            this.read=read;
89            this.write=write;
90        }
91
92        /* ------------------------------------------------------------ */
93        /*
94         * @see java.lang.Runnable#run()
95         */
96        public void run()
97        {
98            try {
99                if (in!=null)
100                    copy(in,out,-1);
101                else
102                    copy(read,write,-1);
103            }
104            catch(IOException e)
105            {
106                LOG.ignore(e);
107                try{
108                    if (out!=null)
109                        out.close();
110                    if (write!=null)
111                        write.close();
112                }
113                catch(IOException e2)
114                {
115                    LOG.ignore(e2);
116                }
117            }
118        }
119    }
120
121    /* ------------------------------------------------------------------- */
122    /** Copy Stream in to Stream out until EOF or exception.
123     * in own thread
124     */
125    public static void copyThread(InputStream in, OutputStream out)
126    {
127        try{
128            Job job=new Job(in,out);
129            if (!Singleton.__pool.dispatch(job))
130                job.run();
131        }
132        catch(Exception e)
133        {
134            LOG.warn(e);
135        }
136    }
137
138    /* ------------------------------------------------------------------- */
139    /** Copy Stream in to Stream out until EOF or exception.
140     */
141    public static void copy(InputStream in, OutputStream out)
142         throws IOException
143    {
144        copy(in,out,-1);
145    }
146
147    /* ------------------------------------------------------------------- */
148    /** Copy Stream in to Stream out until EOF or exception
149     * in own thread
150     */
151    public static void copyThread(Reader in, Writer out)
152    {
153        try
154        {
155            Job job=new Job(in,out);
156            if (!Singleton.__pool.dispatch(job))
157                job.run();
158        }
159        catch(Exception e)
160        {
161            LOG.warn(e);
162        }
163    }
164
165    /* ------------------------------------------------------------------- */
166    /** Copy Reader to Writer out until EOF or exception.
167     */
168    public static void copy(Reader in, Writer out)
169         throws IOException
170    {
171        copy(in,out,-1);
172    }
173
174    /* ------------------------------------------------------------------- */
175    /** Copy Stream in to Stream for byteCount bytes or until EOF or exception.
176     */
177    public static void copy(InputStream in,
178                            OutputStream out,
179                            long byteCount)
180         throws IOException
181    {
182        byte buffer[] = new byte[bufferSize];
183        int len=bufferSize;
184
185        if (byteCount>=0)
186        {
187            while (byteCount>0)
188            {
189                int max = byteCount<bufferSize?(int)byteCount:bufferSize;
190                len=in.read(buffer,0,max);
191
192                if (len==-1)
193                    break;
194
195                byteCount -= len;
196                out.write(buffer,0,len);
197            }
198        }
199        else
200        {
201            while (true)
202            {
203                len=in.read(buffer,0,bufferSize);
204                if (len<0 )
205                    break;
206                out.write(buffer,0,len);
207            }
208        }
209    }
210
211    /* ------------------------------------------------------------------- */
212    /** Copy Reader to Writer for byteCount bytes or until EOF or exception.
213     */
214    public static void copy(Reader in,
215                            Writer out,
216                            long byteCount)
217         throws IOException
218    {
219        char buffer[] = new char[bufferSize];
220        int len=bufferSize;
221
222        if (byteCount>=0)
223        {
224            while (byteCount>0)
225            {
226                if (byteCount<bufferSize)
227                    len=in.read(buffer,0,(int)byteCount);
228                else
229                    len=in.read(buffer,0,bufferSize);
230
231                if (len==-1)
232                    break;
233
234                byteCount -= len;
235                out.write(buffer,0,len);
236            }
237        }
238        else if (out instanceof PrintWriter)
239        {
240            PrintWriter pout=(PrintWriter)out;
241            while (!pout.checkError())
242            {
243                len=in.read(buffer,0,bufferSize);
244                if (len==-1)
245                    break;
246                out.write(buffer,0,len);
247            }
248        }
249        else
250        {
251            while (true)
252            {
253                len=in.read(buffer,0,bufferSize);
254                if (len==-1)
255                    break;
256                out.write(buffer,0,len);
257            }
258        }
259    }
260
261    /* ------------------------------------------------------------ */
262    /** Copy files or directories
263     * @param from
264     * @param to
265     * @throws IOException
266     */
267    public static void copy(File from,File to) throws IOException
268    {
269        if (from.isDirectory())
270            copyDir(from,to);
271        else
272            copyFile(from,to);
273    }
274
275    /* ------------------------------------------------------------ */
276    public static void copyDir(File from,File to) throws IOException
277    {
278        if (to.exists())
279        {
280            if (!to.isDirectory())
281                throw new IllegalArgumentException(to.toString());
282        }
283        else
284            to.mkdirs();
285
286        File[] files = from.listFiles();
287        if (files!=null)
288        {
289            for (int i=0;i<files.length;i++)
290            {
291                String name = files[i].getName();
292                if (".".equals(name) || "..".equals(name))
293                    continue;
294                copy(files[i],new File(to,name));
295            }
296        }
297    }
298
299    /* ------------------------------------------------------------ */
300    public static void copyFile(File from,File to) throws IOException
301    {
302        FileInputStream in=new FileInputStream(from);
303        FileOutputStream out=new FileOutputStream(to);
304        copy(in,out);
305        in.close();
306        out.close();
307    }
308
309    /* ------------------------------------------------------------ */
310    /** Read input stream to string.
311     */
312    public static String toString(InputStream in)
313        throws IOException
314    {
315        return toString(in,null);
316    }
317
318    /* ------------------------------------------------------------ */
319    /** Read input stream to string.
320     */
321    public static String toString(InputStream in,String encoding)
322        throws IOException
323    {
324        StringWriter writer=new StringWriter();
325        InputStreamReader reader = encoding==null?new InputStreamReader(in):new InputStreamReader(in,encoding);
326
327        copy(reader,writer);
328        return writer.toString();
329    }
330
331    /* ------------------------------------------------------------ */
332    /** Read input stream to string.
333     */
334    public static String toString(Reader in)
335        throws IOException
336    {
337        StringWriter writer=new StringWriter();
338        copy(in,writer);
339        return writer.toString();
340    }
341
342
343    /* ------------------------------------------------------------ */
344    /** Delete File.
345     * This delete will recursively delete directories - BE CAREFULL
346     * @param file The file to be deleted.
347     */
348    public static boolean delete(File file)
349    {
350        if (!file.exists())
351            return false;
352        if (file.isDirectory())
353        {
354            File[] files = file.listFiles();
355            for (int i=0;files!=null && i<files.length;i++)
356                delete(files[i]);
357        }
358        return file.delete();
359    }
360
361    /* ------------------------------------------------------------ */
362    /**
363     * closes any {@link Closeable}
364     *
365     * @param c the closeable to close
366     */
367    public static void close(Closeable c)
368    {
369        try
370        {
371            if (c != null)
372                c.close();
373        }
374        catch (IOException e)
375        {
376            LOG.ignore(e);
377        }
378    }
379
380    /**
381     * closes an input stream, and logs exceptions
382     *
383     * @param is the input stream to close
384     */
385    public static void close(InputStream is)
386    {
387        try
388        {
389            if (is != null)
390                is.close();
391        }
392        catch (IOException e)
393        {
394            LOG.ignore(e);
395        }
396    }
397
398    /**
399     * closes a reader, and logs exceptions
400     *
401     * @param reader the reader to close
402     */
403    public static void close(Reader reader)
404    {
405        try
406        {
407            if (reader != null)
408                reader.close();
409        } catch (IOException e)
410        {
411            LOG.ignore(e);
412        }
413    }
414
415    /**
416     * closes a writer, and logs exceptions
417     *
418     * @param writer the writer to close
419     */
420    public static void close(Writer writer)
421    {
422        try
423        {
424            if (writer != null)
425                writer.close();
426        } catch (IOException e)
427        {
428            LOG.ignore(e);
429        }
430    }
431
432    /* ------------------------------------------------------------ */
433    public static byte[] readBytes(InputStream in)
434        throws IOException
435    {
436        ByteArrayOutputStream bout = new ByteArrayOutputStream();
437        copy(in,bout);
438        return bout.toByteArray();
439    }
440
441    /* ------------------------------------------------------------ */
442    /**
443     * closes an output stream, and logs exceptions
444     *
445     * @param os the output stream to close
446     */
447    public static void close(OutputStream os)
448    {
449        try
450        {
451            if (os != null)
452                os.close();
453        }
454        catch (IOException e)
455        {
456            LOG.ignore(e);
457        }
458    }
459
460    /* ------------------------------------------------------------ */
461    /**
462     * @return An outputstream to nowhere
463     */
464    public static OutputStream getNullStream()
465    {
466        return __nullStream;
467    }
468
469    /* ------------------------------------------------------------ */
470    /**
471     * @return An outputstream to nowhere
472     */
473    public static InputStream getClosedStream()
474    {
475        return __closedStream;
476    }
477
478    /* ------------------------------------------------------------ */
479    /* ------------------------------------------------------------ */
480    private static class NullOS extends OutputStream
481    {
482        @Override
483        public void close(){}
484        @Override
485        public void flush(){}
486        @Override
487        public void write(byte[]b){}
488        @Override
489        public void write(byte[]b,int i,int l){}
490        @Override
491        public void write(int b){}
492    }
493    private static NullOS __nullStream = new NullOS();
494
495
496    /* ------------------------------------------------------------ */
497    /* ------------------------------------------------------------ */
498    private static class ClosedIS extends InputStream
499    {
500        @Override
501        public int read() throws IOException
502        {
503            return -1;
504        }
505    }
506    private static ClosedIS __closedStream = new ClosedIS();
507
508    /* ------------------------------------------------------------ */
509    /**
510     * @return An writer to nowhere
511     */
512    public static Writer getNullWriter()
513    {
514        return __nullWriter;
515    }
516
517    /* ------------------------------------------------------------ */
518    /**
519     * @return An writer to nowhere
520     */
521    public static PrintWriter getNullPrintWriter()
522    {
523        return __nullPrintWriter;
524    }
525
526    /* ------------------------------------------------------------ */
527    /* ------------------------------------------------------------ */
528    private static class NullWrite extends Writer
529    {
530        @Override
531        public void close(){}
532        @Override
533        public void flush(){}
534        @Override
535        public void write(char[]b){}
536        @Override
537        public void write(char[]b,int o,int l){}
538        @Override
539        public void write(int b){}
540        @Override
541        public void write(String s){}
542        @Override
543        public void write(String s,int o,int l){}
544    }
545    private static NullWrite __nullWriter = new NullWrite();
546    private static PrintWriter __nullPrintWriter = new PrintWriter(__nullWriter);
547}
548
549
550
551
552
553
554
555
556
557