/** * 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.basic; import org.fusesource.restygwt.client.Defaults; import org.fusesource.restygwt.client.Method; import org.fusesource.restygwt.client.MethodCallback; import org.fusesource.restygwt.client.Resource; import org.fusesource.restygwt.client.RestServiceProxy; import org.fusesource.restygwt.client.cache.VolatileQueueableCacheStorage; import org.fusesource.restygwt.client.cache.QueueableCacheStorage; import org.fusesource.restygwt.client.callback.CachingCallbackFilter; import org.fusesource.restygwt.client.callback.CallbackFactory; import org.fusesource.restygwt.client.callback.FilterawareRequestCallback; import org.fusesource.restygwt.client.callback.DefaultFilterawareRequestCallback; import org.fusesource.restygwt.client.callback.ModelChangeCallbackFilter; import org.fusesource.restygwt.client.dispatcher.CachingDispatcherFilter; import org.fusesource.restygwt.client.dispatcher.FilterawareDispatcher; import org.fusesource.restygwt.client.dispatcher.DefaultFilterawareDispatcher; import com.google.gwt.core.client.GWT; import com.google.gwt.event.shared.EventBus; import com.google.gwt.event.shared.SimpleEventBus; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.user.client.Timer; /** * test to check if {@link CachingCallbackFilter} {@link QueueableCacheStorage} * and caching stuff in complete works as expected * * @author <a href="mailto:andi.balke@gmail.com">andi</a> */ public class CacheCallbackTestGwt extends GWTTestCase { private BlockingTimeoutService service; private final int TESTCLASS_DELAY_TIMEOUT = 15000; @Override public String getModuleName() { return "org.fusesource.restygwt.CachingTestGwt"; } /** * prove all callbacks are registered, called and unregistered without * using the cache. in this test all calls will reach the server. * * this is done by just calling the same method multiple times */ public void testNonCachingCallback() { service.noncachingCall(0, new MethodCallback<Void>() { @Override public void onSuccess(Method method, Void response) { GWT.log("passing first call"); } @Override public void onFailure(Method method, Throwable exception) { fail("failure on read: " + exception.getMessage()); } }); service.noncachingCall(1, new MethodCallback<Void>() { @Override public void onSuccess(Method method, Void response) { GWT.log("passing second call"); } @Override public void onFailure(Method method, Throwable exception) { fail("failure on read: " + exception.getMessage()); } }); service.noncachingCall(2, new MethodCallback<Void>() { @Override public void onSuccess(Method method, Void response) { GWT.log("passing third call"); finishTest(); } @Override public void onFailure(Method method, Throwable exception) { fail("failure on read: " + exception.getMessage()); } }); // wait... we are in async testing... delayTestFinish(TESTCLASS_DELAY_TIMEOUT); } /** * prove all callbacks are registered, performed and unregistered with * using the cache. * * not all calls will reach the server, {@link VolatileQueueableCacheStorage} will * need to handle some of the callbacks by its own. * * this is done by just calling the same method multiple times * * first the simple case: * use the cache when the first method call is back from backend. there wont be * any callback queuing yet. */ public void testSequential_NonQueuing_CachingCallback() { // backend reaching call service.cachingCall(0, new MethodCallback<Void>() { @Override public void onSuccess(Method method, Void response) { GWT.log("passing first non-queuing call"); } @Override public void onFailure(Method method, Throwable exception) { fail("failure on read: " + exception.getMessage()); } }); // wait a second for callback to be back for sure // usually there should be something like Thread.sleep, but thats not possible here new Timer() { public void run() { /* * two calls that are handled directly by the cache * (no backend interaction at all) */ service.cachingCall(0, new MethodCallback<Void>() { @Override public void onSuccess(Method method, Void response) { GWT.log("passing second non-queuing call"); } @Override public void onFailure(Method method, Throwable exception) { fail("failure on read: " + exception.getMessage()); } }); } }.schedule(1000); // this is the third one, started in 3 seconds new Timer() { public void run() { service.cachingCall(0, new MethodCallback<Void>() { @Override public void onSuccess(Method method, Void response) { GWT.log("passing third non-queuing call"); finishTest(); } @Override public void onFailure(Method method, Throwable exception) { fail("failure on read: " + exception.getMessage()); } }); } }.schedule(3000); // wait... we are in async testing... delayTestFinish(TESTCLASS_DELAY_TIMEOUT); } public void testSequential_Queuing_CachingCallback() { // backend reaching call service.cachingQueuingCall(2, new MethodCallback<Void>() { @Override public void onSuccess(Method method, Void response) { GWT.log("passing first queuing call"); } @Override public void onFailure(Method method, Throwable exception) { fail("failure on read: " + exception.getMessage()); } }); /* * same call again to get this callback queued * and called when the first is back from backend */ service.cachingQueuingCall(2, new MethodCallback<Void>() { @Override public void onSuccess(Method method, Void response) { GWT.log("passing second queuing call"); finishTest(); } @Override public void onFailure(Method method, Throwable exception) { fail("failure on read: " + exception.getMessage()); } }); // wait... we are in async testing... delayTestFinish(TESTCLASS_DELAY_TIMEOUT); } /** * usually this stuff is all done by gin in a real application. or at least there * would be a central place which is not the activity in the end. */ @Override public void gwtSetUp() { /* * configure RESTY to use cache, usually done in gin */ final EventBus eventBus = new SimpleEventBus(); final QueueableCacheStorage cacheStorage = new VolatileQueueableCacheStorage(); final FilterawareDispatcher dispatcher = new DefaultFilterawareDispatcher(); dispatcher.addFilter(new CachingDispatcherFilter( cacheStorage, new CallbackFactory() { public FilterawareRequestCallback createCallback(Method method) { final FilterawareRequestCallback retryingCallback = new DefaultFilterawareRequestCallback( method); retryingCallback.addFilter(new CachingCallbackFilter(cacheStorage)); retryingCallback.addFilter(new ModelChangeCallbackFilter(eventBus)); return retryingCallback; } })); Defaults.setDispatcher(dispatcher); /* * setup the service, usually done in gin */ Resource resource = new Resource(GWT.getModuleBaseURL()); service = GWT.create(BlockingTimeoutService.class); ((RestServiceProxy) service).setResource(resource); } }