001package votorola.g.web.gwt; // Copyright 2012, Michael Allan.  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE.
002
003import com.google.gwt.jsonp.client.JsonpRequest;
004import com.google.gwt.user.client.rpc.AsyncCallback;
005
006
007/** A callback wrapper that uses an atomizer to enforce non-overlapping JSONP
008  * request/response exchanges.
009  */
010public final class AtomicAsyncCallback<T,R> implements AsyncCallback<T>
011{
012
013
014    /** Partially creates an AtomicAsyncCallback for {@linkplain #init(JsonpRequest) init}
015      * to finish.
016      *
017      *     @param atomizer the exchange atomizer to use.
018      *     @param callback the callback to guard.
019      */
020    public static <T,R> AtomicAsyncCallback<T,R> wrap( final JSONPAtomizer<R> atomizer,
021      final AsyncCallback<T> callback )
022    {
023        return new AtomicAsyncCallback<T,R>( atomizer, callback );
024    }
025
026
027
028    private AtomicAsyncCallback( JSONPAtomizer<R> _atomizer, AsyncCallback<T> _callback )
029    {
030        atomizer = _atomizer;
031        callback = _callback;
032    }
033
034
035
036    /** Completes the creation of this callback.  Call once only.  If the specified
037      * request completes before another is issued on the same atomizer, then one of
038      * {@linkplain #onFailure(Throwable) onFailure} or {@linkplain #onSuccess onSuccess}
039      * is called.  Otherwise the request is abandoned.
040      */
041    public void init( JsonpRequest<R> _request )
042    {
043        request = _request;
044        atomizer.setPendingRequest( request );
045    }
046
047
048
049   // - A s y n c - C a l l b a c k ------------------------------------------------------
050
051
052    public void onFailure( final Throwable x )
053    {
054        assert request != null: "init was called";
055        if( request != atomizer.pendingRequest() ) return;
056
057        atomizer.clearPendingRequest( request );
058        callback.onFailure( x );
059    }
060
061
062
063    public void onSuccess( final T result )
064    {
065        assert request != null: "init was called";
066        if( request != atomizer.pendingRequest() ) return;
067
068        atomizer.clearPendingRequest( request );
069        callback.onSuccess( result );
070    }
071
072
073
074//// P r i v a t e ///////////////////////////////////////////////////////////////////////
075
076
077    private final JSONPAtomizer<R> atomizer;
078
079
080
081    private final AsyncCallback<T> callback;
082
083
084
085    private JsonpRequest<R> request; // final when initialized
086
087
088}