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 RepositorySystemSession session; 230 231 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 }