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.connection.strategy.connector.streaming;
023
024import com.google.gwt.core.client.GWT;
025import com.google.gwt.user.client.rpc.SerializationException;
026import com.google.gwt.user.client.rpc.SerializationStreamFactory;
027import com.google.gwt.user.client.rpc.SerializationStreamReader;
028import com.google.gwt.user.client.rpc.ServiceDefTarget;
029import com.google.gwt.user.client.ui.Frame;
030import com.google.gwt.user.client.ui.RootPanel;
031import de.novanic.eventservice.client.event.DomainEvent;
032import de.novanic.eventservice.client.event.RemoteEventServiceRuntimeException;
033import de.novanic.eventservice.client.event.service.EventService;
034import de.novanic.eventservice.client.event.service.EventServiceAsync;
035
036/**
037 * The {@link de.novanic.eventservice.client.connection.strategy.connector.ConnectionStrategyClientConnector} listens for occurred events ({@link de.novanic.eventservice.client.event.Event})
038 * of the server side and has the task to encode / process the transferred events at the client side.
039 *
040 * The {@link de.novanic.eventservice.client.connection.strategy.connector.streaming.GWTStreamingClientConnector} is an
041 * GWT specific implementation of streaming. It implements the forever frame technique with a high number of GWT on-board methods.
042 *
043 * Streaming means that the connection is hold open for a specified time and when an event
044 * occurs, the answer / event is streamed directly to the client without closing and re-open the connection. The connection is
045 * closed and re-opened (by the client) when the configured max. waiting time is reached.
046 *
047 * @author sstrohschein
048 *         <br>Date: 25.04.2010
049 *         <br>Time: 23:02:50
050 */
051public class GWTStreamingClientConnector extends DefaultStreamingClientConnector
052{
053    private Frame myStreamingConnectorFrame;
054    private String myServiceURL;
055
056    /**
057     * Initializes the {@link de.novanic.eventservice.client.connection.strategy.connector.ConnectionStrategyClientConnector} with
058     * the {@link de.novanic.eventservice.client.event.service.EventServiceAsync}.
059     *
060     * That implementation prepares the processing of occurred, serialized events.
061     * @param anEventService the {@link de.novanic.eventservice.client.event.service.EventServiceAsync}
062     */
063    public void init(EventServiceAsync anEventService) {
064        myServiceURL = ((ServiceDefTarget)anEventService).getServiceEntryPoint();
065        initReceiveEventScript(this);
066        super.init(anEventService);
067    }
068
069    /**
070     * Deactivates the {@link de.novanic.eventservice.client.connection.strategy.connector.ConnectionStrategyClientConnector}.
071     *
072     * That implementation removes the forever frame, so the listening is stopped and cleared up. 
073     */
074    public void deactivate() {
075        if(myStreamingConnectorFrame != null) {
076            RootPanel.get().remove(myStreamingConnectorFrame);
077            myStreamingConnectorFrame = null;
078        }
079    }
080
081    /**
082     * Initializes or refreshes the forever frame.
083     */
084    private void initStreamingConnectorFrame() {
085        if(myStreamingConnectorFrame == null) {
086                        myStreamingConnectorFrame = new Frame(myServiceURL);
087                        myStreamingConnectorFrame.setVisible(false);
088                RootPanel.get().add(myStreamingConnectorFrame);
089        } else {
090                //refresh / restart the connection
091                myStreamingConnectorFrame.setUrl(myServiceURL);
092        }
093    }
094
095    /**
096     * De-serializes an occurred event with GWT serialization methods.
097     * @param anEvent event to de-serialize
098     * @return de-serialized event
099     */
100    protected DomainEvent deserializeEvent(String anEvent) {
101        try {
102            SerializationStreamFactory theSerializationStreamFactory = GWT.create(EventService.class);
103            SerializationStreamReader theSerializationStreamReader = theSerializationStreamFactory.createStreamReader(anEvent);
104            return (DomainEvent)theSerializationStreamReader.readObject();
105        } catch(SerializationException e) {
106            throw new RemoteEventServiceRuntimeException("Error on de-serializing event \"" + anEvent + "\"!", e);
107        }
108    }
109
110    /**
111     * Initializes or refreshes the forever frame (see {@link GWTStreamingClientConnector#initStreamingConnectorFrame()}).
112     */
113    protected void listen() {
114        initStreamingConnectorFrame();
115    }
116
117    /**
118     * Initializes the processing of occurring events.
119     * @param aThisReference reference
120     */
121    private native void initReceiveEventScript(DefaultStreamingClientConnector aThisReference) /*-{
122        $wnd.receiveEvent = function(anEvent) { aThisReference.@de.novanic.eventservice.client.connection.strategy.connector.streaming.GWTStreamingClientConnector::receiveEvent(Ljava/lang/String;)(anEvent) };
123        }-*/;
124}