1 /*
2 * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License").
5 * You may not use this file except in compliance with the License.
6 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15 package com.amazonaws.event;
16
17 import com.amazonaws.SdkClientException;
18
19 /**
20 * Listener interface for transfer progress events.
21 * <p>
22 * This class could be used for both Amazon S3 and Amazon Glacier clients. The
23 * legacy Amazon S3 progress listener
24 * com.amazonaws.services.s3.model.ProgressListener has been deprecated in favor
25 * of this new class.
26 * </p>
27 *
28 * @see ProgressEvent
29 */
30 public interface ProgressListener {
31 public static final ProgressListener NOOP = new NoOpProgressListener();
32
33 static class NoOpProgressListener implements ProgressListener, DeliveryMode {
34
35 @Override
36 public boolean isSyncCallSafe() {
37 return true;
38 }
39
40 @Override
41 public void progressChanged(ProgressEvent progressEvent) {
42 }
43 }
44
45 /**
46 * Called when progress has changed, such as additional bytes transferred,
47 * transfer failed, etc. The execution of the callback of this listener is managed
48 * by {@link SDKProgressPublisher}. Implementation of this interface
49 * should never block.
50 * <p>
51 * If the implementation follows the best practice and doesn't block, it
52 * should then extends from {@link SyncProgressListener}.
53 * <p>
54 * Note any exception thrown by the listener will get ignored.
55 * Should there be need to capture any such exception, you may consider
56 * wrapping the listener with {@link ExceptionReporter#wrap(ProgressListener)}.
57 *
58 * @param progressEvent
59 * The event describing the progress change.
60 *
61 * @see SDKProgressPublisher
62 * @see ExceptionReporter
63 */
64 public void progressChanged(ProgressEvent progressEvent);
65
66 /**
67 * A utility class for capturing and reporting the first exception thrown by
68 * a given progress listener. Note once an exception is thrown by the
69 * underlying listener, all subsequent events will no longer be notified to
70 * the listener.
71 */
72 public static class ExceptionReporter implements ProgressListener, DeliveryMode {
73 private final ProgressListener listener;
74 private final boolean syncCallSafe;
75 private volatile Throwable cause;
76
77 public ExceptionReporter(ProgressListener listener) {
78 if (listener == null)
79 throw new IllegalArgumentException();
80 this.listener = listener;
81 if (listener instanceof DeliveryMode) {
82 DeliveryMode cs = (DeliveryMode) listener;
83 syncCallSafe = cs.isSyncCallSafe();
84 } else
85 syncCallSafe = false;
86 }
87
88 /**
89 * Delivers the progress event to the underlying listener but only if
90 * there has not been an exception previously thrown by the listener.
91 * <p>
92 * {@inheritDoc}
93 */
94 @Override public void progressChanged(ProgressEvent progressEvent) {
95 if (cause != null)
96 return;
97 try {
98 this.listener.progressChanged(progressEvent);
99 } catch(Throwable t) {
100 cause = t;
101 }
102 }
103
104 /**
105 * Throws the underlying exception, if any, as an
106 * {@link SdkClientException}; or do nothing otherwise.
107 */
108 public void throwExceptionIfAny() {
109 if (cause != null)
110 throw new SdkClientException(cause);
111 }
112
113 /**
114 * Returns the underlying exception, if any; or null otherwise.
115 */
116 public Throwable getCause() {
117 return cause;
118 }
119
120 /**
121 * Returns a wrapper for the given listener to capture the first
122 * exception thrown.
123 */
124 public static ExceptionReporter wrap(ProgressListener listener) {
125 return new ExceptionReporter(listener);
126 }
127
128 @Override public boolean isSyncCallSafe() { return syncCallSafe; }
129 }
130 }
131