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 int numberOfBufferSegments = (int)
647             numberOfBytes / ( BUFFER_SEGMENT_SIZE * MINIMUM_AMOUNT_OF_TRANSFER_CHUNKS );
648         final int potentialBufferSize = numberOfBufferSegments * BUFFER_SEGMENT_SIZE;
649         return min( MAXIMUM_BUFFER_SIZE, max( DEFAULT_BUFFER_SIZE, potentialBufferSize ) );
650     }
651 
652     // ----------------------------------------------------------------------
653     //
654     // ----------------------------------------------------------------------
655 
656     protected void fireTransferProgress( TransferEvent transferEvent, byte[] buffer, int n )
657     {
658         transferEventSupport.fireTransferProgress( transferEvent, buffer, n );
659     }
660 
661     protected void fireGetCompleted( Resource resource, File localFile )
662     {
663         long timestamp = System.currentTimeMillis();
664 
665         TransferEvent transferEvent =
666             new TransferEvent( this, resource, TransferEvent.TRANSFER_COMPLETED, TransferEvent.REQUEST_GET );
667 
668         transferEvent.setTimestamp( timestamp );
669 
670         transferEvent.setLocalFile( localFile );
671 
672         transferEventSupport.fireTransferCompleted( transferEvent );
673     }
674 
675     protected void fireGetStarted( Resource resource, File localFile )
676     {
677         long timestamp = System.currentTimeMillis();
678 
679         TransferEvent transferEvent =
680             new TransferEvent( this, resource, TransferEvent.TRANSFER_STARTED, TransferEvent.REQUEST_GET );
681 
682         transferEvent.setTimestamp( timestamp );
683 
684         transferEvent.setLocalFile( localFile );
685 
686         transferEventSupport.fireTransferStarted( transferEvent );
687     }
688 
689     protected void fireGetInitiated( Resource resource, File localFile )
690     {
691         long timestamp = System.currentTimeMillis();
692 
693         TransferEvent transferEvent =
694             new TransferEvent( this, resource, TransferEvent.TRANSFER_INITIATED, TransferEvent.REQUEST_GET );
695 
696         transferEvent.setTimestamp( timestamp );
697 
698         transferEvent.setLocalFile( localFile );
699 
700         transferEventSupport.fireTransferInitiated( transferEvent );
701     }
702 
703     protected void firePutInitiated( Resource resource, File localFile )
704     {
705         long timestamp = System.currentTimeMillis();
706 
707         TransferEvent transferEvent =
708             new TransferEvent( this, resource, TransferEvent.TRANSFER_INITIATED, TransferEvent.REQUEST_PUT );
709 
710         transferEvent.setTimestamp( timestamp );
711 
712         transferEvent.setLocalFile( localFile );
713 
714         transferEventSupport.fireTransferInitiated( transferEvent );
715     }
716 
717     protected void firePutCompleted( Resource resource, File localFile )
718     {
719         long timestamp = System.currentTimeMillis();
720 
721         TransferEvent transferEvent =
722             new TransferEvent( this, resource, TransferEvent.TRANSFER_COMPLETED, TransferEvent.REQUEST_PUT );
723 
724         transferEvent.setTimestamp( timestamp );
725 
726         transferEvent.setLocalFile( localFile );
727 
728         transferEventSupport.fireTransferCompleted( transferEvent );
729     }
730 
731     protected void firePutStarted( Resource resource, File localFile )
732     {
733         long timestamp = System.currentTimeMillis();
734 
735         TransferEvent transferEvent =
736             new TransferEvent( this, resource, TransferEvent.TRANSFER_STARTED, TransferEvent.REQUEST_PUT );
737 
738         transferEvent.setTimestamp( timestamp );
739 
740         transferEvent.setLocalFile( localFile );
741 
742         transferEventSupport.fireTransferStarted( transferEvent );
743     }
744 
745     protected void fireSessionDisconnected()
746     {
747         long timestamp = System.currentTimeMillis();
748 
749         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_DISCONNECTED );
750 
751         sessionEvent.setTimestamp( timestamp );
752 
753         sessionEventSupport.fireSessionDisconnected( sessionEvent );
754     }
755 
756     protected void fireSessionDisconnecting()
757     {
758         long timestamp = System.currentTimeMillis();
759 
760         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_DISCONNECTING );
761 
762         sessionEvent.setTimestamp( timestamp );
763 
764         sessionEventSupport.fireSessionDisconnecting( sessionEvent );
765     }
766 
767     protected void fireSessionLoggedIn()
768     {
769         long timestamp = System.currentTimeMillis();
770 
771         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_LOGGED_IN );
772 
773         sessionEvent.setTimestamp( timestamp );
774 
775         sessionEventSupport.fireSessionLoggedIn( sessionEvent );
776     }
777 
778     protected void fireSessionLoggedOff()
779     {
780         long timestamp = System.currentTimeMillis();
781 
782         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_LOGGED_OFF );
783 
784         sessionEvent.setTimestamp( timestamp );
785 
786         sessionEventSupport.fireSessionLoggedOff( sessionEvent );
787     }
788 
789     protected void fireSessionOpened()
790     {
791         long timestamp = System.currentTimeMillis();
792 
793         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_OPENED );
794 
795         sessionEvent.setTimestamp( timestamp );
796 
797         sessionEventSupport.fireSessionOpened( sessionEvent );
798     }
799 
800     protected void fireSessionOpening()
801     {
802         long timestamp = System.currentTimeMillis();
803 
804         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_OPENING );
805 
806         sessionEvent.setTimestamp( timestamp );
807 
808         sessionEventSupport.fireSessionOpening( sessionEvent );
809     }
810 
811     protected void fireSessionConnectionRefused()
812     {
813         long timestamp = System.currentTimeMillis();
814 
815         SessionEvent sessionEvent = new SessionEvent( this, SessionEvent.SESSION_CONNECTION_REFUSED );
816 
817         sessionEvent.setTimestamp( timestamp );
818 
819         sessionEventSupport.fireSessionConnectionRefused( sessionEvent );
820     }
821 
822     protected void fireSessionError( Exception exception )
823     {
824         long timestamp = System.currentTimeMillis();
825 
826         SessionEvent sessionEvent = new SessionEvent( this, exception );
827 
828         sessionEvent.setTimestamp( timestamp );
829 
830         sessionEventSupport.fireSessionError( sessionEvent );
831 
832     }
833 
834     protected void fireTransferDebug( String message )
835     {
836         transferEventSupport.fireDebug( message );
837     }
838 
839     protected void fireSessionDebug( String message )
840     {
841         sessionEventSupport.fireDebug( message );
842     }
843 
844     public boolean hasTransferListener( TransferListener listener )
845     {
846         return transferEventSupport.hasTransferListener( listener );
847     }
848 
849     public void addTransferListener( TransferListener listener )
850     {
851         transferEventSupport.addTransferListener( listener );
852     }
853 
854     public void removeTransferListener( TransferListener listener )
855     {
856         transferEventSupport.removeTransferListener( listener );
857     }
858 
859     public void addSessionListener( SessionListener listener )
860     {
861         sessionEventSupport.addSessionListener( listener );
862     }
863 
864     public boolean hasSessionListener( SessionListener listener )
865     {
866         return sessionEventSupport.hasSessionListener( listener );
867     }
868 
869     public void removeSessionListener( SessionListener listener )
870     {
871         sessionEventSupport.removeSessionListener( listener );
872     }
873 
874     protected void fireTransferError( Resource resource, Exception e, int requestType )
875     {
876         TransferEvent transferEvent = new TransferEvent( this, resource, e, requestType );
877         transferEventSupport.fireTransferError( transferEvent );
878     }
879 
880 
881     public SessionEventSupport getSessionEventSupport()
882     {
883         return sessionEventSupport;
884     }
885 
886     public void setSessionEventSupport( SessionEventSupport sessionEventSupport )
887     {
888         this.sessionEventSupport = sessionEventSupport;
889     }
890 
891     public TransferEventSupport getTransferEventSupport()
892     {
893         return transferEventSupport;
894     }
895 
896     public void setTransferEventSupport( TransferEventSupport transferEventSupport )
897     {
898         this.transferEventSupport = transferEventSupport;
899     }
900 
901     /**
902      * This method is used if you are not streaming the transfer, to make sure any listeners dependent on state
903      * (eg checksum observers) succeed.
904      */
905     protected void postProcessListeners( Resource resource, File source, int requestType )
906         throws TransferFailedException
907     {
908         byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
909 
910         TransferEvent transferEvent = new TransferEvent( this, resource, TransferEvent.TRANSFER_PROGRESS, requestType );
911         transferEvent.setTimestamp( System.currentTimeMillis() );
912         transferEvent.setLocalFile( source );
913 
914         InputStream input = null;
915         try
916         {
917             input = new FileInputStream( source );
918 
919             while ( true )
920             {
921                 int n = input.read( buffer );
922 
923                 if ( n == -1 )
924                 {
925                     break;
926                 }
927 
928                 fireTransferProgress( transferEvent, buffer, n );
929             }
930 
931             input.close();
932             input = null;
933         }
934         catch ( IOException e )
935         {
936             fireTransferError( resource, e, requestType );
937 
938             throw new TransferFailedException( "Failed to post-process the source file", e );
939         }
940         finally
941         {
942             IOUtil.close( input );
943         }
944     }
945 
946     public void putDirectory( File sourceDirectory, String destinationDirectory )
947         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
948     {
949         throw new UnsupportedOperationException( "The wagon you are using has not implemented putDirectory()" );
950     }
951 
952     public boolean supportsDirectoryCopy()
953     {
954         return false;
955     }
956 
957     protected static String getPath( String basedir, String dir )
958     {
959         String path;
960         path = basedir;
961         if ( !basedir.endsWith( "/" ) && !dir.startsWith( "/" ) )
962         {
963             path += "/";
964         }
965         path += dir;
966         return path;
967     }
968 
969     public boolean isInteractive()
970     {
971         return interactive;
972     }
973 
974     public void setInteractive( boolean interactive )
975     {
976         this.interactive = interactive;
977     }
978 
979     public List<String> getFileList( String destinationDirectory )
980         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
981     {
982         throw new UnsupportedOperationException( "The wagon you are using has not implemented getFileList()" );
983     }
984 
985     public boolean resourceExists( String resourceName )
986         throws TransferFailedException, AuthorizationException
987     {
988         throw new UnsupportedOperationException( "The wagon you are using has not implemented resourceExists()" );
989     }
990 
991     protected ProxyInfo getProxyInfo( String protocol, String host )
992     {
993         if ( proxyInfoProvider != null )
994         {
995             ProxyInfo proxyInfo = proxyInfoProvider.getProxyInfo( protocol );
996             if ( !ProxyUtils.validateNonProxyHosts( proxyInfo, host ) )
997             {
998                 return proxyInfo;
999             }
1000         }
1001         return null;
1002     }
1003 
1004     public RepositoryPermissions getPermissionsOverride()
1005     {
1006         return permissionsOverride;
1007     }
1008 
1009     public void setPermissionsOverride( RepositoryPermissions permissionsOverride )
1010     {
1011         this.permissionsOverride = permissionsOverride;
1012     }
1013 
1014     public void setReadTimeout( int readTimeout )
1015     {
1016         this.readTimeout = readTimeout;
1017     }
1018 
1019     public int getReadTimeout()
1020     {
1021         return this.readTimeout;
1022     }
1023 }