http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/BaseApiServlet.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/BaseApiServlet.java
 
b/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/BaseApiServlet.java
deleted file mode 100644
index 6ddf7b4..0000000
--- 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/BaseApiServlet.java
+++ /dev/null
@@ -1,201 +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.dataapi;
-
-import com.google.common.collect.Lists;
-import com.google.wave.api.InvalidRequestException;
-import com.google.wave.api.JsonRpcResponse;
-import com.google.wave.api.OperationRequest;
-import com.google.wave.api.ProtocolVersion;
-import com.google.wave.api.RobotSerializer;
-import com.google.wave.api.data.converter.EventDataConverterManager;
-import com.google.wave.api.impl.GsonFactory;
-
-import net.oauth.OAuthAccessor;
-import net.oauth.OAuthException;
-import net.oauth.OAuthMessage;
-import net.oauth.OAuthValidator;
-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.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.wave.ParticipantId;
-import org.waveprotocol.wave.util.logging.Log;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.net.URISyntaxException;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * The base {@link HttpServlet} for {@link DataApiServlet} and
- * {@link ActiveApiServlet}.
- * 
- * @author [email protected] (Lennard de Rijk)
- * @author [email protected] (Yuri Z.)
- */
-@SuppressWarnings("serial")
-public abstract class BaseApiServlet extends HttpServlet {
-
-  private static final Log LOG = Log.get(BaseApiServlet.class);
-  private static final WaveletProvider.SubmitRequestListener 
LOGGING_REQUEST_LISTENER =
-      new LoggingRequestListener(LOG);
-  private static final String JSON_CONTENT_TYPE = "application/json";
-
-  private final RobotSerializer robotSerializer;
-  private final EventDataConverterManager converterManager;
-  private final WaveletProvider waveletProvider;
-  private final OperationServiceRegistry operationRegistry;
-  private final ConversationUtil conversationUtil;
-  private final OAuthValidator validator;
-  
-  /** Holds incoming operation requests. */
-  private List<OperationRequest> operations;
-
-  public BaseApiServlet(RobotSerializer robotSerializer,
-      EventDataConverterManager converterManager, WaveletProvider 
waveletProvider,
-      OperationServiceRegistry operationRegistry, ConversationUtil 
conversationUtil,
-      OAuthValidator validator) {
-    this.robotSerializer = robotSerializer;
-    this.converterManager = converterManager;
-    this.waveletProvider = waveletProvider;
-    this.conversationUtil = conversationUtil;
-    this.operationRegistry = operationRegistry;
-    this.validator = validator;
-  }
-
-  /**
-   *  Validates OAUTH and executes operations.
-   * 
-   * @param req the request.
-   * @param resp the response.
-   * @param message the OAUTH message.
-   * @param accessor the OAUTH accessor.
-   * @param participant the author for which to perform the robot operations.
-   * @throws IOException if encountered errors during writing of a response.
-   */
-  protected final void processOpsRequest(HttpServletRequest req, 
HttpServletResponse resp, OAuthMessage message,
-      OAuthAccessor accessor, ParticipantId participant) throws IOException {
-    try {
-      validator.validateMessage(message, accessor);
-    } catch (OAuthException e) {
-      LOG.info("The message does not conform to OAuth", e);
-      resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-      return;
-    } catch (URISyntaxException e) {
-      LOG.info("The message URL is invalid", e);
-      resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-      return;
-    }
-
-    String apiRequest;
-    try {
-      // message.readBodyAsString() doesn't work due to a NPE in the OAuth
-      // libraries.
-      BufferedReader reader = req.getReader();
-      apiRequest = reader.readLine();
-    } catch (IOException e) {
-      LOG.warning("Unable to read the incoming request", e);
-      throw e;
-    }
-
-    LOG.info("Received the following Json: " + apiRequest);
-    try {
-      operations = robotSerializer.deserializeOperations(apiRequest);
-    } catch (InvalidRequestException e) {
-      LOG.info("Unable to parse Json to list of OperationRequests: " + 
apiRequest);
-      resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
-          "Unable to parse Json to list of OperationRequests: " + apiRequest);
-      return;
-    }
-
-    // Create an unbound context.
-    ProtocolVersion version = OperationUtil.getProtocolVersion(operations);
-    OperationContextImpl context = new OperationContextImpl(
-        waveletProvider, converterManager.getEventDataConverter(version), 
conversationUtil);
-
-    executeOperations(context, operations, participant);
-    handleResults(context, resp, version);
-  }
-
-  /**
-   * Executes operations in the given context.
-   *
-   * @param context the context to perform the operations in.
-   * @param operations the operations to perform.
-   * @param author the author for which to perform the robot operations.
-   */
-  private void executeOperations(
-      OperationContext context, List<OperationRequest> operations, 
ParticipantId author) {
-    for (OperationRequest operation : operations) {
-      OperationUtil.executeOperation(operation, operationRegistry, context, 
author);
-    }
-  }
-
-  /**
-   * Handles an {@link OperationResults} by submitting the deltas that are
-   * generated and writing a response to the robot.
-   *
-   * @param results the results of the operations performed.
-   * @param resp the servlet to write the response in.
-   * @param version the version of the protocol to use for writing a response.
-   * @throws IOException if the response can not be written.
-   */
-  private void handleResults(
-      OperationResults results, HttpServletResponse resp, ProtocolVersion 
version)
-      throws IOException {
-    OperationUtil.submitDeltas(results, waveletProvider, 
LOGGING_REQUEST_LISTENER);
-    
-    // Ensure that responses are returned in the same order as corresponding
-    // requests.
-    LinkedList<JsonRpcResponse> responses = Lists.newLinkedList();
-    for (OperationRequest operation : operations) {
-      String opId = operation.getId();
-      JsonRpcResponse response = results.getResponses().get(opId);
-      responses.addLast(response);
-    }
-
-    String jsonResponse =
-        robotSerializer.serialize(responses, 
GsonFactory.JSON_RPC_RESPONSE_LIST_TYPE, version);
-    LOG.info("Returning the following Json: " + jsonResponse);
-
-    // Write the response back through the HttpServlet
-    try {
-      resp.setContentType(JSON_CONTENT_TYPE);
-      PrintWriter writer = resp.getWriter();
-      writer.append(jsonResponse);
-      writer.flush();
-      resp.setStatus(HttpServletResponse.SC_OK);
-    } catch (IOException e) {
-      LOG.severe("IOException during writing of a response", e);
-      throw e;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiOAuthServlet.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiOAuthServlet.java
 
b/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiOAuthServlet.java
deleted file mode 100644
index 6c31853..0000000
--- 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiOAuthServlet.java
+++ /dev/null
@@ -1,416 +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.dataapi;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.cache.CacheBuilder;
-import com.google.gxp.base.GxpContext;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-
-import net.oauth.OAuth;
-import net.oauth.OAuthAccessor;
-import net.oauth.OAuthConsumer;
-import net.oauth.OAuthException;
-import net.oauth.OAuthMessage;
-import net.oauth.OAuthProblemException;
-import net.oauth.OAuthServiceProvider;
-import net.oauth.OAuthValidator;
-import net.oauth.server.HttpRequestMessage;
-
-import org.waveprotocol.box.server.authentication.SessionManager;
-import org.waveprotocol.box.server.gxp.OAuthAuthorizeTokenPage;
-import org.waveprotocol.wave.model.id.TokenGenerator;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.util.logging.Log;
-import org.waveprotocol.box.server.gxp.OAuthAuthorizationCodePage;
-import org.waveprotocol.wave.model.util.CharBase64;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.TimeUnit;
-
-import javax.inject.Singleton;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * Servlet responsible for the 3-legged OAuth dance required for the Data api.
- *
- * @author [email protected] (Lennard de Rijk)
- * @author [email protected] (A. Kaplanov)
- */
-@SuppressWarnings("serial")
-@Singleton
-public class DataApiOAuthServlet extends HttpServlet {
-
-  public static final String DATA_API_OAUTH_PATH = "/robot/dataapi/oauth";
-  private static final Log LOG = Log.get(DataApiOAuthServlet.class);
-  private static final String ANONYMOUS_TOKEN = "anonymous";
-  private static final String ANONYMOUS_TOKEN_SECRET = "anonymous";
-  private static final String HTML_CONTENT_TYPE = "text/html";
-  private static final String PLAIN_CONTENT_TYPE = "text/plain";
-  private static final int TOKEN_LENGTH = 8;
-  private static final int XSRF_TOKEN_TIMEOUT_HOURS = 12;
-
-  private final String requestTokenPath;
-  private final String authorizeTokenPath;
-  private final String accessTokenPath;
-  private final String allTokensPath;
-  private final OAuthServiceProvider serviceProvider;
-  private final OAuthValidator validator;
-  private final DataApiTokenContainer tokenContainer;
-  private final SessionManager sessionManager;
-  private final TokenGenerator tokenGenerator;
-  // TODO(ljvderijk): We should refactor this and use it for our other pages.
-  private final ConcurrentMap<ParticipantId, String> xsrfTokens;
-
-  @Inject
-  public DataApiOAuthServlet(@Named("request_token_path") String 
requestTokenPath,
-      @Named("authorize_token_path") String authorizeTokenPath,
-      @Named("access_token_path") String accessTokenPath,
-      @Named("all_tokens_path") String allTokensPath,
-      OAuthServiceProvider serviceProvider,
-      OAuthValidator validator, DataApiTokenContainer tokenContainer,
-      SessionManager sessionManager, TokenGenerator tokenGenerator) {
-    this.requestTokenPath = requestTokenPath;
-    this.authorizeTokenPath = authorizeTokenPath;
-    this.accessTokenPath = accessTokenPath;
-    this.allTokensPath = allTokensPath;
-    this.serviceProvider = serviceProvider;
-    this.validator = validator;
-    this.tokenContainer = tokenContainer;
-    this.sessionManager = sessionManager;
-    this.tokenGenerator = tokenGenerator;
-    this.xsrfTokens =
-        CacheBuilder.newBuilder()
-          .expireAfterWrite(XSRF_TOKEN_TIMEOUT_HOURS, TimeUnit.HOURS)
-          .<ParticipantId, String>build().asMap();
-  }
-
-  @Override
-  protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws IOException {
-    routeRequest(req, resp);
-  }
-
-
-  @Override
-  protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
throws IOException {
-    routeRequest(req, resp);
-  }
-
-  /** Routes all requests to the appropriate handler */
-  private void routeRequest(HttpServletRequest req, HttpServletResponse resp) 
throws IOException {
-    String pathInfo = req.getPathInfo();
-    if (pathInfo.equals(requestTokenPath)) {
-      doRequestToken(req, resp);
-    } else if (pathInfo.equals(authorizeTokenPath)) {
-      doAuthorizeToken(req, resp);
-    } else if (pathInfo.equals(accessTokenPath)) {
-      doExchangeToken(req, resp);
-    } else if (pathInfo.equals(allTokensPath)) {
-      doAllTokens(req, resp);
-    } else {
-      resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
-    }
-  }
-
-  /**
-   * Handles the request to get a new unauthorized request token.
-   */
-  private void doRequestToken(HttpServletRequest req, HttpServletResponse 
resp) throws IOException {
-    OAuthMessage message = new HttpRequestMessage(req, 
req.getRequestURL().toString());
-
-    // Anyone can generate a request token.
-    OAuthConsumer consumer =
-        new OAuthConsumer("", ANONYMOUS_TOKEN, ANONYMOUS_TOKEN_SECRET, 
serviceProvider);
-    OAuthAccessor accessor = new OAuthAccessor(consumer);
-    try {
-      validator.validateMessage(message, accessor);
-    } catch (OAuthException e) {
-      LOG.info("The message does not conform to OAuth", e);
-      resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-      return;
-    } catch (URISyntaxException e) {
-      LOG.info("The message URL is invalid", e);
-      resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-      return;
-    }
-
-    accessor = tokenContainer.generateRequestToken(consumer);
-
-    resp.setContentType(OAuth.FORM_ENCODED);
-    ServletOutputStream out = resp.getOutputStream();
-    OAuth.formEncode(OAuth.newList(
-        OAuth.OAUTH_TOKEN, accessor.requestToken,
-        OAuth.OAUTH_TOKEN_SECRET, accessor.tokenSecret,
-        OAuth.OAUTH_CALLBACK_CONFIRMED, "true"),
-        out);
-    out.close();
-    resp.setStatus(HttpServletResponse.SC_OK);
-  }
-
-  /**
-   * Handles the request to authorize a token. Checks if the user is logged in,
-   * if not the user is redirected to the login page.
-   *
-   * <p>
-   * If it is a GET request the user will be asked whether permission should be
-   * given. For a POST request we will handle the user's decision.
-   */
-  private void doAuthorizeToken(HttpServletRequest req, HttpServletResponse 
resp)
-      throws IOException {
-    // Check if the OAuth parameters are present, even if we don't use them
-    // during a GET request.
-    OAuthMessage message = new HttpRequestMessage(req, 
req.getRequestURL().toString());
-    try {
-      message.requireParameters(OAuth.OAUTH_CALLBACK, OAuth.OAUTH_TOKEN);
-    } catch (OAuthProblemException e) {
-      LOG.info("Parameter absent", e);
-      resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
-      return;
-    }
-
-    // Check if the user is logged in, else redirect to login.
-    ParticipantId user = sessionManager.getLoggedInUser(req.getSession(false));
-    if (user == null) {
-      resp.sendRedirect(sessionManager.getLoginUrl(
-          DATA_API_OAUTH_PATH + authorizeTokenPath + "?" + 
req.getQueryString()));
-      return;
-    }
-
-    // Check if the request token is valid, note that this doesn't hold after
-    // the call to the container since the token might time out.
-    try {
-      tokenContainer.getRequestTokenAccessor(message.getToken());
-    } catch (OAuthProblemException e) {
-      LOG.info("Trying to load a non existing token for authorization", e);
-      resp.sendError(e.getHttpStatusCode(), e.getMessage());
-      return;
-    }
-
-    if (req.getMethod().equals("GET")) {
-      doAuthorizeTokenGet(req, resp, user);
-    } else if (req.getMethod().equals("POST")) {
-      doAuthorizeTokenPost(req, resp, user, message);
-    } else {
-      throw new IllegalStateException(
-          "This method shouldn't be called outside GET or POST requests");
-    }
-  }
-
-  /**
-   * Handles the GET request to authorize a token by displaying the page asking
-   * for user's permission.
-   *
-   * @param req {@link HttpServletRequest} received.
-   * @param resp {@link HttpServletResponse} to write the response in.
-   * @param user User who wants to authorize the token.
-   */
-  private void doAuthorizeTokenGet(
-      HttpServletRequest req, HttpServletResponse resp, ParticipantId user) 
throws IOException {
-    Preconditions.checkNotNull(user, "User must be supplied");
-    // Ask the user for permission.
-    OAuthAuthorizeTokenPage.write(resp.getWriter(), new 
GxpContext(req.getLocale()),
-        user.getAddress(), getOrGenerateXsrfToken(user));
-    resp.setContentType(HTML_CONTENT_TYPE);
-    resp.setStatus(HttpServletResponse.SC_OK);
-    return;
-  }
-
-  /**
-   * Method that handles the POST request for the authorize token page. The
-   * token will be rejected if the user pressed the cancel button. Otherwise 
the
-   * token will be authorized.
-   *
-   * @param req {@link HttpServletRequest} received.
-   * @param resp {@link HttpServletResponse} to write the response in.
-   * @param user user who is authorizing the token.
-   * @param message the {@link OAuthMessage} present in the request.
-   */
-  private void doAuthorizeTokenPost(
-      HttpServletRequest req, HttpServletResponse resp, ParticipantId user, 
OAuthMessage message)
-      throws IOException {
-    Preconditions.checkNotNull(user, "User must be supplied");
-
-    // Check the XSRF token.
-    if (Strings.isNullOrEmpty(req.getParameter("token"))
-        || !req.getParameter("token").equals(xsrfTokens.get(user))) {
-      LOG.warning(
-          "Request without a valid  xsrf token received from " + 
req.getRemoteAddr() + " for user "
-              + user);
-      resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid XSRF 
token");
-      return;
-    }
-    // Check whether the user agreed to give access.
-    if (req.getParameter("cancel") != null) {
-      try {
-        tokenContainer.rejectRequestToken(message.getToken());
-      } catch (OAuthProblemException e) {
-        LOG.info("Rejecting a request token failed", e);
-        resp.sendError(e.getHttpStatusCode(), e.getMessage());
-        return;
-      }
-      resp.setContentType(PLAIN_CONTENT_TYPE);
-      resp.getWriter().append("No access granted, you can now close this 
page.");
-      resp.setStatus(HttpServletResponse.SC_OK);
-      return;
-    } else if (req.getParameter("agree") == null) {
-      // User did not agree nor disagree, bad request.
-      LOG.warning(
-          "Bad request when authorzing a token from " + req.getRemoteAddr() + 
" for user " + user);
-      resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
-      return;
-    }
-
-    // Authorize the token.
-    OAuthAccessor accessor;
-    try {
-      accessor = tokenContainer.authorizeRequestToken(message.getToken(), 
user);
-    } catch (OAuthProblemException e) {
-      LOG.info("Authorizing a request token failed", e);
-      resp.sendError(e.getHttpStatusCode(), e.getMessage());
-      return;
-    }
-
-    // Create the callback url and send the user to it
-    String callback = message.getParameter(OAuth.OAUTH_CALLBACK);
-    callback = OAuth.addParameters(callback, OAuth.OAUTH_TOKEN, 
accessor.requestToken);
-    resp.sendRedirect(callback);
-  }
-
-  /**
-   * Exchanges an authorized request token with an access token.
-   */
-  private void doExchangeToken(HttpServletRequest req, HttpServletResponse 
resp)
-      throws IOException {
-    OAuthMessage message = new HttpRequestMessage(req, 
req.getRequestURL().toString());
-
-    String requestToken = message.getToken();
-    OAuthAccessor accessor;
-    try {
-      accessor = tokenContainer.getRequestTokenAccessor(requestToken);
-    } catch (OAuthProblemException e) {
-      LOG.info("Request token unknown", e);
-      resp.sendError(e.getHttpStatusCode(), e.getMessage());
-      return;
-    }
-
-    try {
-      validator.validateMessage(message, accessor);
-    } catch (OAuthException e) {
-      LOG.info("The message does not conform to OAuth", e);
-      resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-      return;
-    } catch (URISyntaxException e) {
-      LOG.info("The message URL is invalid", e);
-      resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-      return;
-    }
-
-    OAuthAccessor authorizedAccessor;
-    try {
-      authorizedAccessor = 
tokenContainer.generateAccessToken(accessor.requestToken);
-    } catch (OAuthProblemException e) {
-      LOG.info("Request token unknown", e);
-      resp.sendError(e.getHttpStatusCode(), e.getMessage());
-      return;
-    }
-
-    resp.setContentType(OAuth.FORM_ENCODED);
-    ServletOutputStream out = resp.getOutputStream();
-    OAuth.formEncode(OAuth.newList(
-        OAuth.OAUTH_TOKEN, authorizedAccessor.accessToken,
-        OAuth.OAUTH_TOKEN_SECRET, authorizedAccessor.tokenSecret,
-        OAuth.OAUTH_CALLBACK_CONFIRMED, "true"),
-        out);
-    out.close();
-    resp.setStatus(HttpServletResponse.SC_OK);
-  }
-
-  /**
-   * Perform full Auth dance and print tokens.
-   */
-  private void doAllTokens(HttpServletRequest req, HttpServletResponse resp) 
throws IOException {
-    OAuthMessage message = new HttpRequestMessage(req, 
req.getRequestURL().toString());
-    String requestToken = message.getToken();
-    if (requestToken == null) {
-      OAuthConsumer consumer =
-          new OAuthConsumer("", ANONYMOUS_TOKEN, ANONYMOUS_TOKEN_SECRET, 
serviceProvider);
-      OAuthAccessor accessor = tokenContainer.generateRequestToken(consumer);
-      String url = accessor.consumer.serviceProvider.userAuthorizationURL
-          + "?oauth_token=" + accessor.requestToken + "&oauth_callback="
-          + req.getRequestURL().toString() + "&hd=default";
-      resp.sendRedirect(url);
-    } else {
-      OAuthAccessor accessor;
-      try {
-        accessor = tokenContainer.getRequestTokenAccessor(requestToken);
-      } catch (OAuthProblemException e) {
-        LOG.info("Request token unknown", e);
-        resp.sendError(e.getHttpStatusCode(), e.getMessage());
-        return;
-      }
-      OAuthAccessor authorizedAccessor;
-      try {
-        authorizedAccessor = 
tokenContainer.generateAccessToken(accessor.requestToken);
-      } catch (OAuthProblemException e) {
-        LOG.info("Request token unknown", e);
-        resp.sendError(e.getHttpStatusCode(), e.getMessage());
-        return;
-      }
-      String authorizationCode = authorizedAccessor.requestToken + " "
-          + authorizedAccessor.accessToken + " " + 
authorizedAccessor.tokenSecret;
-      String base64AuthCode = CharBase64.encode(authorizationCode.getBytes());
-      OAuthAuthorizationCodePage.write(resp.getWriter(), new 
GxpContext(req.getLocale()),
-          base64AuthCode);
-      resp.setContentType(HTML_CONTENT_TYPE);
-      resp.setStatus(HttpServletResponse.SC_OK);
-    }
-  }
-
-  /**
-   * Gets or generates an XSRF token for the given user.
-   *
-   * <p>
-   * XSRF is an attack where, for instance, another web site makes the user's
-   * browser do a POST request to authorize a request token. Because the user's
-   * browser might contain an valid login cookie for "Wave in a Box" this would
-   * succeed. By adding a hidden field on each form with a random token and
-   * checking the presence of this token the attack can be countered because 
the
-   * attacker does not know the token.
-   *
-   * @param user the user to generate a token for.
-   */
-  @VisibleForTesting
-  String getOrGenerateXsrfToken(ParticipantId user) {
-    String token = tokenGenerator.generateToken(TOKEN_LENGTH);
-    String previousToken = xsrfTokens.putIfAbsent(user, token);
-    if (previousToken != null) {
-      token = previousToken;
-    }
-    return token;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiOperationServiceRegistry.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiOperationServiceRegistry.java
 
b/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiOperationServiceRegistry.java
deleted file mode 100644
index cfaf64a..0000000
--- 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiOperationServiceRegistry.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.dataapi;
-
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.wave.api.OperationType;
-
-import org.waveprotocol.box.server.robots.AbstractOperationServiceRegistry;
-import org.waveprotocol.box.server.robots.operations.*;
-
-/**
- * A registry of {@link OperationService}s for the data API.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public final class DataApiOperationServiceRegistry extends 
AbstractOperationServiceRegistry {
-  // Suppressing warnings about operations that are deprecated but still used 
by
-  // the default client libraries
-  @SuppressWarnings("deprecation")
-  @Inject
-  public DataApiOperationServiceRegistry(Injector injector) {
-    super();
-
-    // Register all the OperationProviders
-    register(OperationType.ROBOT_NOTIFY, DoNothingService.create());
-    register(OperationType.ROBOT_NOTIFY_CAPABILITIES_HASH, 
DoNothingService.create());
-    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.ROBOT_CREATE_WAVELET, 
CreateWaveletService.create());
-    register(OperationType.ROBOT_FETCH_WAVE, FetchWaveService.create());
-    register(OperationType.DOCUMENT_MODIFY, DocumentModifyService.create());
-    register(OperationType.ROBOT_SEARCH, 
injector.getInstance(SearchService.class));
-    register(OperationType.WAVELET_SET_TITLE, WaveletSetTitleService.create());
-    register(OperationType.ROBOT_FOLDER_ACTION, FolderActionService.create());
-    register(OperationType.ROBOT_FETCH_PROFILES, 
injector.getInstance(FetchProfilesService.class));
-    register(OperationType.ROBOT_EXPORT_SNAPSHOT, 
ExportSnapshotService.create());
-    register(OperationType.ROBOT_EXPORT_DELTAS, ExportDeltasService.create());
-    register(OperationType.ROBOT_EXPORT_ATTACHMENT, 
injector.getInstance(ExportAttachmentService.class));
-    register(OperationType.ROBOT_IMPORT_DELTAS, 
injector.getInstance(ImportDeltasService.class));
-    register(OperationType.ROBOT_IMPORT_ATTACHMENT, 
injector.getInstance(ImportAttachmentService.class));
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiServlet.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiServlet.java
 
b/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiServlet.java
deleted file mode 100644
index 18743b5..0000000
--- 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiServlet.java
+++ /dev/null
@@ -1,93 +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.dataapi;
-
-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 net.oauth.OAuth;
-import net.oauth.OAuthAccessor;
-import net.oauth.OAuthMessage;
-import net.oauth.OAuthProblemException;
-import net.oauth.OAuthValidator;
-import net.oauth.server.HttpRequestMessage;
-
-import org.waveprotocol.box.server.robots.OperationServiceRegistry;
-import org.waveprotocol.box.server.robots.util.ConversationUtil;
-import org.waveprotocol.box.server.waveserver.WaveletProvider;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.util.logging.Log;
-
-import java.io.IOException;
-
-import javax.inject.Singleton;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * {@link HttpServlet} that serves as the endpoint for the Data Api.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-@SuppressWarnings("serial")
-@Singleton
-public class DataApiServlet extends BaseApiServlet {
-
-  private static final Log LOG = Log.get(DataApiServlet.class);
-  private final DataApiTokenContainer tokenContainer;
-  
-  @Inject
-  public DataApiServlet(RobotSerializer robotSerializer,
-      EventDataConverterManager converterManager, WaveletProvider 
waveletProvider,
-      @Named("DataApiRegistry") OperationServiceRegistry operationRegistry,
-      ConversationUtil conversationUtil, OAuthValidator validator,
-      DataApiTokenContainer tokenContainer) {
-    super(robotSerializer, converterManager, waveletProvider, 
operationRegistry, conversationUtil,
-        validator);
-    this.tokenContainer = tokenContainer;
-  }
-  
-  /**
-   * Entry point for the Data API Calls.
-   */
-  @Override
-  protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
throws IOException {
-    OAuthMessage message = new HttpRequestMessage(req, 
req.getRequestURL().toString());
-
-    OAuthAccessor accessor;
-    try {
-      message.requireParameters(OAuth.OAUTH_TOKEN);
-      accessor = 
tokenContainer.getAccessTokenAccessor(message.getParameter(OAuth.OAUTH_TOKEN));
-    } catch (OAuthProblemException e) {
-      LOG.info("No valid OAuth token present", e);
-      // Have to set status here manually, cannot use e.getHttpStatusCode
-      // because message.requireParameters doesn't set it in the exception.
-      resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
-      return;
-    }
-    ParticipantId participant =
-        (ParticipantId) 
accessor.getProperty(DataApiTokenContainer.USER_PROPERTY_NAME);
-    
-    processOpsRequest(req, resp, message, accessor, participant);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiTokenContainer.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiTokenContainer.java
 
b/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiTokenContainer.java
deleted file mode 100644
index 6032088..0000000
--- 
a/wave/src/main/java/org/waveprotocol/box/server/robots/dataapi/DataApiTokenContainer.java
+++ /dev/null
@@ -1,226 +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.dataapi;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.collect.MapMaker;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-import net.oauth.OAuth;
-import net.oauth.OAuthAccessor;
-import net.oauth.OAuthConsumer;
-import net.oauth.OAuthProblemException;
-
-import org.waveprotocol.box.server.util.OAuthUtil;
-import org.waveprotocol.wave.model.id.TokenGenerator;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.util.logging.Log;
-
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Container to handle request and access tokens for the Data Api.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-@Singleton
-public final class DataApiTokenContainer {
-
-  private static final Log LOG = Log.get(DataApiTokenContainer.class);
-
-  /** Length of a token in number of characters */
-  private static final int TOKEN_LENGTH = 48;
-
-  /** Number of minutes a request token is valid */
-  private static final int REQUEST_TOKEN_EXPIRATION = 10;
-
-  /**
-   * Number of minutes an access token is valid, public so this can be shown to
-   * the user
-   */
-  public static final int ACCESS_TOKEN_EXPIRATION = 60;
-  public static final String USER_PROPERTY_NAME = "user";
-
-  /** Map containing unauthorized accessors indexed on their request token */
-  private ConcurrentMap<String, OAuthAccessor> requestTokenAccessors;
-
-  /** Map containing the authorized accessors indexed on the access token */
-  private ConcurrentMap<String, OAuthAccessor> accessTokenAccessors;
-
-  /** Used to generate OAuth tokens */
-  private final TokenGenerator tokenGenerator;
-
-  @Inject
-  @VisibleForTesting
-  DataApiTokenContainer(TokenGenerator tokenGenerator) {
-    this.tokenGenerator = tokenGenerator;
-
-    requestTokenAccessors =
-        CacheBuilder.newBuilder().expireAfterWrite(REQUEST_TOKEN_EXPIRATION, 
TimeUnit.MINUTES)
-        .<String, OAuthAccessor>build().asMap();
-    accessTokenAccessors =
-        CacheBuilder.newBuilder().expireAfterWrite(ACCESS_TOKEN_EXPIRATION, 
TimeUnit.MINUTES)
-        .<String, OAuthAccessor>build().asMap();
-  }
-
-  /**
-   * Gets the {@link OAuthAccessor} that is identified by the given request
-   * token. Any changes made to the accessor's fields, except the consumer, 
will
-   * not be reflected in this container.
-   *
-   * @param requestToken the request token used for identification.
-   * @throws OAuthProblemException if the token does not map to an accessor.
-   */
-  public OAuthAccessor getRequestTokenAccessor(String requestToken) throws 
OAuthProblemException {
-    OAuthAccessor accessor = requestTokenAccessors.get(requestToken);
-    if (accessor == null) {
-      OAuthProblemException exception =
-          OAuthUtil.newOAuthProblemException(OAuth.Problems.TOKEN_REJECTED);
-      exception.setParameter(OAuth.OAUTH_TOKEN, requestToken);
-      throw exception;
-    }
-    return accessor.clone();
-  }
-
-  /**
-   * Gets the authorized {@link OAuthAccessor} that is identified by the given
-   * access token. Any changes made to the accessor's fields, except the
-   * consumer, will not be reflected in this container.
-   *
-   * @param accessToken the access token used for identification.
-   * @throws OAuthProblemException if the token does not map to an accessor.
-   */
-  public OAuthAccessor getAccessTokenAccessor(String accessToken) throws 
OAuthProblemException {
-    OAuthAccessor accessor = accessTokenAccessors.get(accessToken);
-    if (accessor == null) {
-      OAuthProblemException exception =
-          OAuthUtil.newOAuthProblemException(OAuth.Problems.TOKEN_REJECTED);
-      exception.setParameter(OAuth.OAUTH_TOKEN, accessToken);
-      throw exception;
-    }
-    return accessor.clone();
-  }
-
-  /**
-   * Generates a new request token for the given {@link OAuthConsumer}.
-   *
-   * @param consumer the consumer to generate the token for.
-   */
-  public OAuthAccessor generateRequestToken(OAuthConsumer consumer) {
-    Preconditions.checkNotNull(consumer, "Consumer must not be null");
-
-    // Accessor can be generated up front with a token secret that does not 
need
-    // to be unique.
-    OAuthAccessor accessor = new OAuthAccessor(consumer);
-    accessor.tokenSecret = generateToken();
-
-    do {
-      accessor.requestToken = generateToken();
-    } while (requestTokenAccessors.putIfAbsent(accessor.requestToken, 
accessor) != null);
-
-    return accessor.clone();
-  }
-
-  /**
-   * Authorizes a request token to be exchanged for an access token.
-   *
-   * @param requestToken the request token used for identification.
-   * @param user the user that has authorized the token.
-   * @throws OAuthProblemException if the request token does not map to an
-   *         accessor or if the token was already used.
-   */
-  public OAuthAccessor authorizeRequestToken(String requestToken, 
ParticipantId user)
-      throws OAuthProblemException {
-    Preconditions.checkNotNull(user, "User must not be null");
-
-    OAuthAccessor accessor = getRequestTokenAccessor(requestToken);
-
-    if (accessor.getProperty(USER_PROPERTY_NAME) != null) {
-      throw OAuthUtil.newOAuthProblemException(OAuth.Problems.TOKEN_USED);
-    }
-
-    accessor.setProperty(USER_PROPERTY_NAME, user);
-    requestTokenAccessors.put(requestToken, accessor);
-
-    LOG.info("Authorized request token for " + user);
-    return accessor.clone();
-  }
-
-  /**
-   * Rejects authorization of a request token.
-   *
-   * @param requestToken the request token used for identification.
-   * @throws OAuthProblemException if the request token does not map to an
-   *         accessor or if the token was already used.
-   */
-  public void rejectRequestToken(String requestToken) throws 
OAuthProblemException {
-    OAuthAccessor accessor = getRequestTokenAccessor(requestToken);
-
-    if (accessor.getProperty(USER_PROPERTY_NAME) != null) {
-      throw OAuthUtil.newOAuthProblemException(OAuth.Problems.TOKEN_USED);
-    }
-
-    // Can't use remove(String, OAuthAccessor) since equals is not defined.
-    requestTokenAccessors.remove(requestToken);
-    LOG.info("Rejected request token " + requestToken);
-  }
-
-  /**
-   * Authorize the {@link OAuthAccessor} by generating a new access token and
-   * token secret.
-   *
-   * @param requestToken the requestToken used for identifying the accessor 
that
-   *        needs to be authorized.
-   * @return a new {@link OAuthAccessor} with the access token and token secret
-   *         set.
-   * @throws OAuthProblemException if the request token in the accessor is not
-   *         known.
-   */
-  public OAuthAccessor generateAccessToken(String requestToken) throws 
OAuthProblemException {
-    OAuthAccessor accessor = getRequestTokenAccessor(requestToken);
-
-    if (accessor.getProperty(USER_PROPERTY_NAME) == null) {
-      // User has not given the consumer permission yet.
-      throw 
OAuthUtil.newOAuthProblemException(OAuth.Problems.PERMISSION_UNKNOWN);
-    }
-
-    // Token secret does not need to unique so can be generated now.
-    accessor.tokenSecret = generateToken();
-
-    do {
-      accessor.accessToken = generateToken();
-    } while (accessTokenAccessors.putIfAbsent(accessor.accessToken, accessor) 
!= null);
-    requestTokenAccessors.remove(accessor.requestToken);
-
-    LOG.info("Generated access token for " + 
accessor.getProperty(USER_PROPERTY_NAME));
-    return accessor.clone();
-  }
-
-  /**
-   * Generates an OAuth token.
-   */
-  private String generateToken() {
-    return tokenGenerator.generateToken(TOKEN_LENGTH);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/box/server/robots/operations/BlipOperationServices.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/box/server/robots/operations/BlipOperationServices.java
 
b/wave/src/main/java/org/waveprotocol/box/server/robots/operations/BlipOperationServices.java
deleted file mode 100644
index 767d7f9..0000000
--- 
a/wave/src/main/java/org/waveprotocol/box/server/robots/operations/BlipOperationServices.java
+++ /dev/null
@@ -1,425 +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.base.Preconditions;
-import com.google.common.collect.Maps;
-import com.google.wave.api.ApiIdSerializer;
-import com.google.wave.api.BlipData;
-import com.google.wave.api.Element;
-import com.google.wave.api.InvalidRequestException;
-import com.google.wave.api.OperationRequest;
-import com.google.wave.api.OperationType;
-import com.google.wave.api.JsonRpcConstant.ParamsProperty;
-import com.google.wave.api.data.ApiView;
-import com.google.wave.api.event.WaveletBlipCreatedEvent;
-
-import org.waveprotocol.box.server.robots.OperationContext;
-import org.waveprotocol.box.server.robots.util.ConversationUtil;
-import org.waveprotocol.box.server.robots.util.OperationUtil;
-import org.waveprotocol.wave.model.conversation.ConversationBlip;
-import org.waveprotocol.wave.model.conversation.ObservableConversation;
-import org.waveprotocol.wave.model.conversation.ObservableConversationBlip;
-import org.waveprotocol.wave.model.conversation.ObservableConversationView;
-import org.waveprotocol.wave.model.conversation.WaveletBasedConversation;
-import org.waveprotocol.wave.model.document.Doc;
-import org.waveprotocol.wave.model.document.Document;
-import org.waveprotocol.wave.model.document.util.LineContainers;
-import org.waveprotocol.wave.model.document.util.Point;
-import org.waveprotocol.wave.model.document.util.XmlStringBuilder;
-import org.waveprotocol.wave.model.id.InvalidIdException;
-import org.waveprotocol.wave.model.wave.ObservableWavelet;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.model.wave.opbased.OpBasedWavelet;
-
-/**
- * {@link OperationService} for methods that create or deletes a blip.
- *
- * <p>
- * These methods are:
- * <li>{@link OperationType#BLIP_CONTINUE_THREAD}</li>
- * <li>{@link OperationType#BLIP_CREATE_CHILD}</li>
- * <li>{@link OperationType#WAVELET_APPEND_BLIP}</li>
- * <li>{@link OperationType#DOCUMENT_APPEND_INLINE_BLIP}</li>
- * <li>{@link OperationType#DOCUMENT_APPEND_MARKUP}</li>
- * <li>{@link OperationType#DOCUMENT_INSERT_INLINE_BLIP}</li>
- * <li>{@link OperationType#DOCUMENT_INSERT_INLINE_BLIP_AFTER_ELEMENT}</li>
- * <li>{@link OperationType#BLIP_DELETE}</li>.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public class BlipOperationServices implements OperationService {
-
-  private BlipOperationServices() {
-  }
-
-  @Override
-  public void execute(
-      OperationRequest operation, OperationContext context, ParticipantId 
participant)
-      throws InvalidRequestException {
-    OpBasedWavelet wavelet = context.openWavelet(operation, participant);
-    ObservableConversationView conversationView = 
context.openConversation(operation, participant);
-
-    String waveletId = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.WAVELET_ID);
-    String conversationId;
-
-    try {
-      // TODO(anorth): Remove this round-trip when the API instead talks about
-      // opaque conversation ids, and doesn't use legacy id serialization.
-      conversationId = WaveletBasedConversation.idFor(
-          ApiIdSerializer.instance().deserialiseWaveletId(waveletId));
-    } catch (InvalidIdException e) {
-      throw new InvalidRequestException("Invalid conversation id", operation, 
e);
-    }
-    ObservableConversation conversation = 
conversationView.getConversation(conversationId);
-
-    OperationType type = OperationUtil.getOperationType(operation);
-    switch (type) {
-      case BLIP_CONTINUE_THREAD:
-        continueThread(operation, context, participant, conversation);
-        break;
-      case BLIP_CREATE_CHILD:
-        createChild(operation, context, participant, conversation);
-        break;
-      case WAVELET_APPEND_BLIP:
-        appendBlip(operation, context, participant, conversation);
-        break;
-      case DOCUMENT_APPEND_INLINE_BLIP:
-        appendInlineBlip(operation, context, participant, wavelet, 
conversation);
-        break;
-      case DOCUMENT_APPEND_MARKUP:
-        appendMarkup(operation, context, participant, wavelet, conversation);
-        break;
-      case DOCUMENT_INSERT_INLINE_BLIP:
-        insertInlineBlip(operation, context, participant, wavelet, 
conversation);
-        break;
-      case DOCUMENT_INSERT_INLINE_BLIP_AFTER_ELEMENT:
-        insertInlineBlipAfterElement(operation, context, participant, wavelet, 
conversation);
-        break;
-      case BLIP_DELETE:
-        delete(operation, context, participant, conversation);
-        break;
-      default:
-        throw new UnsupportedOperationException(
-            "This OperationService does not implement operation of type " + 
type.method());
-    }
-  }
-
-  /**
-   * Implementation of the {@link OperationType#BLIP_CONTINUE_THREAD} method. 
It
-   * appends a new blip to the end of the thread of the blip specified in the
-   * operation.
-   *
-   * @param operation the operation to execute.
-   * @param context the context of the operation.
-   * @param participant the participant performing this operation.
-   * @param conversation the conversation to operate on.
-   * @throws InvalidRequestException if the operation fails to perform
-   */
-  private void continueThread(OperationRequest operation, OperationContext 
context,
-      ParticipantId participant, ObservableConversation conversation)
-      throws InvalidRequestException {
-    Preconditions.checkArgument(
-        OperationUtil.getOperationType(operation) == 
OperationType.BLIP_CONTINUE_THREAD,
-        "Unsupported operation " + operation);
-
-    BlipData blipData = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_DATA);
-    String parentBlipId = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_ID);
-    ConversationBlip parentBlip = context.getBlip(conversation, parentBlipId);
-
-    ConversationBlip newBlip = parentBlip.getThread().appendBlip();
-    context.putBlip(blipData.getBlipId(), newBlip);
-
-    putContentForNewBlip(newBlip, blipData.getContent());
-    processBlipCreatedEvent(operation, context, participant, conversation, 
newBlip);
-  }
-
-  /**
-   * Implementation of the {@link OperationType#BLIP_CREATE_CHILD} method. It
-   * appends a new reply thread to the blip specified in the operation.
-   *
-   * @param operation the operation to execute.
-   * @param context the context of the operation.
-   * @param participant the participant performing this operation.
-   * @param conversation the conversation to operate on.
-   * @throws InvalidRequestException if the operation fails to perform
-   */
-  private void createChild(OperationRequest operation, OperationContext 
context,
-      ParticipantId participant, ObservableConversation conversation)
-      throws InvalidRequestException {
-    Preconditions.checkArgument(
-        OperationUtil.getOperationType(operation) == 
OperationType.BLIP_CREATE_CHILD,
-        "Unsupported operation " + operation);
-
-    BlipData blipData = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_DATA);
-    String parentBlipId = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_ID);
-    ConversationBlip parentBlip = context.getBlip(conversation, parentBlipId);
-
-    ConversationBlip newBlip = parentBlip.addReplyThread().appendBlip();
-    context.putBlip(blipData.getBlipId(), newBlip);
-
-    putContentForNewBlip(newBlip, blipData.getContent());
-    processBlipCreatedEvent(operation, context, participant, conversation, 
newBlip);
-  }
-
-  /**
-   * Implementation for the {@link OperationType#WAVELET_APPEND_BLIP} method. 
It
-   * appends a blip at the end of the root thread.
-   *
-   * @param operation the operation to execute.
-   * @param context the context of the operation.
-   * @param participant the participant performing this operation.
-   * @param conversation the conversation to operate on.
-   * @throws InvalidRequestException if the operation fails to perform
-   */
-  private void appendBlip(OperationRequest operation, OperationContext context,
-      ParticipantId participant, ObservableConversation conversation)
-      throws InvalidRequestException {
-    Preconditions.checkArgument(
-        OperationUtil.getOperationType(operation) == 
OperationType.WAVELET_APPEND_BLIP,
-        "Unsupported operation " + operation);
-
-    BlipData blipData = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_DATA);
-
-    ObservableConversationBlip newBlip = 
conversation.getRootThread().appendBlip();
-    context.putBlip(blipData.getBlipId(), newBlip);
-
-    putContentForNewBlip(newBlip, blipData.getContent());
-    processBlipCreatedEvent(operation, context, participant, conversation, 
newBlip);
-  }
-
-  /**
-   * Implementation for the {@link OperationType#DOCUMENT_APPEND_INLINE_BLIP}
-   * method. It appends an inline blip on a new line in the blip specified in
-   * the operation.
-   *
-   * @param operation the operation to execute.
-   * @param context the context of the operation.
-   * @param participant the participant performing this operation.
-   * @param wavelet the wavelet to operate on.
-   * @param conversation the conversation to operate on.
-   * @throws InvalidRequestException if the operation fails to perform
-   */
-  private void appendInlineBlip(OperationRequest operation, OperationContext 
context,
-      ParticipantId participant, ObservableWavelet wavelet, 
ObservableConversation conversation)
-      throws InvalidRequestException {
-    Preconditions.checkArgument(
-        OperationUtil.getOperationType(operation) == 
OperationType.DOCUMENT_APPEND_INLINE_BLIP,
-        "Unsupported operation " + operation);
-
-    BlipData blipData = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_DATA);
-    String parentBlipId = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_ID);
-    ConversationBlip parentBlip = context.getBlip(conversation, parentBlipId);
-
-    // Append a new, empty line to the doc for the inline anchor.
-    Document doc = parentBlip.getContent();
-    Doc.E line = LineContainers.appendLine(doc, 
XmlStringBuilder.createEmpty());
-
-    // Insert new inline thread with the blip at the empty sentence.
-    int location = doc.getLocation(Point.after(doc, line));
-    ConversationBlip newBlip = 
parentBlip.addReplyThread(location).appendBlip();
-    context.putBlip(blipData.getBlipId(), newBlip);
-
-    putContentForNewBlip(newBlip, blipData.getContent());
-    processBlipCreatedEvent(operation, context, participant, conversation, 
newBlip);
-  }
-
-  /**
-   * Implementation for the {@link OperationType#DOCUMENT_APPEND_MARKUP}
-   * method. It appends markup within the blip specified in
-   * the operation.
-   *
-   * @param operation the operation to execute.
-   * @param context the context of the operation.
-   * @param participant the participant performing this operation.
-   * @param wavelet the wavelet to operate on.
-   * @param conversation the conversation to operate on.
-   * @throws InvalidRequestException if the operation fails to perform
-   */
-  private void appendMarkup(OperationRequest operation, OperationContext 
context,
-      ParticipantId participant, ObservableWavelet wavelet, 
ObservableConversation conversation)
-      throws InvalidRequestException {
-    Preconditions.checkArgument(
-        OperationUtil.getOperationType(operation) == 
OperationType.DOCUMENT_APPEND_MARKUP,
-        "Unsupported operation " + operation);
-
-    String content = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.CONTENT);
-    String blipId = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_ID);
-    ConversationBlip convBlip = context.getBlip(conversation, blipId);
-
-    // Create builder from xml content.
-    XmlStringBuilder markupBuilder = 
XmlStringBuilder.createFromXmlString(content);
-
-    // Append the new markup to the blip doc.
-    Document doc = convBlip.getContent();
-    LineContainers.appendLine(doc, markupBuilder);
-
-    // Report success.
-    context.constructResponse(operation, Maps.<ParamsProperty, Object> 
newHashMap());
-  }
-
-  /**
-   * Implementation for the {@link OperationType#DOCUMENT_INSERT_INLINE_BLIP}
-   * method. It inserts an inline blip at the location specified in the
-   * operation.
-   *
-   * @param operation the operation to execute.
-   * @param context the context of the operation.
-   * @param participant the participant performing this operation.
-   * @param wavelet the wavelet to operate on.
-   * @param conversation the conversation to operate on.
-   * @throws InvalidRequestException if the operation fails to perform
-   */
-  private void insertInlineBlip(OperationRequest operation, OperationContext 
context,
-      ParticipantId participant, ObservableWavelet wavelet, 
ObservableConversation conversation)
-      throws InvalidRequestException {
-    Preconditions.checkArgument(
-        OperationUtil.getOperationType(operation) == 
OperationType.DOCUMENT_INSERT_INLINE_BLIP,
-        "Unsupported operation " + operation);
-
-    BlipData blipData = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_DATA);
-    String parentBlipId = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_ID);
-    ConversationBlip parentBlip = context.getBlip(conversation, parentBlipId);
-
-    Integer index = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.INDEX);
-    if (index <= 0) {
-      throw new InvalidRequestException(
-          "Can't inline a blip on position <= 0, got " + index, operation);
-    }
-
-    ApiView view = new ApiView(parentBlip.getContent(), wavelet);
-    int xmlLocation = view.transformToXmlOffset(index);
-
-    // Insert new inline thread with the blip at the location as specified.
-    ConversationBlip newBlip = 
parentBlip.addReplyThread(xmlLocation).appendBlip();
-    context.putBlip(blipData.getBlipId(), newBlip);
-
-    putContentForNewBlip(newBlip, blipData.getContent());
-    processBlipCreatedEvent(operation, context, participant, conversation, 
newBlip);
-  }
-
-  /**
-   * Implementation for the
-   * {@link OperationType#DOCUMENT_INSERT_INLINE_BLIP_AFTER_ELEMENT} method. It
-   * inserts an inline blip after the element specified in the operation.
-   *
-   * @param operation the operation to execute.
-   * @param context the context of the operation.
-   * @param participant the participant performing this operation.
-   * @param wavelet the wavelet to operate on.
-   * @param conversation the conversation to operate on.
-   * @throws InvalidRequestException if the operation fails to perform
-   */
-  private void insertInlineBlipAfterElement(OperationRequest operation, 
OperationContext context,
-      ParticipantId participant, OpBasedWavelet wavelet, 
ObservableConversation conversation)
-      throws InvalidRequestException {
-    Preconditions.checkArgument(OperationUtil.getOperationType(operation)
-        == OperationType.DOCUMENT_INSERT_INLINE_BLIP_AFTER_ELEMENT,
-        "Unsupported operation " + operation);
-
-    BlipData blipData = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_DATA);
-    String parentBlipId = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_ID);
-    ConversationBlip parentBlip = context.getBlip(conversation, parentBlipId);
-
-    Element element = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.ELEMENT);
-
-    // view.locateElement will tell where the element actually is.
-    ApiView view = new ApiView(parentBlip.getContent(), wavelet);
-    int elementApiLocation = view.locateElement(element);
-
-    if (elementApiLocation == -1) {
-      throw new InvalidRequestException("Requested element not found", 
operation);
-    }
-
-    // Insert just after the requested element
-    int xmlLocation = view.transformToXmlOffset(elementApiLocation + 1);
-
-    // Insert new inline thread with the blip at the location of the element.
-    ConversationBlip newBlip = 
parentBlip.addReplyThread(xmlLocation).appendBlip();
-    context.putBlip(blipData.getBlipId(), newBlip);
-
-    putContentForNewBlip(newBlip, blipData.getContent());
-    processBlipCreatedEvent(operation, context, participant, conversation, 
newBlip);
-  }
-
-  /**
-   * Implementation for the {@link OperationType#BLIP_DELETE} method. It 
deletes
-   * the blip specified in the operation.
-   *
-   * @param operation the operation to execute.
-   * @param context the context of the operation.
-   * @param participant the participant performing this operation.
-   * @param conversation the conversation to operate on.
-   * @throws InvalidRequestException if the operation fails to perform
-   */
-  private void delete(OperationRequest operation, OperationContext context,
-      ParticipantId participant, ObservableConversation conversation)
-      throws InvalidRequestException {
-    Preconditions.checkArgument(
-        OperationUtil.getOperationType(operation) == OperationType.BLIP_DELETE,
-        "Unsupported operation " + operation);
-
-    String blipId = OperationUtil.getRequiredParameter(operation, 
ParamsProperty.BLIP_ID);
-    context.getBlip(conversation, blipId).delete();
-    // report success.
-    context.constructResponse(operation, Maps.<ParamsProperty, Object> 
newHashMap());
-  }
-
-  /**
-   * Inserts content into the new blip.
-   *
-   * @param newBlip the newly created blip.
-   * @param content the content to add.
-   */
-  private void putContentForNewBlip(ConversationBlip newBlip, String content) {
-    if (content.length() > 0 && content.charAt(0) == '\n') {
-      // While the client libraries force a newline to be sent as the first
-      // character we'll remove it here since the new blip we created already
-      // contains a newline.
-      content = content.substring(1);
-    }
-    XmlStringBuilder builder = XmlStringBuilder.createText(content);
-    LineContainers.appendToLastLine(newBlip.getContent(), builder);
-  }
-
-  /**
-   * Processes a {@link WaveletBlipCreatedEvent} and puts it into the context.
-   *
-   * @param operation the operation that has been performed
-   * @param context the context of the operation.
-   * @param participant the participant performing the operation.
-   * @param conversation the conversation to which the new blip was added
-   * @param newBlip the newly created blip.
-   * @throws InvalidRequestException if the event could not be processed.
-   */
-  private void processBlipCreatedEvent(OperationRequest operation, 
OperationContext context,
-      ParticipantId participant, ObservableConversation conversation, 
ConversationBlip newBlip)
-      throws InvalidRequestException {
-    WaveletBlipCreatedEvent event =
-        new WaveletBlipCreatedEvent(null, null, participant.getAddress(),
-            System.currentTimeMillis(), 
ConversationUtil.getRootBlipId(conversation),
-            newBlip.getId());
-    context.processEvent(operation, event);
-  }
-
-  public static BlipOperationServices create() {
-    return new BlipOperationServices();
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/box/server/robots/operations/CreateWaveletService.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/box/server/robots/operations/CreateWaveletService.java
 
b/wave/src/main/java/org/waveprotocol/box/server/robots/operations/CreateWaveletService.java
deleted file mode 100644
index 963d52b..0000000
--- 
a/wave/src/main/java/org/waveprotocol/box/server/robots/operations/CreateWaveletService.java
+++ /dev/null
@@ -1,132 +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 static 
org.waveprotocol.box.server.robots.util.RobotsUtil.createEmptyRobotWavelet;
-
-import com.google.common.collect.Lists;
-import com.google.wave.api.ApiIdSerializer;
-import com.google.wave.api.InvalidRequestException;
-import com.google.wave.api.JsonRpcConstant.ParamsProperty;
-import com.google.wave.api.OperationRequest;
-import com.google.wave.api.event.WaveletCreatedEvent;
-import com.google.wave.api.impl.WaveletData;
-
-import org.waveprotocol.box.server.robots.OperationContext;
-import org.waveprotocol.box.server.robots.RobotWaveletData;
-import org.waveprotocol.box.server.robots.util.OperationUtil;
-import org.waveprotocol.wave.model.conversation.ObservableConversationBlip;
-import org.waveprotocol.wave.model.conversation.ObservableConversationView;
-import org.waveprotocol.wave.model.conversation.WaveletBasedConversation;
-import org.waveprotocol.wave.model.id.InvalidIdException;
-import org.waveprotocol.wave.model.id.WaveId;
-import org.waveprotocol.wave.model.id.WaveletId;
-import org.waveprotocol.wave.model.id.WaveletName;
-import org.waveprotocol.wave.model.wave.InvalidParticipantAddress;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.model.wave.opbased.OpBasedWavelet;
-
-import java.util.List;
-
-/**
- * Implementation of the "wavelet.create" and "robot.createwavelet" operations.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public class CreateWaveletService implements OperationService {
-
-  private CreateWaveletService() {
-  }
-
-  /**
-   * Creates a new wavelet that is conversational based on the given
-   * {@link WaveletData}. Note that this is the robot api version of wavelet
-   * data not to be confused with
-   * {@link org.waveprotocol.wave.model.wave.data.WaveletData}.
-   *
-   * <p>
-   * The wavelet data must define the wave id in the temporary format otherwise
-   * it can not be opened by subsequent operations when calling
-   * {@link OperationContext#openWavelet(String, String, ParticipantId)} with
-   * the temporary wave id and wavelet id.
-   *
-   * @param operation the operation to execute.
-   * @param context the context of the operation.
-   * @param participant the participant performing this operation.
-   * @throws InvalidRequestException if the operation fails to perform.
-   */
-  @Override
-  public void execute(
-      OperationRequest operation, OperationContext context, ParticipantId 
participant)
-      throws InvalidRequestException {
-    WaveletData waveletData =
-        OperationUtil.getRequiredParameter(operation, 
ParamsProperty.WAVELET_DATA);
-
-    // The loop validates the addresses present in the wavelet data before
-    // creating a new wavelet.
-    List<ParticipantId> participants = Lists.newArrayList(participant);
-    for (String address : waveletData.getParticipants()) {
-      try {
-        participants.add(ParticipantId.of(address));
-      } catch (InvalidParticipantAddress e) {
-        throw new InvalidRequestException(
-            address + " is not a valid participant address", operation);
-      }
-    }
-
-    WaveletName waveletName = 
context.getConversationUtil().generateWaveletName();
-    RobotWaveletData newWavelet = createEmptyRobotWavelet(participant, 
waveletName);
-    OpBasedWavelet opBasedWavelet = newWavelet.getOpBasedWavelet(participant);
-
-    WaveletBasedConversation.makeWaveletConversational(opBasedWavelet);
-
-    ObservableConversationView conversation =
-        context.getConversationUtil().buildConversation(opBasedWavelet);
-    ObservableConversationBlip rootBlip = 
conversation.getRoot().getRootThread().appendBlip();
-
-    for (ParticipantId newParticipant : participants) {
-      opBasedWavelet.addParticipant(newParticipant);
-    }
-
-    // Store the temporary id of the wavelet and rootblip so that future
-    // operations can reference it.
-    try {
-      WaveId waveId = 
ApiIdSerializer.instance().deserialiseWaveId(waveletData.getWaveId());
-      WaveletId waveletId =
-          
ApiIdSerializer.instance().deserialiseWaveletId(waveletData.getWaveletId());
-      context.putWavelet(waveId, waveletId, newWavelet);
-    } catch (InvalidIdException e) {
-      throw new InvalidRequestException("Invalid id", operation, e);
-    }
-    context.putBlip(waveletData.getRootBlipId(), rootBlip);
-
-    String message = OperationUtil.getOptionalParameter(operation, 
ParamsProperty.MESSAGE);
-    WaveletCreatedEvent event =
-        new WaveletCreatedEvent(null, null, participant.getAddress(), 
System.currentTimeMillis(),
-            rootBlip.getId(), message,
-            ApiIdSerializer.instance().serialiseWaveId(waveletName.waveId),
-            
ApiIdSerializer.instance().serialiseWaveletId(waveletName.waveletId));
-    context.processEvent(operation, event);
-  }
-
-  public static CreateWaveletService create() {
-    return new CreateWaveletService();
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/box/server/robots/operations/DoNothingService.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/box/server/robots/operations/DoNothingService.java
 
b/wave/src/main/java/org/waveprotocol/box/server/robots/operations/DoNothingService.java
deleted file mode 100644
index 4eb08b2..0000000
--- 
a/wave/src/main/java/org/waveprotocol/box/server/robots/operations/DoNothingService.java
+++ /dev/null
@@ -1,50 +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.Maps;
-import com.google.wave.api.OperationRequest;
-import com.google.wave.api.JsonRpcConstant.ParamsProperty;
-
-import org.waveprotocol.box.server.robots.OperationContext;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-
-/**
- * {@link OperationService} that just returns an empty response. Used for
- * robot.notify operation in the active robot and data api where we inspect 
this
- * operation to see which protocol version it uses but not produce any results.
- *
- * @author [email protected] (Lennard de Rijk)
- */
-public final class DoNothingService implements OperationService {
-
-  public static DoNothingService create() {
-    return new DoNothingService();
-  }
-
-  private DoNothingService() {
-  }
-
-  @Override
-  public void execute(
-      OperationRequest operation, OperationContext context, ParticipantId 
participant) {
-    context.constructResponse(operation, Maps.<ParamsProperty, Object> 
newHashMap());
-  }
-}

Reply via email to