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