View Javadoc
1   package org.apache.maven.wagon;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.wagon.authentication.AuthenticationException;
23  import org.apache.maven.wagon.authentication.AuthenticationInfo;
24  import org.apache.maven.wagon.authorization.AuthorizationException;
25  import org.apache.maven.wagon.events.SessionEvent;
26  import org.apache.maven.wagon.events.SessionEventSupport;
27  import org.apache.maven.wagon.events.SessionListener;
28  import org.apache.maven.wagon.events.TransferEvent;
29  import org.apache.maven.wagon.events.TransferEventSupport;
30  import org.apache.maven.wagon.events.TransferListener;
31  import org.apache.maven.wagon.proxy.ProxyInfo;
32  import org.apache.maven.wagon.proxy.ProxyInfoProvider;
33  import org.apache.maven.wagon.proxy.ProxyUtils;
34  import org.apache.maven.wagon.repository.Repository;
35  import org.apache.maven.wagon.repository.RepositoryPermissions;
36  import org.apache.maven.wagon.resource.Resource;
37  import org.codehaus.plexus.util.IOUtil;
38  
39  import java.io.File;
40  import java.io.FileInputStream;
41  import java.io.FileNotFoundException;
42  import java.io.IOException;
43  import java.io.InputStream;
44  import java.io.OutputStream;
45  import java.nio.ByteBuffer;
46  import java.nio.channels.Channels;
47  import java.nio.channels.ReadableByteChannel;
48  import java.util.List;
49  
50  import static java.lang.Math.max;
51  import static java.lang.Math.min;
52  
53  /**
54   * Implementation of common facilities for Wagon providers.
55   *
56   * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
57   */
58  public abstract class AbstractWagon
59      implements Wagon
60  {
61      protected static final int DEFAULT_BUFFER_SIZE = 4 * 1024;
62      protected static final int MAXIMUM_BUFFER_SIZE = 512 * 1024;
63  
64      /**
65       * To efficiently buffer data, use a multiple of 4 KiB as this is likely to match the hardware
66       * buffer size of certain storage devices.
67       */
68      protected static final int BUFFER_SEGMENT_SIZE = 4 * 1024;
69  
70      /**
71       * The desired minimum amount of chunks in which a {@link Resource} shall be
72       * {@link #transfer(Resource, InputStream, OutputStream, int, long) transferred}.
73       * This corresponds to the minimum times {@link #fireTransferProgress(TransferEvent, byte[], int)}
74       * is executed. 100 notifications is a conservative value that will lead to small chunks for
75       * any artifact less that {@link #BUFFER_SEGMENT_SIZE} * {@link #MINIMUM_AMOUNT_OF_TRANSFER_CHUNKS}
76       * in size.
77       */
78      protected static final int MINIMUM_AMOUNT_OF_TRANSFER_CHUNKS = 100;
79  
80      protected Repository repository;
81  
82      protected SessionEventSupport sessionEventSupport = new SessionEventSupport();
83  
84      protected TransferEventSupport transferEventSupport = new TransferEventSupport();
85  
86      protected AuthenticationInfo authenticationInfo;
87  
88      protected boolean interactive = true;
89  
90  
91      private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
92  
93      /**
94       * read timeout value
95       *
96       * @since 2.2
97       */
98      private int readTimeout =
99          Integer.parseInt( System.getProperty( "maven.wagon.rto", Integer.toString( Wagon.DEFAULT_READ_TIMEOUT ) ) );
100 
101     private ProxyInfoProvider proxyInfoProvider;
102 
103     /**
104      * @deprecated
105      */
106     protected ProxyInfo proxyInfo;
107 
108     private RepositoryPermissions permissionsOverride;
109 
110     // ----------------------------------------------------------------------
111     // Accessors
112     // ----------------------------------------------------------------------
113 
114     public Repository getRepository()
115     {
116         return repository;
117     }
118 
119     public ProxyInfo getProxyInfo()
120     {
121         return proxyInfoProvider != null ? proxyInfoProvider.getProxyInfo( null ) : null;
122     }
123 
124     public AuthenticationInfo getAuthenticationInfo()
125     {
126         return authenticationInfo;
127     }
128 
129     // ----------------------------------------------------------------------
130     // Connection
131     // ----------------------------------------------------------------------
132 
133     public void openConnection()
134         throws ConnectionException, AuthenticationException
135     {
136         try
137         {
138             openConnectionInternal();
139         }
140         catch ( ConnectionException e )
141         {
142             fireSessionConnectionRefused();
143 
144             throw e;
145         }
146         catch ( AuthenticationException e )
147         {
148             fireSessionConnectionRefused();
149 
150             throw e;
151         }
152     }
153 
154     public void connect( Repository repository )
155         throws ConnectionException, AuthenticationException
156     {
157         connect( repository, null, (ProxyInfoProvider) null );
158     }
159 
160     public void connect( Repository repository, ProxyInfo proxyInfo )
161         throws ConnectionException, AuthenticationException
162     {
163         connect( repository, null, proxyInfo );
164     }
165 
166     public void connect( Repository repository, ProxyInfoProvider proxyInfoProvider )
167         throws ConnectionException, AuthenticationException
168     {
169         connect( repository, null, proxyInfoProvider );
170     }
171 
172     public void connect( Repository repository, AuthenticationInfo authenticationInfo )
173         throws ConnectionException, AuthenticationException
174     {
175         connect( repository, authenticationInfo, (ProxyInfoProvider) null );
176     }
177 
178     public void connect( Repository repository, AuthenticationInfo authenticationInfo, ProxyInfo proxyInfo )
179         throws ConnectionException, AuthenticationException
180     {
181         final ProxyInfo proxy = proxyInfo;
182         connect( repository, authenticationInfo, new ProxyInfoProvider()
183         {
184             public ProxyInfo getProxyInfo( String protocol )
185             {
186                 if ( protocol == null || proxy == null || protocol.equalsIgnoreCase( proxy.getType() ) )
187                 {
188                     return proxy;
189                 }
190                 else
191                 {
192                     return null;
193                 }
194             }
195         } );
196     }
197 
198     public void connect( Repository repository, AuthenticationInfo authenticationInfo,
199                          ProxyInfoProvider proxyInfoProvider )
200         throws ConnectionException, AuthenticationException
201     {
202         if ( repository == null )
203         {
204             throw new NullPointerException( "repository cannot be null" );
205         }
206 
207         if ( permissionsOverride != null )
208         {
209             repository.setPermissions( permissionsOverride );
210         }
211 
212         this.repository = repository;
213 
214         if ( authenticationInfo == null )
215         {
216             authenticationInfo = new AuthenticationInfo();
217         }
218 
219         if ( authenticationInfo.getUserName() == null )
220         {
221             // Get user/pass that were encoded in the URL.
222             if ( repository.getUsername() != null )
223             {
224                 authenticationInfo.setUserName( repository.getUsername() );
225                 if ( repository.getPassword() != null && authenticationInfo.getPassword() == null )
226                 {
227                     authenticationInfo.setPassword( repository.getPassword() );
228                 }
229             }
230         }
231 
232         this.authenticationInfo = authenticationInfo;
233 
234         this.proxyInfoProvider = proxyInfoProvider;
235 
236         fireSessionOpening();
237 
238         openConnection();
239 
240         fireSessionOpened();
241     }
242 
243     protected abstract void openConnectionInternal()
244         throws ConnectionException, AuthenticationException;
245 
246     public void disconnect()
247         throws ConnectionException
248     {
249         fireSessionDisconnecting();
250 
251         try
252         {
253             closeConnection();
254         }
255         catch ( ConnectionException e )
256         {
257             fireSessionError( e );
258             throw e;
259         }
260 
261         fireSessionDisconnected();
262     }
263 
264     protected abstract void closeConnection()
265         throws ConnectionException;
266 
267     protected void createParentDirectories( File destination )
268         throws TransferFailedException
269     {
270         File destinationDirectory = destination.getParentFile();
271         try
272         {
273             destinationDirectory = destinationDirectory.getCanonicalFile();
274         }
275         catch ( IOException e )
276         {
277             // not essential to have a canonical file
278         }
279         if ( destinationDirectory != null && !destinationDirectory.exists() )
280         {
281             destinationDirectory.mkdirs();
282             if ( !destinationDirectory.exists() )
283             {
284                 throw new TransferFailedException(
285                     "Specified destination directory cannot be created: " + destinationDirectory );
286             }
287         }
288     }
289 
290     public void setTimeout( int timeoutValue )
291     {
292         connectionTimeout = timeoutValue;
293     }
294 
295     public int getTimeout()
296     {
297         return connectionTimeout;
298     }
299 
300     // ----------------------------------------------------------------------
301     // Stream i/o
302     // ----------------------------------------------------------------------
303 
304     protected void getTransfer( Resource resource, File destination, InputStream input )
305         throws TransferFailedException
306     {
307         getTransfer( resource, destination, input, true, Long.MAX_VALUE );
308     }
309 
310     protected void getTransfer( Resource resource, OutputStream output, InputStream input )
311         throws TransferFailedException
312     {
313         getTransfer( resource, output, input, true, Long.MAX_VALUE );
314     }
315 
316     @Deprecated
317     protected void getTransfer( Resource resource, File destination, InputStream input, boolean closeInput,
318                                 int maxSize )
319         throws TransferFailedException
320     {
321         getTransfer( resource, destination, input, closeInput, (long) maxSize );
322     }
323 
324     protected void getTransfer( Resource resource, File destination, InputStream input, boolean closeInput,
325                                 long maxSize )
326         throws TransferFailedException
327     {
328         // ensure that the destination is created only when we are ready to transfer
329         fireTransferDebug( "attempting to create parent directories for destination: " + destination.getName() );
330         createParentDirectories( destination );
331 
332         fireGetStarted( resource, destination );
333 
334         OutputStream output = null;
335         try
336         {
337             output = new LazyFileOutputStream( destination );
338             getTransfer( resource, output, input, closeInput, maxSize );
339             output.close();
340             output = null;
341         }
342         catch ( final IOException e )
343         {
344             if ( destination.exists() )
345             {
346                 boolean deleted = destination.delete();
347 
348                 if ( !deleted )
349                 {
350                     destination.deleteOnExit();
351                 }
352             }
353 
354             fireTransferError( resource, e, TransferEvent.REQUEST_GET );
355 
356             String msg = "GET request of: " + resource.getName() + " from " + repository.getName() + " failed";
357 
358             throw new TransferFailedException( msg, e );
359         }
360         catch ( TransferFailedException e )
361         {
362             if ( destination.exists() )
363             {
364                 boolean deleted = destination.delete();
365 
366                 if ( !deleted )
367                 {
368                     destination.deleteOnExit();
369                 }
370             }
371             throw e;
372         }
373         finally
374         {
375             IOUtil.close( output );
376         }
377 
378         fireGetCompleted( resource, destination );
379     }
380 
381     @Deprecated
382     protected void getTransfer( Resource resource, OutputStream output, InputStream input, boolean closeInput,
383                                 int maxSize )
384         throws TransferFailedException
385     {
386         getTransfer( resource, output, input, closeInput, (long) maxSize );
387     }
388 
389     protected void getTransfer( Resource resource, OutputStream output, InputStream input, boolean closeInput,
390                                 long maxSize )
391         throws TransferFailedException
392     {
393         try
394         {
395             transfer( resource, input, output, TransferEvent.REQUEST_GET, maxSize );
396 
397             finishGetTransfer( resource, input, output );
398 
399             if ( closeInput )
400             {
401                 input.close();
402                 input = null;
403             }
404 
405         }
406         catch ( IOException e )
407         {
408             fireTransferError( resource, e, TransferEvent.REQUEST_GET );
409 
410             String msg = "GET request of: " + resource.getName() + " from " + repository.getName() + " failed";
411 
412             throw new TransferFailedException( msg, e );
413         }
414         finally
415         {
416             if ( closeInput )
417             {
418                 IOUtil.close( input );
419             }
420 
421             cleanupGetTransfer( resource );
422         }
423     }
424 
425     protected void finishGetTransfer( Resource resource, InputStream input, OutputStream output )
426         throws TransferFailedException
427     {
428     }
429 
430     protected void cleanupGetTransfer( Resource resource )
431     {
432     }
433 
434     protected void putTransfer( Resource resource, File source, OutputStream output, boolean closeOutput )
435         throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
436     {
437         firePutStarted( resource, source );
438 
439         transfer( resource, source, output, closeOutput );
440 
441         firePutCompleted( resource, source );
442     }
443 
444     /**
445      * Write from {@link File} to {@link OutputStream}
446      *
447      * @param resource    resource to transfer
448      * @param source      file to read from
449      * @param output      output stream
450      * @param closeOutput whether the output stream should be closed or not
451      * @throws TransferFailedException
452      * @throws ResourceDoesNotExistException
453      * @throws AuthorizationException
454      * @since 1.0-beta-1
455      */
456     protected void transfer( Resource resource, File source, OutputStream output, boolean closeOutput )
457         throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
458     {
459         InputStream input = null;
460 
461         try
462         {
463             input = new FileInputStream( source );
464 
465             putTransfer( resource, input, output, closeOutput );
466 
467             input.close();
468             input = null;
469         }
470         catch ( FileNotFoundException e )
471         {
472             fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
473 
474             throw new TransferFailedException( "Specified source file does not exist: " + source, e );
475         }
476         catch ( final IOException e )
477         {
478             fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
479 
480             throw new TransferFailedException( "Failure transferring " + source, e );
481         }
482         finally
483         {
484             IOUtil.close( input );
485         }
486     }
487 
488     protected void putTransfer( Resource resource, InputStream input, OutputStream output, boolean closeOutput )
489         throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
490     {
491         try
492         {
493             transfer( resource, input, output, TransferEvent.REQUEST_PUT,
494                       resource.getContentLength() == WagonConstants.UNKNOWN_LENGTH
495                           ? Long.MAX_VALUE
496                           : resource.getContentLength() );
497 
498             finishPutTransfer( resource, input, output );
499 
500             if ( closeOutput )
501             {
502                 output.close();
503                 output = null;
504             }
505         }
506         catch ( IOException e )
507         {
508             fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
509 
510             String msg = "PUT request to: " + resource.getName() + " in " + repository.getName() + " failed";
511 
512             throw new TransferFailedException( msg, e );
513         }
514         finally
515         {
516             if ( closeOutput )
517             {
518                 IOUtil.close( output );
519             }
520 
521             cleanupPutTransfer( resource );
522         }
523     }
524 
525     protected void cleanupPutTransfer( Resource resource )
526     {
527     }
528 
529     protected void finishPutTransfer( Resource resource, InputStream input, OutputStream output )
530         throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
531     {
532     }
533 
534     /**
535      * Write from {@link InputStream} to {@link OutputStream}.
536      * Equivalent to {@link #transfer(Resource, InputStream, OutputStream, int, int)} with a maxSize equals to
537      * {@link Integer#MAX_VALUE}
538      *
539      * @param resource    resource to transfer
540      * @param input       input stream
541      * @param output      output stream
542      * @param requestType one of {@link TransferEvent#REQUEST_GET} or {@link TransferEvent#REQUEST_PUT}
543      * @throws IOException
544      */
545     protected void transfer( Resource resource, InputStream input, OutputStream output, int requestType )
546         throws IOException
547     {
548         transfer( resource, input, output, requestType, Long.MAX_VALUE );
549     }
550 
551     /**
552      * Write from {@link InputStream} to {@link OutputStream}.
553      * Equivalent to {@link #transfer(Resource, InputStream, OutputStream, int, int)} with a maxSize equals to
554      * {@link Integer#MAX_VALUE}
555      *
556      * @param resource    resource to transfer
557      * @param input       input stream
558      * @param output      output stream
559      * @param requestType one of {@link TransferEvent#REQUEST_GET} or {@link TransferEvent#REQUEST_PUT}
560      * @param maxSize     size of the buffer
561      * @throws IOException
562      * @deprecated Please use the transfer using long as type of maxSize
563      */
564     @Deprecated
565     protected void transfer( Resource resource, InputStream input, OutputStream output, int requestType, int maxSize )
566         throws IOException
567     {
568         transfer( resource, input, output, requestType, (long) maxSize );
569     }
570 
571     /**
572      * Write from {@link InputStream} to {@link OutputStream}.
573      * Equivalent to {@link #transfer(Resource, InputStream, OutputStream, int, long)} with a maxSize equals to
574      * {@link Integer#MAX_VALUE}
575      *
576      * @param resource    resource to transfer
577      * @param input       input stream
578      * @param output      output stream
579      * @param requestType one of {@link TransferEvent#REQUEST_GET} or {@link TransferEvent#REQUEST_PUT}
580      * @param maxSize     size of the buffer
581      * @throws IOException
582      */
583     protected void transfer( Resource resource, InputStream input, OutputStream output, int requestType, long maxSize )
584         throws IOException
585     {
586         ByteBuffer buffer = ByteBuffer.allocate( getBufferCapacityForTransfer( resource.getContentLength() ) );
587         int halfBufferCapacity = buffer.capacity() / 2;
588 
589         TransferEvent transferEvent = new TransferEvent( this, resource, TransferEvent.TRANSFER_PROGRESS, requestType );
590         transferEvent.setTimestamp( System.currentTimeMillis() );
591 
592         ReadableByteChannel in = Channels.newChannel( input );
593 
594         long remaining = maxSize;
595         while ( remaining > 0L )
596         {
597             int read = in.read( buffer );
598 
599             if ( read == -1 )
600             {
601                 // EOF, but some data has not been written yet.
602                 if ( buffer.position() != 0 )
603                 {
604                     buffer.flip();
605                     fireTransferProgress( transferEvent, buffer.array(), buffer.limit() );
606                     output.write( buffer.array(), 0, buffer.limit() );
607                 }
608 
609                 break;
610             }
611 
612             // Prevent minichunking / fragmentation: when less than half the buffer is utilized,
613             // read some more bytes before writing and firing progress.
614             if ( buffer.position() < halfBufferCapacity )
615             {
616                 continue;
617             }
618 
619             buffer.flip();
620             fireTransferProgress( transferEvent, buffer.array(), buffer.limit() );
621             output.write( buffer.array(), 0, buffer.limit() );
622             remaining -= buffer.limit();
623             buffer.clear();
624         }
625         output.flush();
626     }
627 
628     /**
629      * Provides a buffer size for efficiently transferring the given amount of bytes such that
630      * it is not fragmented into too many chunks. For larger files larger buffers are provided such that downstream
631      * {@link #fireTransferProgress(TransferEvent, byte[], int) listeners} are not notified too frequently.
632      * For instance, transferring gigabyte-sized resources would result in millions of notifications when using
633      * only a few kibibytes of buffer, drastically slowing down transfer since transfer progress listeners and
634      * notifications are synchronous and may block, e.g., when writing download progress status to console.
635      *
636      * @param numberOfBytes can be 0 or less, in which case a default buffer size is used.
637      * @return a byte buffer suitable for transferring the given amount of bytes without too many chunks.
638      */
639     protected int getBufferCapacityForTransfer( long numberOfBytes )
640     {
641         if ( numberOfBytes <= 0L )
642         {
643             return DEFAULT_BUFFER_SIZE;
644         }
645 
646         final long numberOfBufferSegments =  numberOfBytes
647                 / ( BUFFER_SEGMENT_SIZE * MINIMUM_AMOUNT_OF_TRANSFER_CHUNKS );
648         final long potentialBufferSize = numberOfBufferSegments * BUFFER_SEGMENT_SIZE;
649         if ( potentialBufferSize > Integer.MAX_VALUE )
650         {
651             return MAXIMUM_BUFFER_SIZE;
652         }
653         return min( MAXIMUM_BUFFER_SIZE, max( DEFAULT_BUFFER_SIZE, (int) potentialBufferSize ) );
654     }
655 
656     // ----------------------------------------------------------------------
657     //
658     // ----------------------------------------------------------------------
659 
660     protected void fireTransferProgress( TransferEvent transferEvent, byte[] buffer, int n )
661     {
662         transferEventSupport.fireTransferProgress( transferEvent, buffer, n );
663     }
664 
665     protected void fireGetCompleted( Resource resource, File localFile )
666     {
667         long timestamp = System.currentTimeMillis();
668 
669         TransferEvent transferEvent =
670             new TransferEvent( this, resource, TransferEvent.TRANSFER_COMPLETED, TransferEvent.REQUEST_GET );
671 
672         transferEvent.setTimestamp( timestamp );
673 
674         transferEvent.setLocalFile( localFile );
675 
676         transferEventSupport.fireTransferCompleted( transferEvent );
677     }
678 
679     protected void fireGetStarted( Resource resource, File localFile )
680     {
681         long timestamp = System.currentTimeMillis();
682 
683         TransferEvent transferEvent =
684             new TransferEvent( this, resource, TransferEvent.TRANSFER_STARTED, TransferEvent.REQUEST_GET );
685 
686         transferEvent.setTimestamp( timestamp );
687 
688         transferEvent.setLocalFile( localFile );
689 
690         transferEventSupport.fireTransferStarted( transferEvent );
691     }
692 
693     protected void fireGetInitiated( Resource resource, File localFile )
694     {
695         long timestamp = System.currentTimeMillis();
696 
697         TransferEvent transferEvent =
698             new TransferEvent( this, resource, TransferEvent.TRANSFER_INITIATED, TransferEvent.REQUEST_GET );
699 
700         transferEvent.setTimestamp( timestamp );
701 
702         transferEvent.setLocalFile( localFile );
703 
704         transferEventSupport.fireTransferInitiated( transferEvent );
705     }
706 
707     protected void firePutInitiated( Resource resource, File localFile )
708     {
709         long timestamp = System.currentTimeMillis();
710 
711         TransferEvent transferEvent =
712             new TransferEvent( this, resource, TransferEvent.TRANSFER_INITIATED, TransferEvent.REQUEST_PUT );
713 
714         transferEvent.setTimestamp( timestamp );
715 
716         transferEvent.setLocalFile( localFile );
717 
718         transferEventSupport.fireTransferInitiated( transferEvent );
719     }
720 
721     protected void firePutCompleted( Resource resource, File localFile )
722     {
723         long timestamp = System.currentTimeMillis();
724 
725         TransferEvent transferEvent =
726             new TransferEvent( this, resource, TransferEvent.TRANSFER_COMPLETED, TransferEvent.REQUEST_PUT );
727 
728         transferEvent.setTimestamp( timestamp );
729 
730         transferEvent.setLocalFile( localFile );
731 
732         transferEventSupport.fireTransferCompleted( transferEvent );
733     }
734 
735     protected void firePutStarted( Resource resource, File localFile )
736     {
737         long timestamp = System.currentTimeMillis();
738 
739         TransferEvent transferEvent =
740             new TransferEvent( this, resource, TransferEvent.TRANSFER_STARTED, TransferEvent.REQUEST_PUT );
741 
742         transferEvent.setTimestamp( timestamp );
743 
744         transferEvent.setLocalFile( localFile );
745 
746         transferEventSupport.fireTransferStarted( transferEvent );
747     }
748 
749     protected void fireSessionDisconnected()
750     {
751         long timestamp = System.currentTimeMillis();
752 
753         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_DISCONNECTED );
754 
755         sessionEvent.setTimestamp( timestamp );
756 
757         sessionEventSupport.fireSessionDisconnected( sessionEvent );
758     }
759 
760     protected void fireSessionDisconnecting()
761     {
762         long timestamp = System.currentTimeMillis();
763 
764         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_DISCONNECTING );
765 
766         sessionEvent.setTimestamp( timestamp );
767 
768         sessionEventSupport.fireSessionDisconnecting( sessionEvent );
769     }
770 
771     protected void fireSessionLoggedIn()
772     {
773         long timestamp = System.currentTimeMillis();
774 
775         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_LOGGED_IN );
776 
777         sessionEvent.setTimestamp( timestamp );
778 
779         sessionEventSupport.fireSessionLoggedIn( sessionEvent );
780     }
781 
782     protected void fireSessionLoggedOff()
783     {
784         long timestamp = System.currentTimeMillis();
785 
786         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_LOGGED_OFF );
787 
788         sessionEvent.setTimestamp( timestamp );
789 
790         sessionEventSupport.fireSessionLoggedOff( sessionEvent );
791     }
792 
793     protected void fireSessionOpened()
794     {
795         long timestamp = System.currentTimeMillis();
796 
797         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_OPENED );
798 
799         sessionEvent.setTimestamp( timestamp );
800 
801         sessionEventSupport.fireSessionOpened( sessionEvent );
802     }
803 
804     protected void fireSessionOpening()
805     {
806         long timestamp = System.currentTimeMillis();
807 
808         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_OPENING );
809 
810         sessionEvent.setTimestamp( timestamp );
811 
812         sessionEventSupport.fireSessionOpening( sessionEvent );
813     }
814 
815     protected void fireSessionConnectionRefused()
816     {
817         long timestamp = System.currentTimeMillis();
818 
819         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_CONNECTION_REFUSED );
820 
821         sessionEvent.setTimestamp( timestamp );
822 
823         sessionEventSupport.fireSessionConnectionRefused( sessionEvent );
824     }
825 
826     protected void fireSessionError( Exception exception )
827     {
828         long timestamp = System.currentTimeMillis();
829 
830         SessionEvent sessionEvent = new SessionEvent( this, exception );
831 
832         sessionEvent.setTimestamp( timestamp );
833 
834         sessionEventSupport.fireSessionError( sessionEvent );
835 
836     }
837 
838     protected void fireTransferDebug( String message )
839     {
840         transferEventSupport.fireDebug( message );
841     }
842 
843     protected void fireSessionDebug( String message )
844     {
845         sessionEventSupport.fireDebug( message );
846     }
847 
848     public boolean hasTransferListener( TransferListener listener )
849     {
850         return transferEventSupport.hasTransferListener( listener );
851     }
852 
853     public void addTransferListener( TransferListener listener )
854     {
855         transferEventSupport.addTransferListener( listener );
856     }
857 
858     public void removeTransferListener( TransferListener listener )
859     {
860         transferEventSupport.removeTransferListener( listener );
861     }
862 
863     public void addSessionListener( SessionListener listener )
864     {
865         sessionEventSupport.addSessionListener( listener );
866     }
867 
868     public boolean hasSessionListener( SessionListener listener )
869     {
870         return sessionEventSupport.hasSessionListener( listener );
871     }
872 
873     public void removeSessionListener( SessionListener listener )
874     {
875         sessionEventSupport.removeSessionListener( listener );
876     }
877 
878     protected void fireTransferError( Resource resource, Exception e, int requestType )
879     {
880         TransferEvent transferEvent = new TransferEvent( this, resource, e, requestType );
881         transferEventSupport.fireTransferError( transferEvent );
882     }
883 
884 
885     public SessionEventSupport getSessionEventSupport()
886     {
887         return sessionEventSupport;
888     }
889 
890     public void setSessionEventSupport( SessionEventSupport sessionEventSupport )
891     {
892         this.sessionEventSupport = sessionEventSupport;
893     }
894 
895     public TransferEventSupport getTransferEventSupport()
896     {
897         return transferEventSupport;
898     }
899 
900     public void setTransferEventSupport( TransferEventSupport transferEventSupport )
901     {
902         this.transferEventSupport = transferEventSupport;
903     }
904 
905     /**
906      * This method is used if you are not streaming the transfer, to make sure any listeners dependent on state
907      * (eg checksum observers) succeed.
908      */
909     protected void postProcessListeners( Resource resource, File source, int requestType )
910         throws TransferFailedException
911     {
912         byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
913 
914         TransferEvent transferEvent = new TransferEvent( this, resource, TransferEvent.TRANSFER_PROGRESS, requestType );
915         transferEvent.setTimestamp( System.currentTimeMillis() );
916         transferEvent.setLocalFile( source );
917 
918         InputStream input = null;
919         try
920         {
921             input = new FileInputStream( source );
922 
923             while ( true )
924             {
925                 int n = input.read( buffer );
926 
927                 if ( n == -1 )
928                 {
929                     break;
930                 }
931 
932                 fireTransferProgress( transferEvent, buffer, n );
933             }
934 
935             input.close();
936             input = null;
937         }
938         catch ( IOException e )
939         {
940             fireTransferError( resource, e, requestType );
941 
942             throw new TransferFailedException( "Failed to post-process the source file", e );
943         }
944         finally
945         {
946             IOUtil.close( input );
947         }
948     }
949 
950     public void putDirectory( File sourceDirectory, String destinationDirectory )
951         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
952     {
953         throw new UnsupportedOperationException( "The wagon you are using has not implemented putDirectory()" );
954     }
955 
956     public boolean supportsDirectoryCopy()
957     {
958         return false;
959     }
960 
961     protected static String getPath( String basedir, String dir )
962     {
963         String path;
964         path = basedir;
965         if ( !basedir.endsWith( "/" ) && !dir.startsWith( "/" ) )
966         {
967             path += "/";
968         }
969         path += dir;
970         return path;
971     }
972 
973     public boolean isInteractive()
974     {
975         return interactive;
976     }
977 
978     public void setInteractive( boolean interactive )
979     {
980         this.interactive = interactive;
981     }
982 
983     public List<String> getFileList( String destinationDirectory )
984         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
985     {
986         throw new UnsupportedOperationException( "The wagon you are using has not implemented getFileList()" );
987     }
988 
989     public boolean resourceExists( String resourceName )
990         throws TransferFailedException, AuthorizationException
991     {
992         throw new UnsupportedOperationException( "The wagon you are using has not implemented resourceExists()" );
993     }
994 
995     protected ProxyInfo getProxyInfo( String protocol, String host )
996     {
997         if ( proxyInfoProvider != null )
998         {
999             ProxyInfo proxyInfo = proxyInfoProvider.getProxyInfo( protocol );
1000             if ( !ProxyUtils.validateNonProxyHosts( proxyInfo, host ) )
1001             {
1002                 return proxyInfo;
1003             }
1004         }
1005         return null;
1006     }
1007 
1008     public RepositoryPermissions getPermissionsOverride()
1009     {
1010         return permissionsOverride;
1011     }
1012 
1013     public void setPermissionsOverride( RepositoryPermissions permissionsOverride )
1014     {
1015         this.permissionsOverride = permissionsOverride;
1016     }
1017 
1018     public void setReadTimeout( int readTimeout )
1019     {
1020         this.readTimeout = readTimeout;
1021     }
1022 
1023     public int getReadTimeout()
1024     {
1025         return this.readTimeout;
1026     }
1027 }