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 }