Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
rhbz833639 Remove editor clients on GWTEventService timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
seanf committed Aug 13, 2012
1 parent 8b5e845 commit d0b7054
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 19 deletions.
@@ -0,0 +1,56 @@
/*
* Copyright 2012, Red Hat, Inc. and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* 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 2.1 of
* the License, or (at your option) any later version.
*
* 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 org.zanata.eventservice;

import javax.servlet.http.HttpServletRequest;

import lombok.Synchronized;

import de.novanic.eventservice.service.connection.id.ConnectionIdGenerator;

/**
* @author Sean Flanigan <a href="mailto:sflaniga@redhat.com">sflaniga@redhat.com</a>
*
*/
public class SequentialConnectionIdGenerator implements ConnectionIdGenerator
{
private static long nextConnectionNum = 0;

@Synchronized
private static long generateConnectionNum()
{
return nextConnectionNum++;
}

@Override
public String generateConnectionId(HttpServletRequest aRequest)
{
return String.valueOf(aRequest.getSession(true).getId() + "-" + generateConnectionNum());
}

@Override
public String getConnectionId(HttpServletRequest aRequest)
{
return aRequest.getParameter("id");
}

}
Expand Up @@ -10,10 +10,12 @@
import org.zanata.webtrans.shared.model.ProjectIterationId;
import org.zanata.webtrans.shared.model.UserWorkspaceContext;
import org.zanata.webtrans.shared.model.WorkspaceId;
import org.zanata.webtrans.shared.rpc.EventServiceConnectedAction;
import org.zanata.webtrans.shared.rpc.ActivateWorkspaceAction;
import org.zanata.webtrans.shared.rpc.ActivateWorkspaceResult;
import org.zanata.webtrans.shared.rpc.ExitWorkspaceAction;
import org.zanata.webtrans.shared.rpc.ExitWorkspaceResult;
import org.zanata.webtrans.shared.rpc.NoOpResult;

import com.allen_sauer.gwt.log.client.Log;
import com.google.common.base.Strings;
Expand Down Expand Up @@ -127,9 +129,22 @@ public void onWindowClosing(ClosingEvent event)
eventProcessor.start(new StartCallback()
{
@Override
public void onSuccess()
public void onSuccess(String connectionId)
{
delayedStartApp();
// tell server the ConnectionId for this EditorClientId
injector.getDispatcher().execute(new EventServiceConnectedAction(connectionId), new AsyncCallback<NoOpResult>()
{
@Override
public void onFailure(Throwable e)
{
RootLayoutPanel.get().add(new HTML("<h1>Server communication failed...</h1>" + "<b>Exception:</b> " + e.getMessage()));
}
@Override
public void onSuccess(NoOpResult result)
{
delayedStartApp();
}
});
}

@Override
Expand Down
Expand Up @@ -32,6 +32,7 @@
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;

import de.novanic.eventservice.client.config.ConfigurationTransferableDependentFactory;
import de.novanic.eventservice.client.event.Event;
import de.novanic.eventservice.client.event.RemoteEventService;
import de.novanic.eventservice.client.event.RemoteEventServiceFactory;
Expand All @@ -49,8 +50,7 @@ private interface EventFactory<T extends GwtEvent<?>>

public static interface StartCallback
{
void onSuccess();

void onSuccess(String connectionId);
void onFailure(Throwable e);
}

Expand Down Expand Up @@ -153,7 +153,8 @@ public void start(final StartCallback callback)
public void onSuccess(Void result)
{
Log.info("EventProcessor is now listening for events in the domain " + domain.getName());
callback.onSuccess();
String connectionId = ConfigurationTransferableDependentFactory.getConfiguration().getConnectionId();
callback.onSuccess(connectionId);
}

@Override
Expand Down
Expand Up @@ -46,4 +46,5 @@ public interface TranslationWorkspace
WorkspaceContext getWorkspaceContext();
void updateUserSelection(EditorClientId editorClientId, TransUnit selectedTransUnit);
TransUnit getUserSelection(EditorClientId editorClientId);
public void onEventServiceConnected(EditorClientId editorClientId, String connectionId);
}
@@ -1,6 +1,7 @@
package org.zanata.webtrans.server;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
Expand All @@ -14,11 +15,13 @@
import org.zanata.webtrans.shared.model.TransUnit;
import org.zanata.webtrans.shared.model.TransUnitId;
import org.zanata.webtrans.shared.model.WorkspaceContext;
import org.zanata.webtrans.shared.rpc.ExitWorkspace;
import org.zanata.webtrans.shared.rpc.SessionEventData;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;

Expand All @@ -38,13 +41,16 @@ public class TranslationWorkspaceImpl implements TranslationWorkspace
private final Domain domain;
private final ConcurrentMap<EditorClientId, PersonSessionDetails> sessions = new MapMaker().makeMap();
private final Multimap<String, EditorClientId> httpSessionToEditorClientId;
private final Map<String, EditorClientId> connectionIdToEditorClientId;
private final ConcurrentMap<TransUnitId, String> editstatus = new MapMaker().makeMap();

private final EventExecutorService eventExecutorService;

{
ArrayListMultimap<String, EditorClientId> almm = ArrayListMultimap.create();
httpSessionToEditorClientId = Multimaps.synchronizedListMultimap(almm);
Map<String, EditorClientId> connMap = Maps.newHashMap();
connectionIdToEditorClientId = Collections.synchronizedMap(connMap);
}

public TranslationWorkspaceImpl(WorkspaceContext workspaceContext)
Expand All @@ -64,9 +70,16 @@ public TranslationWorkspaceImpl(WorkspaceContext workspaceContext)
public void onTimeout(UserInfo userInfo)
{
String connectionId = userInfo.getUserId();
log.info("Timeout for GWTEventService connectionId {0}", connectionId);
// TODO look up EditorClientId for connectionId
// removeEditorClient(editorClientId);
EditorClientId editorClientId = connectionIdToEditorClientId.remove(connectionId);
if (editorClientId != null)
{
log.info("Timeout for GWTEventService connectionId {0}; removing EditorClientId {1}", connectionId, editorClientId);
removeEditorClient(editorClientId);
}
else
{
log.info("Timeout for GWTEventService connectionId {0}; nothing to do", connectionId);
}
}
});
}
Expand Down Expand Up @@ -136,6 +149,13 @@ public void addEditorClient(String httpSessionId, EditorClientId editorClientId,
httpSessionToEditorClientId.put(httpSessionId, editorClientId);
}

@Override
public void onEventServiceConnected(EditorClientId editorClientId, String connectionId)
{
log.info("EditorClientId {0} has connectionId {1}", editorClientId, connectionId);
connectionIdToEditorClientId.put(connectionId, editorClientId);
}

@Override
public Collection<EditorClientId> removeEditorClients(String httpSessionId)
{
Expand All @@ -160,6 +180,11 @@ public boolean removeEditorClient(EditorClientId editorClientId)
if (clientIds != null)
{
clientIds.remove(editorClientId);

// Send GWT Event to clients to update the user list
ExitWorkspace event = new ExitWorkspace(editorClientId, details.getPerson());
publish(event);

log.info("Removed user {0} with editorClientId {1} from workspace {2}", details.getPerson().getId(), editorClientId, workspaceContext);
return true;
}
Expand Down
@@ -0,0 +1,39 @@
package org.zanata.webtrans.server.rpc;

import net.customware.gwt.dispatch.server.ExecutionContext;
import net.customware.gwt.dispatch.shared.ActionException;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.zanata.security.ZanataIdentity;
import org.zanata.webtrans.server.ActionHandlerFor;
import org.zanata.webtrans.server.TranslationWorkspace;
import org.zanata.webtrans.server.TranslationWorkspaceManager;
import org.zanata.webtrans.shared.rpc.EventServiceConnectedAction;
import org.zanata.webtrans.shared.rpc.NoOpResult;

@Name("webtrans.gwt.ActivateEventServiceHandler")
@Scope(ScopeType.STATELESS)
@ActionHandlerFor(EventServiceConnectedAction.class)
public class EventServiceConnectedHandler extends AbstractActionHandler<EventServiceConnectedAction, NoOpResult>
{

@In
TranslationWorkspaceManager translationWorkspaceManager;

@Override
public NoOpResult execute(EventServiceConnectedAction action, ExecutionContext context) throws ActionException
{
ZanataIdentity.instance().checkLoggedIn();
TranslationWorkspace workspace = translationWorkspaceManager.getOrRegisterWorkspace(action.getWorkspaceId());
workspace.onEventServiceConnected(action.getEditorClientId(), action.getConnectionId());
return new NoOpResult();
}

@Override
public void rollback(EventServiceConnectedAction action, NoOpResult result, ExecutionContext context) throws ActionException
{
}
}
Expand Up @@ -11,7 +11,6 @@
import org.zanata.webtrans.server.ActionHandlerFor;
import org.zanata.webtrans.server.TranslationWorkspace;
import org.zanata.webtrans.server.TranslationWorkspaceManager;
import org.zanata.webtrans.shared.rpc.ExitWorkspace;
import org.zanata.webtrans.shared.rpc.ExitWorkspaceAction;
import org.zanata.webtrans.shared.rpc.ExitWorkspaceResult;

Expand All @@ -33,14 +32,7 @@ public ExitWorkspaceResult execute(ExitWorkspaceAction action, ExecutionContext
TranslationWorkspace workspace = translationWorkspaceManager.getOrRegisterWorkspace(action.getWorkspaceId());

// Send ExitWorkspace event to client
boolean isRemoved = workspace.removeEditorClient(action.getEditorClientId());
if (isRemoved)
{
// Send GWT Event to client to update the userlist
ExitWorkspace event = new ExitWorkspace(action.getEditorClientId(), action.getPerson());
workspace.publish(event);
}

workspace.removeEditorClient(action.getEditorClientId());
return new ExitWorkspaceResult(action.getPerson().getId().toString());
}

Expand Down
@@ -0,0 +1,25 @@
package org.zanata.webtrans.shared.rpc;


public class EventServiceConnectedAction extends AbstractWorkspaceAction<NoOpResult>
{

private static final long serialVersionUID = 1L;
private String connectionId;

@SuppressWarnings("unused")
private EventServiceConnectedAction()
{
}

public EventServiceConnectedAction(String connectionId)
{
this.connectionId = connectionId;
}

public String getConnectionId()
{
return connectionId;
}

}
@@ -1,6 +1,7 @@
package org.zanata.webtrans.shared.rpc;


// TODO replace this class with NoOpResult
public class ExitWorkspaceResult implements DispatchResult
{

Expand Down
@@ -1,6 +1,7 @@
package org.zanata.webtrans.shared.rpc;


//TODO replace this class with NoOpResult
public class PublishWorkspaceChatResult implements DispatchResult
{
private static final long serialVersionUID = -611647552706494146L;
Expand Down
@@ -1,6 +1,7 @@
package org.zanata.webtrans.shared.rpc;


//TODO replace this class with NoOpResult
public class TransUnitEditResult implements DispatchResult
{
private static final long serialVersionUID = -950617414456103445L;
Expand Down
3 changes: 1 addition & 2 deletions zanata-war/src/main/resources/eventservice.properties
Expand Up @@ -10,8 +10,7 @@ time.waiting.min=0
time.timeout=90000

# Generator for unique client ids
#eventservice.connection.id.generator=de.novanic.eventservice.service.connection.id.SessionConnectionIdGenerator
eventservice.connection.id.generator=de.novanic.eventservice.service.connection.id.SessionExtendedConnectionIdGenerator
eventservice.connection.id.generator=org.zanata.eventservice.SequentialConnectionIdGenerator

# Connection strategy (server side part / connector) to define the transfer of events between client and server side
eventservice.connection.strategy.server.connector=de.novanic.eventservice.service.connection.strategy.connector.longpolling.LongPollingServerConnector

0 comments on commit d0b7054

Please sign in to comment.