Package com.google.wave.api

Source Code of com.google.wave.api.OperationQueue

/* Copyright (c) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.wave.api;

import com.google.wave.api.JsonRpcConstant.ParamsProperty;
import com.google.wave.api.OperationRequest.Parameter;

import org.waveprotocol.wave.model.id.InvalidIdException;
import org.waveprotocol.wave.model.id.WaveId;
import org.waveprotocol.wave.model.id.WaveletId;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

/**
* A utility class that abstracts the queuing of operations, represented by
* {@link OperationRequest}, using easily callable functions. The
* {@link OperationQueue} queues the resulting operations in order.
*
* Typically there shouldn't be a need to call this directly unless operations
* are needed on entities outside of the scope of the robot. For example, to
* modify a blip that does not exist in the current context, you might specify
* the wave, wavelet, and blip id to generate an operation.
*
* Any calls to this will not be reflected in the robot in any way. For example,
* calling wavelet_append_blip will not result in a new blip being added to the
* robot current context, only an operation to be sent to the robot proxy.
*/
public class OperationQueue implements Serializable {

  /** A random number generator for the temporary ids. */
  private static final Random ID_GENERATOR = new Random();

  /** The format of temporary blip ids. */
  private static final String TEMP_BLIP_ID_FORMAT = "TBD_%s_%s";

  /** The format of temporary wave ids. */
  private static final String TEMP_WAVE_ID_FORMAT = "%s!TBD_%s";

  /** The format of wavelet ids. */
  private static final String TEMP_WAVELET_ID_FORMAT = "%s!conv+root";

  /** The format of new operation ids. */
  private static final String OP_ID_FORMAT = "op%d";

  /** Some class global counters. */
  private static long nextOpId = 1;

  /** The id that can be set for {@code proxyingFor} parameter. */
  private final String proxyForId;

  /** The operation queue. */
  private List<OperationRequest> pendingOperations;

  /**
   * Constructor that creates a new instance of {@link OperationQueue} with
   * an empty queue and no proxying information set.
   */
  public OperationQueue() {
    this(new ArrayList<OperationRequest>(), null);
  }

  /**
   * Constructor that creates a new instance of {@link OperationQueue} with
   * a specified proxying information.
   *
   * @param proxyForId the proxying information.
   */
  public OperationQueue(String proxyForId) {
    this(new ArrayList<OperationRequest>(), proxyForId);
  }

  /**
   * Constructor that creates a new instance of {@link OperationQueue} with
   * a specified queue and proxying information.
   *
   * @param operations the underlying operation queue that should be used for
   *     this {@link OperationQueue}.
   * @param proxyForId the proxying information.
   */
  public OperationQueue(List<OperationRequest> operations, String proxyForId) {
    this.pendingOperations = operations;
    this.proxyForId = proxyForId;
  }

  /**
   * Returns a list of the pending operations that have been queued up.
   *
   * @return the pending operations.
   */
  public List<OperationRequest> getPendingOperations() {
    return pendingOperations;
  }

  /**
   * Returns the id for {@code proxyingFor} parameter.
   *
   * @return the proxying id.
   */
  public String getProxyForId() {
    return proxyForId;
  }

  /**
   * Creates a view of this {@link OperationQueue} with the proxying for set to
   * the given id.
   *
   * This method returns a new instance of an operation queue that shares the
   * operation list, but has a different {@link #proxyForId} set so when the
   * robot uses this new queue, subsequent operations will be sent out with the
   * {@code proxying_for} field set.
   *
   * @param proxyForId the proxying information.
   * @return a view of this {@link OperationQueue} with the proxying information
   *     set.
   */
  public OperationQueue proxyFor(String proxyForId) {
    return new OperationQueue(pendingOperations, proxyForId);
  }

  /**
   * Clears this operation queue.
   */
  public void clear() {
    pendingOperations.clear();
  }

  /**
   * Appends a blip to a wavelet.
   *
   * @param wavelet the wavelet to append the new blip to.
   * @param initialContent the initial content of the new blip.
   * @return an instance of {@link Blip} that represents the new blip.
   */
  public Blip appendBlipToWavelet(Wavelet wavelet, String initialContent) {
    Blip newBlip = newBlip(wavelet, initialContent, null, generateTempBlipId(wavelet),
        wavelet.getRootThread().getId());
    appendOperation(OperationType.WAVELET_APPEND_BLIP, wavelet,
        Parameter.of(ParamsProperty.BLIP_DATA, newBlip.serialize()));
    return newBlip;
  }

  /**
   * Adds a participant to a wavelet.
   *
   * @param wavelet the wavelet that the new participant should be added to.
   * @param participantId the id of the new participant.
   */
  public void addParticipantToWavelet(Wavelet wavelet, String participantId) {
    appendOperation(OperationType.WAVELET_ADD_PARTICIPANT_NEWSYNTAX, wavelet,
        Parameter.of(ParamsProperty.PARTICIPANT_ID, participantId));
  }

  /**
   * Removes a participant from a wavelet.
   *
   * @param wavelet the wavelet that the participant should be removed from.
   * @param participantId the id of the participant to be removed.
   */
  public void removeParticipantFromWavelet(Wavelet wavelet, String participantId) {
    appendOperation(OperationType.WAVELET_REMOVE_PARTICIPANT_NEWSYNTAX, wavelet,
        Parameter.of(ParamsProperty.PARTICIPANT_ID, participantId));
  }

  /**
   * Creates a new wavelet.
   *
   * @param domain the domain to create the wavelet in.
   * @param participants the initial participants on this new wavelet.
   * @return an instance of {@link Wavelet} that represents the new wavelet.
   */
  public Wavelet createWavelet(String domain, Set<String> participants) {
    return createWavelet(domain, participants, "");
  }

  /**
   * Creates a new wavelet with an optional message.
   *
   * @param domain the domain to create the wavelet in.
   * @param participants the initial participants on this new wavelet.
   * @param message an optional payload that is returned with the corresponding
   *     event.
   * @return an instance of {@link Wavelet} that represents the new wavelet.
   */
  public Wavelet createWavelet(String domain, Set<String> participants, String message) {
    Wavelet newWavelet = newWavelet(domain, participants, this);
    OperationRequest operation = appendOperation(OperationType.ROBOT_CREATE_WAVELET,
        newWavelet, Parameter.of(ParamsProperty.WAVELET_DATA, newWavelet.serialize()));

    // Don't add the message if it's null or empty.
    if (message != null && !message.isEmpty()) {
      operation.addParameter(Parameter.of(ParamsProperty.MESSAGE, message));
    }
    return newWavelet;
  }
 
  /**
   * Appends search operation for specified query.
   *
   * @param query the query to execute.
   * @param index the index from which to return results.
   * @param numresults the number of results to return.
   */
  public void search(String query, Integer index, Integer numresults) {
    Parameter queryParam = Parameter.of(ParamsProperty.QUERY, query);
    Parameter indexParam = Parameter.of(ParamsProperty.INDEX, index);
    Parameter numresultsParam = Parameter.of(ParamsProperty.NUM_RESULTS, numresults);
    appendOperation(OperationType.ROBOT_SEARCH, queryParam, indexParam, numresultsParam);
  }

  /**
   * Sets a key-value pair on the data document of a wavelet.
   *
   * @param wavelet to set the data document on.
   * @param name the name of this data.
   * @param value the value of this data.
   */
  public void setDatadocOfWavelet(Wavelet wavelet, String name, String value) {
    appendOperation(OperationType.WAVELET_SET_DATADOC, wavelet,
        Parameter.of(ParamsProperty.DATADOC_NAME, name),
        Parameter.of(ParamsProperty.DATADOC_VALUE, value));
  }

  /**
   * Requests a snapshot of the specified wave.
   *
   * @param waveId the id of the wave that should be fetched.
   * @param waveletId the wavelet id that should be fetched.
   */
  public void fetchWavelet(WaveId waveId, WaveletId waveletId) {
    appendOperation(OperationType.ROBOT_FETCH_WAVE, waveId, waveletId, null);
  }

  /**
   * Sets the title of a wavelet.
   *
   * @param wavelet the wavelet whose title will be changed.
   * @param title the new title to be set.
   */
  public void setTitleOfWavelet(Wavelet wavelet, String title) {
    appendOperation(OperationType.WAVELET_SET_TITLE, wavelet,
        Parameter.of(ParamsProperty.WAVELET_TITLE, title));
  }

  /**
   * Modifies a tag in a wavelet.
   *
   * @param wavelet the wavelet to modify the tag from.
   * @param tag the name of the tag to be modified
   * @param modifyHow how to modify the tag. The default behavior is to add the
   *     tag. Specify {@code remove} to remove, or specify {@code null} or
   *     {@code add} to add.
   */
  public void modifyTagOfWavelet(Wavelet wavelet, String tag, String modifyHow) {
    appendOperation(OperationType.WAVELET_MODIFY_TAG, wavelet,
        Parameter.of(ParamsProperty.NAME, tag),
        Parameter.of(ParamsProperty.MODIFY_HOW, modifyHow));
  }

  /**
   * Creates a child blip of another blip.
   *
   * @param blip the parent blip.
   * @return an instance of {@link Blip} that represents the new child blip.
   */
  public Blip createChildOfBlip(Blip blip) {
    // Create a new thread.
    String tempBlipId = generateTempBlipId(blip.getWavelet());
    Wavelet wavelet = blip.getWavelet();
    BlipThread thread = new BlipThread(tempBlipId, -1, new ArrayList<String>(),
        wavelet.getBlips());

    // Add the new thread to the blip and wavelet.
    blip.addThread(thread);
    wavelet.addThread(thread);

    // Create a new blip in the new thread.
    Blip newBlip = newBlip(blip.getWavelet(), "", blip.getBlipId(), tempBlipId, thread.getId());
    appendOperation(OperationType.BLIP_CREATE_CHILD, blip,
        Parameter.of(ParamsProperty.BLIP_DATA, newBlip.serialize()));
    return newBlip;
  }

  /**
   * Appends a new blip to the end of the thread of the given blip.
   *
   * @param blip the blip whose thread will be appended.
   * @return an instance of {@link Blip} that represents the new blip.
   */
  public Blip continueThreadOfBlip(Blip blip) {
    Blip newBlip = newBlip(blip.getWavelet(), "", blip.getParentBlipId(),
        generateTempBlipId(blip.getWavelet()), blip.getThread().getId());
    appendOperation(OperationType.BLIP_CONTINUE_THREAD, blip,
        Parameter.of(ParamsProperty.BLIP_DATA, newBlip.serialize()));
    return newBlip;
  }

  /**
   * Deletes the specified blip.
   *
   * @param wavelet the wavelet that owns the blip.
   * @param blipId the id of the blip that will be deleted.
   */
  public void deleteBlip(Wavelet wavelet, String blipId) {
    appendOperation(OperationType.BLIP_DELETE, wavelet.getWaveId(), wavelet.getWaveletId(),
        blipId);
  }

  /**
   * Appends content with markup to a blip.
   *
   * @param blip the blip where this markup content should be added to.
   * @param content the markup content that should be added to the blip.
   */
  public void appendMarkupToDocument(Blip blip, String content) {
    appendOperation(OperationType.DOCUMENT_APPEND_MARKUP, blip,
        Parameter.of(ParamsProperty.CONTENT, content));
  }

  /**
   * Submits this operation queue when the given {@code other} operation queue
   * is submitted.
   *
   * @param other the other operation queue to merge this operation queue with.
   */
  public void submitWith(OperationQueue other) {
    other.pendingOperations.addAll(this.pendingOperations);
    this.pendingOperations = other.pendingOperations;
  }

  /**
   * Creates and queues a document modify operation.
   *
   * @param blip the blip to modify.
   * @return an instance of {@code OperationRequest} that represents this
   *     operation. The caller of this method should append the required and/or
   *     optional parameters, such as:
   *     <ul>
   *       <li>{@code modifyAction}</li>
   *       <li>{@code modifyQuery}</li>
   *       <li>{@code index}</li>
   *       <li>{@code range}</li>
   *     </ul>
   */
  public OperationRequest modifyDocument(Blip blip) {
    return appendOperation(OperationType.DOCUMENT_MODIFY, blip);
  }

  /**
   * Inserts a new inline blip at a specified location.
   *
   * @param blip the blip to anchor this inline blip from.
   * @param position the position in the given blip to insert this new inline
   *     blip.
   * @return an instance of {@link Blip} that represents the inline blip.
   */
  public Blip insertInlineBlipToDocument(Blip blip, int position) {
    // Create a new thread.
    String tempBlipId = generateTempBlipId(blip.getWavelet());
    Wavelet wavelet = blip.getWavelet();
    BlipThread thread = new BlipThread(tempBlipId, position, new ArrayList<String>(),
        wavelet.getBlips());

    // Add the new thread to the blip and wavelet.
    blip.addThread(thread);
    wavelet.addThread(thread);

    // Create a new blip in the new thread.
    Blip inlineBlip = newBlip(blip.getWavelet(), "", blip.getBlipId(), tempBlipId,
        thread.getId());
    appendOperation(OperationType.DOCUMENT_INSERT_INLINE_BLIP, blip,
        Parameter.of(ParamsProperty.INDEX, position),
        Parameter.of(ParamsProperty.BLIP_DATA, inlineBlip.serialize()));
    return inlineBlip;
  }

  /**
   * Creates and appends a new operation to the operation queue.
   *
   * @param opType the type of the operation.
   * @param parameters the parameters that should be added as a property of
   *     the operation.
   * @return an instance of {@link OperationRequest} that represents the queued
   *     operation.
   */
  OperationRequest appendOperation(OperationType opType, Parameter... parameters) {
    return appendOperation(opType, null, null, null, parameters);
  }

  /**
   * Creates and appends a new operation to the operation queue.
   *
   * @param opType the type of the operation.
   * @param wavelet the wavelet to apply the operation to.
   * @param parameters the parameters that should be added as a property of
   *     the operation.
   * @return an instance of {@link OperationRequest} that represents the queued
   *     operation.
   */
  OperationRequest appendOperation(OperationType opType, Wavelet wavelet,
      Parameter... parameters) {
    return appendOperation(opType, wavelet.getWaveId(), wavelet.getWaveletId(), null, parameters);
  }

  /**
   * Creates and appends a new operation to the operation queue.
   *
   * @param opType the type of the operation.
   * @param blip the blip to apply this operation to.
   * @param parameters the parameters that should be added as a property of
   *     the operation.
   * @return an instance of {@link OperationRequest} that represents the queued
   *     operation.
   */
  OperationRequest appendOperation(OperationType opType, Blip blip, Parameter... parameters) {
    return appendOperation(opType, blip.getWaveId(), blip.getWaveletId(), blip.getBlipId(),
        parameters);
  }

  /**
   * Creates and appends a new operation to the operation queue.
   *
   * @param opType the type of the operation.
   * @param waveId the wave id in which the operation should be applied to.
   * @param waveletId the wavelet id of the given wave in which the operation
   *     should be applied to.
   * @param blipId the optional blip id of the given wave in which the operation
   *     should be applied to. Not all operations require blip id.
   * @param parameters the parameters that should be added as a property of
   *     the operation.
   * @return an instance of {@link OperationRequest} that represents the queued
   *     operation.
   */
  OperationRequest appendOperation(OperationType opType, WaveId waveId, WaveletId waveletId,
      String blipId, Parameter... parameters) {
    return addOperation(opType, waveId, waveletId, blipId, pendingOperations.size(), parameters);
  }

  /**
   * Creates and prepends a new operation to the operation queue.
   *
   * @param opType the type of the operation.
   * @param waveId the wave id in which the operation should be applied to.
   * @param waveletId the wavelet id of the given wave in which the operation
   *     should be applied to.
   * @param blipId the optional blip id of the given wave in which the operation
   *     should be applied to. Not all operations require blip id.
   * @param parameters the parameters that should be added as a property of
   *     the operation.
   * @return an instance of {@link OperationRequest} that represents the queued
   *     operation.
   */
  OperationRequest prependOperation(OperationType opType, WaveId waveId, WaveletId waveletId,
      String blipId, Parameter... parameters) {
    return addOperation(opType, waveId, waveletId, blipId, 0, parameters);
  }

  /**
   * Creates and adds a new operation to the operation queue.
   *
   * @param opType the type of the operation.
   * @param waveId the wave id in which the operation should be applied to.
   * @param waveletId the wavelet id of the given wave in which the operation
   *     should be applied to.
   * @param blipId the optional blip id of the given wave in which the operation
   *     should be applied to. Not all operations require blip id.
   * @param index the index where this new operation should be added to in the
   *     queue.
   * @param parameters the parameters that should be added as a property of
   *     the operation.
   * @return an instance of {@link OperationRequest} that represents the queued
   *     operation.
   */
  OperationRequest addOperation(OperationType opType, WaveId waveId, WaveletId waveletId,
      String blipId, int index, Parameter... parameters) {
    String waveIdString = null;
    if (waveId != null) {
      waveIdString = ApiIdSerializer.instance().serialiseWaveId(waveId);
    }

    String waveletIdString = null;
    if (waveletId != null) {
      waveletIdString = ApiIdSerializer.instance().serialiseWaveletId(waveletId);
    }

    OperationRequest operation = new OperationRequest(opType.method(),
        String.format(OP_ID_FORMAT, nextOpId++),
        waveIdString, waveletIdString, blipId, parameters);

    // Set the proxying for parameter, if necessary.
    if (proxyForId != null && !proxyForId.isEmpty()) {
      operation.addParameter(Parameter.of(ParamsProperty.PROXYING_FOR, proxyForId));
    }

    pendingOperations.add(index, operation);
    return operation;
  }

  /**
   * Generates a temporary blip id.
   *
   * @param wavelet the wavelet to seed the temporary id.
   * @return a temporary blip id.
   */
  private static String generateTempBlipId(Wavelet wavelet) {
    return String.format(TEMP_BLIP_ID_FORMAT,
        ApiIdSerializer.instance().serialiseWaveletId(wavelet.getWaveletId()),
        ID_GENERATOR.nextInt());
  }

  /**
   * Creates a new {@code Blip} object used for this session. A temporary
   * id will be assigned to the newly created {@code Blip} object.
   *
   * @param wavelet the wavelet that owns this blip.
   * @param initialContent the initial content of the new blip.
   * @param parentBlipId the parent of this blip.
   * @return an instance of new {@code Blip} object used for this session.
   */
  private static Blip newBlip(Wavelet wavelet, String initialContent, String parentBlipId,
      String blipId, String threadId) {
    Blip newBlip = new Blip(blipId, initialContent, parentBlipId, threadId, wavelet);
    if (parentBlipId != null) {
      Blip parentBlip = wavelet.getBlips().get(parentBlipId);
      if (parentBlip != null) {
        parentBlip.getChildBlipIds().add(newBlip.getBlipId());
      }
    }
    wavelet.getBlips().put(newBlip.getBlipId(), newBlip);

    BlipThread thread = wavelet.getThread(threadId);
    if (thread != null) {
      thread.appendBlip(newBlip);
    }
    return newBlip;
  }

  /**
   * Creates a new {@code Wavelet} object used for this session. A temporary
   * wave id will be assigned to this newly created {@code Wavelet} object.
   *
   * @param domain the domain that is used for the wave and wavelet ids.
   * @param participants the participants that should be added to the new
   *     wavelet.
   * @param opQueue the operation queue of the new wavelet.
   * @return an instance of new {@code Wavelet} object used for this
   *     session.
   */
  private static Wavelet newWavelet(String domain, Set<String> participants,
      OperationQueue opQueue) {
    // Make sure that participant list is not null;
    if (participants == null) {
      participants = Collections.emptySet();
    }

    WaveId waveId;
    WaveletId waveletId;
    try {
      waveId = ApiIdSerializer.instance().deserialiseWaveId(
          String.format(TEMP_WAVE_ID_FORMAT, domain, ID_GENERATOR.nextInt()));
      waveletId = ApiIdSerializer.instance().deserialiseWaveletId(
          String.format(TEMP_WAVELET_ID_FORMAT, domain));
    } catch (InvalidIdException e) {
      throw new IllegalStateException("Invalid temporary id", e);
    }

    String rootBlipId = String.format(TEMP_BLIP_ID_FORMAT,
        ApiIdSerializer.instance().serialiseWaveletId(waveletId),
        ID_GENERATOR.nextInt());
    Map<String, Blip> blips = new HashMap<String, Blip>();
    Map<String, String> roles = new HashMap<String, String>();
    Map<String, BlipThread> threads = new HashMap<String, BlipThread>();

    List<String> blipIds = new ArrayList<String>();
    blipIds.add(rootBlipId);
    BlipThread rootThread = new BlipThread("", -1, blipIds, blips);

    Wavelet wavelet = new Wavelet(waveId, waveletId, rootBlipId, rootThread, participants,
        roles, blips, threads, opQueue);

    Blip rootBlip = new Blip(rootBlipId, "", null, "", wavelet);
    blips.put(rootBlipId, rootBlip);

    return wavelet;
  }

  /**
   * Modifies the role of a participant in a wavelet.
   *
   * @param wavelet the wavelet that the participant is on
   * @param participant whose role to modify
   * @param role to set for the participant
   */
  public void modifyParticipantRoleOfWavelet(Wavelet wavelet, String participant, String role) {
    appendOperation(OperationType.WAVELET_MODIFY_PARTICIPANT_ROLE, wavelet,
        Parameter.of(ParamsProperty.PARTICIPANT_ID, participant),
        Parameter.of(ParamsProperty.PARTICIPANT_ROLE, role));
  }

  /**
   * Notifies the robot information.
   *
   * @param protocolVersion the wire protocol version of the robot.
   * @param capabilitiesHash the capabilities hash of the robot.
   */
  public void notifyRobotInformation(ProtocolVersion protocolVersion, String capabilitiesHash) {
    prependOperation(OperationType.ROBOT_NOTIFY, null, null, null,
        Parameter.of(ParamsProperty.PROTOCOL_VERSION, protocolVersion.getVersionString()),
        Parameter.of(ParamsProperty.CAPABILITIES_HASH, capabilitiesHash));
  }

  public void fetchProfiles(FetchProfilesRequest request) {
    appendOperation(OperationType.ROBOT_FETCH_PROFILES,
        Parameter.of(ParamsProperty.FETCH_PROFILES_REQUEST, request));
  }
}
TOP

Related Classes of com.google.wave.api.OperationQueue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.