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 }