View Javadoc

1   /*
2    * Copyright 2004-2007 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.maven.wagon;
17  
18  import java.io.File;
19  import java.util.List;
20  
21  import org.apache.maven.wagon.ConnectionException;
22  import org.apache.maven.wagon.ResourceDoesNotExistException;
23  import org.apache.maven.wagon.TransferFailedException;
24  import org.apache.maven.wagon.Wagon;
25  import org.apache.maven.wagon.authentication.AuthenticationException;
26  import org.apache.maven.wagon.authentication.AuthenticationInfo;
27  import org.apache.maven.wagon.authorization.AuthorizationException;
28  import org.apache.maven.wagon.events.SessionListener;
29  import org.apache.maven.wagon.events.TransferEvent;
30  import org.apache.maven.wagon.events.TransferListener;
31  import org.apache.maven.wagon.observers.Debug;
32  import org.apache.maven.wagon.proxy.ProxyInfo;
33  import org.apache.maven.wagon.proxy.ProxyInfoProvider;
34  import org.apache.maven.wagon.repository.Repository;
35  import org.apache.maven.wagon.resource.Resource;
36  
37  /**
38   * An abstract implementation of the Wagon interface. This implementation manages listener and other common behaviors.
39   *
40   * @author Ben Hale
41   * @author Jeff Caddel - Updates for version 1.0-beta-6 of the Wagon interface
42   * @since 1.1
43   */
44  public abstract class AbstractWagon implements Wagon {
45  
46      private int timeout;
47  
48      private boolean interactive;
49  
50      private Repository repository;
51  
52      private final boolean supportsDirectoryCopy;
53  
54      private final SessionListenerSupport sessionListeners = new SessionListenerSupport(this);
55  
56      private final TransferListenerSupport transferListeners = new TransferListenerSupport(this);
57  
58      protected AbstractWagon(final boolean supportsDirectoryCopy) {
59          this.supportsDirectoryCopy = supportsDirectoryCopy;
60      }
61  
62      public final void addSessionListener(final SessionListener listener) {
63          if (listener.getClass().equals(Debug.class)) {
64              // This is a junky listener that spews things to System.out in an ugly way
65              return;
66          }
67          sessionListeners.addListener(listener);
68      }
69  
70      protected final SessionListenerSupport getSessionListeners() {
71          return sessionListeners;
72      }
73  
74      public final boolean hasSessionListener(final SessionListener listener) {
75          return sessionListeners.hasListener(listener);
76      }
77  
78      public final void removeSessionListener(final SessionListener listener) {
79          sessionListeners.removeListener(listener);
80      }
81  
82      public final void addTransferListener(final TransferListener listener) {
83          transferListeners.addListener(listener);
84      }
85  
86      protected final TransferListenerSupport getTransferListeners() {
87          return transferListeners;
88      }
89  
90      public final boolean hasTransferListener(final TransferListener listener) {
91          return transferListeners.hasListener(listener);
92      }
93  
94      public final void removeTransferListener(final TransferListener listener) {
95          transferListeners.removeListener(listener);
96      }
97  
98      public final Repository getRepository() {
99          return repository;
100     }
101 
102     public final boolean isInteractive() {
103         return interactive;
104     }
105 
106     public final void setInteractive(final boolean interactive) {
107         this.interactive = interactive;
108     }
109 
110     public final void connect(final Repository source) throws ConnectionException, AuthenticationException {
111         doConnect(source, null, null);
112     }
113 
114     public final void connect(final Repository source, final ProxyInfo proxyInfo) throws ConnectionException,
115             AuthenticationException {
116         connect(source, null, proxyInfo);
117     }
118 
119     public final void connect(final Repository source, final AuthenticationInfo authenticationInfo)
120             throws ConnectionException, AuthenticationException {
121         doConnect(source, authenticationInfo, null);
122     }
123 
124     protected void doConnect(final Repository source, final AuthenticationInfo authenticationInfo,
125             final ProxyInfo proxyInfo) throws ConnectionException, AuthenticationException {
126         repository = source;
127         sessionListeners.fireSessionOpening();
128         try {
129             connectToRepository(source, authenticationInfo, proxyInfo);
130         } catch (ConnectionException e) {
131             sessionListeners.fireSessionConnectionRefused();
132             throw e;
133         } catch (AuthenticationException e) {
134             sessionListeners.fireSessionConnectionRefused();
135             throw e;
136         } catch (Exception e) {
137             sessionListeners.fireSessionConnectionRefused();
138             throw new ConnectionException("Could not connect to repository", e);
139         }
140         sessionListeners.fireSessionLoggedIn();
141         sessionListeners.fireSessionOpened();
142     }
143 
144     public final void connect(final Repository source, final AuthenticationInfo authenticationInfo,
145             final ProxyInfo proxyInfo) throws ConnectionException, AuthenticationException {
146         doConnect(source, authenticationInfo, proxyInfo);
147     }
148 
149     public final void disconnect() throws ConnectionException {
150         sessionListeners.fireSessionDisconnecting();
151         try {
152             disconnectFromRepository();
153         } catch (ConnectionException e) {
154             sessionListeners.fireSessionConnectionRefused();
155             throw e;
156         } catch (Exception e) {
157             sessionListeners.fireSessionConnectionRefused();
158             throw new ConnectionException("Could not disconnect from repository", e);
159         }
160         sessionListeners.fireSessionLoggedOff();
161         sessionListeners.fireSessionDisconnected();
162     }
163 
164     public final void get(final String resourceName, final File destination) throws TransferFailedException,
165             ResourceDoesNotExistException, AuthorizationException {
166         Resource resource = new Resource(resourceName);
167         transferListeners.fireTransferInitiated(resource, TransferEvent.REQUEST_GET);
168         transferListeners.fireTransferStarted(resource, TransferEvent.REQUEST_GET);
169 
170         try {
171             getResource(resourceName, destination, new TransferProgress(resource, TransferEvent.REQUEST_GET,
172                     transferListeners));
173             transferListeners.fireTransferCompleted(resource, TransferEvent.REQUEST_GET);
174         } catch (TransferFailedException e) {
175             throw e;
176         } catch (ResourceDoesNotExistException e) {
177             throw e;
178         } catch (AuthorizationException e) {
179             throw e;
180         } catch (Exception e) {
181             transferListeners.fireTransferError(resource, TransferEvent.REQUEST_GET, e);
182             throw new TransferFailedException("Transfer of resource " + destination + "failed", e);
183         }
184     }
185 
186     @SuppressWarnings("rawtypes")
187     public final List getFileList(final String destinationDirectory) throws TransferFailedException,
188             ResourceDoesNotExistException, AuthorizationException {
189         try {
190             return listDirectory(destinationDirectory);
191         } catch (TransferFailedException e) {
192             throw e;
193         } catch (ResourceDoesNotExistException e) {
194             throw e;
195         } catch (AuthorizationException e) {
196             throw e;
197         } catch (Exception e) {
198             sessionListeners.fireSessionError(e);
199             throw new TransferFailedException("Listing of directory " + destinationDirectory + "failed", e);
200         }
201     }
202 
203     public final boolean getIfNewer(final String resourceName, final File destination, final long timestamp)
204             throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
205         Resource resource = new Resource(resourceName);
206         try {
207             if (isRemoteResourceNewer(resourceName, timestamp)) {
208                 get(resourceName, destination);
209                 return true;
210             } else {
211                 return false;
212             }
213         } catch (TransferFailedException e) {
214             throw e;
215         } catch (ResourceDoesNotExistException e) {
216             throw e;
217         } catch (AuthorizationException e) {
218             throw e;
219         } catch (Exception e) {
220             transferListeners.fireTransferError(resource, TransferEvent.REQUEST_GET, e);
221             throw new TransferFailedException("Transfer of resource " + destination + "failed", e);
222         }
223     }
224 
225     public final void openConnection() throws ConnectionException, AuthenticationException {
226         // Nothing to do here (never called by the wagon manager)
227     }
228 
229     public final void put(final File source, final String destination) throws TransferFailedException,
230             ResourceDoesNotExistException, AuthorizationException {
231         Resource resource = new Resource(destination);
232         transferListeners.fireTransferInitiated(resource, TransferEvent.REQUEST_PUT);
233         transferListeners.fireTransferStarted(resource, TransferEvent.REQUEST_PUT);
234 
235         try {
236             putResource(source, destination, new TransferProgress(resource, TransferEvent.REQUEST_PUT,
237                     transferListeners));
238             transferListeners.fireTransferCompleted(resource, TransferEvent.REQUEST_PUT);
239         } catch (TransferFailedException e) {
240             throw e;
241         } catch (ResourceDoesNotExistException e) {
242             throw e;
243         } catch (AuthorizationException e) {
244             throw e;
245         } catch (Exception e) {
246             transferListeners.fireTransferError(resource, TransferEvent.REQUEST_PUT, e);
247             throw new TransferFailedException("Transfer of resource " + destination + "failed", e);
248         }
249     }
250 
251     /**
252      * On S3 there are no true "directories". An S3 bucket is essentially a Hashtable of files stored by key. The
253      * integration between a traditional file system and an S3 bucket is to use the path of the file on the local file
254      * system as the key to the file in the bucket. The S3 bucket does not contain a separate key for the directory
255      * itself.
256      */
257     public final void putDirectory(final File sourceDirectory, final String destinationDirectory)
258             throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
259         // Cycle through all the files in this directory
260         for (File f : sourceDirectory.listFiles()) {
261             // We hit a directory
262             if (f.isDirectory()) {
263                 // Recurse into the sub-directory and store any files we find
264                 putDirectory(f, destinationDirectory + "/" + f.getName());
265             } else {
266                 // Normal file, store it into S3
267                 put(f, destinationDirectory + "/" + f.getName());
268             }
269         }
270     }
271 
272     public final boolean resourceExists(final String resourceName) throws TransferFailedException,
273             AuthorizationException {
274         try {
275             return doesRemoteResourceExist(resourceName);
276         } catch (TransferFailedException e) {
277             throw e;
278         } catch (AuthorizationException e) {
279             throw e;
280         } catch (Exception e) {
281             sessionListeners.fireSessionError(e);
282             throw new TransferFailedException("Listing of resource " + resourceName + "failed", e);
283         }
284     }
285 
286     public final boolean supportsDirectoryCopy() {
287         return supportsDirectoryCopy;
288     }
289 
290     /**
291      * Subclass must implement with specific connection behavior
292      *
293      * @param source
294      * The repository connection information
295      * @param authenticationInfo
296      * Authentication information, if any
297      * @param proxyInfo
298      * Proxy information, if any
299      * @throws Exception
300      * Implementations can throw any exception and it will be handled by the base class
301      */
302     protected abstract void connectToRepository(Repository source, AuthenticationInfo authenticationInfo,
303             ProxyInfo proxyInfo) throws Exception;
304 
305     /**
306      * Subclass must implement with specific detection behavior
307      *
308      * @param resourceName
309      * The remote resource to detect
310      * @return true if the remote resource exists
311      * @throws Exception
312      * Implementations can throw any exception and it will be handled by the base class
313      */
314     protected abstract boolean doesRemoteResourceExist(String resourceName) throws Exception;
315 
316     /**
317      * Subclasses must implement with specific disconnection behavior
318      *
319      * @throws Exception
320      * Implementations can throw any exception and it will be handled by the base class
321      */
322     protected abstract void disconnectFromRepository() throws Exception;
323 
324     /**
325      * Subclass must implement with specific get behavior
326      *
327      * @param resourceName
328      * The name of the remote resource to read
329      * @param destination
330      * The local file to write to
331      * @param progress
332      * A progress notifier for the upload. It must be used or hashes will not be calculated correctly
333      * @throws Exception
334      * Implementations can throw any exception and it will be handled by the base class
335      */
336     protected abstract void getResource(String resourceName, File destination, TransferProgress progress)
337             throws Exception;
338 
339     /**
340      * Subclass must implement with newer detection behavior
341      *
342      * @param resourceName
343      * The name of the resource being compared
344      * @param timestamp
345      * The timestamp to compare against
346      * @return true if the current version of the resource is newer than the timestamp
347      * @throws Exception
348      * Implementations can throw any exception and it will be handled by the base class
349      */
350     protected abstract boolean isRemoteResourceNewer(String resourceName, long timestamp) throws Exception;
351 
352     /**
353      * Subclass must implement with specific directory listing behavior
354      *
355      * @param directory
356      * The directory to list files in
357      * @return A collection of file names
358      * @throws Exception
359      * Implementations can throw any exception and it will be handled by the base class
360      */
361     protected abstract List<String> listDirectory(String directory) throws Exception;
362 
363     /**
364      * Subclasses must implement with specific put behavior
365      *
366      * @param source
367      * The local source file to read from
368      * @param destination
369      * The name of the remote resource to write to
370      * @param progress
371      * A progress notifier for the upload. It must be used or hashes will not be calculated correctly
372      * @throws Exception
373      * Implementations can throw any exception and it will be handled by the base class
374      */
375     protected abstract void putResource(File source, String destination, TransferProgress progress) throws Exception;
376 
377     public void connect(final Repository source, final AuthenticationInfo authenticationInfo,
378             final ProxyInfoProvider proxyInfoProvider) throws ConnectionException, AuthenticationException {
379         doConnect(source, authenticationInfo, null);
380     }
381 
382     public void connect(final Repository source, final ProxyInfoProvider proxyInfoProvider) throws ConnectionException,
383             AuthenticationException {
384         doConnect(source, null, null);
385     }
386 
387     public int getTimeout() {
388         return this.timeout;
389     }
390 
391     public void setTimeout(final int timeoutValue) {
392         this.timeout = timeoutValue;
393     }
394 
395 }