/** * Copyright (C) 2009-2012 the original author or authors. * See the notice.md file distributed with this work for additional * information regarding copyright ownership. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fusesource.restygwt.client.callback; import java.util.List; import java.util.logging.Logger; import org.fusesource.restygwt.client.Method; import org.fusesource.restygwt.client.cache.CacheKey; import org.fusesource.restygwt.client.cache.ComplexCacheKey; import org.fusesource.restygwt.client.cache.Domain; import org.fusesource.restygwt.client.cache.QueueableCacheStorage; import com.google.gwt.core.client.GWT; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.Response; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONValue; import com.google.gwt.logging.client.LogConfiguration; public class CachingCallbackFilter implements CallbackFilter { protected final QueueableCacheStorage cache; public CachingCallbackFilter(QueueableCacheStorage cache) { this.cache = cache; } /** * the real filter method, called independent of the response code * * TODO method.getResponse() is not equal to response. unfortunately */ @Override public RequestCallback filter(final Method method, final Response response, RequestCallback callback) { final int code = response.getStatusCode(); final CacheKey ck = cacheKey(method.builder); final List<RequestCallback> removedCallbacks = cache.removeCallbacks(ck); if (removedCallbacks != null){ callback = new RequestCallback() { @Override public void onResponseReceived(Request request, Response response) { if (GWT.isClient() && LogConfiguration.loggingIsEnabled()) { Logger.getLogger(CachingCallbackFilter.class.getName()) .finer("call "+ removedCallbacks.size() + " more queued callbacks for " + ck); } // call all callbacks found in cache for (RequestCallback cb : removedCallbacks) { cb.onResponseReceived(request, response); } } @Override public void onError(Request request, Throwable exception) { if (LogConfiguration.loggingIsEnabled()) { Logger.getLogger(CachingCallbackFilter.class.getName()) .severe("cannot call " + (removedCallbacks.size()+1) + " callbacks for " + ck + " due to error: " + exception.getMessage()); } if (LogConfiguration.loggingIsEnabled()) { Logger.getLogger(CachingCallbackFilter.class.getName()) .finer("call "+ removedCallbacks.size() + " more queued callbacks for " + ck); } // and all the others, found in cache for (RequestCallback cb : removedCallbacks) { cb.onError(request, exception); } } }; } else { if (GWT.isClient() && LogConfiguration.loggingIsEnabled()) { Logger.getLogger(CachingCallbackFilter.class.getName()).finer("removed one or no " + "callback for cachekey " + ck); } } if (isCachingStatusCode(code)) { cacheResult(method, response); return callback; } if (GWT.isClient() && LogConfiguration.loggingIsEnabled()) { Logger.getLogger(CachingCallbackFilter.class.getName()) .info("cannot cache due to invalid response code: " + code); } return callback; } protected boolean isCachingStatusCode(final int code) { return code < Response.SC_MULTIPLE_CHOICES // code < 300 && code >= Response.SC_OK; // code >= 200 } protected CacheKey cacheKey(final RequestBuilder builder) { return new ComplexCacheKey(builder); } protected void cacheResult(final Method method, final Response response) { CacheKey cacheKey = cacheKey(method.builder); if (GWT.isClient() && LogConfiguration.loggingIsEnabled()) { Logger.getLogger(CachingCallbackFilter.class.getName()).finer("cache to " + cacheKey + ": " + response); } cache.putResult(cacheKey, response, getCacheDomains(method)); } /** * when using the {@link Domain} annotation on services, we are able to group responses * of a service to invalidate them later on more fine grained. this method resolves a * possible ``domain`` to allow grouping. * * @return array of names of cache domains */ protected String[] getCacheDomains(final Method method) { if (null == method.getData().get(Domain.CACHE_DOMAIN_KEY)) return null; final JSONValue jsonValue = JSONParser.parseStrict(method.getData() .get(Domain.CACHE_DOMAIN_KEY)); if (null == jsonValue) { return null; } final JSONArray jsonArray = jsonValue.isArray(); if (null != jsonArray) { final String[] dd = new String[jsonArray.size()]; for (int i = 0; i < jsonArray.size(); ++i) { dd[i] = jsonArray.get(i).isString().stringValue(); } return dd; } return null; } }