http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/operations/SearchService.java
----------------------------------------------------------------------
diff --git 
a/src/org/waveprotocol/box/server/robots/operations/SearchService.java 
b/src/org/waveprotocol/box/server/robots/operations/SearchService.java
deleted file mode 100644
index e8eeedd..0000000
--- a/src/org/waveprotocol/box/server/robots/operations/SearchService.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.operations;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.inject.Inject;
-import com.google.wave.api.InvalidRequestException;
-import com.google.wave.api.JsonRpcConstant.ParamsProperty;
-import com.google.wave.api.OperationRequest;
-import com.google.wave.api.SearchResult;
-import org.waveprotocol.box.server.robots.OperationContext;
-import org.waveprotocol.box.server.robots.util.OperationUtil;
-import org.waveprotocol.box.server.waveserver.SearchProvider;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import java.util.Map;
-
-/**
- * {@link OperationService} for the "search" operation.
- *
- * @author [email protected] (Lennard de Rijk)
- * @author [email protected] (Joseph Gentle)
- */
-public class SearchService implements OperationService {
-
-  /**
-   * The number of search results to return if not defined in the request.
-   * Defined in the spec.
-   */
-  private static final int DEFAULT_NUMBER_SEARCH_RESULTS = 10;
-
-  private final SearchProvider searchProvider;
-
-  @Inject
-  public SearchService(SearchProvider searchProvider) {
-    this.searchProvider = searchProvider;
-  }
-
-  @Override
-  public void execute(
-      OperationRequest operation, OperationContext context, ParticipantId 
participant)
-      throws InvalidRequestException {
-    String query = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.QUERY);
-    int index = OperationUtil.getOptionalParameter(operation, 
ParamsProperty.INDEX, 0);
-    int numResults = OperationUtil.getOptionalParameter(
-        operation, ParamsProperty.NUM_RESULTS, DEFAULT_NUMBER_SEARCH_RESULTS);
-
-    SearchResult result = search(participant, query, index, numResults);
-
-    Map<ParamsProperty, Object> data =
-        ImmutableMap.<ParamsProperty, Object> 
of(ParamsProperty.SEARCH_RESULTS, result);
-    context.constructResponse(operation, data);
-  }
-
-  // Note that this search implementation is only of prototype quality.
-  private SearchResult search(
-      ParticipantId participant, String query, int startAt, int numResults) {
-    return searchProvider.search(participant, query, startAt, numResults);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/operations/WaveletSetTitleService.java
----------------------------------------------------------------------
diff --git 
a/src/org/waveprotocol/box/server/robots/operations/WaveletSetTitleService.java 
b/src/org/waveprotocol/box/server/robots/operations/WaveletSetTitleService.java
deleted file mode 100644
index ee52fc9..0000000
--- 
a/src/org/waveprotocol/box/server/robots/operations/WaveletSetTitleService.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.operations;
-
-import com.google.wave.api.InvalidRequestException;
-import com.google.wave.api.JsonRpcConstant.ParamsProperty;
-import com.google.wave.api.OperationRequest;
-
-import org.waveprotocol.box.server.robots.OperationContext;
-import org.waveprotocol.box.server.robots.util.OperationUtil;
-import org.waveprotocol.wave.model.conversation.ObservableConversation;
-import org.waveprotocol.wave.model.conversation.TitleHelper;
-import org.waveprotocol.wave.model.document.Document;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-
-/**
- * Implements the "wavelet.setTitle" operation.
- *
- * @author [email protected] (Yuri Zelikov)
- */
-public class WaveletSetTitleService implements OperationService {
-
-  @Override
-  public void execute(
-      OperationRequest operation, OperationContext context, ParticipantId 
participant)
-      throws InvalidRequestException {
-    
-    String title =
-        OperationUtil.getRequiredParameter(operation, 
ParamsProperty.WAVELET_TITLE);
-    ObservableConversation conversation =
-        context.openConversation(operation, participant).getRoot();
-    String blipId = conversation.getRootThread().getFirstBlip().getId();
-    Document doc = context.getBlip(conversation, blipId).getContent();
-    TitleHelper.setExplicitTitle(doc, title);
-  }
-
-  public static WaveletSetTitleService create() {
-    return new WaveletSetTitleService();
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/passive/EventGenerator.java
----------------------------------------------------------------------
diff --git a/src/org/waveprotocol/box/server/robots/passive/EventGenerator.java 
b/src/org/waveprotocol/box/server/robots/passive/EventGenerator.java
deleted file mode 100644
index c45b73e..0000000
--- a/src/org/waveprotocol/box/server/robots/passive/EventGenerator.java
+++ /dev/null
@@ -1,626 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.passive;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.wave.api.BlipData;
-import com.google.wave.api.Context;
-import com.google.wave.api.Gadget;
-import com.google.wave.api.data.converter.ContextResolver;
-import com.google.wave.api.data.converter.EventDataConverter;
-import com.google.wave.api.event.*;
-import com.google.wave.api.impl.EventMessageBundle;
-import com.google.wave.api.robot.Capability;
-import com.google.wave.api.robot.RobotName;
-import org.waveprotocol.box.server.robots.util.ConversationUtil;
-import org.waveprotocol.box.server.util.WaveletDataUtil;
-import org.waveprotocol.wave.model.conversation.*;
-import org.waveprotocol.wave.model.document.Doc.E;
-import org.waveprotocol.wave.model.document.Doc.N;
-import org.waveprotocol.wave.model.document.Doc.T;
-import org.waveprotocol.wave.model.document.DocHandler;
-import org.waveprotocol.wave.model.document.ObservableDocument;
-import org.waveprotocol.wave.model.document.indexed.DocumentEvent;
-import 
org.waveprotocol.wave.model.document.indexed.DocumentEvent.AnnotationChanged;
-import 
org.waveprotocol.wave.model.document.indexed.DocumentEvent.AttributesModified;
-import 
org.waveprotocol.wave.model.document.indexed.DocumentEvent.ContentInserted;
-import org.waveprotocol.wave.model.document.raw.impl.Node;
-import org.waveprotocol.wave.model.operation.OperationException;
-import org.waveprotocol.wave.model.operation.SilentOperationSink;
-import 
org.waveprotocol.wave.model.operation.wave.BasicWaveletOperationContextFactory;
-import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta;
-import org.waveprotocol.wave.model.operation.wave.WaveletBlipOperation;
-import org.waveprotocol.wave.model.operation.wave.WaveletOperation;
-import org.waveprotocol.wave.model.wave.*;
-import org.waveprotocol.wave.model.wave.data.ObservableWaveletData;
-import org.waveprotocol.wave.model.wave.opbased.OpBasedWavelet;
-import org.waveprotocol.wave.model.wave.opbased.WaveletListenerImpl;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Generates Robot API Events from operations applied to a Wavelet.
- *
- * <p>
- * Events that exist in the API:
- * <li>WaveletBlipCreated (DONE)</li>
- * <li>WaveletBlipRemoved (DONE)</li>
- * <li>WaveletParticipantsChanged (DONE)</li>
- * <li>WaveletSelfAdded (DONE)</li>
- * <li>WaveletSelfRemoved (DONE)</li>
- * <li>DocumentChanged (DONE)</li>
- * <li>AnnotatedTextChanged (DONE)</li>
- * <li>FormButtonClicked (TBD)</li>
- * <li>GadgetStateChanged (DONE)</li>
- * <li>BlipContributorChanged (TBD)</li>
- * <li>WaveletTagsChanged (TBD)</li>
- * <li>WaveletTitleChanged (TBD)</li>
- * <li>BlipSubmitted (Will not be supported, submit ops will be phased 
out)</li>
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public class EventGenerator {
-
-  private static class EventGeneratingWaveletListener extends 
WaveletListenerImpl {
-    @SuppressWarnings("unused")
-    private final Map<EventType, Capability> capabilities;
-
-    /**
-     * Creates a {@link WaveletListener} which will generate events according 
to
-     * the capabilities.
-     *
-     * @param capabilities the capabilities which we are interested in.
-     */
-    public EventGeneratingWaveletListener(Map<EventType, Capability> 
capabilities) {
-      this.capabilities = capabilities;
-    }
-    // TODO(ljvderijk): implement more events. This class should listen for
-    // non-conversational blip changes and robot data documents as indicated by
-    // IdConstants.ROBOT_PREFIX
-  }
-
-  private class EventGeneratingConversationListener extends 
ConversationListenerImpl {
-    private final Map<EventType, Capability> capabilities;
-    private final Conversation conversation;
-    private final EventMessageBundle messages;
-
-    // Event collectors
-    private final List<String> participantsAdded = Lists.newArrayList();
-    private final List<String> participantsRemoved = Lists.newArrayList();
-
-    // Changes for each delta
-    private ParticipantId deltaAuthor;
-    private Long deltaTimestamp;
-
-    /**
-     * Creates a {@link ObservableConversation.Listener} which will generate
-     * events according to the capabilities.
-     *
-     * @param conversation the conversation we are observing.
-     * @param capabilities the capabilities which we are interested in.
-     * @param messages the bundle to put the events in.
-     */
-    public EventGeneratingConversationListener(Conversation conversation,
-        Map<EventType, Capability> capabilities, EventMessageBundle messages, 
RobotName robotName) {
-      this.conversation = conversation;
-      this.capabilities = capabilities;
-      this.messages = messages;
-    }
-
-    /**
-     * Prepares this listener for events coming from a single delta.
-     *
-     * @param author the author of the delta.
-     * @param timestamp the timestamp of the delta.
-     */
-    public void deltaBegin(ParticipantId author, long timestamp) {
-      Preconditions.checkState(
-          deltaAuthor == null && deltaTimestamp == null, "DeltaEnd wasn't 
called");
-      Preconditions.checkNotNull(author, "Author should not be null");
-      Preconditions.checkNotNull(timestamp, "Timestamp should not be null");
-
-      deltaAuthor = author;
-      deltaTimestamp = timestamp;
-    }
-
-    @Override
-    public void onParticipantAdded(ParticipantId participant) {
-      if (capabilities.containsKey(EventType.WAVELET_PARTICIPANTS_CHANGED)) {
-        boolean removedBefore = 
participantsRemoved.remove(participant.getAddress());
-        if (!removedBefore) {
-          participantsAdded.add(participant.getAddress());
-        }
-      }
-
-      // This deviates from Google Wave production which always sends this
-      // event, even if it wasn't present in your capabilities.
-      if (capabilities.containsKey(EventType.WAVELET_SELF_ADDED) && 
participant.equals(robotId)) {
-        // The robot has been added
-        String rootBlipId = ConversationUtil.getRootBlipId(conversation);
-        WaveletSelfAddedEvent event = new WaveletSelfAddedEvent(
-            null, null, deltaAuthor.getAddress(), deltaTimestamp, rootBlipId);
-        addEvent(event, capabilities, rootBlipId, messages);
-      }
-    }
-
-    @Override
-    public void onParticipantRemoved(ParticipantId participant) {
-      if (capabilities.containsKey(EventType.WAVELET_PARTICIPANTS_CHANGED)) {
-        participantsRemoved.add(participant.getAddress());
-      }
-
-      if (capabilities.containsKey(EventType.WAVELET_SELF_REMOVED) && 
participant.equals(robotId)) {
-        String rootBlipId = ConversationUtil.getRootBlipId(conversation);
-        WaveletSelfRemovedEvent event = new WaveletSelfRemovedEvent(
-            null, null, deltaAuthor.getAddress(), deltaTimestamp, rootBlipId);
-        addEvent(event, capabilities, rootBlipId, messages);
-      }
-    }
-
-    @Override
-    public void onBlipAdded(ObservableConversationBlip blip) {
-      if (capabilities.containsKey(EventType.WAVELET_BLIP_CREATED)) {
-        String rootBlipId = ConversationUtil.getRootBlipId(conversation);
-        WaveletBlipCreatedEvent event = new WaveletBlipCreatedEvent(
-            null, null, deltaAuthor.getAddress(), deltaTimestamp, rootBlipId, 
blip.getId());
-        addEvent(event, capabilities, rootBlipId, messages);
-      }
-    }
-
-    @Override
-    public void onBlipDeleted(ObservableConversationBlip blip) {
-      if (capabilities.containsKey(EventType.WAVELET_BLIP_REMOVED)) {
-        String rootBlipId = ConversationUtil.getRootBlipId(conversation);
-        WaveletBlipRemovedEvent event = new WaveletBlipRemovedEvent(
-            null, null, deltaAuthor.getAddress(), deltaTimestamp, rootBlipId, 
blip.getId());
-        addEvent(event, capabilities, rootBlipId, messages);
-      }
-    }
-
-    /**
-     * Generates the events that are collected over the span of one delta.
-     */
-    public void deltaEnd() {
-      if (!participantsAdded.isEmpty() || !participantsRemoved.isEmpty()) {
-        String rootBlipId = ConversationUtil.getRootBlipId(conversation);
-
-        WaveletParticipantsChangedEvent event =
-            new WaveletParticipantsChangedEvent(null, null, 
deltaAuthor.getAddress(),
-                deltaTimestamp, rootBlipId, participantsAdded, 
participantsRemoved);
-        addEvent(event, capabilities, rootBlipId, messages);
-      }
-      clearOncePerDeltaCollectors();
-
-      deltaAuthor = null;
-      deltaTimestamp = null;
-    }
-
-    /**
-     * Clear the data structures responsible for collecting data for events 
that
-     * should only be fired once per delta.
-     */
-    private void clearOncePerDeltaCollectors() {
-      participantsAdded.clear();
-      participantsRemoved.clear();
-    }
-  }
-
-  private class EventGeneratingDocumentHandler implements DocHandler {
-
-    /** Public so we can manage the subscription */
-    public final ObservableDocument doc;
-
-    private final ConversationBlip blip;
-    private final Map<EventType, Capability> capabilities;
-    private final EventMessageBundle messages;
-    private ParticipantId deltaAuthor;
-    private Long deltaTimestamp;
-
-    /**
-     * Set to true if a {@link DocumentChangedEvent} has been generated by this
-     * handler.
-     */
-    private boolean documentChangedEventGenerated;
-
-    private EventDataConverter converter;
-    private Wavelet wavelet;
-
-    public EventGeneratingDocumentHandler(ObservableDocument doc, 
ConversationBlip blip,
-        Map<EventType, Capability> capabilities, EventMessageBundle messages,
-        ParticipantId deltaAuthor, Long deltaTimestamp, Wavelet wavelet,
-        EventDataConverter converter) {
-      this.doc = doc;
-      this.blip = blip;
-      this.capabilities = capabilities;
-      this.messages = messages;
-      this.converter = converter;
-      this.wavelet = wavelet;
-      setAuthorAndTimeStamp(deltaAuthor, deltaTimestamp);
-    }
-
-    @Override
-    public void onDocumentEvents(EventBundle<N, E, T> event) {
-      Iterable<DocumentEvent<N, E, T>> eventComponents = 
event.getEventComponents();
-
-      for (DocumentEvent<N, E, T> eventComponent : eventComponents) {
-        if (eventComponent.getType() == DocumentEvent.Type.ANNOTATION_CHANGED) 
{
-          if (capabilities.containsKey(EventType.ANNOTATED_TEXT_CHANGED)) {
-            AnnotationChanged<N, E, T> anotationChangedEvent =
-                (AnnotationChanged<N, E, T>) eventComponent;
-            AnnotatedTextChangedEvent apiEvent =
-                new AnnotatedTextChangedEvent(null, null, 
deltaAuthor.getAddress(), deltaTimestamp,
-                    blip.getId(), anotationChangedEvent.key, 
anotationChangedEvent.newValue);
-            addEvent(apiEvent, capabilities, blip.getId(), messages);
-          }
-        } else {
-          // used to distinguish between attribute changes and gadget state
-          // changes
-          Boolean gadgetStateChangeEvent = false;
-          if (eventComponent.getType() == DocumentEvent.Type.ATTRIBUTES) {
-            if (capabilities.containsKey(EventType.GADGET_STATE_CHANGED)) {
-              Map<String, String> oldState = new HashMap<>();
-              Integer index = -1;
-              try {
-                AttributesModified<N, E, T> attributesModified =
-                    (AttributesModified<N, E, T>) eventComponent;
-                // When a gadget state changes, the AttributesModifies event 
has
-                // always
-                // an oldValue map of the form {"value", something} (key is
-                // always value).
-                // To obtain the key of the changed state, the attribute "name"
-                // has to be obtained
-                // from the Element of the AttributesModified event.
-                String name =
-                    ((org.waveprotocol.wave.model.document.raw.impl.Element) 
attributesModified
-                        .getElement()).getAttribute("name");
-                String oldValue = 
attributesModified.getOldValues().get("value");
-                if (name != null || oldValue != null) {
-                  oldState.put(name, oldValue);
-                }
-                BlipData b = converter.toBlipData(blip, wavelet, messages);
-                Map<Integer, com.google.wave.api.Element> elements = 
b.getElements();
-                Set<Integer> keys = elements.keySet();
-                // The gadget element provided by the eventComponent
-                org.waveprotocol.wave.model.document.raw.impl.Element 
rawGadget =
-                    ((Node) 
attributesModified.getElement()).getParentElement();
-                for (Integer key : keys) {
-                  try {
-                    Gadget gadget = (Gadget) elements.get(key);
-                    if (sameGadgets(rawGadget, gadget)) {
-                      index = key;
-                      break;
-                    }
-                  } catch (ClassCastException e) {
-                    // if it is not a gadget we do not compare them
-                  }
-                }
-              } catch (ClassCastException e) {
-                e.printStackTrace();
-              }
-              if (oldState.size() != 0 && index != -1) {
-                // if the attribute changed belongs to a gadget
-                gadgetStateChangeEvent = true;
-                final GadgetStateChangedEvent gadgetEvent =
-                    new GadgetStateChangedEvent(null, messages, 
deltaAuthor.getAddress(),
-                        deltaTimestamp, blip.getId(), index, oldState);
-                addEvent(gadgetEvent, capabilities, blip.getId(), messages);
-              }
-            }
-          }
-          if (capabilities.containsKey(EventType.FORM_BUTTON_CLICKED)) {
-            if (eventComponent.getType() == 
DocumentEvent.Type.CONTENT_INSERTED) {
-              ContentInserted<N, E, T> contentInserted = (ContentInserted<N, 
E, T>) eventComponent;
-              org.waveprotocol.wave.model.document.raw.impl.Element 
elementInserted =
-                ((org.waveprotocol.wave.model.document.raw.impl.Element)
-                  contentInserted.getSubtreeElement());
-              if (elementInserted.getTagName().equals("click")) {
-                FormButtonClickedEvent buttonClickedEvent =
-                    new FormButtonClickedEvent(null, null,
-                        elementInserted.getAttribute("clicker"), 
Long.decode(elementInserted
-                            .getAttribute("time")), blip.getId(), 
elementInserted
-                            .getParentElement().getAttribute("name"));
-                addEvent(buttonClickedEvent, capabilities, blip.getId(), 
messages);
-              }
-            }
-          }
-          if (capabilities.containsKey(EventType.DOCUMENT_CHANGED)
-              && !documentChangedEventGenerated && !gadgetStateChangeEvent) {
-            DocumentChangedEvent apiEvent =
-                new DocumentChangedEvent(null, null, deltaAuthor.getAddress(), 
deltaTimestamp,
-                    blip.getId());
-            addEvent(apiEvent, capabilities, blip.getId(), messages);
-            // Only one documentChangedEvent should be generated per bundle.
-            documentChangedEventGenerated = true;
-          }
-        }
-      }
-    }
-
-    /**
-     * Sets the author and timestamp for the events that will be coming in.
-     * Should be changed at least for every delta that will touch the document
-     * that the handler is listening to.
-     *
-     * @param author the author of the delta.
-     * @param timestamp the timestamp at which the delta is applied.
-     */
-    public void setAuthorAndTimeStamp(ParticipantId author, long timestamp) {
-      Preconditions.checkNotNull(author, "Author should not be null");
-      Preconditions.checkNotNull(timestamp, "Timestamp should not be null");
-      this.deltaAuthor = author;
-      this.deltaTimestamp = timestamp;
-    }
-
-    /**
-     * Check if an {@link 
org.waveprotocol.wave.model.document.raw.impl.Element}
-     * is and a {@link Gadget}
-     *
-     * @param rawElement
-     * @param element
-     * @return
-     */
-    private boolean 
sameGadgets(org.waveprotocol.wave.model.document.raw.impl.Element rawElement,
-        Gadget element) {
-      String ifr1 = rawElement.getAttribute("ifr");
-      String ifr2 = element.getProperty("ifr");
-      return (ifr1 != null && ifr1.equals(ifr2));
-    }
-  }
-
-  /**
-   * Adds an {@link Event} to the given {@link EventMessageBundle}.
-   *
-   * If a blip id is specified this will be added to the
-   * {@link EventMessageBundle}'s required blips list with the context given by
-   * the robot's capabilities. If a robot does not specify a context for this
-   * event the default context will be used. Ergo this code is not responsible
-   * for filtering operations that a robot is not interested in.
-   *
-   * @param event to add.
-   * @param capabilities the capabilities to get the context from.
-   * @param blipId id of the blip this event is related to, may be null.
-   * @param messages {@link EventMessageBundle} to edit.
-   */
-  private void addEvent(Event event, Map<EventType, Capability> capabilities, 
String blipId,
-      EventMessageBundle messages) {
-    if (!isEventFilteredOut(event)) {
-      // Add the given blip to the required blip lists with the context
-      // specified by the robot's capabilities.
-      if (!Strings.isNullOrEmpty(blipId)) {
-        Capability capability = capabilities.get(event.getType());
-        List<Context> contexts;
-        if (capability == null) {
-          contexts = Capability.DEFAULT_CONTEXT;
-        } else {
-          contexts = capability.getContexts();
-        }
-        messages.requireBlip(blipId, contexts);
-      }
-      // Add the event to the bundle.
-      messages.addEvent(event);
-    }
-  }
-
-  /**
-   * Checks whether the event should be filtered out. It can happen
-   * if the robot received several deltas where in some delta it is added to
-   * the wavelet but it didn't receive the WAVELET_SELF_ADDED event yet.
-   * Or if robot already received WAVELET_SELF_REMOVED
-   * event - then it should not receive events after that.
-   *
-   * @param event  the event to filter.
-   * @return true if the event should be filtered out
-   */
-  protected boolean isEventFilteredOut(Event event) {
-    boolean isEventSuspensionOveriden = false;
-    if (event.getType().equals(EventType.WAVELET_SELF_REMOVED)) {
-      // Stop processing events.
-      isEventProcessingSuspended = true;
-      // Allow robot receive WAVELET_SELF_REMOVED event, but suspend after 
that.
-      isEventSuspensionOveriden = true;
-    }
-    if (event.getType().equals(EventType.WAVELET_SELF_ADDED)) {
-      // Start processing events.
-      isEventProcessingSuspended = false;
-    }
-    if ((isEventProcessingSuspended && !isEventSuspensionOveriden)
-        || event.getModifiedBy().equals(robotName.toParticipantAddress())) {
-      // Robot was removed from wave or this is self generated event.
-      return true;
-    }
-    return false;
-  }
-
-  /**
-   * The name of the Robot to which this {@link EventGenerator} belongs. Used
-   * for events where "self" is important.
-   */
-  private final RobotName robotName;
-
-  /** Used to create conversations. */
-  private final ConversationUtil conversationUtil;
-
-  /**
-   * Indicates that robot was removed from wavelet and thus event processing
-   * should be suspended.
-   */
-  private boolean isEventProcessingSuspended;
-
-  private final ParticipantId robotId;
-
-  /**
-   * Constructs a new {@link EventGenerator} for the robot with the given name.
-   *
-   * @param robotName the name of the robot.
-   * @param conversationUtil used to create conversations.
-   */
-  public EventGenerator(RobotName robotName, ConversationUtil 
conversationUtil) {
-    this.robotName = robotName;
-    this.conversationUtil = conversationUtil;
-    this.robotId = ParticipantId.ofUnsafe(robotName.toParticipantAddress());
-  }
-
-  /**
-   * Generates the {@link EventMessageBundle} for the specified capabilities.
-   *
-   * @param waveletAndDeltas for which the events are to be generated
-   * @param capabilities the capabilities to filter events on
-   * @param converter converter for generating the API implementations of
-   *        WaveletData and BlipData.
-   * @returns true if an event was generated, false otherwise
-   */
-  public EventMessageBundle generateEvents(WaveletAndDeltas waveletAndDeltas,
-      Map<EventType, Capability> capabilities, EventDataConverter converter) {
-    EventMessageBundle messages = new 
EventMessageBundle(robotName.toEmailAddress(), "");
-    ObservableWaveletData snapshot =
-        
WaveletDataUtil.copyWavelet(waveletAndDeltas.getSnapshotBeforeDeltas());
-    isEventProcessingSuspended = !snapshot.getParticipants().contains(robotId);
-
-    if (robotName.hasProxyFor()) {
-      // This robot is proxying so set the proxy field.
-      messages.setProxyingFor(robotName.getProxyFor());
-    }
-
-    // Sending any operations will cause an exception.
-    OpBasedWavelet wavelet =
-        new OpBasedWavelet(snapshot.getWaveId(), snapshot,
-            // This doesn't thrown an exception, the sinks will
-            new BasicWaveletOperationContextFactory(null),
-            ParticipationHelper.DEFAULT, SilentOperationSink.VOID, 
SilentOperationSink.VOID);
-
-    ObservableConversation conversation = getRootConversation(wavelet);
-
-    if (conversation == null) {
-      return messages;
-    }
-
-    // Start listening
-    EventGeneratingConversationListener conversationListener =
-        new EventGeneratingConversationListener(conversation, capabilities, 
messages, robotName);
-    conversation.addListener(conversationListener);
-    EventGeneratingWaveletListener waveletListener =
-        new EventGeneratingWaveletListener(capabilities);
-    wavelet.addListener(waveletListener);
-
-    Map<String, EventGeneratingDocumentHandler> docHandlers = 
Maps.newHashMap();
-    try {
-      for (TransformedWaveletDelta delta : waveletAndDeltas.getDeltas()) {
-        // TODO(ljvderijk): Set correct timestamp and hashed version once
-        // wavebus sends them along
-        long timestamp = 0L;
-        conversationListener.deltaBegin(delta.getAuthor(), timestamp);
-
-        for (WaveletOperation op : delta) {
-          // Check if we need to attach a doc handler.
-          if ((op instanceof WaveletBlipOperation)) {
-            attachDocHandler(conversation, op, docHandlers, capabilities, 
messages,
-                delta.getAuthor(), timestamp, wavelet, converter);
-          }
-          op.apply(snapshot);
-        }
-        conversationListener.deltaEnd();
-      }
-    } catch (OperationException e) {
-      throw new IllegalStateException("Operation failed to apply when 
generating events", e);
-    } finally {
-      conversation.removeListener(conversationListener);
-      wavelet.removeListener(waveletListener);
-      for (EventGeneratingDocumentHandler docHandler : docHandlers.values()) {
-        docHandler.doc.removeListener(docHandler);
-      }
-    }
-
-    if (messages.getEvents().isEmpty()) {
-      // No events found, no need to resolve contexts
-      return messages;
-    }
-
-    // Resolve the context of the bundle now that all events have been
-    // processed.
-    ContextResolver.resolveContext(messages, wavelet, conversation, converter);
-
-    return messages;
-  }
-
-  /**
-   * Attaches a doc handler to the blip the operation applies to.
-   *
-   * @param conversation the conversation the op is to be applied to.
-   * @param op the op to be applied
-   * @param docHandlers the list of attached dochandlers.
-   * @param capabilities the capabilities of the robot.
-   * @param messages the bundle to put the generated events in.
-   * @param deltaAuthor the author of the events generated.
-   * @param timestamp the timestamp at which these events occurred.
-   */
-  private void attachDocHandler(ObservableConversation conversation, 
WaveletOperation op,
-      Map<String, EventGeneratingDocumentHandler> docHandlers,
-      Map<EventType, Capability> capabilities, EventMessageBundle messages,
-      ParticipantId deltaAuthor, long timestamp, Wavelet wavelet, 
EventDataConverter converter) {
-    WaveletBlipOperation blipOp = (WaveletBlipOperation) op;
-    String blipId = blipOp.getBlipId();
-    // Ignoring the documents outside the conversation such as tags
-    // and robot data docs.
-    ObservableConversationBlip blip = conversation.getBlip(blipId);
-    if (blip != null) {
-      String blipId1 = blip.getId();
-
-      EventGeneratingDocumentHandler docHandler = docHandlers.get(blipId1);
-      if (docHandler == null) {
-        ObservableDocument doc = (ObservableDocument) blip.getContent();
-        docHandler =
-            new EventGeneratingDocumentHandler(doc, blip, capabilities, 
messages, deltaAuthor,
-                timestamp, wavelet, converter);
-        doc.addListener(docHandler);
-        docHandlers.put(blipId1, docHandler);
-      } else {
-        docHandler.setAuthorAndTimeStamp(deltaAuthor, timestamp);
-      }
-    }
-  }
-
-  /**
-   * Returns the root conversation from the given wavelet. Or null if there is
-   * none.
-   *
-   * @param wavelet the wavelet to get the conversation from.
-   */
-  private ObservableConversation getRootConversation(ObservableWavelet 
wavelet) {
-    if (!WaveletBasedConversation.waveletHasConversation(wavelet)) {
-      // No conversation present, bail.
-      return null;
-    }
-
-    ObservableConversation conversation = 
conversationUtil.buildConversation(wavelet).getRoot();
-    if (conversation.getRootThread().getFirstBlip() == null) {
-      // No root blip is present, this will cause Robot API code
-      // to fail when resolving the context of events. This might be fixed 
later
-      // on by making changes to the ContextResolver.
-      return null;
-    }
-    return conversation;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/passive/OperationServiceRegistryImpl.java
----------------------------------------------------------------------
diff --git 
a/src/org/waveprotocol/box/server/robots/passive/OperationServiceRegistryImpl.java
 
b/src/org/waveprotocol/box/server/robots/passive/OperationServiceRegistryImpl.java
deleted file mode 100644
index 89f7d98..0000000
--- 
a/src/org/waveprotocol/box/server/robots/passive/OperationServiceRegistryImpl.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.passive;
-
-import com.google.inject.Inject;
-import com.google.wave.api.OperationType;
-
-import org.waveprotocol.box.server.robots.AbstractOperationServiceRegistry;
-import org.waveprotocol.box.server.robots.operations.BlipOperationServices;
-import org.waveprotocol.box.server.robots.operations.CreateWaveletService;
-import org.waveprotocol.box.server.robots.operations.DocumentModifyService;
-import org.waveprotocol.box.server.robots.operations.FolderActionService;
-import org.waveprotocol.box.server.robots.operations.NotifyOperationService;
-import org.waveprotocol.box.server.robots.operations.OperationService;
-import org.waveprotocol.box.server.robots.operations.ParticipantServices;
-import org.waveprotocol.box.server.robots.operations.WaveletSetTitleService;
-
-/**
- * Class for registering and accessing {@link OperationService} to execute
- * operations for use in the Passive Robot API.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public final class OperationServiceRegistryImpl extends 
AbstractOperationServiceRegistry {
-
-  // Suppressing warnings about operations that are deprecated but still used 
by
-  // the default client libraries.
-  @SuppressWarnings("deprecation")
-  @Inject
-  OperationServiceRegistryImpl(NotifyOperationService notifyOpService) {
-    super();
-
-    // Register all the OperationProviders
-    register(OperationType.ROBOT_NOTIFY, notifyOpService);
-    register(OperationType.ROBOT_NOTIFY_CAPABILITIES_HASH, notifyOpService);
-    register(OperationType.WAVELET_ADD_PARTICIPANT_NEWSYNTAX, 
ParticipantServices.create());
-    register(OperationType.WAVELET_APPEND_BLIP, 
BlipOperationServices.create());
-    register(OperationType.WAVELET_REMOVE_PARTICIPANT_NEWSYNTAX, 
ParticipantServices.create());
-    register(OperationType.BLIP_CONTINUE_THREAD, 
BlipOperationServices.create());
-    register(OperationType.BLIP_CREATE_CHILD, BlipOperationServices.create());
-    register(OperationType.BLIP_DELETE, BlipOperationServices.create());
-    register(OperationType.DOCUMENT_APPEND_INLINE_BLIP, 
BlipOperationServices.create());
-    register(OperationType.DOCUMENT_APPEND_MARKUP, 
BlipOperationServices.create());
-    register(OperationType.DOCUMENT_INSERT_INLINE_BLIP, 
BlipOperationServices.create());
-    register(OperationType.DOCUMENT_INSERT_INLINE_BLIP_AFTER_ELEMENT,
-        BlipOperationServices.create());
-    register(OperationType.WAVELET_CREATE, CreateWaveletService.create());
-    register(OperationType.DOCUMENT_MODIFY, DocumentModifyService.create());
-    register(OperationType.WAVELET_SET_TITLE, WaveletSetTitleService.create());
-    register(OperationType.ROBOT_FOLDER_ACTION, FolderActionService.create());
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/passive/Robot.java
----------------------------------------------------------------------
diff --git a/src/org/waveprotocol/box/server/robots/passive/Robot.java 
b/src/org/waveprotocol/box/server/robots/passive/Robot.java
deleted file mode 100644
index 7098512..0000000
--- a/src/org/waveprotocol/box/server/robots/passive/Robot.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.passive;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.ListMultimap;
-import com.google.wave.api.OperationRequest;
-import com.google.wave.api.data.converter.EventDataConverterManager;
-import com.google.wave.api.impl.EventMessageBundle;
-import com.google.wave.api.robot.CapabilityFetchException;
-import com.google.wave.api.robot.RobotName;
-
-import org.waveprotocol.box.common.DeltaSequence;
-import org.waveprotocol.box.server.account.RobotAccountData;
-import org.waveprotocol.box.server.persistence.PersistenceException;
-import org.waveprotocol.box.server.robots.RobotCapabilities;
-import org.waveprotocol.box.server.util.WaveletDataUtil;
-import org.waveprotocol.box.server.waveserver.WaveletProvider;
-import org.waveprotocol.wave.model.id.WaveletName;
-import org.waveprotocol.wave.model.operation.OperationException;
-import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;
-import org.waveprotocol.wave.util.logging.Log;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map.Entry;
-
-/**
- * Represents a Robot in the passive API. Is responsible for providing a filter
- * for events it is interested in. Is also able of sending events to robots and
- * executing the operations it receives. It submits the delta back to the
- * {@link RobotsGateway}.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public class Robot implements Runnable {
-
-  private static final Log LOG = Log.get(Robot.class);
-  /** Appended to the robot url which forms the endpoint for sending rpc calls 
*/
-  public static final String RPC_URL = "/_wave/robot/jsonrpc";
-  /**
-   * Appended to the robot url which forms the endpoint for getting the
-   * capabilities
-   */
-  public static final String CAPABILITIES_URL = "/_wave/capabilities.xml";
-
-  private final RobotName robotName;
-  // This is not final because it needs to be updated when the capabilities
-  // change.
-  // TODO(ljvderijk): Keep up to date with other updates to account?
-  private RobotAccountData account;
-  private final RobotsGateway gateway;
-  private final RobotConnector connector;
-  private final EventDataConverterManager converterManager;
-  /**
-   * This map acts as a queue of wavelets to process events for. The methods
-   * that add, updated and remove wavelets synchronize on this object to ensure
-   * consistency in face of concurrent changes.
-   */
-  private final ListMultimap<WaveletName, WaveletAndDeltas> 
waveletAndDeltasMap =
-      LinkedListMultimap.<WaveletName, WaveletAndDeltas> create();
-  private final EventGenerator eventGenerator;
-  private final RobotOperationApplicator operationApplicator;
-
-  /**
-   * Constructs a new Robot which is characterized by its {@link RobotName}.
-   *
-   * @param robotName the name of the {@link Robot}.
-   * @param account the {@link RobotAccountData} belonging to this
-   *        {@link Robot}.
-   * @param gateway the gateway this robot belongs to.
-   * @param connector the {@link RobotConnector} to make connections to
-   *        {@link Robot}s.
-   * @param converterManager used to convert to Robot API objects.
-   * @param waveletProvider used to access wavelets and submit deltas.
-   * @param eventGenerator used to generate events
-   * @param operationApplicator used to apply the robot operations returned by 
a
-   *        robot.
-   */
-  Robot(RobotName robotName, RobotAccountData account, RobotsGateway gateway,
-      RobotConnector connector, EventDataConverterManager converterManager,
-      WaveletProvider waveletProvider, EventGenerator eventGenerator,
-      RobotOperationApplicator operationApplicator) {
-    Preconditions.checkArgument(account.isVerified(), "Account must be 
verified");
-    this.robotName = robotName;
-    this.gateway = gateway;
-    this.connector = connector;
-    this.converterManager = converterManager;
-    this.eventGenerator = eventGenerator;
-    this.operationApplicator = operationApplicator;
-
-    setAccount(account);
-  }
-
-  /**
-   * Sets the account for this Robot. The address of the account must match the
-   * address in the {@link RobotName}.
-   *
-   * @param account the account to set.
-   */
-  void setAccount(RobotAccountData account) {
-    
Preconditions.checkArgument(robotName.toEmailAddress().equals(account.getId().getAddress()),
-        String.format("The given RobotAccountData doesn't match the RobotName. 
%s != %s",
-            account.getId(), robotName.toEmailAddress()));
-    this.account = account;
-  }
-
-  /**
-   * Returns the name of this robot.
-   */
-  RobotName getRobotName() {
-    return robotName;
-  }
-
-  /**
-   * The {@link RobotAccountData} of this robot.
-   */
-  RobotAccountData getAccount() {
-    return account;
-  }
-
-  /**
-   * Processes a wavelet update for this {@link Robot}.
-   *
-   * <p>
-   * The robot keeps an internal queue of wavelets that are to be processed 
when
-   * run() is called. A new entry in the queue is made on two occasions. First
-   * if the robot has nothing enqueued for the given wavelet, secondly if the
-   * robot does have an update enqueued for the given wavelet but the deltas
-   * that are given are not contiguous with the current data.
-   *
-   * <p>
-   * This method synchronizes on the queue because we might be appending deltas
-   * while dequeueWavelet() is being called.
-   *
-   * @param wavelet the wavelet this update is taking place on.
-   * @param deltas the deltas that have been applied to the given wavelet.
-   * @throws OperationException if an update for a new wavelet could not be
-   *         processed.
-   */
-  void waveletUpdate(ReadableWaveletData wavelet, DeltaSequence deltas)
-      throws OperationException {
-    WaveletName waveletName = WaveletDataUtil.waveletNameOf(wavelet);
-
-    synchronized (waveletAndDeltasMap) {
-      // This returns a view which we can append new delta collections to.
-      List<WaveletAndDeltas> wavelets = waveletAndDeltasMap.get(waveletName);
-
-      if (wavelets.isEmpty()) {
-        WaveletAndDeltas waveletAndDeltas = WaveletAndDeltas.create(wavelet, 
deltas);
-        wavelets.add(waveletAndDeltas);
-      } else {
-        WaveletAndDeltas waveletAndDeltas = wavelets.get(wavelets.size() - 1);
-        if (waveletAndDeltas.areContiguousToCurrentVersion(deltas)) {
-          waveletAndDeltas.appendDeltas(wavelet, deltas);
-        } else {
-          // We are missing deltas, create a new collection.
-          waveletAndDeltas = WaveletAndDeltas.create(wavelet, deltas);
-          wavelets.add(waveletAndDeltas);
-        }
-      }
-    }
-  }
-
-  /**
-   * Dequeues a wavelet for this {@link Robot}.
-   *
-   * <p>
-   * This method synchronizes on the queue because deltas might be added in
-   * waveletUpdate().
-   *
-   * @return the next {@link WaveletAndDeltas} in the queue, null if there is
-   *         none.
-   */
-  @VisibleForTesting
-  WaveletAndDeltas dequeueWavelet() {
-    synchronized (waveletAndDeltasMap) {
-      Iterator<Entry<WaveletName, WaveletAndDeltas>> iterator =
-          waveletAndDeltasMap.entries().iterator();
-      if (!iterator.hasNext()) {
-        return null;
-      }
-      WaveletAndDeltas wavelet = iterator.next().getValue();
-      iterator.remove();
-      return wavelet;
-    }
-  }
-
-  /**
-   * Runs this {@link Robot} by checking its queue for a new wavelet and then
-   * processing this wavelet. In the end the {@link Robot} will check whether 
it
-   * needs to requeue itself in the RobotGateway or that no further actions 
need
-   * to be taken.
-   */
-  @Override
-  public void run() {
-    try {
-      LOG.fine(robotName + " called for processing");
-
-      WaveletAndDeltas wavelet = dequeueWavelet();
-      if (wavelet == null) {
-        gateway.doneRunning(this);
-        return;
-      }
-      process(wavelet);
-    } catch (RuntimeException e) {
-      LOG.severe("Unexpected error occurred when robot " + robotName + " was 
called", e);
-    }
-
-    // Requeue since we either had an exception or we processed a wavelet.
-    gateway.doneRunning(this);
-    gateway.ensureScheduled(this);
-  }
-
-  /**
-   * Processes a single {@link WaveletAndDeltas} by generating events that a
-   * {@link Robot} is subscribed to. These events are then sent off to the 
robot
-   * using the {@link RobotConnector} passed during construction. The 
operations
-   * returned by the robot are then processed by the
-   * {@link RobotOperationApplicator}.
-   *
-   * @param wavelet the {@link WaveletAndDeltas} to process.
-   */
-  private void process(WaveletAndDeltas wavelet) {
-    if (account.getCapabilities() == null) {
-      try {
-        LOG.info(robotName + ": Initializing capabilities");
-        gateway.updateRobotAccount(this);
-      } catch (CapabilityFetchException e) {
-        ReadableWaveletData snapshot = wavelet.getSnapshotAfterDeltas();
-        LOG.info(
-            "Couldn't initialize the capabilities of robot(" + robotName
-                + "), dropping its wavelet(" + 
WaveletDataUtil.waveletNameOf(snapshot)
-                + ") at version " + wavelet.getVersionAfterDeltas(), e);
-        return;
-      } catch (PersistenceException e) {
-        ReadableWaveletData snapshot = wavelet.getSnapshotAfterDeltas();
-        LOG.info(
-            "Couldn't initialize the capabilities of robot(" + robotName
-                + "), dropping its wavelet(" + 
WaveletDataUtil.waveletNameOf(snapshot)
-                + ") at version " + wavelet.getVersionAfterDeltas(), e);
-        return;
-      }
-    }
-
-    RobotCapabilities capabilities = account.getCapabilities();
-    EventMessageBundle messages =
-        eventGenerator.generateEvents(wavelet, 
capabilities.getCapabilitiesMap(),
-            
converterManager.getEventDataConverter(capabilities.getProtocolVersion()));
-
-    if (messages.getEvents().isEmpty()) {
-      // No events were generated, we are done
-      LOG.info(robotName + ": no events were generated");
-      return;
-    }
-
-    LOG.info(robotName + ": sending events");
-    List<OperationRequest> response =
-        connector.sendMessageBundle(messages, this, 
capabilities.getProtocolVersion());
-    LOG.info(robotName + ": received operations");
-
-    operationApplicator.applyOperations(
-        response, wavelet.getSnapshotAfterDeltas(), 
wavelet.getVersionAfterDeltas(), account);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/passive/RobotConnector.java
----------------------------------------------------------------------
diff --git a/src/org/waveprotocol/box/server/robots/passive/RobotConnector.java 
b/src/org/waveprotocol/box/server/robots/passive/RobotConnector.java
deleted file mode 100644
index 355196f..0000000
--- a/src/org/waveprotocol/box/server/robots/passive/RobotConnector.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.passive;
-
-import com.google.inject.Inject;
-import com.google.wave.api.InvalidRequestException;
-import com.google.wave.api.OperationRequest;
-import com.google.wave.api.ProtocolVersion;
-import com.google.wave.api.RobotSerializer;
-import com.google.wave.api.impl.EventMessageBundle;
-import com.google.wave.api.robot.CapabilityFetchException;
-import com.google.wave.api.robot.RobotCapabilitiesParser;
-import com.google.wave.api.robot.RobotConnection;
-import com.google.wave.api.robot.RobotConnectionException;
-
-import org.waveprotocol.box.server.account.RobotAccountData;
-import org.waveprotocol.box.server.account.RobotAccountDataImpl;
-import org.waveprotocol.box.server.robots.RobotCapabilities;
-import org.waveprotocol.wave.util.logging.Log;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * This class sends {@link EventMessageBundle} to a robot and receives their
- * response. It will gracefully handle failure by acting like the robot sent no
- * operations.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public class RobotConnector {
-
-  private static final Log LOG = Log.get(RobotConnector.class);
-
-  private final RobotConnection connection;
-
-  private final RobotSerializer serializer;
-
-  @Inject
-  public RobotConnector(RobotConnection connection, RobotSerializer 
serializer) {
-    this.connection = connection;
-    this.serializer = serializer;
-  }
-
-  /**
-   * Synchronously sends an {@link EventMessageBundle} off to a robot and hands
-   * back the response in the form of a list of {@link OperationRequest}s.
-   *
-   * @param bundle the bundle to send to the robot.
-   * @param robot the {@link RobotAccountData} of the robot.
-   * @param version the version that we should speak to the robot.
-   * @returns list of {@link OperationRequest}s that the robot wants to have
-   *          executed.
-   */
-  public List<OperationRequest> sendMessageBundle(
-      EventMessageBundle bundle, Robot robot, ProtocolVersion version) {
-    String serializedBundle = serializer.serialize(bundle, version);
-
-    String robotUrl = robot.getAccount().getUrl() + Robot.RPC_URL;
-    LOG.info("Sending: " + serializedBundle + " to " + robotUrl);
-
-    try {
-      String response = connection.postJson(robotUrl, serializedBundle);
-      LOG.info("Received: " + response + " from " + robotUrl);
-      return serializer.deserializeOperations(response);
-    } catch (RobotConnectionException e) {
-      LOG.info("Failed to receive a response from " + robotUrl, e);
-    } catch (InvalidRequestException e) {
-      LOG.info("Failed to deserialize passive API response", e);
-    }
-
-    // Return an empty list and let the caller ignore the failure
-    return Collections.emptyList();
-  }
-
-  /**
-   * Returns a new {@link RobotAccountData} updated with the new capabilities
-   * using the given {@link RobotAccountData}.
-   *
-   * @param account The {@link RobotAccountData} to update the capabilities 
for.
-   * @param activeApiUrl the url of the Active Robot API.
-   * @throws CapabilityFetchException if the capabilities couldn't be retrieved
-   *         or parsed.
-   */
-  public RobotAccountData fetchCapabilities(RobotAccountData account, String 
activeApiUrl)
-      throws CapabilityFetchException {
-    RobotCapabilitiesParser parser = new RobotCapabilitiesParser(
-        account.getUrl() + Robot.CAPABILITIES_URL, connection, activeApiUrl);
-    RobotCapabilities capabilities = new RobotCapabilities(
-        parser.getCapabilities(), parser.getCapabilitiesHash(), 
parser.getProtocolVersion());
-
-    return new RobotAccountDataImpl(account.getId(), account.getUrl(), 
account.getConsumerSecret(),
-        capabilities, account.isVerified());
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/passive/RobotOperationApplicator.java
----------------------------------------------------------------------
diff --git 
a/src/org/waveprotocol/box/server/robots/passive/RobotOperationApplicator.java 
b/src/org/waveprotocol/box/server/robots/passive/RobotOperationApplicator.java
deleted file mode 100644
index efb40b8..0000000
--- 
a/src/org/waveprotocol/box/server/robots/passive/RobotOperationApplicator.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.passive;
-
-import com.google.wave.api.OperationRequest;
-import com.google.wave.api.ProtocolVersion;
-import com.google.wave.api.data.converter.EventDataConverterManager;
-import com.google.wave.api.event.EventType;
-import com.google.wave.api.event.OperationErrorEvent;
-import org.waveprotocol.box.server.account.RobotAccountData;
-import org.waveprotocol.box.server.robots.OperationContext;
-import org.waveprotocol.box.server.robots.OperationContextImpl;
-import org.waveprotocol.box.server.robots.OperationResults;
-import org.waveprotocol.box.server.robots.OperationServiceRegistry;
-import org.waveprotocol.box.server.robots.RobotWaveletData;
-import org.waveprotocol.box.server.robots.operations.OperationService;
-import org.waveprotocol.box.server.robots.util.ConversationUtil;
-import org.waveprotocol.box.server.robots.util.LoggingRequestListener;
-import org.waveprotocol.box.server.robots.util.OperationUtil;
-import org.waveprotocol.box.server.waveserver.WaveletProvider;
-import org.waveprotocol.wave.model.version.HashedVersion;
-import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;
-import org.waveprotocol.wave.util.logging.Log;
-
-import java.util.List;
-
-/**
- * This class is responsible for applying operations received from a Robot in
- * the Passive API. Operations that fail will result in an
- * {@link OperationErrorEvent} being generated and they might be sent off to 
the
- * robot after all of the robot's operations have been completed.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public class RobotOperationApplicator {
-
-  private static final Log LOG = Log.get(RobotOperationApplicator.class);
-
-  private final static WaveletProvider.SubmitRequestListener 
LOGGING_REQUEST_LISTENER =
-      new LoggingRequestListener(LOG);
-
-  private final EventDataConverterManager converterManager;
-  private final WaveletProvider waveletProvider;
-  private final OperationServiceRegistry operationRegistry;
-  private final ConversationUtil conversationUtil;
-
-  /**
-   * Constructs a new {@link RobotOperationApplicator}.
-   *
-   * @param converterManager used to convert to Robot API objects
-   * @param waveletProvider used to retrieve wavelets and submit deltas
-   * @param operationRegistry registry containing the {@link OperationService}s
-   *        that this applicator can perform.
-   * @param conversationUtil used to create conversations.
-   */
-  public RobotOperationApplicator(EventDataConverterManager converterManager,
-      WaveletProvider waveletProvider, OperationServiceRegistry 
operationRegistry,
-      ConversationUtil conversationUtil) {
-    this.converterManager = converterManager;
-    this.waveletProvider = waveletProvider;
-    this.operationRegistry = operationRegistry;
-    this.conversationUtil = conversationUtil;
-  }
-
-  /**
-   * Applies the operations within the context of the wavelet.
-   *
-   * @param operations the operations to apply
-   * @param wavelet the wavelet which is the context in which this operation is
-   *        performed.
-   * @param hashedVersion the version of the wavelet to which to apply the
-   *        operations to.
-   * @param account the account for which to apply robot operations.
-   */
-  void applyOperations(List<OperationRequest> operations, ReadableWaveletData 
wavelet,
-      HashedVersion hashedVersion, RobotAccountData account) {
-    // The robots we support should be sending us their version in their first
-    // operation
-    ProtocolVersion protocolVersion = 
OperationUtil.getProtocolVersion(operations);
-
-    OperationContextImpl context = new OperationContextImpl(waveletProvider,
-        converterManager.getEventDataConverter(protocolVersion), 
conversationUtil,
-        new RobotWaveletData(wavelet, hashedVersion));
-
-    executeOperations(context, operations, account);
-    handleResults(context, account);
-  }
-
-  /**
-   * Executes operations in the given context.
-   *
-   * @param context the context to perform the operations in.
-   * @param operations the operations to perform.
-   * @param account the account for which to execute robot operations.
-   */
-  private void executeOperations(
-      OperationContext context, List<OperationRequest> operations, 
RobotAccountData account) {
-    for (OperationRequest operation : operations) {
-      // Get the operation of the author taking into account the proxying for
-      // field.
-      OperationUtil.executeOperation(operation, operationRegistry, context, 
account.getId());
-    }
-  }
-
-  /**
-   * Handles an {@link OperationResults} by submitting the deltas it generates
-   * and sending off any events to the robot. Note that currently no events are
-   * send off to the robot.
-   *
-   * @param results the results of the operations performed
-   * @param account the account for which to handle results of robot 
operations.
-   */
-  private void handleResults(OperationResults results, RobotAccountData 
account) {
-    OperationUtil.submitDeltas(results, waveletProvider, 
LOGGING_REQUEST_LISTENER);
-
-    // TODO(ljvderijk): In theory we should be sending off all events that are
-    // generated by the operations. Currently not done in production. We should
-    // make it possible though.
-    boolean notifyOnError =
-        
account.getCapabilities().getCapabilitiesMap().containsKey(EventType.OPERATION_ERROR);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/passive/RobotsGateway.java
----------------------------------------------------------------------
diff --git a/src/org/waveprotocol/box/server/robots/passive/RobotsGateway.java 
b/src/org/waveprotocol/box/server/robots/passive/RobotsGateway.java
deleted file mode 100644
index d2a08b1..0000000
--- a/src/org/waveprotocol/box/server/robots/passive/RobotsGateway.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.passive;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import com.google.wave.api.RobotSerializer;
-import com.google.wave.api.data.converter.EventDataConverterManager;
-import com.google.wave.api.robot.CapabilityFetchException;
-import com.google.wave.api.robot.RobotName;
-
-import org.waveprotocol.box.common.DeltaSequence;
-import org.waveprotocol.box.server.account.AccountData;
-import org.waveprotocol.box.server.account.RobotAccountData;
-import org.waveprotocol.box.server.persistence.AccountStore;
-import org.waveprotocol.box.server.persistence.PersistenceException;
-import org.waveprotocol.box.server.robots.operations.NotifyOperationService;
-import org.waveprotocol.box.server.robots.util.ConversationUtil;
-import org.waveprotocol.box.server.waveserver.WaveBus;
-import org.waveprotocol.box.server.waveserver.WaveletProvider;
-import org.waveprotocol.wave.model.id.WaveletName;
-import org.waveprotocol.wave.model.operation.OperationException;
-import org.waveprotocol.wave.model.operation.wave.AddParticipant;
-import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta;
-import org.waveprotocol.wave.model.operation.wave.WaveletOperation;
-import org.waveprotocol.wave.model.version.HashedVersion;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;
-import org.waveprotocol.wave.util.logging.Log;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Executor;
-
-
-/**
- * Gateway for the Passive Robot API, this class can be subscribed to the
- * WaveBus and fires of separate threads to handle any updates for Robots.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public class RobotsGateway implements WaveBus.Subscriber {
-
-  private static final Log LOG = Log.get(RobotsGateway.class);
-
-  private final WaveletProvider waveletProvider;
-  private final AccountStore accountStore;
-  private final EventDataConverterManager converterManager;
-  private final RobotConnector connector;
-  private final Map<RobotName, Robot> allRobots = Maps.newHashMap();
-  private final Set<RobotName> runnableRobots = Sets.newHashSet();
-  private final Executor executor;
-  private final ConversationUtil conversationUtil;
-  private final NotifyOperationService notifyOpService;
-
-  @Inject
-  @VisibleForTesting
-  RobotsGateway(WaveletProvider waveletProvider, RobotConnector connector,
-      AccountStore accountStore, RobotSerializer serializer,
-      EventDataConverterManager converterManager, @Named("GatewayExecutor") 
Executor executor,
-      ConversationUtil conversationUtil, NotifyOperationService 
notifyOpService) {
-    this.waveletProvider = waveletProvider;
-    this.accountStore = accountStore;
-    this.converterManager = converterManager;
-    this.connector = connector;
-    this.executor = executor;
-    this.conversationUtil = conversationUtil;
-    this.notifyOpService = notifyOpService;
-  }
-
-  @Override
-  public void waveletCommitted(WaveletName waveletName, HashedVersion version) 
{
-    // We ignore this event.
-  }
-
-  @Override
-  public void waveletUpdate(ReadableWaveletData wavelet, DeltaSequence deltas) 
{
-    Set<ParticipantId> currentAndNewParticipants = 
Sets.newHashSet(wavelet.getParticipants());
-    for (TransformedWaveletDelta delta : deltas) {
-      // Participants added or removed in this delta get the whole delta.
-      for (WaveletOperation op : delta) {
-        if (op instanceof AddParticipant) {
-          ParticipantId p = ((AddParticipant) op).getParticipantId();
-          currentAndNewParticipants.add(p);
-        }
-      }
-    }
-    // Robot should receive also deltas that contain AddParticipant ops.
-    // EventGenerator will take care to filter out events before the add.
-    for (ParticipantId participant : currentAndNewParticipants) {
-      RobotName robotName = RobotName.fromAddress(participant.getAddress());
-      if (robotName == null) {
-        // Not a valid robot name, next.
-        continue;
-      }
-
-      ParticipantId robotId = 
ParticipantId.ofUnsafe(robotName.toEmailAddress());
-      AccountData account;
-      try {
-        account = accountStore.getAccount(robotId);
-      } catch (PersistenceException e) {
-        LOG.severe("Failed to retrieve the account data for " + 
robotId.getAddress(), e);
-        continue;
-      }
-
-      if (account != null && account.isRobot()) {
-        RobotAccountData robotAccount = account.asRobot();
-        if (robotAccount.isVerified()) {
-          Robot robot = getOrCreateRobot(robotName, robotAccount);
-          updateRobot(robot, wavelet, deltas);
-        }
-      }
-    }
-  }
-
-  /**
-   * Gets or creates a {@link Robot} for the given name.
-   *
-   * @param robotName the name of the robot.
-   * @param account the {@link RobotAccountData} belonging to the given
-   *        {@link RobotName}.
-   */
-  private Robot getOrCreateRobot(RobotName robotName, RobotAccountData 
account) {
-    Robot robot = allRobots.get(robotName);
-
-    if (robot == null) {
-      robot = createNewRobot(robotName, account);
-      allRobots.put(robotName, robot);
-    }
-    return robot;
-  }
-
-  /**
-   * Creates a new {@link Robot}.
-   *
-   * @param robotName the name of the robot.
-   * @param account the {@link RobotAccountData} belonging to the given
-   *        {@link RobotName}.
-   */
-  private Robot createNewRobot(RobotName robotName, RobotAccountData account) {
-    EventGenerator eventGenerator = new EventGenerator(robotName, 
conversationUtil);
-    RobotOperationApplicator operationApplicator =
-        new RobotOperationApplicator(converterManager, waveletProvider,
-            new OperationServiceRegistryImpl(notifyOpService), 
conversationUtil);
-    return new Robot(robotName, account, this, connector, converterManager, 
waveletProvider,
-        eventGenerator, operationApplicator);
-  }
-
-  /**
-   * Updates a {@link Robot} with information about a waveletUpdate event.
-   *
-   * @param robot The robot to process the update for.
-   * @param wavelet the wavelet on which the update is occuring.
-   * @param deltas the deltas the have been applied to the given wavelet.
-   */
-  private void updateRobot(Robot robot, ReadableWaveletData wavelet, 
DeltaSequence deltas) {
-    try {
-      robot.waveletUpdate(wavelet, deltas);
-      ensureScheduled(robot);
-    } catch (OperationException e) {
-      LOG.warning("Unable to update robot(" + robot.getRobotName() + ")", e);
-    }
-  }
-
-  /**
-   * Ensures that a robot is submitted to the executor, might submit the
-   * {@link Robot} if it hasn't been submitted yet.
-   *
-   * <p>
-   * Synchronized in combination with done() to keep proper track of the robots
-   * that have been submitted.
-   *
-   * @param robot the {@link Robot} to enqueue
-   */
-  public synchronized void ensureScheduled(Robot robot) {
-    if (!runnableRobots.contains(robot.getRobotName())) {
-      LOG.info("Enqueing robot: " + robot.getRobotName());
-      runnableRobots.add(robot.getRobotName());
-      executor.execute(robot);
-    }
-  }
-
-  /**
-   * Signal that a robot is done running. Synchronized with ensureRunnable 
since
-   * that method needs to have a synchronized view on the runnableRobots for
-   * submitting task to the executor.
-   *
-   * @param robot the {@link Robot} which is done working.
-   */
-  public synchronized void doneRunning(Robot robot) {
-    runnableRobots.remove(robot.getRobotName());
-  }
-
-  /**
-   * Updates the account for the given {@link Robot}.
-   *
-   * @param robot the {@link Robot} to update.
-   * @throws CapabilityFetchException if the capabilities could not be fetched
-   *         or parsed.
-   */
-  public void updateRobotAccount(Robot robot) throws CapabilityFetchException,
-      PersistenceException {
-    // TODO: Pass in activeAPIUrl
-    String activeApiUrl = "";
-    RobotAccountData newAccount = 
connector.fetchCapabilities(robot.getAccount(), activeApiUrl);
-    accountStore.putAccount(newAccount);
-    robot.setAccount(newAccount);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/passive/WaveletAndDeltas.java
----------------------------------------------------------------------
diff --git 
a/src/org/waveprotocol/box/server/robots/passive/WaveletAndDeltas.java 
b/src/org/waveprotocol/box/server/robots/passive/WaveletAndDeltas.java
deleted file mode 100644
index 1b4fbf6..0000000
--- a/src/org/waveprotocol/box/server/robots/passive/WaveletAndDeltas.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.passive;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-
-import org.waveprotocol.box.common.DeltaSequence;
-import org.waveprotocol.box.server.util.WaveletDataUtil;
-import org.waveprotocol.wave.model.id.WaveletName;
-import org.waveprotocol.wave.model.operation.OperationException;
-import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta;
-import org.waveprotocol.wave.model.operation.wave.WaveletDelta;
-import org.waveprotocol.wave.model.operation.wave.WaveletOperation;
-import org.waveprotocol.wave.model.version.HashedVersion;
-import org.waveprotocol.wave.model.wave.data.ObservableWaveletData;
-import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;
-import org.waveprotocol.wave.model.wave.data.WaveletData;
-
-import java.util.List;
-
-/**
- * A wavelet snapshot and a sequence of deltas applying to that snapshot.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public class WaveletAndDeltas {
-
-  /**
-   * Snapshot of the wavelet before any deltas are applied.
-   */
-  private final ReadableWaveletData snapshotBeforeDeltas;
-
-  /**
-   * Contiguous deltas applying to snapshotBeforeDeltas.
-   */
-  private DeltaSequence deltas;
-
-  /**
-   * Cached result of applying all deltas to the first snapshot.
-   */
-  private ObservableWaveletData snapshotAfterDeltas;
-
-  /**
-   * The name of the wavelet in this container.
-   */
-  private final WaveletName waveletName;
-
-  /**
-   * Constructs a {@link WaveletAndDeltas} from wavelet data and a tail of the
-   * sequence of transformed deltas leading to that snapshot. Takes a copy of
-   * the WaveletData so that operations can happily applied to it.
-   *
-   * The resulting version of the last delta must match the snapshot's version.
-   *
-   * @param snapshot the state of the wavelet after the deltas have been
-   *        applied.
-   * @param deltas the deltas in the order they have been applied to the
-   *        wavelet.
-   * @throws OperationException if the operations can not be rolled back to
-   *         create a snapshot before the deltas have been applied.
-   */
-  public static WaveletAndDeltas create(ReadableWaveletData snapshot, 
DeltaSequence deltas)
-      throws OperationException {
-    HashedVersion endVersion = deltas.isEmpty() ? snapshot.getHashedVersion() :
-        deltas.getEndVersion();
-    Preconditions.checkArgument(snapshot.getVersion() == 
endVersion.getVersion(),
-        String.format("Version of snapshot %s doesn't match the end version 
%s",
-            snapshot.getVersion(), endVersion));
-
-    ObservableWaveletData preDeltaWavelet = 
WaveletDataUtil.copyWavelet(snapshot);
-    rollback(preDeltaWavelet, deltas);
-    ObservableWaveletData postDeltaWavelet = 
WaveletDataUtil.copyWavelet(snapshot);
-    return new WaveletAndDeltas(preDeltaWavelet, postDeltaWavelet, deltas);
-  }
-
-  /**
-   * Reverses the operations detailed in the list of deltas on the given
-   * wavelet.
-   *
-   * @param wavelet {@link ObservableWaveletData} to apply operations to
-   * @param deltas the {@link WaveletDelta} containing the operations
-   *        which we should revert on the given wavelet.
-   * @throws OperationException if the operations can not be rolled back.
-   */
-  private static void rollback(ObservableWaveletData wavelet, 
List<TransformedWaveletDelta> deltas)
-      throws OperationException {
-    List<WaveletOperation> inverseOps = Lists.newArrayList();
-
-    // Go through everything in reverse order
-    for (int i = deltas.size() - 1; i >= 0; i--) {
-      TransformedWaveletDelta delta = deltas.get(i);
-      // Metadata such as the last modified ts will change due to the rollback
-      // of operations.
-      for (int j = delta.size() - 1; j >= 0; j--) {
-        WaveletOperation op = delta.get(j);
-        WaveletOperation inverseOp = WaveletOperationInverter.invert(op);
-        inverseOps.add(inverseOp);
-      }
-    }
-
-    long startVersion = wavelet.getVersion();
-    int opCount = 0;
-    for (WaveletOperation inverseOp : inverseOps) {
-      inverseOp.apply(wavelet);
-      opCount++;
-    }
-    if (wavelet.getVersion() != startVersion - opCount) {
-      throw new OperationException("Expected end version " + (startVersion - 
opCount)
-          + " doesn't match the version of the wavelet " + 
wavelet.getVersion());
-    }
-  }
-
-  /**
-   * Constructs a {@link WaveletAndDeltas} from the given {@link WaveletData}
-   * and {@link WaveletDelta}s.
-   *
-   * @param preDeltasSnapshot the state of the wavelet before the deltas have
-   *        been applied.
-   * @param postDeltasSnapshot the state of the wavelet after the deltas have
-   *        been applied.
-   * @param deltas deltas in the order they have been applied to the wavelet.
-   */
-  private WaveletAndDeltas(ObservableWaveletData preDeltasSnapshot,
-      ObservableWaveletData postDeltasSnapshot, DeltaSequence deltas) {
-    this.snapshotBeforeDeltas = preDeltasSnapshot;
-    this.deltas = deltas;
-    this.snapshotAfterDeltas = postDeltasSnapshot;
-    this.waveletName = WaveletDataUtil.waveletNameOf(preDeltasSnapshot);
-  }
-
-  /**
-   * Returns the wavelet before any deltas have been applied.
-   */
-  public ReadableWaveletData getSnapshotBeforeDeltas() {
-    return snapshotBeforeDeltas;
-  }
-
-  /**
-   * Returns all deltas collected.
-   */
-  public DeltaSequence getDeltas() {
-    return deltas;
-  }
-
-  /**
-   * Returns the latest snapshot with all deltas applied.
-   */
-  public ReadableWaveletData getSnapshotAfterDeltas() {
-    return snapshotAfterDeltas;
-  }
-
-  /**
-   * Returns the {@link HashedVersion} of the wavelet after all deltas have 
been
-   * applied.
-   */
-  public HashedVersion getVersionAfterDeltas() {
-    return deltas.isEmpty() ? snapshotAfterDeltas.getHashedVersion() : 
deltas.getEndVersion();
-  }
-
-  /**
-   * Appends the given deltas to the deltas already stored. Updates the latest
-   * snapshot and latest version as well. This method will make a copy of the
-   * snapshot.
-   *
-   * @param updatedSnapshot the snapshot after deltas have been applied
-   * @param newDeltas the deltas that have been applied since the last call to
-   *        appendDeltas.
-   */
-  public void appendDeltas(ReadableWaveletData updatedSnapshot,
-      DeltaSequence newDeltas) {
-    HashedVersion newEndVersion = newDeltas.getEndVersion();
-    Preconditions.checkArgument(
-        !newDeltas.isEmpty(), "There were no new deltas passed to 
appendDeltas");
-    Preconditions.checkArgument(updatedSnapshot.getVersion() == 
newEndVersion.getVersion(),
-        String.format("Version of snapshot %s doesn't match the HashedVersion 
%s",
-            updatedSnapshot.getVersion(), newEndVersion));
-    Preconditions.checkArgument(areContiguousToCurrentVersion(newDeltas), 
String.format(
-        "Deltas are not contiguous to the current version(%s) %s", 
getVersionAfterDeltas(), deltas));
-    WaveletName updatedWaveletName = 
WaveletDataUtil.waveletNameOf(updatedSnapshot);
-    Preconditions.checkArgument(updatedWaveletName.equals(waveletName),
-        String.format(
-            "Updated wavelet doesn't have the same name as with which this 
class has been "
-                + "instantiated. %s != %s", updatedWaveletName, waveletName));
-
-    // TODO(ljvderijk): This should actually be applying the deltas, however
-    // they do not contain a timestamp at this time.
-    snapshotAfterDeltas = WaveletDataUtil.copyWavelet(updatedSnapshot);
-    deltas = DeltaSequence.join(deltas, newDeltas);
-  }
-
-  /**
-   * Returns true if the given deltas apply to the current version of this
-   * wavelet and they are contiguous.
-   *
-   * @param deltas the list of deltas to check.
-   */
-  public boolean areContiguousToCurrentVersion(DeltaSequence deltas) {
-    return deltas.getStartVersion() == getVersionAfterDeltas().getVersion();
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/passive/WaveletOperationInverter.java
----------------------------------------------------------------------
diff --git 
a/src/org/waveprotocol/box/server/robots/passive/WaveletOperationInverter.java 
b/src/org/waveprotocol/box/server/robots/passive/WaveletOperationInverter.java
deleted file mode 100644
index 3b7e124..0000000
--- 
a/src/org/waveprotocol/box/server/robots/passive/WaveletOperationInverter.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.box.server.robots.passive;
-
-import org.waveprotocol.wave.model.document.operation.algorithm.DocOpInverter;
-import org.waveprotocol.wave.model.operation.wave.AddParticipant;
-import org.waveprotocol.wave.model.operation.wave.BlipContentOperation;
-import org.waveprotocol.wave.model.operation.wave.BlipOperation;
-import org.waveprotocol.wave.model.operation.wave.BlipOperationVisitor;
-import org.waveprotocol.wave.model.operation.wave.NoOp;
-import org.waveprotocol.wave.model.operation.wave.RemoveParticipant;
-import org.waveprotocol.wave.model.operation.wave.SubmitBlip;
-import org.waveprotocol.wave.model.operation.wave.VersionUpdateOp;
-import org.waveprotocol.wave.model.operation.wave.WaveletBlipOperation;
-import org.waveprotocol.wave.model.operation.wave.WaveletOperation;
-import org.waveprotocol.wave.model.operation.wave.WaveletOperationContext;
-import org.waveprotocol.wave.model.operation.wave.WaveletOperationVisitor;
-
-/**
- * Approximately inverts an applied wavelet operation.
- *
- * The only contract this inverter provides is that:
- *
- * <pre class="code">invert(o) ; o == id </pre>
- *
- * i.e., given any state {@code s} that was reached by an operation {@code o},
- * the "previous" state {@code s'} can be constructed {@code s' = invert(o)(s)}
- * such that applying {@code o} to it will return to the given state {@code s}.
- *
- * This inverter does not accept operations that do not appear in a wavelet's
- * history (e.g., {@link VersionUpdateOp}).
- *
- * TODO(anorth): Move to {@link org.waveprotocol.wave.model.operation.wave}.
- *
- * @author [email protected] (David Hearnden)
- */
-final class WaveletOperationInverter implements WaveletOperationVisitor {
-
-  /**
-   * Inverts a blip operation, ignoring metadata.
-   */
-  final static class BlipOperationInverter implements BlipOperationVisitor {
-    private final WaveletOperationContext reverseContext;
-    private BlipOperation inverse;
-
-    BlipOperationInverter(WaveletOperationContext reverseContext) {
-      this.reverseContext = reverseContext;
-    }
-
-    static BlipOperation invert(WaveletOperationContext reverseContext, 
BlipOperation op) {
-      return new BlipOperationInverter(reverseContext).visit(op);
-    }
-
-    private BlipOperation visit(BlipOperation op) {
-      op.acceptVisitor(this);
-      return inverse;
-    }
-
-    @Override
-    public void visitBlipContentOperation(BlipContentOperation op) {
-      inverse = new BlipContentOperation(reverseContext, 
DocOpInverter.invert(op.getContentOp()));
-    }
-
-    @Override
-    public void visitSubmitBlip(SubmitBlip op) {
-      inverse = new SubmitBlip(reverseContext);
-    }
-  }
-
-  private final WaveletOperationContext reverseContext;
-  private WaveletOperation inverse;
-
-  WaveletOperationInverter(WaveletOperationContext reverseContext) {
-    this.reverseContext = reverseContext;
-  }
-
-  /**
-   * Inverts an operation.
-   */
-  static WaveletOperation invert(WaveletOperation op) {
-    WaveletOperationContext forwardContext = op.getContext();
-    WaveletOperationContext reverseContext = new WaveletOperationContext( //
-        forwardContext.getCreator(),
-        // Lie, and keep the same modification time.
-        forwardContext.getTimestamp(),
-        // Correctly invert the version increment.
-        -forwardContext.getVersionIncrement(),
-        // Lie again, and report the hashed version as the same as after op.
-        // This makes it out of sync with the version number.
-        forwardContext.getHashedVersion());
-    return new WaveletOperationInverter(reverseContext).visit(op);
-  }
-
-  private WaveletOperation visit(WaveletOperation op) {
-    op.acceptVisitor(this);
-    return inverse;
-  }
-
-  @Override
-  public void visitWaveletBlipOperation(WaveletBlipOperation op) {
-    inverse = new WaveletBlipOperation(
-        op.getBlipId(), BlipOperationInverter.invert(reverseContext, 
op.getBlipOp()));
-  }
-
-  @Override
-  public void visitVersionUpdateOp(VersionUpdateOp op) {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  public void visitAddParticipant(AddParticipant op) {
-    inverse = new RemoveParticipant(reverseContext, op.getParticipantId());
-  }
-
-  @Override
-  public void visitRemoveParticipant(RemoveParticipant op) {
-    inverse = new AddParticipant(reverseContext, op.getParticipantId());
-  }
-
-  @Override
-  public void visitNoOp(NoOp op) {
-    inverse = new NoOp(reverseContext);
-  }
-}

Reply via email to