All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.novanic.eventservice.client.event.DefaultRemoteEventConnector Maven / Gradle / Ivy

The newest version!
/*
 * GWTEventService
 * Copyright (c) 2011 and beyond, strawbill UG (haftungsbeschr?nkt)
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 * Other licensing for GWTEventService may also be possible on request.
 * Please view the license.txt of the project for more information.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package de.novanic.eventservice.client.event;

import com.google.gwt.user.client.rpc.AsyncCallback;

import java.util.List;

import com.google.gwt.user.client.rpc.StatusCodeException;
import de.novanic.eventservice.client.config.ConfigurationTransferableDependentFactory;
import de.novanic.eventservice.client.config.EventServiceConfigurationTransferable;
import de.novanic.eventservice.client.connection.callback.AsyncCallbackWrapper;
import de.novanic.eventservice.client.connection.strategy.connector.ConnectionStrategyClientConnector;
import de.novanic.eventservice.client.event.listener.EventNotification;
import de.novanic.eventservice.client.connection.strategy.connector.RemoteEventConnector;
import de.novanic.eventservice.client.logger.ClientLogger;
import de.novanic.eventservice.client.logger.ClientLoggerFactory;
import de.novanic.eventservice.client.event.domain.Domain;
import de.novanic.eventservice.client.event.domain.DomainFactory;
import de.novanic.eventservice.client.event.filter.EventFilter;
import de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent;
import de.novanic.eventservice.client.event.listener.unlisten.DefaultUnlistenEvent;
import de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener;

/**
 * RemoteEventConnector should handle the connections between client- and the server side.
 *
 * @author sstrohschein
 *         
Date: 14.10.2008 *
Time: 11:34:45 */ public abstract class DefaultRemoteEventConnector implements RemoteEventConnector { private static final ClientLogger LOG = ClientLoggerFactory.getClientLogger(); private boolean isActive; private EventServiceConfigurationTransferable myConfiguration; private ConnectionStrategyClientConnector myConnectionStrategyClientConnector; private UnlistenEvent myUnlistenEvent; private int myErrorCount; /** * Initializes the listen method implementation with a {@link de.novanic.eventservice.client.connection.strategy.connector.ConnectionStrategyClientConnector} from the configuration. * That is required to specify the listen / connection strategy. The connection strategy can't be changed, when the listening has already started / an listener was added. * @param aConfiguration configuration */ public synchronized ConnectionStrategyClientConnector initListen(EventServiceConfigurationTransferable aConfiguration) { if(isActive) { throw new RemoteEventServiceRuntimeException("Invalid attempt to change the connection strategy after listening was started!"); } if(aConfiguration == null) { throw new RemoteEventServiceRuntimeException("Invalid attempt to initialize the listening without a configuration!"); } myConfiguration = aConfiguration; ConfigurationTransferableDependentFactory theConfigDependentFactory = ConfigurationTransferableDependentFactory.getInstance(aConfiguration); return (myConnectionStrategyClientConnector = theConfigDependentFactory.getConnectionStrategyClientConnector()); } /** * Deactivates the connector for all domains (no events can be got from the domains). */ public synchronized void deactivate() { if(isActive) { isActive = false; myConnectionStrategyClientConnector.deactivate(); LOG.log("RemoteEventConnector deactivated."); } } /** * Checks if the connector is active (listening). * @return true when active/listening, otherwise false */ public boolean isActive() { return isActive; } /** * Activates the connector for the domain. An {@link de.novanic.eventservice.client.event.filter.EventFilter} * to filter events on the server side is optional. * @param aDomain domain to activate * @param anEventFilter EventFilter to filter the events on the server side (optional) * @param anEventNotification supports the notification about incoming events * @param aCallback callback */ public void activate(Domain aDomain, EventFilter anEventFilter, EventNotification anEventNotification, AsyncCallback aCallback) { LOG.log("Activate RemoteEventConnector for domain \"" + aDomain + "\"."); activateStart(aDomain, anEventFilter, new ActivationCallback(anEventNotification, aCallback)); } /** * Registers an {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} to the server side which * will be triggered when a timeout or unlisten/deactivation for a domain occurs. * The UnlistenEvent will also be hold at the client side to trigger on local timeouts (for e.g. connection errors). * @param anUnlistenScope scope of the unlisten events to receive * @param anUnlistenEvent {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} which can contain custom data * @param aCallback callback */ public void registerUnlistenEvent(UnlistenEventListener.Scope anUnlistenScope, UnlistenEvent anUnlistenEvent, AsyncCallback aCallback) { myUnlistenEvent = anUnlistenEvent; } /** * Activates the connector for the domain. An {@link de.novanic.eventservice.client.event.filter.EventFilter} * to filter events on the server side is optional. * @param aDomain domain to activate * @param anEventFilter EventFilter to filter the events on the server side (optional) * @param aCallback callback */ protected abstract void activateStart(Domain aDomain, EventFilter anEventFilter, AsyncCallback aCallback); /** * Creates the {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} for local timeouts. * @param anEventNotification {@link de.novanic.eventservice.client.event.listener.EventNotification} for the triggered * {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} */ private void fireUnlistenEvent(EventNotification anEventNotification) { if(myUnlistenEvent == null) { myUnlistenEvent = new DefaultUnlistenEvent(); } myUnlistenEvent.setTimeout(false); myUnlistenEvent.setLocal(true); final DomainEvent theUnlistenDomainEvent = new DefaultDomainEvent(myUnlistenEvent, DomainFactory.UNLISTEN_DOMAIN); anEventNotification.onNotify(theUnlistenDomainEvent); } /** * Callback to activate listening of RemoteEventConnector. */ private final class ActivationCallback extends AsyncCallbackWrapper { private final EventNotification myEventNotification; private ActivationCallback(EventNotification anEventNotification, AsyncCallback aCallback) { super(aCallback); myEventNotification = anEventNotification; } /** * Starts listening to get events from the server side. * @param aResult unused * @see de.novanic.eventservice.client.event.GWTRemoteEventConnector.ListenEventCallback#callListen() */ public void onSuccess(T aResult) { if(!isActive) { if(myConnectionStrategyClientConnector != null) { LOG.log("RemoteEventConnector activated."); isActive = true; final ListenEventCallback theListenEventCallback = new ListenEventCallback(myEventNotification); theListenEventCallback.callListen(); } else { throw new RemoteEventServiceRuntimeException("No connection strategy was set at the start of listening!"); } } super.onSuccess(aResult); } public void onFailure(Throwable aThrowable) { LOG.error("Error on register client for domain!", aThrowable); fireUnlistenEvent(myEventNotification); super.onFailure(aThrowable); } } /** * The ListenEventCallback is used to produce the listen cycle. It is attached as callback for the listen server call. */ private final class ListenEventCallback implements AsyncCallback> { private EventNotification myEventNotification; private ListenEventCallback(EventNotification anEventNotification) { myEventNotification = anEventNotification; } /** * When an error occurs while listening for events, reconnect attempts are started (when configured) and an unlisten event * will be processed when the connection error could not be solved (to clean-up the client side). * @param aThrowable */ public void onFailure(Throwable aThrowable) { if((aThrowable instanceof StatusCodeException) && !isNotableStatusCode((StatusCodeException)aThrowable)) { //Status code 0 is not handled as an error. Some browsers send this status code when the user leaves the site/application. //The module is unloaded in this case and it has no negative effects to the application. Therefore it isn't a notable error. LOG.log("The current connection was terminated with status code " + ((StatusCodeException)aThrowable).getStatusCode() + '.'); fireUnlistenEvent(myEventNotification); //client side clean-up } else { LOG.error("Error on processing event!", aThrowable); if(++myErrorCount > myConfiguration.getReconnectAttemptCount()) { fireUnlistenEvent(myEventNotification); //client side clean-up } else { LOG.log("Reconnecting after error..."); callListen(); } } } /** * Calls listen on the server side and put itself as the callback to produces the listen cycle as long as the * RemoteEventConnector is active. * @param anEvents) events to process * @see de.novanic.eventservice.client.event.GWTRemoteEventConnector.ListenEventCallback#callListen() */ public void onSuccess(List anEvents) { myErrorCount = 0; if(anEvents != null) { for(DomainEvent theEvent: anEvents) { myEventNotification.onNotify(theEvent); } callListen(); } else { //if the remote service doesn't know the client, all listeners will be removed and the connection becomes inactive deactivate(); myEventNotification.onAbort(); } } /** * Calls listen at the server side to receive events. */ public synchronized void callListen() { if(isActive) { //after getting an event, register itself to listen for the next events myConnectionStrategyClientConnector.listen(myEventNotification, this); } } /** * Checks if the status code is a valid error code. For example status code 0 is rather an informational status code * instead of a notable error status code. * @param aStatusCodeException {@link StatusCodeException} which occurred with the status code * @return true when it is a notable error status code, otherwise false */ private boolean isNotableStatusCode(StatusCodeException aStatusCodeException) { return aStatusCodeException.getStatusCode() != 0; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy