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