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