Package com.google.wave.api.data.converter.v21

Source Code of com.google.wave.api.data.converter.v21.EventDataConverterV21

/**
* 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 com.google.wave.api.data.converter.v21;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.wave.api.Annotation;
import com.google.wave.api.ApiIdSerializer;
import com.google.wave.api.BlipData;
import com.google.wave.api.Range;
import com.google.wave.api.data.ApiView;
import com.google.wave.api.data.ElementSerializer;
import com.google.wave.api.data.converter.EventDataConverter;
import com.google.wave.api.impl.EventMessageBundle;
import com.google.wave.api.impl.WaveletData;

import org.waveprotocol.wave.model.account.DocumentBasedRoles;
import org.waveprotocol.wave.model.conversation.Conversation;
import org.waveprotocol.wave.model.conversation.ConversationBlip;
import org.waveprotocol.wave.model.conversation.ConversationThread;
import org.waveprotocol.wave.model.conversation.TagsDocument;
import org.waveprotocol.wave.model.conversation.TitleHelper;
import org.waveprotocol.wave.model.document.Document;
import org.waveprotocol.wave.model.document.ObservableDocument;
import org.waveprotocol.wave.model.document.RangedAnnotation;
import org.waveprotocol.wave.model.document.util.XmlStringBuilder;
import org.waveprotocol.wave.model.id.IdConstants;
import org.waveprotocol.wave.model.id.IdUtil;
import org.waveprotocol.wave.model.wave.ParticipantId;
import org.waveprotocol.wave.model.wave.Wavelet;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
* An implementation of {@link EventDataConverter} for all protocol versions
* that are less than or equal to v0.21.
*
*/
public class EventDataConverterV21 implements EventDataConverter {

  @Override
  public WaveletData toWaveletData(Wavelet wavelet, Conversation conversation,
      EventMessageBundle eventMessageBundle) {
    final WaveletData waveletData = new WaveletData();
    waveletData.setCreationTime(wavelet.getCreationTime());
    waveletData.setCreator(wavelet.getCreatorId().getAddress());
    waveletData.setWaveId(ApiIdSerializer.instance().serialiseWaveId(wavelet.getWaveId()));
    waveletData.setWaveletId(ApiIdSerializer.instance().serialiseWaveletId(wavelet.getId()));
    waveletData.setLastModifiedTime(wavelet.getLastModifiedTime());
    waveletData.setParticipants(idsToParticipantIdList(wavelet.getParticipantIds()));
    waveletData.setRootBlipId(conversation.getRootThread().getFirstBlip().getId());
    waveletData.setTitle(getTitle(wavelet, conversation));
    waveletData.setVersion(wavelet.getVersion());

    // Add Data Docs. All data documents are silently name spaced under the
    // robot prefix to avoid conflicts. Any docId containing a '+' will be
    // ignored for now.
    for (String documentId : wavelet.getDocumentIds()) {
      if (IdUtil.isRobotDocId(documentId)) {
        String[] parts = IdUtil.split(documentId);
        if (parts.length == 2) {
          Document document = wavelet.getDocument(documentId);
          String val = XmlStringBuilder.innerXml(document).getXmlString();
          waveletData.setDataDocument(parts[1], val);
        }
      }
    }

    // Add the tags.
    if (wavelet.getDocument(IdConstants.TAGS_DOC_ID) != null) {
      @SuppressWarnings({"unchecked", "rawtypes"})
      TagsDocument tags = new TagsDocument(wavelet.getDocument(IdConstants.TAGS_DOC_ID));
      tags.addListener(new TagsDocument.Listener() {
        @Override
        public void onAdd(String tagName) {
          waveletData.addTag(tagName);
        }
        @Override
        public void onRemove(int tagPosition) {
          // Not called.
        }});
      tags.processInitialState();
    }

    // Add the participant roles.
    ObservableDocument rolesDocument = wavelet.getDocument(IdConstants.ROLES_DATA_DOC_ID);
    if (rolesDocument != null) {
      DocumentBasedRoles roles = DocumentBasedRoles.create(rolesDocument);
      for (ParticipantId participantId : wavelet.getParticipantIds()) {
        waveletData.setParticipantRole(participantId.getAddress(),
            roles.getRole(participantId).name());
      }
    }
    return waveletData;
  }

  @Override
  public BlipData toBlipData(ConversationBlip blip, Wavelet wavelet,
      EventMessageBundle eventMessageBundle) {
    ConversationBlip parentBlip = findBlipParent(blip);
    BlipData blipData = new BlipData();
    blipData.setCreator(blip.getAuthorId().getAddress());
    blipData.setContributors(idsToParticipantIdList(blip.getContributorIds()));
    blipData.setBlipId(blip.getId());
    blipData.setLastModifiedTime(blip.getLastModifiedTime());
    blipData.setVersion(blip.getLastModifiedVersion());
    blipData.setParentBlipId(parentBlip == null ? null : parentBlip.getId());
    blipData.setWaveId(ApiIdSerializer.instance().serialiseWaveId(wavelet.getWaveId()));
    blipData.setWaveletId(ApiIdSerializer.instance().serialiseWaveletId(wavelet.getId()));
    blipData.setChildBlipIds(toBlipIdList(findBlipChildren(blip)));

    ApiView apiView = new ApiView(blip.getContent(), wavelet);
    // Set content.
    blipData.setContent(apiView.apiContents());
    // Set Annotations.
    blipData.setAnnotations(extractAnnotations(blip.getContent(), apiView));
    // blip.getContent().rangedAnnotations(0, blip.getContent().size(), null),
    // Set Form Elements.
    blipData.setElements(ElementSerializer.serialize(blip.getContent(), wavelet));
    return blipData;
  }

  /**
   * Finds the children of a blip, defined as the next sibling blip and the
   * first blip in each reply thread.
   *
   * @param blip the blip.
   * @return the children of the given blip.
   */
  @Override
  public List<ConversationBlip> findBlipChildren(ConversationBlip blip) {
    List<ConversationBlip> siblings = Lists.newArrayList();
    ConversationBlip nextSibling = findNextSibling(blip);
    if (nextSibling != null) {
      siblings.add(nextSibling);
    }
    for (ConversationThread reply : blip.getReplyThreads()) {
      if (reply.getFirstBlip() != null) {
        siblings.add(reply.getFirstBlip());
      }
    }
    return siblings;
  }

  /**
   * Finds the parent of a blip. The parent is the preceding blip in the thread,
   * or the blip to which the thread is a reply for the first blip in a thread.
   * The first blip of the root thread has no parent.
   *
   * @param blip the blip.
   * @return the blip's parent, or {@code null} if the blip is the first blip
   *     in a conversation.
   */
  @Override
  public ConversationBlip findBlipParent(ConversationBlip blip) {
    ConversationThread containingThread = blip.getThread();
    if (containingThread.getFirstBlip() == blip
        && containingThread != blip.getConversation().getRootThread()) {
      return containingThread.getParentBlip();
    }
    return findPreviousSibling(blip);
  }

  /**
   * Converts a collection of {@link ParticipantId}s to a list of addresses.
   *
   * @param participantIds the participant ids to convert.
   * @return a list of addresses.
   */
  public List<String> idsToParticipantIdList(Collection<ParticipantId> participantIds) {
    List<String> addresses = Lists.newArrayListWithCapacity(participantIds.size());
    for (ParticipantId id : participantIds) {
      addresses.add(id.getAddress());
    }
    return addresses;
  }

  /**
   * Finds the previous sibling of a blip in a thread. The first blip in a
   * thread has no previous sibling.
   *
   * @param blip the blip.
   * @return the previous sibling of the blip, or {@code null}.
   */
  @VisibleForTesting
  static ConversationBlip findPreviousSibling(ConversationBlip blip) {
    ConversationThread thread = blip.getThread();
    ConversationBlip previous = null;
    for (ConversationBlip sibling : thread.getBlips()) {
      if (sibling == blip) {
        break;
      }
      previous = sibling;
    }
    return previous;
  }

  /**
   * Finds the next sibling of a blip in a thread. The last blip in a thread has
   * no next sibling.
   *
   * @param blip the blip.
   * @return the next sibling of the blip, or {@code null} if blip is the last
   *     blip in a thread.
   */
  @VisibleForTesting
  static ConversationBlip findNextSibling(ConversationBlip blip) {
    ConversationThread thread = blip.getThread();
    Iterator<? extends ConversationBlip> blips = thread.getBlips().iterator();
    boolean foundBlip = false;
    while (!foundBlip && blips.hasNext()) {
      if (blips.next() == blip) {
        foundBlip = true;
      }
    }
    return blips.hasNext() ? blips.next() : null;
  }

  /**
   * Retrieves the title of a {@link Wavelet}.
   *
   * @param wavelet The {@link Wavelet} to retrieve the title from.
   * @param conversation The wavelet conversation
   * @return the title of the {@link Wavelet}, or an empty string if it has
   *     no title.
   */
  private static String getTitle(Wavelet wavelet, Conversation conversation) {
    ConversationThread rootThread = conversation.getRootThread();
    if (rootThread == null) {
      return "";
    }
    ConversationBlip firstBlip = rootThread.getFirstBlip();
    if (firstBlip == null) {
      return "";
    }
    Document doc = firstBlip.getContent();
    return TitleHelper.extractTitle(doc);
  }

  /**
   * Extracts the blip ids of the given list of blips.
   *
   * @param children the blips.
   * @return the blip ids of the blips.
   */
  private static List<String> toBlipIdList(List<ConversationBlip> children) {
    List<String> ids = Lists.newArrayListWithCapacity(children.size());
    for (ConversationBlip child : children) {
      ids.add(child.getId());
    }
    return ids;
  }

  /**
   * Extracts all annotations that span inside the body tag of the given
   * document.
   *
   * @param doc the document to get the annotations from.
   * @param apiView provides a utility function to convert an xml offset point
   *     into text offset.
   * @return the annotations represented as a list of {@link Annotation}.
   */
  private static List<Annotation> extractAnnotations(Document doc, ApiView apiView) {
    List<Annotation> result = Lists.newArrayList();
    for (RangedAnnotation<String> annotation : doc.rangedAnnotations(0, doc.size(), null)) {
      if (annotation.key() != null && annotation.value() != null) {
        int start = apiView.transformToTextOffset(annotation.start());
        int end = apiView.transformToTextOffset(annotation.end());
        result.add(new Annotation(annotation.key(), annotation.value(), new Range(start, end)));
      }
    }
    return result;
  }
}
TOP

Related Classes of com.google.wave.api.data.converter.v21.EventDataConverterV21

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.