Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.coweb.LateJoinHandler Maven / Gradle / Ivy
package org.coweb;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.logging.Logger;
import org.cometd.bayeux.Message;
import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.bayeux.server.ConfigurableServerChannel;
import org.cometd.bayeux.server.ServerChannel;
import org.cometd.bayeux.server.ServerMessage;
import org.cometd.bayeux.server.ServerSession;
import org.cometd.bayeux.server.LocalSession;
import org.eclipse.jetty.util.ajax.JSON;
//import org.coweb.LateJoinHandler.BatchUpdateMessage;
public class LateJoinHandler {
protected SessionHandler sessionHandler = null;
protected ServiceHandler serviceHandler = null;
protected SessionManager sessionManager = null;
protected SessionModerator sessionModerator = null;
protected UpdaterTypeMatcher updaterTypeMatcher = null;
protected boolean cacheState = true;
private static final Logger log = Logger.getLogger(LateJoinHandler.class
.getName());
private Map updatees = new HashMap();
protected Map> updaters = new HashMap>();
/**
* List of available siteids. An index with a null value is an available
* siteid, otherwise the slot is filled with ServerSession's clientid (i.e.
* {@link org.cometd.bayeux.Session#getId}).
*/
protected ArrayList siteids = new ArrayList(5);
private Object[] lastState = null;
/**
* Map of bayeux client id to ServerSession. "clientId" is defined as the return value
* of {@link org.cometd.bayeux.Session#getId}. For LocalSession/ServerSession pairs, the
* values are identical (e.g. for the SessionModerator Session pair).
*/
private Map clientids = new HashMap();
public LateJoinHandler(SessionHandler sessionHandler,
Map config) {
this.siteids.add(0, "reserved");
for (int i = 1; i < 5; i++) {
this.siteids.add(i, null);
}
this.sessionHandler = sessionHandler;
this.serviceHandler = this.sessionHandler.getServiceHandler();
this.sessionManager = SessionManager.getInstance();
if (config.containsKey("cacheState")) {
this.cacheState = ((Boolean) config.get("cacheState"))
.booleanValue();
}
String classStr = "org.coweb.DefaultUpdaterTypeMatcher";
if (config.containsKey("updaterTypeMatcher")) {
classStr = (String) config.get("updaterTypeMatcher");
}
try {
Class extends UpdaterTypeMatcher> c = Class.forName(classStr)
.asSubclass(UpdaterTypeMatcher.class);
this.updaterTypeMatcher = c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// get the moderator
this.sessionModerator = sessionHandler.getSessionModerator();
ServerSession client = this.sessionModerator.getServerSession();
// make sure the moderator has joined the conference and has a site
// id before anyone joins. User slot 0 for moderator.
this.siteids.set(0, client.getId());
this.sessionModerator.setSessionAttribute("siteid", new Integer(0));
this.clientids.put(client.getId(), client);
//this.addUpdater(client, false);
}
public ServerSession getServerSessionFromSiteid(String siteStr) {
try {
int siteid = Integer.valueOf(siteStr);
String clientId = this.siteids.get(siteid);
if (clientId == null)
return null;
return this.clientids.get(clientId);
} catch (Exception e) {
;
}
return null;
}
public void clearCacheState() {
this.lastState = null;
}
public void onClientJoin(ServerSession client, Message message) {
int siteId = this.getSiteForClient(client);
log.info("client site id = " + siteId);
if (siteId == -1) {
siteId = this.addSiteForClient(client);
log.info("new site id = " + siteId);
}
Map roster = this.getRosterList(client);
// ArrayListdata = new ArrayList();
Object[] data = new Object[0];
log.fine("data = " + data);
boolean sendState = false;
Map ext = message.getExt();
@SuppressWarnings("unchecked")
Map cobwebData = (Map) ext.get("coweb");
String updaterType = (String) cobwebData.get("updaterType");
client.setAttribute("updaterType", updaterType);
log.info("updaterType = " + updaterType);
if (this.updaters.isEmpty()) {
this.addUpdater(client, false);
sendState = true;
} else if (this.lastState == null) {
this.assignUpdater(client, updaterType);
sendState = false;
} else {
data = this.lastState;
sendState = true;
}
client.batch(new BatchUpdateMessage(client, siteId, roster, data,
sendState));
}
public void onUpdaterSendState(ServerSession client, Message message) {
//log.info(message.getJSON());
String clientId = client.getId();
Map data = message.getDataAsMap();
String token = (String) data.get("token");
if (token == null) {
this.sessionHandler.removeBadClient(client);
return;
}
List tokens = this.updaters.get(clientId);
if (tokens == null) {
this.sessionHandler.removeBadClient(client);
return;
}
if (!tokens.remove(token)) {
this.sessionHandler.removeBadClient(client);
return;
}
ServerSession updatee = this.updatees.get(token);
if (updatee == null)
return;
this.updatees.remove(token);
if (this.cacheState) {
this.lastState = (Object[]) data.get("state");
log.fine("got state from client");
log.fine(JSON.toString(this.lastState));
}
ServerMessage.Mutable msg = this.sessionManager.getBayeux()
.newMessage();
msg.setChannel("/service/session/join/state");
if (this.cacheState) {
log.info("sending cached state");
msg.setData(this.lastState);
} else {
log.info("sending state from updater");
msg.setData((Object[]) data.get("state"));
}
msg.setLazy(false);
updatee.deliver(this.sessionManager.getServerSession(), msg);
}
public void onUpdaterSubscribe(ServerSession client, Message message) {
this.addUpdater(client, true);
}
/**
* returns true if this was the last updater.
*/
public boolean onClientRemove(ServerSession client) {
log.info("siteId = " + client.getAttribute("siteid"));
this.removeUpdater(client);
if (this.getUpdaterCount() == 0) {
log.info("removing last updater, ending coweb session");
return true;
}
return false;
}
public boolean onEndSession() {
this.updatees.clear();
this.updaters.clear();
this.siteids.clear();
this.lastState = null;
this.clientids.clear();
return true;
}
protected void addUpdater(ServerSession serverSession, boolean notify) {
String clientId = serverSession.getId();
// check if this client is already an updater and ignore unless this is
// the first updater
if (this.updaters.containsKey(clientId) && !this.updaters.isEmpty()) {
return;
}
// serverSession.setAttribute("username", clientId);
log.fine("adding " + clientId + " to list of updaters");
this.updaters.put(clientId, new ArrayList());
if (notify) {
this.sendRosterAvailable(serverSession);
}
}
private void sendRosterAvailable(ServerSession client) {
log.info("sending roster available");
ServerSession from = this.sessionManager.getServerSession();
Integer siteId = (Integer) client.getAttribute("siteid");
String username = (String) client.getAttribute("username");
Map data = new HashMap();
data.put("siteId", siteId);
data.put("username", username);
String rosterAvailableChannel = this.sessionHandler
.getRosterAvailableChannel();
for (ServerSession c : this.sessionHandler.getAttendees()) {
c.deliver(from, rosterAvailableChannel, data, null);
}
}
protected void sendRosterUnavailable(ServerSession client) {
log.fine("CollabSessionHandler::sendRosterAvailable");
/* create channel */
BayeuxServer server = this.sessionManager.getBayeux();
ServerChannel.Initializer initializer = new ServerChannel.Initializer() {
@Override
public void configureChannel(ConfigurableServerChannel channel) {
channel.setPersistent(true);
}
};
String rosterUnavailableChannel = this.sessionHandler
.getRosterUnavailableChannel();
server.createIfAbsent(rosterUnavailableChannel, initializer);
ServerChannel channel = server.getChannel(rosterUnavailableChannel);
if (channel == null) {
return;
}
ServerSession from = this.sessionManager.getServerSession();
Integer siteId = (Integer) client.getAttribute("siteid");
String username = (String) client.getAttribute("username");
Map data = new HashMap();
data.put("siteId", siteId);
data.put("username", username);
log.fine(data.toString());
channel.publish(from, data, null);
}
public String toString() {
return "LateJoinHandler";
}
protected int getSiteForClient(ServerSession client) {
if (this.siteids.contains(client.getId())) {
return this.siteids.indexOf(client.getId());
}
return -1;
}
protected int addSiteForClient(ServerSession client) {
int index = this.siteids.indexOf(null);
if (index == -1) {
index = this.siteids.size();
this.siteids.ensureCapacity(this.siteids.size() + 1);
this.siteids.add(index, client.getId());
} else
this.siteids.set(index, client.getId());
client.setAttribute("siteid", new Integer(index));
this.clientids.put(client.getId(), client);
return index;
}
protected int removeSiteForClient(ServerSession client) {
if (client == null) {
log.severe("removeSiteForClient ******* client is null *******");
return -1;
}
int siteid = this.siteids.indexOf(client.getId());
if (siteid == -1) {
log.severe("removeSiteForClient ****** Cannot find client in siteids list *******");
Integer i = (Integer) client.getAttribute("siteid");
if (i == null) {
log.severe("******* Client Does not have siteId attribute - Ghost *******");
}
return -1;
}
this.siteids.set(siteid, null);
return siteid;
}
protected Map getRosterList(ServerSession client) {
Map roster = new HashMap();
for (String clientId : this.updaters.keySet()) {
ServerSession c = this.clientids.get(clientId);
Integer siteId = (Integer) c.getAttribute("siteid");
roster.put(siteId, (String) c.getAttribute("username"));
}
return roster;
}
private void assignUpdater(ServerSession updatee, String updaterType) {
log.info("assignUpdater *****************");
ServerSession from = this.sessionManager.getServerSession();
if (this.updaters.isEmpty()) {
this.addUpdater(updatee, false);
((ServerSession)updatee).deliver(from, "/service/session/join/state",
new ArrayList(), null);
return;
}
String updaterId = null;
ServerSession updater = null;
if (!updaterType.equals("default")) {
String matchedType = updaterTypeMatcher.match(updaterType,
getAvailableUpdaterTypes());
if (matchedType != null) {
for (String id : this.updaters.keySet()) {
updater = this.clientids.get(id);
if (updater.getAttribute("updaterType").equals(matchedType)) {
updaterId = id;
log.info("found an updater type matched to ["
+ matchedType + "]");
break;
}
}
}
}
if (updaterId == null) {
Random r = new Random();
int idx = r.nextInt(this.updaters.size());
log.info("using default updater type");
Object[] keys = this.updaters.keySet().toArray();
updaterId = (String) keys[idx];
updater = this.clientids.get(updaterId);
}
log.info("assigning updater " + updater.getAttribute("siteid") + " to "
+ updatee.getAttribute("siteid"));
SecureRandom s = new SecureRandom();
String token = new BigInteger(130, s).toString(32);
// .println("found updater " + updaterId);
(this.updaters.get(updaterId)).add(token);
this.updatees.put(token, updatee);
updater.deliver(from, "/service/session/updater", token, null);
}
protected void removeUpdater(ServerSession client) {
log.fine("CollabDelegate::removeUpdater " + client);
this.removeSiteForClient(client);
List tokenList = this.updaters.get(client.getId());
this.updaters.remove(client.getId());
if (tokenList == null) {
for (String token : this.updatees.keySet()) {
ServerSession updatee = this.updatees.get(token);
if (updatee.getId().equals(client.getId())) {
this.updatees.remove(token);
}
}
} else {
log.fine("sending roster unavailable");
this.sendRosterUnavailable(client);
if (!tokenList.isEmpty()) {
log.fine("this updater was updating someone");
for (String token : tokenList) {
ServerSession updatee = this.updatees.get(token);
if (updatee == null)
continue;
// this.updatees.remove(token);
String updaterType = (String) client
.getAttribute("updaterType");
if (updaterType == null) {
updaterType = "default";
}
this.assignUpdater(updatee, updaterType);
}
}
}
}
private int getUpdaterCount() {
return this.updaters.size();
}
private List getAvailableUpdaterTypes() {
List availableUpdaterTypes = new ArrayList();
for (String id : this.updaters.keySet()) {
ServerSession updater = this.clientids.get(id);
availableUpdaterTypes.add((String) updater
.getAttribute("updaterType"));
}
return availableUpdaterTypes;
}
class BatchUpdateMessage implements Runnable {
private ServerSession client = null;
private Object data = null;
private Map roster = null;
private int siteId = -1;
private boolean sendState = false;
/**
*
* Sends all the important information to a client upon joining.
* The data parameter should be an Object[] with three elements:
*
* [{topic: coweb.state.set.collab_name, value: application state}, ...] (this will be an array)
* {topic: coweb.engine.state, value: TODO}
* {topic: coweb.pause.state, value: TODO}
*
*
* @param siteId site id
* @param roster current session roster
* @param data session state
* @param sendState whether or not to send session state
*/
BatchUpdateMessage(ServerSession client, int siteId, Map roster,
Object data, boolean sendState) {
this.client = client;
this.siteId = siteId;
this.roster = roster;
this.data = data;
this.sendState = sendState;
}
@Override
public void run() {
SessionManager manager = SessionManager.getInstance();
ServerSession server = manager.getServerSession();
this.client.deliver(server, "/service/session/join/siteid",
this.siteId, null);
this.client.deliver(server, "/service/session/join/roster",
this.roster, null);
if (this.sendState) {
this.client.deliver(server, "/service/session/join/state",
this.data, null);
}
}
}
}