View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.transfer;
20  
21  import java.nio.ByteBuffer;
22  
23  import org.eclipse.aether.RepositorySystemSession;
24  
25  import static java.util.Objects.requireNonNull;
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       * The type of the event.
37       */
38      public enum EventType {
39  
40          /**
41           * @see TransferListener#transferInitiated(TransferEvent)
42           */
43          INITIATED,
44  
45          /**
46           * @see TransferListener#transferStarted(TransferEvent)
47           */
48          STARTED,
49  
50          /**
51           * @see TransferListener#transferProgressed(TransferEvent)
52           */
53          PROGRESSED,
54  
55          /**
56           * @see TransferListener#transferCorrupted(TransferEvent)
57           */
58          CORRUPTED,
59  
60          /**
61           * @see TransferListener#transferSucceeded(TransferEvent)
62           */
63          SUCCEEDED,
64  
65          /**
66           * @see TransferListener#transferFailed(TransferEvent)
67           */
68          FAILED
69      }
70  
71      /**
72       * The type of the request/transfer being performed.
73       */
74      public enum RequestType {
75  
76          /**
77           * Download artifact/metadata.
78           */
79          GET,
80  
81          /**
82           * Check artifact/metadata existence only.
83           */
84          GET_EXISTENCE,
85  
86          /**
87           * Upload artifact/metadata.
88           */
89          PUT,
90      }
91  
92      private final EventType type;
93  
94      private final RequestType requestType;
95  
96      private final RepositorySystemSession session;
97  
98      private final TransferResource resource;
99  
100     private final ByteBuffer dataBuffer;
101 
102     private final long transferredBytes;
103 
104     private final Exception exception;
105 
106     TransferEvent(Builder builder) {
107         type = builder.type;
108         requestType = builder.requestType;
109         session = builder.session;
110         resource = builder.resource;
111         dataBuffer = builder.dataBuffer;
112         transferredBytes = builder.transferredBytes;
113         exception = builder.exception;
114     }
115 
116     /**
117      * Gets the type of the event.
118      *
119      * @return The type of the event, never {@code null}.
120      */
121     public EventType getType() {
122         return type;
123     }
124 
125     /**
126      * Gets the type of the request/transfer.
127      *
128      * @return The type of the request/transfer, never {@code null}.
129      */
130     public RequestType getRequestType() {
131         return requestType;
132     }
133 
134     /**
135      * Gets the repository system session during which the event occurred.
136      *
137      * @return The repository system session during which the event occurred, never {@code null}.
138      */
139     public RepositorySystemSession getSession() {
140         return session;
141     }
142 
143     /**
144      * Gets the resource that is being transferred.
145      *
146      * @return The resource being transferred, never {@code null}.
147      */
148     public TransferResource getResource() {
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         return transferredBytes;
164     }
165 
166     /**
167      * Gets the byte buffer holding the transferred bytes since the last event. A listener must assume this buffer to be
168      * owned by the event source and must not change any byte in this buffer. Also, the buffer is only valid for the
169      * duration of the event callback, i.e. the next event might reuse the same buffer (with updated contents).
170      * Therefore, if the actual event processing is deferred, the byte buffer would have to be cloned to create an
171      * immutable snapshot of its contents.
172      *
173      * @return The (read-only) byte buffer or {@code null} if not applicable to the event, i.e. if the event type is not
174      *         {@link EventType#PROGRESSED}.
175      */
176     public ByteBuffer getDataBuffer() {
177         return (dataBuffer != null) ? dataBuffer.asReadOnlyBuffer() : null;
178     }
179 
180     /**
181      * Gets the number of bytes that have been transferred since the last event.
182      *
183      * @return The number of bytes that have been transferred since the last event, possibly zero but never negative.
184      * @see #getTransferredBytes()
185      */
186     public int getDataLength() {
187         return (dataBuffer != null) ? dataBuffer.remaining() : 0;
188     }
189 
190     /**
191      * Gets the error that occurred during the transfer.
192      *
193      * @return The error that occurred or {@code null} if none.
194      */
195     public Exception getException() {
196         return exception;
197     }
198 
199     @Override
200     public String toString() {
201         return getRequestType() + " " + getType() + " " + getResource();
202     }
203 
204     /**
205      * A builder to create transfer events.
206      */
207     public static final class Builder {
208 
209         EventType type;
210 
211         RequestType requestType;
212 
213         final RepositorySystemSession session;
214 
215         final TransferResource resource;
216 
217         ByteBuffer dataBuffer;
218 
219         long transferredBytes;
220 
221         Exception exception;
222 
223         /**
224          * Creates a new transfer event builder for the specified session and the given resource.
225          *
226          * @param session The repository system session, must not be {@code null}.
227          * @param resource The resource being transferred, must not be {@code null}.
228          */
229         public Builder(RepositorySystemSession session, TransferResource resource) {
230             this.session = requireNonNull(session, "repository system session cannot be null");
231             this.resource = requireNonNull(resource, "transfer resource cannot be null");
232             type = EventType.INITIATED;
233             requestType = RequestType.GET;
234         }
235 
236         private Builder(Builder prototype) {
237             session = prototype.session;
238             resource = prototype.resource;
239             type = prototype.type;
240             requestType = prototype.requestType;
241             dataBuffer = prototype.dataBuffer;
242             transferredBytes = prototype.transferredBytes;
243             exception = prototype.exception;
244         }
245 
246         /**
247          * Creates a new transfer event builder from the current values of this builder. The state of this builder
248          * remains unchanged.
249          *
250          * @return The new event builder, never {@code null}.
251          */
252         public Builder copy() {
253             return new Builder(this);
254         }
255 
256         /**
257          * Sets the type of the event and resets event-specific fields. In more detail, the data buffer and the
258          * exception fields are set to {@code null}. Furthermore, the total number of transferred bytes is set to
259          * {@code 0} if the event type is {@link EventType#STARTED}.
260          *
261          * @param type The type of the event, must not be {@code null}.
262          * @return This event builder for chaining, never {@code null}.
263          */
264         public Builder resetType(EventType type) {
265             this.type = requireNonNull(type, "event type cannot be null");
266             dataBuffer = null;
267             exception = null;
268             switch (type) {
269                 case INITIATED:
270                 case STARTED:
271                     transferredBytes = 0L;
272                 default:
273             }
274             return this;
275         }
276 
277         /**
278          * Sets the type of the event. When re-using the same builder to generate a sequence of events for one transfer,
279          * {@link #resetType(TransferEvent.EventType)} might be more handy.
280          *
281          * @param type The type of the event, must not be {@code null}.
282          * @return This event builder for chaining, never {@code null}.
283          */
284         public Builder setType(EventType type) {
285             this.type = requireNonNull(type, "event type cannot be null");
286             return this;
287         }
288 
289         /**
290          * Sets the type of the request/transfer.
291          *
292          * @param requestType The request/transfer type, must not be {@code null}.
293          * @return This event builder for chaining, never {@code null}.
294          */
295         public Builder setRequestType(RequestType requestType) {
296             this.requestType = requireNonNull(requestType, "request type cannot be null");
297             return this;
298         }
299 
300         /**
301          * Sets the total number of bytes that have been transferred so far during the download/upload of the resource.
302          * If a download is being resumed, the count must include the bytes that were already downloaded in the previous
303          * attempt and from which the current transfer started. In this case, the event type {@link EventType#STARTED}
304          * should indicate from what byte the download resumes.
305          *
306          * @param transferredBytes The total number of bytes that have been transferred so far during the
307          *            download/upload of the resource, must not be negative.
308          * @return This event builder for chaining, never {@code null}.
309          * @see TransferResource#setResumeOffset(long)
310          */
311         public Builder setTransferredBytes(long transferredBytes) {
312             if (transferredBytes < 0L) {
313                 throw new IllegalArgumentException("number of transferred bytes cannot be negative");
314             }
315             this.transferredBytes = transferredBytes;
316             return this;
317         }
318 
319         /**
320          * Increments the total number of bytes that have been transferred so far during the download/upload.
321          *
322          * @param transferredBytes The number of bytes that have been transferred since the last event, must not be
323          *            negative.
324          * @return This event builder for chaining, never {@code null}.
325          */
326         public Builder addTransferredBytes(long transferredBytes) {
327             if (transferredBytes < 0L) {
328                 throw new IllegalArgumentException("number of transferred bytes cannot be negative");
329             }
330             this.transferredBytes += transferredBytes;
331             return this;
332         }
333 
334         /**
335          * Sets the byte buffer holding the transferred bytes since the last event.
336          *
337          * @param buffer The byte buffer holding the transferred bytes since the last event, may be {@code null} if not
338          *            applicable to the event.
339          * @param offset The starting point of valid bytes in the array.
340          * @param length The number of valid bytes, must not be negative.
341          * @return This event builder for chaining, never {@code null}.
342          */
343         public Builder setDataBuffer(byte[] buffer, int offset, int length) {
344             return setDataBuffer((buffer != null) ? ByteBuffer.wrap(buffer, offset, length) : null);
345         }
346 
347         /**
348          * Sets the byte buffer holding the transferred bytes since the last event.
349          *
350          * @param dataBuffer The byte buffer holding the transferred bytes since the last event, may be {@code null} if
351          *            not applicable to the event.
352          * @return This event builder for chaining, never {@code null}.
353          */
354         public Builder setDataBuffer(ByteBuffer dataBuffer) {
355             this.dataBuffer = dataBuffer;
356             return this;
357         }
358 
359         /**
360          * Sets the error that occurred during the transfer.
361          *
362          * @param exception The error that occurred during the transfer, may be {@code null} if none.
363          * @return This event builder for chaining, never {@code null}.
364          */
365         public Builder setException(Exception exception) {
366             this.exception = exception;
367             return this;
368         }
369 
370         /**
371          * Builds a new transfer event from the current values of this builder. The state of the builder itself remains
372          * unchanged.
373          *
374          * @return The transfer event, never {@code null}.
375          */
376         public TransferEvent build() {
377             return new TransferEvent(this);
378         }
379     }
380 }