001/* 002 * GWTEventService 003 * Copyright (c) 2011 and beyond, strawbill UG (haftungsbeschr?nkt) 004 * 005 * This is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Lesser General Public License as 007 * published by the Free Software Foundation; either version 3 of 008 * the License, or (at your option) any later version. 009 * Other licensing for GWTEventService may also be possible on request. 010 * Please view the license.txt of the project for more information. 011 * 012 * This software is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this software; if not, write to the Free 019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 021 */ 022package de.novanic.eventservice.client.event; 023 024import com.google.gwt.user.client.rpc.AsyncCallback; 025import de.novanic.eventservice.client.config.EventServiceConfigurationTransferable; 026import de.novanic.eventservice.client.connection.strategy.connector.RemoteEventConnector; 027import de.novanic.eventservice.client.event.command.ClientCommand; 028import de.novanic.eventservice.client.event.command.InitEventServiceCommand; 029import de.novanic.eventservice.client.event.command.schedule.ClientCommandSchedulerFactory; 030 031import java.util.LinkedList; 032import java.util.Queue; 033 034/** 035 * The RemoteEventServiceAccessor provides general methods for command execution and manages the 036 * {@link de.novanic.eventservice.client.connection.strategy.connector.RemoteEventConnector}. 037 * 038 * @author sstrohschein 039 * <br>Date: 04.07.2010 040 * <br>Time: 13:21:19 041 */ 042public abstract class RemoteEventServiceAccessor 043{ 044 private RemoteEventConnector myRemoteEventConnector; 045 private Queue<ClientCommand<?>> myClientCommandQueue; 046 private boolean isSessionInitialized; 047 048 /** 049 * Constructor of the AbstractRemoteEventService to manage the {@link de.novanic.eventservice.client.connection.strategy.connector.RemoteEventConnector}. 050 * @param aRemoteEventConnector {@link de.novanic.eventservice.client.connection.strategy.connector.RemoteEventConnector} for the connection 051 * between client side and server side 052 */ 053 protected RemoteEventServiceAccessor(RemoteEventConnector aRemoteEventConnector) { 054 myRemoteEventConnector = aRemoteEventConnector; 055 } 056 057 /** 058 * Checks if the RemoteEventService is active (listening). 059 * @return true when active/listening, otherwise false 060 */ 061 protected boolean isListenActive() { 062 return myRemoteEventConnector.isActive(); 063 } 064 065 /** 066 * Starts the init command and schedules all other commands till the init command is finished. That must be done 067 * to avoid double initialized sessions (race condition GWT issue 1846). 068 * @param aClientCommand command to schedule 069 * @param <R> Return type of the command callback 070 */ 071 protected <R> void schedule(final ClientCommand<R> aClientCommand) { 072 if(myClientCommandQueue == null) { 073 myClientCommandQueue = new LinkedList<ClientCommand<?>>(); 074 InitEventServiceCommand theInitCommand = new InitEventServiceCommand(getRemoteEventConnector(), new InitCommandCallback()); 075 theInitCommand.execute(); 076 } 077 myClientCommandQueue.add(aClientCommand); 078 executeCommands(); 079 } 080 081 /** 082 * Executes the scheduled commands ({@link ClientCommand}. The commands can be scheduled with 083 * {@link RemoteEventServiceAccessor#schedule(de.novanic.eventservice.client.event.command.ClientCommand)}. 084 */ 085 private void executeCommands() { 086 if(isSessionInitialized) { 087 ClientCommand<?> theClientCommand; 088 while(myClientCommandQueue != null && (theClientCommand = myClientCommandQueue.poll()) != null) { 089 theClientCommand.execute(); 090 } 091 } 092 } 093 094 /** 095 * Returns the managed {@link de.novanic.eventservice.client.connection.strategy.connector.RemoteEventConnector}. 096 * @return managed {@link de.novanic.eventservice.client.connection.strategy.connector.RemoteEventConnector} 097 */ 098 protected RemoteEventConnector getRemoteEventConnector() { 099 return myRemoteEventConnector; 100 } 101 102 protected void reset() { 103 isSessionInitialized = false; 104 myClientCommandQueue = null; 105 getRemoteEventConnector().deactivate(); 106 } 107 108 /** 109 * Callback for the init command. 110 */ 111 private class InitCommandCallback implements AsyncCallback<EventServiceConfigurationTransferable> 112 { 113 /** 114 * Executes the scheduled commands on success. 115 * @param aConfiguration configuration for the client side 116 */ 117 public void onSuccess(EventServiceConfigurationTransferable aConfiguration) { 118 getRemoteEventConnector().initListen(aConfiguration); 119 finishFirstCall(); 120 } 121 122 /** 123 * Throws a runtime exception when the event service couldn't be activated / initialized. 124 * @param aThrowable throwable caused by a failed server call 125 */ 126 public void onFailure(Throwable aThrowable) { 127 throw new RemoteEventServiceRuntimeException("Error on activating / initializing \"" + RemoteEventService.class.getName() + "\"!", aThrowable); 128 } 129 130 /** 131 * Executes the scheduled commands. 132 */ 133 private void finishFirstCall() { 134 //Schedule the next command after the callback is finished. The timer is needed, because some browsers doesn't 135 //notice the server call cycle, when the next command is executed directly. 136 ClientCommandSchedulerFactory.getInstance().getClientCommandScheduler().schedule(new ClientCommand<Void>() { 137 public void execute() { 138 isSessionInitialized = true; 139 executeCommands(); 140 } 141 142 public AsyncCallback<Void> getCommandCallback() { return null; } 143 }); 144 } 145 } 146 147 /** 148 * Empty callback 149 */ 150 protected static class VoidAsyncCallback implements AsyncCallback<Void> 151 { 152 public void onFailure(Throwable aThrowable) {} 153 154 public void onSuccess(Void aResult) {} 155 } 156}