// Copyright 2012 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.collide.client.collaboration; import com.google.collide.client.communication.MessageFilter; import com.google.collide.client.communication.MessageFilter.MessageRecipient; import com.google.collide.dto.DocOp; import com.google.collide.dto.RoutingTypes; import com.google.collide.dto.ServerToClientDocOp; import com.google.collide.dto.client.DtoClientImpls.ServerToClientDocOpImpl; import com.google.collide.dto.client.DtoClientImpls.ServerToClientDocOpsImpl; import com.google.collide.json.shared.JsonArray; import com.google.collide.json.shared.JsonStringMap; import com.google.collide.shared.util.JsonCollections; /** * Receives {@link ServerToClientDocOp} from the {@link MessageFilter} and * forwards them. */ public class IncomingDocOpDemultiplexer { public static IncomingDocOpDemultiplexer create(MessageFilter messageFilter) { IncomingDocOpDemultiplexer receiver = new IncomingDocOpDemultiplexer(messageFilter); messageFilter.registerMessageRecipient(RoutingTypes.SERVERTOCLIENTDOCOP, receiver.messageReceiver); messageFilter.registerMessageRecipient(RoutingTypes.SERVERTOCLIENTDOCOPS, receiver.bulkMessageReceiver); return receiver; } public interface Receiver { /* * TODO: if a client wants to have in-order doc ops, we should * really be passing each DocOpReceiver the list of BulkReceivers so it can * callback the same time it would normally call into the OT stack (this * ensures ordering and even recovered doc ops). */ /** * Called when a doc op is received from the server. These may be * out-of-order and during doc op recovery, this will NOT be called. */ void onDocOpReceived(ServerToClientDocOpImpl docOpDto, DocOp docOp); } private final MessageFilter.MessageRecipient<ServerToClientDocOpImpl> messageReceiver = new MessageRecipient<ServerToClientDocOpImpl>() { @Override public void onMessageReceived(ServerToClientDocOpImpl message) { handleServerToClientDocOpMsg(message); } }; private final MessageFilter.MessageRecipient<ServerToClientDocOpsImpl> bulkMessageReceiver = new MessageRecipient<ServerToClientDocOpsImpl>() { @Override public void onMessageReceived(ServerToClientDocOpsImpl message) { for (int i = 0, n = message.getDocOps().size(); i < n; i++) { handleServerToClientDocOpMsg((ServerToClientDocOpImpl) message.getDocOps().get(i)); } } }; /** Map from file edit session key to receiver */ private final JsonStringMap<Receiver> receivers = JsonCollections.createMap(); private final JsonArray<Receiver> bulkReceivers = JsonCollections.createArray(); private final MessageFilter messageFilter; private IncomingDocOpDemultiplexer(MessageFilter messageFilter) { this.messageFilter = messageFilter; } public void teardown() { messageFilter.removeMessageRecipient(RoutingTypes.SERVERTOCLIENTDOCOP); } /** * Adds a {@link Receiver} that will receive all DocOp messages. */ public void addBulkReceiver(Receiver receiver) { bulkReceivers.add(receiver); } public void removeBulkReceiver(Receiver receiver) { bulkReceivers.remove(receiver); } public void setReceiver(String fileEditSessionKey, Receiver receiver) { receivers.put(fileEditSessionKey, receiver); } public void handleServerToClientDocOpMsg(ServerToClientDocOpImpl message) { // Early exit if nobody is listening. Receiver receiver = receivers.get(message.getFileEditSessionKey()); if (receiver == null && bulkReceivers.size() == 0) { return; } DocOp docOp = message.getDocOp2(); // Send to the registered receiver for the file edit session. if (receiver != null) { receiver.onDocOpReceived(message, docOp); } // Send to bulk receivers. for (int i = 0; i < bulkReceivers.size(); i++) { bulkReceivers.get(i).onDocOpReceived(message, docOp); } } }