View Javadoc
1   /*******************************************************************************
2    * Copyright (c) 2010, 2013 Sonatype, Inc.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *    Sonatype, Inc. - initial API and implementation
10   *******************************************************************************/
11  package org.eclipse.aether.transfer;
12  
13  import java.nio.ByteBuffer;
14  
15  import org.eclipse.aether.RepositorySystemSession;
16  
17  /**
18   * An event fired to a transfer listener during an artifact/metadata transfer.
19   * 
20   * @see TransferListener
21   * @see TransferEvent.Builder
22   */
23  public final class TransferEvent
24  {
25  
26      /**
27       * The type of the event.
28       */
29      public enum EventType
30      {
31  
32          /**
33           * @see TransferListener#transferInitiated(TransferEvent)
34           */
35          INITIATED,
36  
37          /**
38           * @see TransferListener#transferStarted(TransferEvent)
39           */
40          STARTED,
41  
42          /**
43           * @see TransferListener#transferProgressed(TransferEvent)
44           */
45          PROGRESSED,
46  
47          /**
48           * @see TransferListener#transferCorrupted(TransferEvent)
49           */
50          CORRUPTED,
51  
52          /**
53           * @see TransferListener#transferSucceeded(TransferEvent)
54           */
55          SUCCEEDED,
56  
57          /**
58           * @see TransferListener#transferFailed(TransferEvent)
59           */
60          FAILED
61  
62      }
63  
64      /**
65       * The type of the request/transfer being performed.
66       */
67      public enum RequestType
68      {
69  
70          /**
71           * Download artifact/metadata.
72           */
73          GET,
74  
75          /**
76           * Check artifact/metadata existence only.
77           */
78          GET_EXISTENCE,
79  
80          /**
81           * Upload artifact/metadata.
82           */
83          PUT,
84  
85      }
86  
87      private final EventType type;
88  
89      private final RequestType requestType;
90  
91      private final RepositorySystemSession session;
92  
93      private final TransferResource resource;
94  
95      private final ByteBuffer dataBuffer;
96  
97      private final long transferredBytes;
98  
99      private final Exception exception;
100 
101     TransferEvent( Builder builder )
102     {
103         type = builder.type;
104         requestType = builder.requestType;
105         session = builder.session;
106         resource = builder.resource;
107         dataBuffer = builder.dataBuffer;
108         transferredBytes = builder.transferredBytes;
109         exception = builder.exception;
110     }
111 
112     /**
113      * Gets the type of the event.
114      * 
115      * @return The type of the event, never {@code null}.
116      */
117     public EventType getType()
118     {
119         return type;
120     }
121 
122     /**
123      * Gets the type of the request/transfer.
124      * 
125      * @return The type of the request/transfer, never {@code null}.
126      */
127     public RequestType getRequestType()
128     {
129         return requestType;
130     }
131 
132     /**
133      * Gets the repository system session during which the event occurred.
134      * 
135      * @return The repository system session during which the event occurred, never {@code null}.
136      */
137     public RepositorySystemSession getSession()
138     {
139         return session;
140     }
141 
142     /**
143      * Gets the resource that is being transferred.
144      * 
145      * @return The resource being transferred, never {@code null}.
146      */
147     public TransferResource getResource()
148     {
149         return resource;
150     }
151 
152     /**
153      * Gets the total number of bytes that have been transferred since the download/upload of the resource was started.
154      * If a download has been resumed, the returned count includes the bytes that were already downloaded during the
155      * previous attempt. In other words, the ratio of transferred bytes to the content length of the resource indicates
156      * the percentage of transfer completion.
157      * 
158      * @return The total number of bytes that have been transferred since the transfer started, never negative.
159      * @see #getDataLength()
160      * @see TransferResource#getResumeOffset()
161      */
162     public long getTransferredBytes()
163     {
164         return transferredBytes;
165     }
166 
167     /**
168      * Gets the byte buffer holding the transferred bytes since the last event. A listener must assume this buffer to be
169      * owned by the event source and must not change any byte in this buffer. Also, the buffer is only valid for the
170      * duration of the event callback, i.e. the next event might reuse the same buffer (with updated contents).
171      * Therefore, if the actual event processing is deferred, the byte buffer would have to be cloned to create an
172      * immutable snapshot of its contents.
173      * 
174      * @return The (read-only) byte buffer or {@code null} if not applicable to the event, i.e. if the event type is not
175      *         {@link EventType#PROGRESSED}.
176      */
177     public ByteBuffer getDataBuffer()
178     {
179         return ( dataBuffer != null ) ? dataBuffer.asReadOnlyBuffer() : null;
180     }
181 
182     /**
183      * Gets the number of bytes that have been transferred since the last event.
184      * 
185      * @return The number of bytes that have been transferred since the last event, possibly zero but never negative.
186      * @see #getTransferredBytes()
187      */
188     public int getDataLength()
189     {
190         return ( dataBuffer != null ) ? dataBuffer.remaining() : 0;
191     }
192 
193     /**
194      * Gets the error that occurred during the transfer.
195      * 
196      * @return The error that occurred or {@code null} if none.
197      */
198     public Exception getException()
199     {
200         return exception;
201     }
202 
203     @Override
204     public String toString()
205     {
206         return getRequestType() + " " + getType() + " " + getResource();
207     }
208 
209     /**
210      * A builder to create transfer events.
211      */
212     public static final class Builder
213     {
214 
215         EventType type;
216 
217         RequestType requestType;
218 
219         RepositorySystemSession session;
220 
221         TransferResource resource;
222 
223         ByteBuffer dataBuffer;
224 
225         long transferredBytes;
226 
227         Exception exception;
228 
229         /**
230          * Creates a new transfer event builder for the specified session and the given resource.
231          * 
232          * @param session The repository system session, must not be {@code null}.
233          * @param resource The resource being transferred, must not be {@code null}.
234          */
235         public Builder( RepositorySystemSession session, TransferResource resource )
236         {
237             if ( session == null )
238             {
239                 throw new IllegalArgumentException( "session not specified" );
240             }
241             if ( resource == null )
242             {
243                 throw new IllegalArgumentException( "transfer resource not specified" );
244             }
245             this.session = session;
246             this.resource = resource;
247             type = EventType.INITIATED;
248             requestType = RequestType.GET;
249         }
250 
251         private Builder( Builder prototype )
252         {
253             session = prototype.session;
254             resource = prototype.resource;
255             type = prototype.type;
256             requestType = prototype.requestType;
257             dataBuffer = prototype.dataBuffer;
258             transferredBytes = prototype.transferredBytes;
259             exception = prototype.exception;
260         }
261 
262         /**
263          * Creates a new transfer event builder from the current values of this builder. The state of this builder
264          * remains unchanged.
265          * 
266          * @return The new event builder, never {@code null}.
267          */
268         public Builder copy()
269         {
270             return new Builder( this );
271         }
272 
273         /**
274          * Sets the type of the event and resets event-specific fields. In more detail, the data buffer and the
275          * exception fields are set to {@code null}. Furthermore, the total number of transferred bytes is set to
276          * {@code 0} if the event type is {@link EventType#STARTED}.
277          * 
278          * @param type The type of the event, must not be {@code null}.
279          * @return This event builder for chaining, never {@code null}.
280          */
281         public Builder resetType( EventType type )
282         {
283             if ( type == null )
284             {
285                 throw new IllegalArgumentException( "event type not specified" );
286             }
287             this.type = type;
288             dataBuffer = null;
289             exception = null;
290             switch ( type )
291             {
292                 case INITIATED:
293                 case STARTED:
294                     transferredBytes = 0;
295                 default:
296             }
297             return this;
298         }
299 
300         /**
301          * Sets the type of the event. When re-using the same builder to generate a sequence of events for one transfer,
302          * {@link #resetType(TransferEvent.EventType)} might be more handy.
303          * 
304          * @param type The type of the event, must not be {@code null}.
305          * @return This event builder for chaining, never {@code null}.
306          */
307         public Builder setType( EventType type )
308         {
309             if ( type == null )
310             {
311                 throw new IllegalArgumentException( "event type not specified" );
312             }
313             this.type = type;
314             return this;
315         }
316 
317         /**
318          * Sets the type of the request/transfer.
319          * 
320          * @param requestType The request/transfer type, must not be {@code null}.
321          * @return This event builder for chaining, never {@code null}.
322          */
323         public Builder setRequestType( RequestType requestType )
324         {
325             if ( requestType == null )
326             {
327                 throw new IllegalArgumentException( "request type not specified" );
328             }
329             this.requestType = requestType;
330             return this;
331         }
332 
333         /**
334          * Sets the total number of bytes that have been transferred so far during the download/upload of the resource.
335          * If a download is being resumed, the count must include the bytes that were already downloaded in the previous
336          * attempt and from which the current transfer started. In this case, the event type {@link EventType#STARTED}
337          * should indicate from what byte the download resumes.
338          * 
339          * @param transferredBytes The total number of bytes that have been transferred so far during the
340          *            download/upload of the resource, must not be negative.
341          * @return This event builder for chaining, never {@code null}.
342          * @see TransferResource#setResumeOffset(long)
343          */
344         public Builder setTransferredBytes( long transferredBytes )
345         {
346             if ( transferredBytes < 0 )
347             {
348                 throw new IllegalArgumentException( "number of transferred bytes cannot be negative" );
349             }
350             this.transferredBytes = transferredBytes;
351             return this;
352         }
353 
354         /**
355          * Increments the total number of bytes that have been transferred so far during the download/upload.
356          * 
357          * @param transferredBytes The number of bytes that have been transferred since the last event, must not be
358          *            negative.
359          * @return This event builder for chaining, never {@code null}.
360          */
361         public Builder addTransferredBytes( long transferredBytes )
362         {
363             if ( transferredBytes < 0 )
364             {
365                 throw new IllegalArgumentException( "number of transferred bytes cannot be negative" );
366             }
367             this.transferredBytes += transferredBytes;
368             return this;
369         }
370 
371         /**
372          * Sets the byte buffer holding the transferred bytes since the last event.
373          * 
374          * @param buffer The byte buffer holding the transferred bytes since the last event, may be {@code null} if not
375          *            applicable to the event.
376          * @param offset The starting point of valid bytes in the array.
377          * @param length The number of valid bytes, must not be negative.
378          * @return This event builder for chaining, never {@code null}.
379          */
380         public Builder setDataBuffer( byte[] buffer, int offset, int length )
381         {
382             return setDataBuffer( ( buffer != null ) ? ByteBuffer.wrap( buffer, offset, length ) : null );
383         }
384 
385         /**
386          * Sets the byte buffer holding the transferred bytes since the last event.
387          * 
388          * @param dataBuffer The byte buffer holding the transferred bytes since the last event, may be {@code null} if
389          *            not applicable to the event.
390          * @return This event builder for chaining, never {@code null}.
391          */
392         public Builder setDataBuffer( ByteBuffer dataBuffer )
393         {
394             this.dataBuffer = dataBuffer;
395             return this;
396         }
397 
398         /**
399          * Sets the error that occurred during the transfer.
400          * 
401          * @param exception The error that occurred during the transfer, may be {@code null} if none.
402          * @return This event builder for chaining, never {@code null}.
403          */
404         public Builder setException( Exception exception )
405         {
406             this.exception = exception;
407             return this;
408         }
409 
410         /**
411          * Builds a new transfer event from the current values of this builder. The state of the builder itself remains
412          * unchanged.
413          * 
414          * @return The transfer event, never {@code null}.
415          */
416         public TransferEvent build()
417         {
418             return new TransferEvent( this );
419         }
420 
421     }
422 
423 }