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