KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > excalibur > source > impl > HTTPClientSource


1 /*
2  * Copyright 2002-2004 The Apache Software Foundation
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  *
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.excalibur.source.impl;
18
19 import java.io.File JavaDoc;
20 import java.io.FileInputStream JavaDoc;
21 import java.io.FileOutputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.Date JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.Map JavaDoc;
29
30 import org.apache.avalon.framework.activity.Initializable;
31 import org.apache.avalon.framework.logger.AbstractLogEnabled;
32 import org.apache.avalon.framework.logger.Logger;
33 import org.apache.avalon.framework.parameters.ParameterException;
34 import org.apache.avalon.framework.parameters.Parameterizable;
35 import org.apache.avalon.framework.parameters.Parameters;
36 import org.apache.commons.httpclient.Header;
37 import org.apache.commons.httpclient.HttpClient;
38 import org.apache.commons.httpclient.HttpMethod;
39 import org.apache.commons.httpclient.HttpStatus;
40 import org.apache.commons.httpclient.NameValuePair;
41 import org.apache.commons.httpclient.methods.DeleteMethod;
42 import org.apache.commons.httpclient.methods.GetMethod;
43 import org.apache.commons.httpclient.methods.HeadMethod;
44 import org.apache.commons.httpclient.methods.PostMethod;
45 import org.apache.commons.httpclient.methods.PutMethod;
46 import org.apache.excalibur.source.*;
47 import org.apache.excalibur.source.impl.validity.TimeStampValidity;
48
49 /**
50  * HTTP URL Source object, based on the Jakarta Commons
51  * <a HREF="http://jakarta.apache.org/commons/httpclient/">HttpClient</a>
52  * project.
53  *
54  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
55  * @version CVS $Id: HTTPClientSource.java,v 1.4 2004/02/28 11:47:24 cziegeler Exp $
56  */

57 public class HTTPClientSource extends AbstractLogEnabled
58     implements ModifiableSource, Initializable, Parameterizable
59 {
60     /**
61      * Constant used for identifying POST requests.
62      */

63     public static final String JavaDoc POST = "POST";
64
65     /**
66      * Constant used for identifying GET requests.
67      */

68     public static final String JavaDoc GET = "GET";
69
70     /**
71      * Constant used for configuring the proxy hostname.
72      */

73     public static final String JavaDoc PROXY_HOST = "proxy.host";
74
75     /**
76      * Constant used for configuring the proxy port number.
77      */

78     public static final String JavaDoc PROXY_PORT = "proxy.port";
79
80     /**
81      * Constant used when obtaining the Content-Type from HTTP Headers
82      */

83     public static final String JavaDoc CONTENT_TYPE = "Content-Type";
84
85     /**
86      * Constant used when obtaining the Content-Length from HTTP Headers
87      */

88     public static final String JavaDoc CONTENT_LENGTH = "Content-Length";
89
90     /**
91      * Constant used when obtaining the Last-Modified date from HTTP Headers
92      */

93     public static final String JavaDoc LAST_MODIFIED = "Last-Modified";
94
95     /**
96      * The URI being accessed.
97      */

98     private final String JavaDoc m_uri;
99
100     /**
101      * Contextual parameters passed via the {@link SourceFactory}.
102      */

103     private final Map JavaDoc m_parameters;
104
105     /**
106      * The {@link HttpClient} object.
107      */

108     private HttpClient m_client;
109
110     /**
111      * Proxy port if set via configuration.
112      */

113     private int m_proxyPort;
114
115     /**
116      * Proxy host if set via configuration.
117      */

118     private String JavaDoc m_proxyHost;
119
120     /**
121      * Whether the data held within this instance is currently accurate.
122      */

123     private boolean m_dataValid;
124
125     /**
126      * Whether the resource exists on the server.
127      */

128     private boolean m_exists;
129
130     /**
131      * The mime type of the resource on the server.
132      */

133     private String JavaDoc m_mimeType;
134
135     /**
136      * The content length of the resource on the server.
137      */

138     private long m_contentLength;
139
140     /**
141      * The last modified date of the resource on the server.
142      */

143     private long m_lastModified;
144
145     /**
146      * Stored {@link SourceValidity} object.
147      */

148     private SourceValidity m_cachedValidity;
149
150     /**
151      * Cached last modification date.
152      */

153     private long m_cachedLastModificationDate;
154
155     /**
156      * Constructor, creates a new {@link HTTPClientSource} instance.
157      *
158      * @param uri URI
159      * @param parameters contextual parameters passed to this instance
160      * @exception Exception if an error occurs
161      */

162     public HTTPClientSource( final String JavaDoc uri, final Map JavaDoc parameters )
163         throws Exception JavaDoc
164     {
165         m_uri = uri;
166         m_parameters =
167             parameters == null ? Collections.EMPTY_MAP : parameters;
168     }
169
170     /**
171      * Parameterizes this {@link HTTPClientSource} instance.
172      *
173      * @param params a {@link Parameters} instance.
174      * @exception ParameterException if an error occurs
175      */

176     public void parameterize( final Parameters params )
177         throws ParameterException
178     {
179         m_proxyHost = params.getParameter( PROXY_HOST, null );
180         m_proxyPort = params.getParameterAsInteger( PROXY_PORT, -1 );
181
182         if ( getLogger().isDebugEnabled() )
183         {
184             final String JavaDoc message =
185                 m_proxyHost == null || m_proxyPort == -1
186                 ? "No proxy configured"
187                 : "Configured with proxy host "
188                   + m_proxyHost + " port " + m_proxyPort;
189
190             getLogger().debug( message );
191         }
192     }
193
194     /**
195      * Initializes this {@link HTTPClientSource} instance.
196      *
197      * @exception Exception if an error occurs
198      */

199     public void initialize() throws Exception JavaDoc
200     {
201         m_client = new HttpClient();
202
203         if ( m_proxyHost != null && m_proxyPort != -1 )
204         {
205             m_client.getHostConfiguration().setProxy( m_proxyHost, m_proxyPort );
206         }
207
208         m_dataValid = false;
209     }
210
211     /**
212      * Method to discover what kind of request is being made from the
213      * parameters map passed in to this Source's constructor.
214      *
215      * @return the method type, or if no method type can be found,
216      * HTTP GET is assumed.
217      */

218     private String JavaDoc findMethodType()
219     {
220         final String JavaDoc method =
221             (String JavaDoc) m_parameters.get( SourceResolver.METHOD );
222         return method == null ? GET : method;
223     }
224
225     /**
226      * Helper method to create the required {@link HttpMethod} object
227      * based on parameters passed to this {@link HTTPClientSource} object.
228      *
229      * @return a {@link HttpMethod} object.
230      */

231     private HttpMethod getMethod()
232     {
233         final String JavaDoc method = findMethodType();
234
235         // create a POST method if requested
236
if ( POST.equals( method ) )
237         {
238             return createPostMethod(
239                 m_uri,
240                 (SourceParameters) m_parameters.get( SourceResolver.URI_PARAMETERS )
241             );
242         }
243
244         // default method is GET
245
return createGetMethod( m_uri );
246     }
247
248     /**
249      * Factory method to create a new {@link PostMethod} with the given
250      * {@link SourceParameters} object.
251      *
252      * @param uri URI
253      * @param params {@link SourceParameters}
254      * @return a {@link PostMethod} instance
255      */

256     private PostMethod createPostMethod(
257         final String JavaDoc uri, final SourceParameters params
258     )
259     {
260         final PostMethod post = new PostMethod( uri );
261
262         if ( params == null )
263         {
264             return post;
265         }
266
267         for ( final Iterator JavaDoc names = params.getParameterNames();
268               names.hasNext();
269         )
270         {
271             final String JavaDoc name = (String JavaDoc) names.next();
272
273             for ( final Iterator JavaDoc values = params.getParameterValues( name );
274                   values.hasNext();
275             )
276             {
277                 final String JavaDoc value = (String JavaDoc) values.next();
278                 post.addParameter( new NameValuePair( name, value ) );
279             }
280         }
281
282         return post;
283     }
284
285     /**
286      * Factory method to create a {@link GetMethod} object.
287      *
288      * @param uri URI
289      * @return a {@link GetMethod} instance
290      */

291     private GetMethod createGetMethod( final String JavaDoc uri )
292     {
293         final GetMethod method = new GetMethod( uri );
294
295         // add all parameters as headers
296
for ( final Iterator JavaDoc i = m_parameters.keySet().iterator(); i.hasNext(); )
297         {
298             final String JavaDoc key = (String JavaDoc) i.next();
299             final String JavaDoc value = (String JavaDoc) m_parameters.get( key );
300
301             if ( getLogger().isDebugEnabled() )
302             {
303                 getLogger().debug(
304                     "Adding header '" + key + "', with value '" + value + "'"
305                 );
306             }
307
308             method.setRequestHeader( key, value );
309         }
310
311         return method;
312     }
313
314     /**
315      * Factory method to create a {@link HeadMethod} object.
316      *
317      * @param uri URI
318      * @return a {@link HeadMethod} instance
319      */

320     private HeadMethod createHeadMethod( final String JavaDoc uri )
321     {
322         return new HeadMethod( uri );
323     }
324
325     /**
326      * Factory method to create a {@link PutMethod} object.
327      *
328      * @param uri URI to upload <code>uploadFile</code> to
329      * @param uploadFile {@link File} to be uploaded
330      * @return a {@link PutMethod} instance
331      * @exception IOException if an error occurs
332      */

333     private PutMethod createPutMethod(
334         final String JavaDoc uri, final File JavaDoc uploadFile
335     )
336         throws IOException JavaDoc
337     {
338         final PutMethod put = new PutMethod( uri );
339         put.setRequestBody(
340             new FileInputStream JavaDoc( uploadFile.getAbsolutePath() )
341         );
342         return put;
343     }
344
345     /**
346      * Factory method to create a {@link DeleteMethod} object.
347      *
348      * @param uri URI to delete
349      * @return {@link DeleteMethod} instance.
350      */

351     private DeleteMethod createDeleteMethod( final String JavaDoc uri )
352     {
353         return new DeleteMethod( uri );
354     }
355
356     /**
357      * Method to make response data available if possible without
358      * actually making an actual request (ie. via HTTP HEAD).
359      */

360     private void updateData()
361     {
362         // no request made so far, attempt to get some response data.
363
if ( !m_dataValid )
364         {
365             if ( GET.equals( findMethodType() ) )
366             {
367                 try
368                 {
369                     final HttpMethod head = createHeadMethod( m_uri );
370                     executeMethod( head );
371                     head.releaseConnection();
372                     return;
373                 }
374                 catch ( final IOException JavaDoc e )
375                 {
376                     if ( getLogger().isDebugEnabled() )
377                     {
378                         getLogger().debug(
379                             "Unable to determine response data, using defaults", e
380                         );
381                     }
382                 }
383             }
384
385             // default values when response data is not available
386
m_exists = false;
387             m_mimeType = null;
388             m_contentLength = -1;
389             m_lastModified = 0;
390             m_dataValid = true;
391         }
392     }
393
394     /**
395      * Executes a particular {@link HttpMethod} and updates internal
396      * data storage.
397      *
398      * @param method {@link HttpMethod} to execute
399      * @return response code from server
400      * @exception IOException if an error occurs
401      */

402     private int executeMethod( final HttpMethod method )
403         throws IOException JavaDoc
404     {
405         final int response = m_client.executeMethod( method );
406
407         updateExists( method );
408         updateMimeType( method );
409         updateContentLength( method );
410         updateLastModified( method );
411
412         // all finished, return response code to the caller.
413
return response;
414     }
415
416     /**
417      * Method to update whether a referenced resource exists, after
418      * executing a particular {@link HttpMethod}.
419      *
420      * <p>REVISIT: exists() would be better called canRead()
421      * or similar, as a resource can exist but not be readable.</p>
422      *
423      * @param method {@link HttpMethod} executed.
424      */

425     private void updateExists( final HttpMethod method )
426     {
427         final int response = method.getStatusCode();
428
429         // The following returns true, if the user can successfully get
430
// an InputStream without receiving errors? ie. if we receive a
431
// HTTP 200 (OK), 201 (CREATED), 206 (PARTIAL CONTENT)
432

433         // REVISIT(MC): need a special way to handle 304 (NOT MODIFIED)
434
// 204 & 205 in the future
435

436         // resource does not exist if HttpClient returns a 404 or a 410
437
m_exists = (response == HttpStatus.SC_OK ||
438                     response == HttpStatus.SC_CREATED ||
439                     response == HttpStatus.SC_PARTIAL_CONTENT);
440     }
441
442     /**
443      * Method to ascertain whether the given resource actually exists.
444      *
445      * @return <code>true</code> if the resource pointed to by the
446      * URI during construction exists, <code>false</code>
447      * otherwise.
448      */

449     public boolean exists()
450     {
451         updateData();
452         return m_exists;
453     }
454
455     /**
456      * Method to obtain an {@link InputStream} to read the response
457      * from the server.
458      *
459      * @return {@link InputStream} containing data sent from the server.
460      * @throws IOException if some I/O problem occurs.
461      * @throws SourceNotFoundException if the source doesn't exist.
462      */

463     public InputStream JavaDoc getInputStream()
464         throws IOException JavaDoc, SourceNotFoundException
465     {
466         final HttpMethod method = getMethod();
467         final int response = executeMethod( method );
468         m_dataValid = true;
469
470         // throw SourceNotFoundException - according to Source API we
471
// need to throw this if the source doesn't exist.
472
if ( !exists() )
473         {
474             final StringBuffer JavaDoc error = new StringBuffer JavaDoc();
475             error.append( "Unable to retrieve URI: " );
476             error.append( m_uri );
477             error.append( " (" );
478             error.append( response );
479             error.append( ")" );
480
481             throw new SourceNotFoundException( error.toString() );
482         }
483
484         return method.getResponseBodyAsStream();
485     }
486
487     /**
488      * Obtain the absolute URI this {@link Source} object references.
489      *
490      * @return the absolute URI this {@link String} object references.
491      */

492     public String JavaDoc getURI()
493     {
494         return m_uri;
495     }
496
497     /**
498      * Return the URI scheme identifier, ie. the part preceding the fist ':'
499      * in the URI (see <a HREF="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>).
500      *
501      * @return the URI scheme identifier
502      */

503     public String JavaDoc getScheme()
504     {
505         return SourceUtil.getScheme( m_uri );
506     }
507     
508     /**
509      * Obtain a {@link SourceValidity} object.
510      *
511      * @return a {@link SourceValidity} object, or
512      * <code>null</code> if this is not possible.
513      */

514     public SourceValidity getValidity()
515     {
516         // Implementation taken from URLSource.java, Kudos :)
517

518         final long lm = getLastModified();
519
520         if ( lm > 0 )
521         {
522             if ( lm == m_cachedLastModificationDate )
523             {
524                 return m_cachedValidity;
525             }
526
527             m_cachedLastModificationDate = lm;
528             m_cachedValidity = new TimeStampValidity( lm );
529             return m_cachedValidity;
530         }
531
532         return null;
533     }
534
535     /**
536      * Refreshes this {@link Source} object.
537      */

538     public void refresh()
539     {
540         recycle();
541     }
542
543     /**
544      * Method to update the mime type of a resource after
545      * executing a particular {@link HttpMethod}.
546      *
547      * @param method {@link HttpMethod} executed
548      */

549     private void updateMimeType( final HttpMethod method )
550     {
551         // REVISIT: should this be the mime-type, or the content-type -> URLSource
552
// returns the Content-Type, so we'll follow that for now.
553
final Header header = method.getResponseHeader( CONTENT_TYPE );
554         m_mimeType = header == null ? null : header.getValue();
555     }
556
557     /**
558      * Obtain the mime-type for the referenced resource.
559      *
560      * @return mime-type for the referenced resource.
561      */

562     public String JavaDoc getMimeType()
563     {
564         updateData();
565         return m_mimeType;
566     }
567
568     /**
569      * Method to update the content length of a resource after
570      * executing a particular {@link HttpMethod}.
571      *
572      * @param method {@link HttpMethod} executed
573      */

574     private void updateContentLength( final HttpMethod method )
575     {
576         try
577         {
578             final Header length =
579                 method.getResponseHeader( CONTENT_LENGTH );
580             m_contentLength =
581                 length == null ? -1 : Long.parseLong( length.getValue() );
582         }
583         catch ( final NumberFormatException JavaDoc e )
584         {
585             if ( getLogger().isDebugEnabled() )
586             {
587                 getLogger().debug(
588                     "Unable to determine content length, returning -1", e
589                 );
590             }
591
592             m_contentLength = -1;
593         }
594     }
595
596     /**
597      * Obtain the content length of the referenced resource.
598      *
599      * @return content length of the referenced resource, or
600      * -1 if unknown/uncalculatable
601      */

602     public long getContentLength()
603     {
604         updateData();
605         return m_contentLength;
606     }
607
608     /**
609      * Method to update the last modified date of a resource after
610      * executing a particular {@link HttpMethod}.
611      *
612      * @param method {@link HttpMethod} executed
613      */

614     private void updateLastModified( final HttpMethod method )
615     {
616         final Header lastModified = method.getResponseHeader( LAST_MODIFIED );
617         m_lastModified =
618             lastModified == null ? 0 : Date.parse( lastModified.getValue() );
619     }
620
621     /**
622      * Get the last modification date of this source. This date is
623      * measured in milliseconds since the Epoch (00:00:00 GMT, January 1, 1970).
624      *
625      * @return the last modification date or <code>0</code> if unknown.
626      */

627     public long getLastModified()
628     {
629         updateData();
630         return m_lastModified;
631     }
632
633     /**
634      * Recycles this {@link HTTPClientSource} object so that it may be reused
635      * to refresh it's content.
636      */

637     private void recycle()
638     {
639         m_dataValid = false;
640     }
641
642     /////////////////////////// ModifiableSource methods
643

644     /**
645      * Obtain an {@link OutputStream} to write to. The {@link OutputStream}
646      * returned actually references a temporary local file, which will
647      * be written to the server upon closing.
648      *
649      * @return an {@link OutputStream} instance
650      * @exception IOException if an error occurs
651      */

652     public OutputStream JavaDoc getOutputStream() throws IOException JavaDoc
653     {
654         final File JavaDoc tempFile = File.createTempFile("httpclient", "tmp");
655         return new WrappedFileOutputStream( tempFile, getLogger() );
656     }
657
658     /**
659      * Internal class which extends {@link FileOutputStream} to
660      * automatically upload the data written to it, upon a {@link #close}
661      * operation.
662      */

663     private class WrappedFileOutputStream extends FileOutputStream JavaDoc
664     {
665         /**
666          * Reference to the File being written itself.
667          */

668         private File JavaDoc m_file;
669
670         /**
671          * Reference to a {@link Logger}.
672          */

673         private final Logger m_logger;
674
675         /**
676          * Constructor, creates a new {@link WrappedFileOutputStream}
677          * instance.
678          *
679          * @param file {@link File} to write to.
680          * @param logger {@link Logger} reference.
681          * @exception IOException if an error occurs
682          */

683         public WrappedFileOutputStream( final File JavaDoc file, final Logger logger )
684             throws IOException JavaDoc
685         {
686             super( file );
687             m_file = file;
688             m_logger = logger;
689         }
690
691         /**
692          * Closes the stream, and uploads the file written to the
693          * server.
694          *
695          * @exception IOException if an error occurs
696          */

697         public void close() throws IOException JavaDoc
698         {
699             super.close();
700
701             if ( m_file != null )
702             {
703                 upload();
704                 m_file.delete();
705                 m_file = null;
706             }
707         }
708
709         /**
710          * Method to test whether this stream can be closed.
711          *
712          * @return <code>true</code> if possible, false otherwise.
713          */

714         public boolean canCancel()
715         {
716             return m_file != null;
717         }
718
719         /**
720          * Cancels this stream.
721          *
722          * @exception IOException if stream is already closed
723          */

724         public void cancel() throws IOException JavaDoc
725         {
726             if ( m_file == null )
727             {
728                 throw new IOException JavaDoc( "Stream already closed" );
729             }
730
731             super.close();
732             m_file.delete();
733             m_file = null;
734         }
735
736         /**
737          * Helper method to attempt uploading of the local data file
738          * to the remove server via a HTTP PUT.
739          *
740          * @exception IOException if an error occurs
741          */

742         private void upload()
743             throws IOException JavaDoc
744         {
745             HttpMethod uploader = null;
746
747             if ( m_logger.isDebugEnabled() )
748             {
749                 m_logger.debug( "Stream closed, writing data to " + m_uri );
750             }
751
752             try
753             {
754                 uploader = createPutMethod( m_uri, m_file );
755                 final int response = executeMethod( uploader );
756
757                 if ( !successfulUpload( response ) )
758                 {
759                     throw new SourceException(
760                         "Write to " + m_uri + " failed (" + response + ")"
761                     );
762                 }
763
764                 if ( m_logger.isDebugEnabled() )
765                 {
766                     m_logger.debug(
767                         "Write to " + m_uri + " succeeded (" + response + ")"
768                     );
769                 }
770             }
771             finally
772             {
773                 if ( uploader != null )
774                 {
775                     uploader.releaseConnection();
776                 }
777             }
778         }
779
780         /**
781          * According to RFC2616 (HTTP 1.1) valid responses for a HTTP PUT
782          * are 201 (Created), 200 (OK), and 204 (No Content).
783          *
784          * @param response response code from the HTTP PUT
785          * @return true if upload was successful, false otherwise.
786          */

787         private boolean successfulUpload( final int response )
788         {
789             return response == HttpStatus.SC_OK
790                 || response == HttpStatus.SC_CREATED
791                 || response == HttpStatus.SC_NO_CONTENT;
792         }
793     }
794
795     /**
796      * Deletes the referenced resource.
797      *
798      * @exception SourceException if an error occurs
799      */

800     public void delete() throws SourceException
801     {
802         try
803         {
804             final int response =
805                 executeMethod( createDeleteMethod( m_uri ) );
806
807             if ( !deleteSuccessful( response ) )
808             {
809                 throw new SourceException(
810                     "Failed to delete " + m_uri + " (" + response + ")"
811                 );
812             }
813
814             if ( getLogger().isDebugEnabled() )
815             {
816                 getLogger().debug( m_uri + " deleted (" + response + ")");
817             }
818         }
819         catch ( final IOException JavaDoc e )
820         {
821             throw new SourceException(
822                 "IOException thrown during delete", e
823             );
824         }
825     }
826
827     /**
828      * According to RFC2616 (HTTP 1.1) valid responses for a HTTP DELETE
829      * are 200 (OK), 202 (Accepted) and 204 (No Content).
830      *
831      * @param response response code from the HTTP PUT
832      * @return true if upload was successful, false otherwise.
833      */

834     private boolean deleteSuccessful( final int response )
835     {
836         return response == HttpStatus.SC_OK
837             || response == HttpStatus.SC_ACCEPTED
838             || response == HttpStatus.SC_NO_CONTENT;
839     }
840
841     /**
842      * Method to determine whether writing to the supplied OutputStream
843      * (which must be that returned from {@link #getOutputStream()}) can
844      * be cancelled
845      *
846      * @return true if writing to the stream can be cancelled,
847      * false otherwise
848      */

849     public boolean canCancel( final OutputStream JavaDoc stream )
850     {
851         // with help from FileSource, dankeschoen lads :)
852

853         if ( stream instanceof WrappedFileOutputStream )
854         {
855             return ((WrappedFileOutputStream) stream).canCancel();
856         }
857
858         throw new IllegalArgumentException JavaDoc(
859             "Output stream supplied was not created by this class"
860         );
861     }
862
863     /**
864      * Cancels any data sent to the {@link OutputStream} returned by
865      * {@link #getOutputStream()}.
866      *
867      * After calling this method, the supplied {@link OutputStream}
868      * should no longer be used.
869      */

870     public void cancel( final OutputStream JavaDoc stream ) throws IOException JavaDoc
871     {
872         if ( stream instanceof WrappedFileOutputStream )
873         {
874             ((WrappedFileOutputStream) stream).cancel();
875         }
876         else
877         {
878             throw new IllegalArgumentException JavaDoc(
879                 "Output stream supplied was not created by this class"
880             );
881         }
882     }
883 }
884
Popular Tags