001    /**
002     * Copyright (C) 2009-2011 the original author or authors.
003     * See the notice.md file distributed with this work for additional
004     * information regarding copyright ownership.
005     *
006     * Licensed under the Apache License, Version 2.0 (the "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.fusesource.restygwt.client.callback;
020    
021    import java.util.logging.Logger;
022    
023    import org.fusesource.restygwt.client.Method;
024    
025    import com.google.gwt.core.client.GWT;
026    import com.google.gwt.http.client.Request;
027    import com.google.gwt.http.client.RequestBuilder;
028    import com.google.gwt.http.client.RequestCallback;
029    import com.google.gwt.http.client.RequestException;
030    import com.google.gwt.http.client.Response;
031    import com.google.gwt.logging.client.LogConfiguration;
032    import com.google.gwt.user.client.Timer;
033    import com.google.gwt.user.client.Window;
034    
035    public class RetryingFilterawareRequestCallback extends DefaultFilterawareRequestCallback {
036    
037        /**
038         * Used by RetryingCallback
039         * default value is 5
040         */
041        protected int numberOfRetries = 5;
042    
043        /**
044         * time to wait for reconnect upon failure
045         */
046        protected int gracePeriod = 1000;
047    
048        protected int currentRetryCounter = 0;
049    
050        public RetryingFilterawareRequestCallback(Method method) {
051            super(method);
052        }
053    
054        public RetryingFilterawareRequestCallback(Method method,
055                int gracePeriodMillis, int numberOfRetries) {
056            super(method);
057            this.gracePeriod = gracePeriodMillis;
058            this.numberOfRetries = numberOfRetries;
059        }
060    
061        @Override
062        public final void onResponseReceived(Request request, Response response) {
063            int code = response.getStatusCode();
064            if (!(code < 300 && code >= 200)) {
065                /*
066                 * retry only on GET requests that are no redirects (301, 302, 303)
067                 */
068                if (code != 301
069                        && code != 302
070                        && code != 303
071                        && code != 404
072                        && (method.builder == null // jsonp method do not have a builder !! 
073                                || method.builder.getHTTPMethod().equalsIgnoreCase("get"))) {
074                    handleErrorGracefully(request, response, requestCallback);
075                } else {
076                    if (LogConfiguration.loggingIsEnabled()) {
077                        Logger.getLogger(RetryingFilterawareRequestCallback.class.getName()).severe(
078                                "ERROR with non-GET method: " + method.builder.getHTTPMethod() + " "
079                                + method.builder.getUrl() + ", " + response.getStatusText());
080                    }
081    
082                    /*
083                     *  RuntimeException token from
084                     *  com.google.gwt.http.client.Request#fireOnResponseReceived()
085                     */
086                    requestCallback.onError(request, new RuntimeException("Response "
087                            + response.getStatusCode() + " for " + method.builder.getHTTPMethod() + " "
088                            + method.builder.getUrl()));
089                }
090                return;
091            } else {
092                // filter only in success case for now
093                runFilters(request, response);
094            }
095        }
096    
097    //    /**
098    //     * TODO when is this used ? maybe just forward to requestCallback.onError
099    //     */
100    //    @Override
101    //    public void onError(Request request, Throwable exception) {
102    //        if (LogConfiguration.loggingIsEnabled()) {
103    //            Logger.getLogger(RetryingFilterawareRequestCallback.class.getName())
104    //                    .severe("call onError in " + this.getClass() + ". this should not happen...");
105    //        }
106    //        requestCallback.onError(request, exception);
107    ////        handleErrorGracefully(null, null, null);
108    //    }
109    
110        public void handleErrorGracefully(Request request, Response response,
111                RequestCallback requestCallback) {
112            // error handling...:
113            if (currentRetryCounter < numberOfRetries) {
114                System.out.println("counter " + currentRetryCounter);
115                if (GWT.isClient() && LogConfiguration.loggingIsEnabled()) {
116                    Logger.getLogger(RetryingFilterawareRequestCallback.class.getName()).severe(
117                            "error handling in progress for: " + method.builder.getHTTPMethod()
118                            + " " + method.builder.getUrl());
119                }
120    
121                currentRetryCounter++;
122    
123                Timer t = new Timer() {
124                    public void run() {
125                        try {
126                            System.out.println("run . . ." + method.builder.getCallback());
127                                        
128                            method.builder.send();
129                        } catch (RequestException ex) {
130                            if (GWT.isClient() && LogConfiguration.loggingIsEnabled()) {
131                                Logger.getLogger(RetryingFilterawareRequestCallback.class.getName())
132                                        .severe(ex.getMessage());
133                            }
134                        }
135                    }
136                };
137    
138                t.schedule(gracePeriod);
139                gracePeriod = gracePeriod * 2;
140            } else {
141                if (GWT.isClient() && LogConfiguration.loggingIsEnabled()) {
142                    Logger.getLogger(RetryingFilterawareRequestCallback.class.getName()).severe("Request failed: "
143                            + method.builder.getHTTPMethod() + " " + method.builder.getUrl()
144                            + " after " + currentRetryCounter + " tries.");
145                }
146    
147                if (null != request
148                        && null != response
149                        && null != requestCallback) {
150                    // got the original callback, call error here
151                    requestCallback.onError(request, new RuntimeException("Response "
152                            + response.getStatusCode() + " for " + method.builder.getHTTPMethod() + " "
153                            + method.builder.getUrl() + " after " + numberOfRetries + " retries."));
154                } else {
155                    // got no callback - well, goodbye
156                    if (Window.confirm("something severly went wrong - error - reload page ?")) {
157                        // Super severe error.
158                        // reload app or redirect.
159                        // ===> this breaks the app but that's by intention.
160                        Window.Location.reload();
161                    }
162                }
163            }
164        }
165    }