View Javadoc

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