1   // ========================================================================
2   // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.util;
16  import java.io.ByteArrayOutputStream;
17  import java.io.File;
18  import java.io.FileInputStream;
19  import java.io.FileOutputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.OutputStream;
23  import java.io.Reader;
24  import java.io.Writer;
25  import java.io.StringWriter;
26  import java.io.InputStreamReader;
27  
28  import org.mortbay.log.Log;
29  import org.mortbay.thread.BoundedThreadPool;
30  import org.mortbay.thread.QueuedThreadPool;
31  
32  /* ======================================================================== */
33  /** IO Utilities.
34   * Provides stream handling utilities in
35   * singleton Threadpool implementation accessed by static members.
36   */
37  public class IO 
38  {
39      /* ------------------------------------------------------------------- */
40      public final static String
41          CRLF      = "\015\012";
42  
43      /* ------------------------------------------------------------------- */
44      public final static byte[]
45          CRLF_BYTES    = {(byte)'\015',(byte)'\012'};
46  
47      /* ------------------------------------------------------------------- */
48      public static int bufferSize = 2*8192;
49      
50      /* ------------------------------------------------------------------- */
51      // TODO get rid of this singleton!
52      private static class Singleton {
53          static final QueuedThreadPool __pool=new QueuedThreadPool();
54          static
55          {
56              try{__pool.start();}
57              catch(Exception e){Log.warn(e); System.exit(1);}
58          }
59      }
60  
61      /* ------------------------------------------------------------------- */
62      static class Job implements Runnable
63      {
64          InputStream in;
65          OutputStream out;
66          Reader read;
67          Writer write;
68  
69          Job(InputStream in,OutputStream out)
70          {
71              this.in=in;
72              this.out=out;
73              this.read=null;
74              this.write=null;
75          }
76          Job(Reader read,Writer write)
77          {
78              this.in=null;
79              this.out=null;
80              this.read=read;
81              this.write=write;
82          }
83          
84          /* ------------------------------------------------------------ */
85          /* 
86           * @see java.lang.Runnable#run()
87           */
88          public void run()
89          {
90              try {
91                  if (in!=null)
92                      copy(in,out,-1);
93                  else
94                      copy(read,write,-1);
95              }
96              catch(IOException e)
97              {
98                  Log.ignore(e);
99                  try{
100                     if (out!=null)
101                         out.close();
102                     if (write!=null)
103                         write.close();
104                 }
105                 catch(IOException e2)
106                 {
107                     Log.ignore(e2);
108                 }
109             }
110         }
111     }
112     
113     /* ------------------------------------------------------------------- */
114     /** Copy Stream in to Stream out until EOF or exception.
115      * in own thread
116      */
117     public static void copyThread(InputStream in, OutputStream out)
118     {
119         try{
120             Job job=new Job(in,out);
121             if (!Singleton.__pool.dispatch(job))
122                 job.run();
123         }
124         catch(Exception e)
125         {
126             Log.warn(e);
127         }
128     }
129     
130     /* ------------------------------------------------------------------- */
131     /** Copy Stream in to Stream out until EOF or exception.
132      */
133     public static void copy(InputStream in, OutputStream out)
134          throws IOException
135     {
136         copy(in,out,-1);
137     }
138     
139     /* ------------------------------------------------------------------- */
140     /** Copy Stream in to Stream out until EOF or exception
141      * in own thread
142      */
143     public static void copyThread(Reader in, Writer out)
144     {
145         try
146         {
147             Job job=new Job(in,out);
148             if (!Singleton.__pool.dispatch(job))
149                 job.run();
150         }
151         catch(Exception e)
152         {
153             Log.warn(e);
154         }
155     }
156     
157     /* ------------------------------------------------------------------- */
158     /** Copy Reader to Writer out until EOF or exception.
159      */
160     public static void copy(Reader in, Writer out)
161          throws IOException
162     {
163         copy(in,out,-1);
164     }
165     
166     /* ------------------------------------------------------------------- */
167     /** Copy Stream in to Stream for byteCount bytes or until EOF or exception.
168      */
169     public static void copy(InputStream in,
170                             OutputStream out,
171                             long byteCount)
172          throws IOException
173     {     
174         byte buffer[] = new byte[bufferSize];
175         int len=bufferSize;
176         
177         if (byteCount>=0)
178         {
179             while (byteCount>0)
180             {
181                 if (byteCount<bufferSize)
182                     len=in.read(buffer,0,(int)byteCount);
183                 else
184                     len=in.read(buffer,0,bufferSize);                   
185                 
186                 if (len==-1)
187                     break;
188                 
189                 byteCount -= len;
190                 out.write(buffer,0,len);
191             }
192         }
193         else
194         {
195             while (true)
196             {
197                 len=in.read(buffer,0,bufferSize);
198                 if (len<0 )
199                     break;
200                 out.write(buffer,0,len);
201             }
202         }
203     }  
204     
205     /* ------------------------------------------------------------------- */
206     /** Copy Reader to Writer for byteCount bytes or until EOF or exception.
207      */
208     public static void copy(Reader in,
209                             Writer out,
210                             long byteCount)
211          throws IOException
212     {  
213         char buffer[] = new char[bufferSize];
214         int len=bufferSize;
215         
216         if (byteCount>=0)
217         {
218             while (byteCount>0)
219             {
220                 if (byteCount<bufferSize)
221                     len=in.read(buffer,0,(int)byteCount);
222                 else
223                     len=in.read(buffer,0,bufferSize);                   
224                 
225                 if (len==-1)
226                     break;
227                 
228                 byteCount -= len;
229                 out.write(buffer,0,len);
230             }
231         }
232         else
233         {
234             while (true)
235             {
236                 len=in.read(buffer,0,bufferSize);
237                 if (len==-1)
238                     break;
239                 out.write(buffer,0,len);
240             }
241         }
242     }
243 
244     /* ------------------------------------------------------------ */
245     /** Copy files or directories
246      * @param from
247      * @param to
248      * @throws IOException
249      */
250     public static void copy(File from,File to) throws IOException
251     {
252         if (from.isDirectory())
253             copyDir(from,to);
254         else
255             copyFile(from,to);
256     }
257 
258     /* ------------------------------------------------------------ */
259     public static void copyDir(File from,File to) throws IOException
260     {
261         if (to.exists())
262         {
263             if (!to.isDirectory())
264                 throw new IllegalArgumentException(to.toString());
265         }
266         else
267             to.mkdirs();
268         
269         File[] files = from.listFiles();
270         if (files!=null)
271         {
272             for (int i=0;i<files.length;i++)
273             {
274                 String name = files[i].getName();
275                 if (".".equals(name) || "..".equals(name))
276                     continue;
277                 copy(files[i],new File(to,name));
278             }
279         }
280     }
281     
282     /* ------------------------------------------------------------ */
283     public static void copyFile(File from,File to) throws IOException
284     {
285         FileInputStream in=new FileInputStream(from);
286         FileOutputStream out=new FileOutputStream(to);
287         copy(in,out);
288         in.close();
289         out.close();
290     }
291     
292     /* ------------------------------------------------------------ */
293     /** Read input stream to string.
294      */
295     public static String toString(InputStream in)
296         throws IOException
297     {
298         return toString(in,null);
299     }
300     
301     /* ------------------------------------------------------------ */
302     /** Read input stream to string.
303      */
304     public static String toString(InputStream in,String encoding)
305         throws IOException
306     {
307         StringWriter writer=new StringWriter();
308         InputStreamReader reader = encoding==null?new InputStreamReader(in):new InputStreamReader(in,encoding);
309         
310         copy(reader,writer);
311         return writer.toString();
312     }
313     
314     /* ------------------------------------------------------------ */
315     /** Read input stream to string.
316      */
317     public static String toString(Reader in)
318         throws IOException
319     {
320         StringWriter writer=new StringWriter();
321         copy(in,writer);
322         return writer.toString();
323     }
324 
325 
326     /* ------------------------------------------------------------ */
327     /** Delete File.
328      * This delete will recursively delete directories - BE CAREFULL
329      * @param file The file to be deleted.
330      */
331     public static boolean delete(File file)
332     {
333         if (!file.exists())
334             return false;
335         if (file.isDirectory())
336         {
337             File[] files = file.listFiles();
338             for (int i=0;files!=null && i<files.length;i++)
339                 delete(files[i]);
340         }
341         return file.delete();
342     }
343 
344     /* ------------------------------------------------------------ */
345     /**
346      * closes an input stream, and logs exceptions
347      *
348      * @param is the input stream to close
349      */
350     public static void close(InputStream is)
351     {
352         try
353         {
354             if (is != null)
355                 is.close();
356         }
357         catch (IOException e)
358         {
359             Log.ignore(e);
360         }
361     }
362 
363     /* ------------------------------------------------------------ */
364     public static byte[] readBytes(InputStream in)
365         throws IOException
366     {
367         ByteArrayOutputStream bout = new ByteArrayOutputStream();
368         copy(in,bout);
369         return bout.toByteArray();
370     }
371     
372     /* ------------------------------------------------------------ */
373     /**
374      * closes an output stream, and logs exceptions
375      *
376      * @param os the output stream to close
377      */
378     public static void close(OutputStream os)
379     {
380         try
381         {
382             if (os != null)
383                 os.close();
384         }
385         catch (IOException e)
386         {
387             Log.ignore(e);
388         }
389     }
390 
391     /* ------------------------------------------------------------ */
392     /** 
393      * @return An outputstream to nowhere
394      */
395     public static OutputStream getNullStream()
396     {
397         return __nullStream;
398     }
399 
400     /* ------------------------------------------------------------ */
401     /** 
402      * @return An outputstream to nowhere
403      */
404     public static InputStream getClosedStream()
405     {
406         return __closedStream;
407     }
408     
409     /* ------------------------------------------------------------ */
410     /* ------------------------------------------------------------ */
411     private static class NullOS extends OutputStream                                    
412     {
413         public void close(){}
414         public void flush(){}
415         public void write(byte[]b){}
416         public void write(byte[]b,int i,int l){}
417         public void write(int b){}
418     }
419     private static NullOS __nullStream = new NullOS();
420 
421     
422     /* ------------------------------------------------------------ */
423     /* ------------------------------------------------------------ */
424     private static class ClosedIS extends InputStream                                    
425     {
426         public int read() throws IOException
427         {
428             return -1;
429         }
430     }
431     private static ClosedIS __closedStream = new ClosedIS();
432     
433     /* ------------------------------------------------------------ */
434     /** 
435      * @return An writer to nowhere
436      */
437     public static Writer getNullWriter()
438     {
439         return __nullWriter;
440     }
441     
442     /* ------------------------------------------------------------ */
443     /* ------------------------------------------------------------ */
444     private static class NullWrite extends Writer                                    
445     {
446         public void close(){}
447         public void flush(){}
448         public void write(char[]b){}
449         public void write(char[]b,int o,int l){}
450         public void write(int b){}
451         public void write(String s){}
452         public void write(String s,int o,int l){}
453     }
454     private static NullWrite __nullWriter = new NullWrite();
455 
456 }
457 
458 
459 
460 
461 
462 
463 
464 
465