http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/Wavelet.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/Wavelet.java b/wave/src/main/java/com/google/wave/api/Wavelet.java deleted file mode 100644 index b132747..0000000 --- a/wave/src/main/java/com/google/wave/api/Wavelet.java +++ /dev/null @@ -1,680 +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 com.google.wave.api; - -import com.google.wave.api.Participants.Role; -import com.google.wave.api.impl.WaveletData; - -import org.waveprotocol.wave.model.id.InvalidIdException; -import org.waveprotocol.wave.model.id.WaveId; -import org.waveprotocol.wave.model.id.WaveletId; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -/** - * A class that models a single wavelet instance. - * - * A single wavelet is composed of metadata, for example, id,creator, creation - * time, last modified time, title. A wavelet is also composed of a set of - * participants, a set of tags, a list of blips, and a data document, which - * is a map of key-value pairs of data. - */ -public class Wavelet implements Serializable { - - /** Delimiter constants for robot participant id. */ - private static final char ROBOT_ID_PROXY_DELIMITER = '+'; - private static final char ROBOT_ID_VERSION_DELIMITER = '#'; - private static final char ROBOT_ID_DOMAIN_DELIMITER = '@'; - - /** The id of the wave that owns this wavelet. */ - private transient WaveId waveId; - - /** The id of this wavelet. */ - private transient WaveletId waveletId; - - /** The serialized form of waveId **/ - private String serializedWaveId; - - /** The serialized form of waveletId **/ - private String serializedWaveletId; - - /** The participant id that created this wavelet. */ - private final String creator; - - /** This wavelet's creation time, in milliseconds. */ - private final long creationTime; - - /** This wavelet's last modified time, in milliseconds. */ - private final long lastModifiedTime; - - /** The id of the root blip of this wavelet. */ - private final String rootBlipId; - - /** The root thread of this wavelet. */ - private final BlipThread rootThread; - - /** The participants of this wavelet. */ - private final Participants participants; - - /** The data documents of this wavelet. */ - private final DataDocuments dataDocuments; - - /** The tags that this wavelet has. */ - private final Tags tags; - - /** The title of this wavelet. */ - private String title; - - /** The blips that are contained in this wavelet. */ - @NonJsonSerializable private final Map<String, Blip> blips; - - /** The conversation threads that are contained in this wavelet. */ - @NonJsonSerializable private final Map<String, BlipThread> threads; - - /** The operation queue to queue operation to the robot proxy. */ - @NonJsonSerializable private final OperationQueue operationQueue; - - /** The address of the current robot. */ - @NonJsonSerializable private String robotAddress; - - /** - * Constructor. - * - * @param waveId the id of the wave that owns this wavelet. - * @param waveletId the id of this wavelet. - * @param creator the creator of this wavelet. - * @param creationTime the creation time of this wavelet. - * @param lastModifiedTime the last modified time of this wavelet. - * @param title the title of this wavelet. - * @param rootBlipId the root blip id of this wavelet. - * @param rootThread the root thread of this wavelet. - * @param participantRoles the roles for those participants - * @param participants the participants of this wavelet. - * @param dataDocuments the data documents of this wavelet. - * @param tags the tags that this wavelet has. - * @param blips the blips that are contained in this wavelet. - * @param threads the conversation threads that are contained in this wavelet. - * @param operationQueue the operation queue to queue operation to the robot - * proxy. - */ - Wavelet(WaveId waveId, WaveletId waveletId, String creator, long creationTime, - long lastModifiedTime, String title, String rootBlipId, BlipThread rootThread, - Map<String, String> participantRoles, Set<String> participants, - Map<String, String> dataDocuments, Set<String> tags, Map<String, Blip> blips, - Map<String, BlipThread> threads, OperationQueue operationQueue) { - this.waveId = waveId; - this.waveletId = waveletId; - this.creator = creator; - this.creationTime = creationTime; - this.lastModifiedTime = lastModifiedTime; - this.title = title; - this.rootBlipId = rootBlipId; - this.rootThread = rootThread; - this.participants = new Participants(participants, participantRoles, this, operationQueue); - this.dataDocuments = new DataDocuments(dataDocuments, this, operationQueue); - this.tags = new Tags(tags, this, operationQueue); - this.blips = blips; - this.threads = threads; - this.operationQueue = operationQueue; - } - - /** - * Constructor. - * - * @param waveId the id of the wave that owns this wavelet. - * @param waveletId the id of this wavelet. - * @param rootBlipId the root blip id of this wavelet. - * @param rootThread the root thread of this wavelet. - * @param participants the participants of this wavelet. - * @param participantRoles the roles for those participants. - * @param blips the blips that are contained in this wavelet. - * @param threads the conversation threads that are contained in this wavelet. - * @param operationQueue the operation queue to queue operation to the robot - * proxy. - */ - Wavelet(WaveId waveId, WaveletId waveletId, String rootBlipId, BlipThread rootThread, - Set<String> participants, Map<String, String> participantRoles, Map<String, Blip> blips, - Map<String, BlipThread> threads, OperationQueue operationQueue) { - this.waveId = waveId; - this.waveletId = waveletId; - this.rootBlipId = rootBlipId; - this.rootThread = rootThread; - this.creator = null; - this.creationTime = -1; - this.lastModifiedTime = -1; - this.title = null; - this.participants = new Participants(participants, participantRoles, this, operationQueue); - this.dataDocuments = new DataDocuments(new HashMap<String, String>(), this, - operationQueue); - this.tags = new Tags(Collections.<String>emptySet(), this, operationQueue); - this.blips = blips; - this.threads = threads; - this.operationQueue = operationQueue; - } - - /** - * Shallow copy constructor. - * - * @param other the other {@link Wavelet} instance to copy. - * @param operationQueue the operation queue for this new wavelet instance. - */ - private Wavelet(Wavelet other, OperationQueue operationQueue) { - this.waveId = other.waveId; - this.waveletId = other.waveletId; - this.creator = other.creator; - this.creationTime = other.creationTime; - this.lastModifiedTime = other.lastModifiedTime; - this.title = other.title; - this.rootBlipId = other.rootBlipId; - this.rootThread = other.rootThread; - this.participants = other.participants; - this.dataDocuments = other.dataDocuments; - this.tags = other.tags; - this.blips = other.blips; - this.threads = other.threads; - this.robotAddress = other.robotAddress; - this.operationQueue = operationQueue; - } - - /** - * Returns the wave id that owns this wavelet. - * - * @return the wave id. - */ - public WaveId getWaveId() { - return waveId; - } - - /** - * Returns the id of this wavelet. - * - * @return the wavelet id. - */ - public WaveletId getWaveletId() { - return waveletId; - } - - /** - * Returns the participant id of the creator of this wavelet. - * - * @return the creator of this wavelet. - */ - public String getCreator() { - return creator; - } - - /** - * Returns the creation time of this wavelet. - * - * @return the wavelet's creation time. - */ - public long getCreationTime() { - return creationTime; - } - - /** - * Returns the last modified time of this wavelet. - * - * @return the wavelet's last modified time. - */ - public long getLastModifiedTime() { - return lastModifiedTime; - } - - /** - * Returns the data documents of this wavelet, which is a series of key-value - * pairs of data. - * - * @return an instance of {@link DataDocuments}, which represents the data - * documents of this wavelet. - */ - public DataDocuments getDataDocuments() { - return dataDocuments; - } - - /** - * Returns a list of participants of this wavelet. - * - * @return an instance of {@link Participants}, which represents the - * participants of this wavelet. - */ - public Participants getParticipants() { - return participants; - } - - /** - * Returns a list of tags of this wavelet. - * - * @return an instance of {@link Tags}, which represents the tags that have - * been associated with this wavelet. - */ - public Tags getTags() { - return tags; - } - - /** - * Returns the title of this wavelet. - * - * @return the wavelet title. - */ - public String getTitle() { - return title; - } - - /** - * Sets the wavelet title. - * - * @param title the new title to be set. - */ - public void setTitle(String title) { - if (title.contains("\n")) { - throw new IllegalArgumentException("Wavelet title should not contain a newline character. " + - "Specified: " + title); - } - - operationQueue.setTitleOfWavelet(this, title); - this.title = title; - - // Adjust the content of the root blip, if it is available in the context. - Blip rootBlip = getRootBlip(); - if (rootBlip != null) { - String content = "\n"; - int indexOfSecondNewline = rootBlip.getContent().indexOf('\n', 1); - if (indexOfSecondNewline != -1) { - content = rootBlip.getContent().substring(indexOfSecondNewline); - } - rootBlip.setContent("\n" + title + content); - } - } - - /** - * Returns the address of the robot that receives events or performs events - * on this wavelet. - * - * @return the robot address. - */ - public String getRobotAddress() { - return robotAddress; - } - - /** - * Sets the address of the robot that receives events or performs events on - * this wavelet. - * - * @param address the robot address. - * @throw IllegalStateException if this method has been called before. - */ - public void setRobotAddress(String address) { - if (this.robotAddress != null) { - throw new IllegalStateException("Robot address has been set previously to " + - this.robotAddress); - } - this.robotAddress = address; - } - - /** - * Returns the id of the root blip of this wavelet. - * - * @return the id of the root blip. - */ - public String getRootBlipId() { - return rootBlipId; - } - - /** - * Returns the root blip of this wavelet. - * - * @return an instance of {@link Blip} that represents the root blip of this - * wavelet. - */ - public Blip getRootBlip() { - return blips.get(rootBlipId); - } - - /** - * @return an instance of {@link BlipThread} that represents the root thread of - * this wavelet. - */ - public BlipThread getRootThread() { - return rootThread; - } - - /** - * Returns a blip with the given id. - * - * @return an instance of {@link Blip} that has the given blip id. - */ - public Blip getBlip(String blipId) { - return blips.get(blipId); - } - - /** - * Returns all blips that are in this wavelet. - * - * @return a map of blips in this wavelet, that is keyed by blip id. - */ - public Map<String, Blip> getBlips() { - return blips; - } - - /** - * Returns a thread with the given id. - * - * @param threadId the thread id. - * @return a thread that has the given thread id. - */ - public BlipThread getThread(String threadId) { - if (threadId == null || threadId.isEmpty()) { - return getRootThread(); - } - return threads.get(threadId); - } - - /** - * Returns all threads that are in this wavelet. - * - * @return a map of threads in this wavelet, that is keyed by thread id. - */ - public Map<String, BlipThread> getThreads() { - return threads; - } - - /** - * Adds a thread to this wavelet. - * - * @param thread the thread to add. - */ - protected void addThread(BlipThread thread) { - threads.put(thread.getId(), thread); - } - - /** - * Returns the operation queue that this wavelet uses to queue operation to - * the robot proxy. - * - * @return an instance of {@link OperationQueue} that represents this - * wavelet's operation queue. - */ - protected OperationQueue getOperationQueue() { - return operationQueue; - } - - /** - * Returns the domain of this wavelet. - * - * @return the wavelet domain, which is encoded in the wave/wavelet id. - */ - public String getDomain() { - return waveId.getDomain(); - } - - /** - * Returns a view of this wavelet that will proxy for the specified id. - * - * A shallow copy of the current wavelet is returned with the - * {@code proxyingFor} field set. Any modifications made to this copy will be - * done using the {@code proxyForId}, i.e. the - * {@code robot+<proxyForId>@appspot.com} address will be used. - * - * If the wavelet was retrieved using the Active Robot API, that is - * by {@code fetchWavelet}, then the address of the robot must be added to the - * wavelet by calling {@code setRobotAddress} with the robot's address - * before calling {@code proxy_for}. - * - * @param proxyForId the id to proxy. Please note that this parameter should - * be properly encoded to ensure that the resulting participant id is - * valid (see {@link Util#checkIsValidProxyForId(String)} for more - * details). - * @return a shallow copy of this wavelet with the proxying information set. - */ - public Wavelet proxyFor(String proxyForId) { - Util.checkIsValidProxyForId(proxyForId); - addProxyingParticipant(proxyForId); - OperationQueue proxiedOperationQueue = operationQueue.proxyFor(proxyForId); - return new Wavelet(this, proxiedOperationQueue); - } - - /** - * Submit this wavelet when the given {@code other} wavelet is submitted. - * - * Wavelets constructed outside of the event callback need to - * be either explicitly submitted using {@code AbstractRobot.submit(Wavelet)} - * or be associated with a different wavelet that will be submitted or is part - * of the event callback. - * - * @param other the other wavelet whose operation queue will be joined with. - */ - public void submitWith(Wavelet other) { - operationQueue.submitWith(other.operationQueue); - } - - /** - * Replies to the conversation in this wavelet. - * - * @param initialContent the initial content of the reply. - * @return an instance of {@link Blip} that represents a transient version of - * the reply. - * - * @throws IllegalArgumentException if {@code initialContent} does not start - * with a newline character. - */ - public Blip reply(String initialContent) { - if (initialContent == null || !initialContent.startsWith("\n")) { - throw new IllegalArgumentException("Initial content should start with a newline character"); - } - return operationQueue.appendBlipToWavelet(this, initialContent); - } - - /** - * Removes a blip from this wavelet. - * - * @param blip the blip to be removed. - */ - public void delete(Blip blip) { - delete(blip.getBlipId()); - } - - /** - * Removes a blip from this wavelet. - * - * @param blipId the id of the blip to be removed. - */ - public void delete(String blipId) { - operationQueue.deleteBlip(this, blipId); - Blip removed = blips.remove(blipId); - - if (removed != null) { - // Remove the blip from the parent blip. - Blip parentBlip = removed.getParentBlip(); - if (parentBlip != null) { - parentBlip.deleteChildBlipId(blipId); - } - - // Remove the blip from the containing thread. - BlipThread thread = removed.getThread(); - if (thread != null) { - thread.removeBlip(removed); - } - - // If the containing thread is now empty, remove it from the parent blip - // and from the wavelet. - if (thread != null && parentBlip != null && thread.isEmpty()) { - parentBlip.removeThread(thread); - threads.remove(thread.getId()); - } - } - } - - /** - * Ads a proxying participant to the wave. - * - * Proxying participants are of the form {@code robot+pr...@domain.com}. This - * convenience method constructs this id and then calls - * {@code wavelet.addParticipant()} operation. - * - * @param proxyForId the id to proxy. - */ - private void addProxyingParticipant(String proxyForId) { - if (robotAddress == null || robotAddress.isEmpty()) { - throw new IllegalStateException("Need a robot address to add a proxying for participant."); - } - - // Parse the id and the domain. - int index = robotAddress.indexOf(ROBOT_ID_DOMAIN_DELIMITER); - String newId = robotAddress.substring(0, index); - String domain = robotAddress.substring(index + 1); - - // Parse the version. - String version = null; - index = newId.indexOf(ROBOT_ID_VERSION_DELIMITER); - if (index != -1) { - version = newId.substring(index + 1); - newId = newId.substring(0, index); - } - - // Remove the previous proxying id. - index = newId.indexOf(ROBOT_ID_PROXY_DELIMITER); - if (index != -1) { - newId = newId.substring(0, index); - } - - // Assemble the new id. - newId += ROBOT_ID_PROXY_DELIMITER + proxyForId; - if (version != null) { - newId += ROBOT_ID_VERSION_DELIMITER + version; - } - newId += ROBOT_ID_DOMAIN_DELIMITER + domain; - participants.add(newId); - } - - /** - * Serializes this {@link Wavelet} into a {@link WaveletData}. - * - * @return an instance of {@link WaveletData} that represents this wavelet. - */ - public WaveletData serialize() { - WaveletData waveletData = new WaveletData(); - - // Add primitive properties. - waveletData.setWaveId(ApiIdSerializer.instance().serialiseWaveId(waveId)); - waveletData.setWaveletId(ApiIdSerializer.instance().serialiseWaveletId(waveletId)); - waveletData.setCreator(creator); - waveletData.setCreationTime(creationTime); - waveletData.setLastModifiedTime(lastModifiedTime); - waveletData.setRootBlipId(rootBlipId); - waveletData.setRootThread(rootThread); - waveletData.setTitle(title); - - // Add tags. - List<String> tags = new ArrayList<String>(); - for (String tag : this.tags) { - tags.add(tag); - } - waveletData.setTags(tags); - - // Add participants. - List<String> participants = new ArrayList<String>(); - for (String participant : this.participants) { - participants.add(participant); - Role role = getParticipants().getParticipantRole(participant); - waveletData.setParticipantRole(participant, role.name()); - } - waveletData.setParticipants(participants); - - // Add data documents. - Map<String, String> dataDocuments = new HashMap<String, String>(); - for (Entry<String, String> entry : this.dataDocuments) { - dataDocuments.put(entry.getKey(), entry.getValue()); - } - waveletData.setDataDocuments(dataDocuments); - - return waveletData; - } - - /** - * Deserializes the given {@link WaveletData} object into an instance of - * {@link Wavelet}. - * - * @param operationQueue the operation queue. - * @param blips the map of blips that are in this wavelet. - * @param waveletData the wavelet data to be deserialized. - * @return an instance of {@link Wavelet}. - */ - public static Wavelet deserialize(OperationQueue operationQueue, Map<String, Blip> blips, - Map<String, BlipThread> threads, WaveletData waveletData) { - WaveId waveId; - WaveletId waveletId; - try { - waveId = ApiIdSerializer.instance().deserialiseWaveId(waveletData.getWaveId()); - waveletId = ApiIdSerializer.instance().deserialiseWaveletId(waveletData.getWaveletId()); - } catch (InvalidIdException e) { - throw new IllegalArgumentException(e); - } - String creator = waveletData.getCreator(); - long creationTime = waveletData.getCreationTime(); - long lastModifiedTime = waveletData.getLastModifiedTime(); - String rootBlipId = waveletData.getRootBlipId(); - - BlipThread originalRootThread = waveletData.getRootThread(); - List<String> rootThreadBlipIds = originalRootThread == null ? - new ArrayList<String>() : - new ArrayList<String>(originalRootThread.getBlipIds()); - BlipThread rootThread = new BlipThread("", -1, rootThreadBlipIds, blips); - - String title = waveletData.getTitle(); - Set<String> participants = new LinkedHashSet<String>(waveletData.getParticipants()); - Set<String> tags = new LinkedHashSet<String>(waveletData.getTags()); - Map<String, String> dataDocuments = waveletData.getDataDocuments(); - Map<String, String> roles = waveletData.getParticipantRoles(); - - return new Wavelet(waveId, waveletId, creator, creationTime, lastModifiedTime, title, - rootBlipId, rootThread, roles, participants, dataDocuments, tags, blips, threads, - operationQueue); - } - - private void writeObject(ObjectOutputStream out) throws IOException { - serializedWaveId = ApiIdSerializer.instance().serialiseWaveId(waveId); - serializedWaveletId = ApiIdSerializer.instance().serialiseWaveletId(waveletId); - out.defaultWriteObject(); - } - - private void readObject(ObjectInputStream in) throws IOException, InvalidIdException { - try { - in.defaultReadObject(); - } catch(ClassNotFoundException e) { - // Fatal. - throw new IOException("Incorrect serial versions" + e); - } - - waveId = ApiIdSerializer.instance().deserialiseWaveId(serializedWaveId); - waveletId = ApiIdSerializer.instance().deserialiseWaveletId(serializedWaveletId); - } -}
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/data/ApiView.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/data/ApiView.java b/wave/src/main/java/com/google/wave/api/data/ApiView.java deleted file mode 100644 index f3a9eb9..0000000 --- a/wave/src/main/java/com/google/wave/api/data/ApiView.java +++ /dev/null @@ -1,419 +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 com.google.wave.api.data; - -import com.google.common.base.Preconditions; -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; -import com.google.wave.api.Element; -import com.google.wave.api.ElementType; -import com.google.wave.api.Gadget; -import com.google.wave.api.Line; - -import org.waveprotocol.wave.model.conversation.Blips; -import org.waveprotocol.wave.model.document.Doc; -import org.waveprotocol.wave.model.document.Doc.E; -import org.waveprotocol.wave.model.document.Doc.N; -import org.waveprotocol.wave.model.document.Doc.T; -import org.waveprotocol.wave.model.document.Document; -import org.waveprotocol.wave.model.document.util.Point; -import org.waveprotocol.wave.model.document.util.XmlStringBuilder; -import org.waveprotocol.wave.model.util.Pair; -import org.waveprotocol.wave.model.wave.Wavelet; - -import java.util.List; - -/** - * Class to represent a document in api view. - * - * - */ -public class ApiView { - - /** - * Simple class to export info about elements in the ApiView. - */ - public static class ElementInfo { - public final Element element; - public final int apiPosition; - public final int xmlPosition; - - public ElementInfo(Element element, int apiPosition, int xmlPosition) { - this.element = element; - this.apiPosition = apiPosition; - this.xmlPosition = xmlPosition; - } - } - - /** - * Storage class to store a bit of the view. It's more a struct than a class. - * Either the content or the element field is set. - */ - private static class Bit { - public String string; - public Element element; - private int xmlPos; - private int xmlSize; - - Bit(Element element, int xmlPos, int xmlSize) { - this.element = element; - this.string = null; - this.xmlPos = xmlPos; - this.xmlSize = xmlSize; - } - - Bit(String string, int xmlPos) { - this.element = null; - this.string = string; - this.xmlPos = xmlPos; - this.xmlSize = string.length(); - } - - /** - * @returns the length of the specified bit. 1 for an element, the string - * length for a string. - */ - public int size() { - if (string != null) { - return string.length(); - } - return 1; - } - } - - private final Document doc; - private final List<Bit> bits = Lists.newArrayList(); - private Wavelet wavelet; - - public ApiView(Document doc, Wavelet wavelet) { - this.doc = doc; - this.wavelet = wavelet; - parse(doc); - } - - private void parse(Document doc) { - E bodyElement = Blips.getBody(doc); - if (bodyElement != null) { - N child = doc.getFirstChild(bodyElement); - while (child != null) { - T asText = doc.asText(child); - int xmlPos = doc.getLocation(child); - if (asText != null) { - bits.add(new Bit(doc.getData(asText), xmlPos)); - } else { - E xmlElement = doc.asElement(child); - if (xmlElement != null) { - Element element = ElementSerializer.xmlToApiElement(doc, xmlElement, wavelet); - // element can be null, but we still want to note that there - // was something unknown. - N next = doc.getNextSibling(child); - int xmlSize; - if (next != null) { - xmlSize = doc.getLocation(next) - xmlPos; - } else { - // At the end of the document. XmlSize is the rest. - xmlSize = doc.size() - 1 - xmlPos; - } - bits.add(new Bit(element, xmlPos, xmlSize)); - } - } - child = doc.getNextSibling(child); - } - } - } - - /** - * Delete the stuff between start and end not including end. - */ - public void delete(int start, int end) { - int len = end - start; - Pair<Integer, Integer> where = locate(start); - int index = where.first; - if (index == bits.size()) { - // outside - return; - } - int offset = where.second; - int xmlStart = bits.get(index).xmlPos + offset; - int xmlEnd = xmlStart; - while (len > 0) { - Bit bit = bits.get(index); - if (bit.string == null) { - // deleting an element: - len -= 1; - shift(index + 1, -bit.xmlSize); - xmlEnd += bit.xmlSize; - bits.remove(index); - } else { - // deleting a string bit - int todelete = bit.string.length() - offset; - if (todelete > len) { - todelete = len; - } - shift(index + 1, -todelete); - xmlEnd += todelete; - len -= todelete; - if (offset > 0) { - bit.string = bit.string.substring(0, offset) + bit.string.substring(offset + todelete); - index += 1; - offset = 0; - } else { - if (todelete < bit.string.length()) { - bit.string = bit.string.substring(todelete); - } else { - bits.remove(index); - } - } - } - } - doc.deleteRange(xmlStart, xmlEnd); - } - - public void insert(int pos, Element element) { - XmlStringBuilder xml = ElementSerializer.apiElementToXml(element); - int beforeSize = doc.size(); - Pair<Integer, Integer> where = locate(pos); - int index = where.first; - if (index == bits.size()) { - // outside. append. - Bit last = bits.get(bits.size() - 1); - Point<Doc.N> point = doc.locate(last.xmlPos + last.xmlSize); - doc.insertXml(point, xml); - bits.add(new Bit(element, last.xmlPos + last.xmlSize, doc.size() - beforeSize)); - return; - } - int offset = where.second; - Bit bit = bits.get(index); - Point<Doc.N> point = doc.locate(bit.xmlPos + offset); - doc.insertXml(point, xml); - int xmlSize = doc.size() - beforeSize; - if (bit.string != null && offset > 0) { - shift(index + 1, xmlSize); - String leftOver = bit.string.substring(offset); - bit.string = bit.string.substring(0, offset); - bit.xmlSize = offset; - int nextIndex = bit.xmlPos + bit.xmlSize; - bits.add(index + 1, new Bit(element, nextIndex, xmlSize)); - nextIndex += xmlSize; - bits.add(index + 2, new Bit(leftOver, nextIndex)); - } else { - bits.add(index, new Bit(element, bits.get(index).xmlPos, xmlSize)); - shift(index + 1, xmlSize); - } - } - - public void insert(int pos, String content) { - boolean first = true; - for (String paragraph : Splitter.on("\n").split(content)) { - if (first) { - first = false; - } else { - insert(pos, new Line()); - pos++; - } - Pair<Integer, Integer> where = locate(pos); - int index = where.first; - if (index == bits.size()) { - // outside. append. - Bit last = bits.get(bits.size() - 1); - bits.add(new Bit(paragraph, last.xmlPos + last.xmlSize)); - doc.insertText(last.xmlPos + last.xmlSize, paragraph); - } else { - int offset = where.second; - Bit bit = bits.get(index); - doc.insertText(bit.xmlPos + offset, paragraph); - if (bit.string != null) { - // if it's a string, add to the existing node - bit.string = bit.string.substring(0, offset) + paragraph + bit.string.substring(offset); - bit.xmlSize += paragraph.length(); - } else { - // if it's an element, insert just before - bits.add(index, new Bit(paragraph, bits.get(index).xmlPos - paragraph.length())); - } - shift(index + 1, paragraph.length()); - } - pos += paragraph.length(); - } - } - - /** - * Increment the xmlPos of everything from bitIndex and up by delta - * - * @param bitIndex - * @param delta - */ - private void shift(int bitIndex, int delta) { - for (int i = bitIndex; i < bits.size(); i++) { - bits.get(i).xmlPos += delta; - } - } - - /** - * Find which bit contains offset. - * - * @param offset - * @return the index of the bit plus whatever was left over or null when - * offset is outside the document. - */ - private Pair<Integer, Integer> locate(int offset) { - int index = 0; - while (bits.size() > index && bits.get(index).size() <= offset) { - offset -= bits.get(index).size(); - index++; - } - return Pair.of(index, offset); - } - - /** - * @returns the api representation of the current contents - */ - public String apiContents() { - StringBuilder res = new StringBuilder(); - for (Bit bit : bits) { - if (bit.string != null) { - res.append(bit.string); - } else { - if (bit.element != null && bit.element.getType().equals(ElementType.LINE)) { - res.append('\n'); - } else { - res.append(' '); - } - } - } - return res.toString(); - } - - /** - * @returns a list of ElementInfo's describing the elements in view. - */ - public List<ElementInfo> getElements() { - List<ElementInfo> res = Lists.newArrayList(); - int index = 0; - for (Bit bit : bits) { - if (bit.element != null) { - res.add(new ElementInfo(bit.element, index, bit.xmlPos)); - } - index += bit.size(); - } - return res; - } - - /** - * Transforms the given {@code xmlOffset} into the text offset. - * - * @param xmlOffset the xml offset to transform. - * @returns the text offset corresponding to the given xml offset. - * - * @throws IllegalArgumentException if the given {@code xmlOffset} is out of - * range. - */ - public int transformToTextOffset(int xmlOffset) { - // Make sure that the offset is valid. - Preconditions.checkArgument(xmlOffset >= 0); - Preconditions.checkArgument(xmlOffset <= doc.size()); - - // Find the right bit that contains the xml offset. - int index = 0; - int textOffset = 0; - while (index < bits.size() - && bits.get(index).xmlPos + bits.get(index).xmlSize - 1 < xmlOffset) { - Bit bit = bits.get(index++); - textOffset += bit.string != null ? bit.string.length() : 1; - } - - // Check if it is beyond the last bit, which is the closing </body> tag. In - // this case, just return textOffset. - if (index == bits.size()) { - return textOffset; - } - - // Return the offset. - Bit bit = bits.get(index); - if (bit.element != null) { - return textOffset; - } - return textOffset + xmlOffset - bit.xmlPos; - } - - /** - * @returns the xml index corresponding to the passed apiIndex. - */ - public int transformToXmlOffset(int apiIndex) { - Pair<Integer, Integer> where = locate(apiIndex); - int index = where.first; - int offset = where.second; - if (index == bits.size()) { - // We're beyond the last bit. Return last bit + offset. - Bit last = bits.get(bits.size() - 1); - return last.xmlPos + last.xmlSize + offset; - } - return bits.get(index).xmlPos + offset; - } - - /** - * Legacy support method. Return the index of the element that looks like the - * one we passed for some value of looks like. - */ - public int locateElement(Element element) { - int index = 0; - for (Bit bit : bits) { - if (bit.element != null && bit.element.getType().equals(element.getType())) { - if (element.getType().equals(ElementType.GADGET)) { - if (propertyMatch(bit.element, element, Gadget.URL)) { - return index; - } - } else if (element.getType().equals(ElementType.LABEL)) { - if (propertyMatch(bit.element, element, "for")) { - return index; - } - } else if (elementMatch(element, bit.element)) { - return index; - } - } - index += bit.size(); - } - return -1; - } - - private boolean propertyMatch(Element element1, Element element2, String prop) { - String val1 = element1.getProperty(prop); - String val2 = element2.getProperty(prop); - return val1 != null && val1.equals(val2); - } - - private boolean elementMatch(Element element1, Element element2) { - // TODO(ljvderijk): Elements should define their own equals method for each - // different type, improvements to the ElementSerializer can also be made. - return element1.getProperties().equals(element2.getProperties()); - } - - /** - * Call reparse when modifications to the underlying documents have been made - * and the api view needs to be updated. - * - * <p> - * TODO(user): Remove this once everything useful can be done through - * ApiView. - */ - public void reparse() { - bits.clear(); - parse(doc); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/data/DocumentHitIterator.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/data/DocumentHitIterator.java b/wave/src/main/java/com/google/wave/api/data/DocumentHitIterator.java deleted file mode 100644 index 42a03c6..0000000 --- a/wave/src/main/java/com/google/wave/api/data/DocumentHitIterator.java +++ /dev/null @@ -1,177 +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 com.google.wave.api.data; - -import com.google.common.base.Preconditions; -import com.google.wave.api.ElementType; -import com.google.wave.api.Range; - -import java.util.Map; -import java.util.Map.Entry; - -/** - * A interface encapsulating iterating through a document. - * - * <p> - * At some point we could consider turning this into an actual Iterable/Iterator - * thing - * - */ -public interface DocumentHitIterator { - - /** - * @returns the next range yielded by this Iterator or null if we're done. - */ - Range next(); - - /** - * Notify the iterator that the underlying document has changed; a change with - * size delta has been applied at where. - */ - void shift(int where, int delta); - - /** - * Singleshot returns a single range. - */ - class Singleshot implements DocumentHitIterator { - - private final Range range; - private boolean called; - - public Singleshot(Range range) { - this.called = false; - this.range = range; - } - - @Override - public Range next() { - if (called) { - return null; - } - called = true; - return this.range; - } - - @Override - public void shift(int where, int delta) { - } - } - - /** - * TextMatcher yields all ranges in the document matching the searched for - * string. - */ - class TextMatcher implements DocumentHitIterator { - - private final ApiView apiView; - private final String searchFor; - private int from; - private int hitsLeft; - - public TextMatcher(ApiView apiView, String searchFor, int maxHits) { - Preconditions.checkNotNull(apiView, "Api view must not be null"); - Preconditions.checkNotNull(searchFor, "The string to search for must not be null"); - - this.apiView = apiView; - this.searchFor = searchFor; - this.from = -1; - this.hitsLeft = maxHits; - } - - @Override - public Range next() { - if (hitsLeft == 0) { - return null; - } - hitsLeft--; - String searchIn = apiView.apiContents(); - int next = searchIn.indexOf(searchFor, from + 1); - if (next == -1) { - return null; - } - from = next; - return new Range(from, from + searchFor.length()); - } - - @Override - public void shift(int where, int delta) { - if (from != -1) { - if (where - 1 <= from) { - from += delta; - } - } - } - } - - /** - * ElementMatcher yields all ranges in the document matching the searched for - * element type. - */ - class ElementMatcher implements DocumentHitIterator { - - private int hitsLeft; - private int index; - private final ApiView apiView; - private final ElementType elementType; - private final Map<String, String> restrictions; - - public ElementMatcher( - ApiView apiView, ElementType elementType, Map<String, String> restrictions, int maxRes) { - Preconditions.checkNotNull(apiView, "Api view must not be null"); - Preconditions.checkNotNull(elementType, "The type of element to search for must not be null"); - Preconditions.checkNotNull(restrictions, "The search restricitions must not be null"); - - this.elementType = elementType; - this.apiView = apiView; - this.index = -1; - this.hitsLeft = maxRes; - this.restrictions = restrictions; - } - - @Override - public Range next() { - if (hitsLeft == 0) { - return null; - } - hitsLeft--; - - for (ApiView.ElementInfo elementInfo : apiView.getElements()) { - if (elementInfo.element.getType().equals(elementType) && elementInfo.apiPosition > index) { - boolean allMatched = true; - for (Entry<String, String> entry : restrictions.entrySet()) { - if (!entry.getValue().equals(elementInfo.element.getProperty(entry.getKey()))) { - allMatched = false; - break; - } - } - if (!allMatched) { - continue; - } - index = elementInfo.apiPosition; - return new Range(index, index + 1); - } - } - return null; - } - - @Override - public void shift(int where, int delta) { - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/data/ElementSerializer.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/data/ElementSerializer.java b/wave/src/main/java/com/google/wave/api/data/ElementSerializer.java deleted file mode 100644 index 42c14b5..0000000 --- a/wave/src/main/java/com/google/wave/api/data/ElementSerializer.java +++ /dev/null @@ -1,647 +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 com.google.wave.api.data; - -import com.google.common.base.CharMatcher; -import com.google.common.base.Splitter; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.wave.api.Attachment; -import com.google.wave.api.Element; -import com.google.wave.api.ElementType; -import com.google.wave.api.FormElement; -import com.google.wave.api.Gadget; -import com.google.wave.api.Image; -import com.google.wave.api.Installer; -import com.google.wave.api.Line; - -import org.waveprotocol.wave.model.conversation.Blips; -import org.waveprotocol.wave.model.document.Doc; -import org.waveprotocol.wave.model.document.Doc.E; -import org.waveprotocol.wave.model.document.Doc.N; -import org.waveprotocol.wave.model.document.Document; -import org.waveprotocol.wave.model.document.util.LineContainers; -import org.waveprotocol.wave.model.document.util.XmlStringBuilder; -import org.waveprotocol.wave.model.id.IdConstants; -import org.waveprotocol.wave.model.wave.Wavelet; - -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Class to support serializing Elements from and to XML. - * - * - */ -public abstract class ElementSerializer { - - // Two maps to easily look up what to serialize - private static final Map<ElementType, ElementSerializer> typeToSerializer = Maps.newHashMap(); - private static final Map<String, ElementSerializer> tagToSerializer = Maps.newHashMap(); - - private static final String CAPTION_TAG = "caption"; - private static final String CLICK_TAG = "click"; - private static final String ATTACHMENT_STR = "attachment"; - private static final String CAPTION_STR = "caption"; - - /** The attachment URL regular expression */ - private static final Pattern ATTACHMENT_URL_PATTERN = Pattern.compile( - "attachment_url\\\"\\ value\\=\\\"([^\\\"]*)\\\""); - - /** The attachment MIME type regular expression */ - private static final Pattern MIME_TYPE_PATTERN = Pattern.compile( - "mime_type\\\"\\ value\\=\\\"([^\\\"]*)\\\""); - - /** Attachment Download Host URL */ - private static String attachmentDownloadHostUrl = ""; - - public static void setAttachmentDownloadHostUrl(String attachmentDownloadHostUrl){ - ElementSerializer.attachmentDownloadHostUrl = attachmentDownloadHostUrl; - } - - public static XmlStringBuilder apiElementToXml(Element e) { - ElementSerializer serializer = typeToSerializer.get(e.getType()); - if (serializer == null) { - return null; - } - return serializer.toXml(e); - } - - public static Element xmlToApiElement(Document doc, Doc.E element, Wavelet wavelet) { - if (element == null) { - return null; - } - ElementSerializer serializer = tagToSerializer.get(doc.getTagName(element)); - if (serializer == null) { - return null; - } - return serializer.fromXml(doc, element, wavelet); - } - - public static String tagNameForElementType(ElementType lookup) { - ElementSerializer serializer = typeToSerializer.get(lookup); - if (serializer != null) { - return serializer.tagName; - } - return null; - } - - public static Map<Integer, Element> serialize(Document doc, Wavelet wavelet) { - Map<Integer, Element> result = Maps.newHashMap(); - ApiView apiView = new ApiView(doc, wavelet); - - Doc.N node = Blips.getBody(doc); - if (node != null) { - // The node is the body; we're after its children - node = doc.getFirstChild(node); - } - while (node != null) { - E element = doc.asElement(node); - if (element != null) { - Element apiElement = xmlToApiElement(doc, element, wavelet); - if (apiElement != null) { - result.put(apiView.transformToTextOffset(doc.getLocation(element)), apiElement); - } - } - node = doc.getNextSibling(node); - } - return result; - } - - private static void register(ElementSerializer serializer) { - typeToSerializer.put(serializer.elementType, serializer); - tagToSerializer.put(serializer.tagName, serializer); - } - - static { - register(new ElementSerializer("label", ElementType.LABEL) { - @Override - public XmlStringBuilder toXml(Element e) { - String value = e.getProperty("value"); - if (value == null) { - value = e.getProperty("defaultValue"); - } - return wrapWithContent(value, "for", e.getProperty("name")); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - FormElement formElement = createFormElement(doc, element); - formElement.setName(doc.getAttribute(element, "for")); - if (doc.getFirstChild(element) != null) { - formElement.setDefaultValue(doc.getData(doc.asText(doc.getFirstChild(element)))); - formElement.setValue(doc.getData(doc.asText(doc.getFirstChild(element)))); - } - return formElement; - } - }); - - register(new ElementSerializer("input", ElementType.INPUT) { - @Override - public XmlStringBuilder toXml(Element e) { - String value = e.getProperty("value"); - if (value == null) { - value = e.getProperty("defaultValue"); - } - return wrapWithContent(value, "name", e.getProperty("name")); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - FormElement formElement = createFormElement( - doc, element, doc.getAttribute(element, "submit")); - // Set the text content. - if (doc.getFirstChild(element) != null) { - formElement.setValue(doc.getData(doc.asText(doc.getFirstChild(element)))); - } - return formElement; - } - }); - - register(new ElementSerializer("password", ElementType.PASSWORD) { - @Override - public XmlStringBuilder toXml(Element e) { - String value = e.getProperty("value"); - if (value == null) { - value = e.getProperty("defaultValue"); - } - return wrap("name", e.getProperty("name"), "value", value); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - return createFormElement(doc, element, doc.getAttribute(element, "value")); - } - }); - - register(new ElementSerializer("textarea", ElementType.TEXTAREA) { - @Override - public XmlStringBuilder toXml(Element e) { - XmlStringBuilder res = XmlStringBuilder.createEmpty(); - String value = e.getProperty("value"); - if (isEmptyOrWhitespace(value)) { - res.append(XmlStringBuilder.createEmpty().wrap(LineContainers.LINE_TAGNAME)); - } else { - Splitter splitter = Splitter.on("\n"); - for (String paragraph : splitter.split(value)) { - res.append(XmlStringBuilder.createEmpty().wrap(LineContainers.LINE_TAGNAME)); - res.append(XmlStringBuilder.createText(paragraph)); - } - } - return res.wrap("textarea", "name", e.getProperty("name")); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - // Set the text content. We're doing a little mini textview here. - StringBuilder value = new StringBuilder(); - Doc.N node = doc.getFirstChild(element); - boolean first = true; - while (node != null) { - Doc.T text = doc.asText(node); - if (text != null) { - value.append(doc.getData(text)); - } - Doc.E docElement = doc.asElement(node); - if (docElement != null && - doc.getTagName(docElement).equals(LineContainers.LINE_TAGNAME)) { - if (first) { - first = false; - } else { - value.append('\n'); - } - } - node = doc.getNextSibling(node); - } - return createFormElement(doc, element, value.toString()); - } - }); - - register(new ElementSerializer("button", ElementType.BUTTON) { - @Override - public XmlStringBuilder toXml(Element element) { - XmlStringBuilder res = XmlStringBuilder.createEmpty(); - res.append(XmlStringBuilder.createText(element.getProperty("value")).wrap(CAPTION_TAG)); - res.append(XmlStringBuilder.createEmpty().wrap("events")); - return res.wrap("button", "name", element.getProperty("name")); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - FormElement formElement = createFormElement(doc, element); - - Doc.N firstChild = doc.getFirstChild(element); - // Get the default value from the caption. - if (firstChild != null && doc.getTagName(doc.asElement(firstChild)).equals(CAPTION_TAG) && - doc.getFirstChild(doc.asElement(firstChild)) != null) { - formElement.setDefaultValue(doc.getData(doc.asText(doc.getFirstChild( - doc.asElement(firstChild))))); - } - - // Get the value from the last click event. - if (firstChild != null && - doc.getNextSibling(firstChild) != null && - doc.asElement(doc.getFirstChild(doc.getNextSibling(firstChild))) != null && - doc.getTagName(doc.asElement(doc.getFirstChild(doc.getNextSibling( - firstChild)))).equals(CLICK_TAG)) { - formElement.setValue("clicked"); - } else { - formElement.setValue(formElement.getDefaultValue()); - } - return formElement; - } - }); - - register(new ElementSerializer("radiogroup", ElementType.RADIO_BUTTON_GROUP) { - @Override - public XmlStringBuilder toXml(Element e) { - return wrap("name", e.getProperty("name")); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - FormElement formElement = createFormElement( - doc, element, doc.getAttribute(element, "value")); - return formElement; - } - }); - - register(new ElementSerializer("radio", ElementType.RADIO_BUTTON) { - @Override - public XmlStringBuilder toXml(Element e) { - return wrap("name", e.getProperty("name"), "group", e.getProperty("value")); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - return new FormElement(getElementType(), - doc.getAttribute(element, "name"), - doc.getAttribute(element, "group")); - } - }); - - register(new ElementSerializer("check", ElementType.CHECK) { - @Override - public XmlStringBuilder toXml(Element e) { - return wrap("name", e.getProperty("name"), - "submit", e.getProperty("defaultValue"), - "value", e.getProperty("value")); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - FormElement formElement = createFormElement( - doc, element, doc.getAttribute(element, "value")); - formElement.setDefaultValue(doc.getAttribute(element, "submit")); - return formElement; - } - }); - - register(new ElementSerializer("extension_installer", ElementType.INSTALLER) { - @Override - public XmlStringBuilder toXml(Element e) { - return wrap("manifest", e.getProperty("manifest")); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - Installer installer = new Installer(); - installer.setManifest(doc.getAttribute(element, "manifest")); - - return installer; - } - }); - - register(new ElementSerializer("gadget", ElementType.GADGET) { - @Override - public XmlStringBuilder toXml(Element element) { - XmlStringBuilder res = XmlStringBuilder.createEmpty(); - if (element.getProperties().containsKey("category")) { - res.append(XmlStringBuilder.createEmpty().wrap( - "category", "name", element.getProperty("category"))); - } - if (element.getProperties().containsKey("title")) { - res.append(XmlStringBuilder.createEmpty().wrap( - "title", "value", element.getProperty("title"))); - } - if (element.getProperties().containsKey("thumbnail")) { - res.append(XmlStringBuilder.createEmpty().wrap( - "thumbnail", "value", element.getProperty("thumbnail"))); - } - for (Map.Entry<String, String> property : element.getProperties().entrySet()) { - if (property.getKey().equals("category") || property.getKey().equals("url") || - property.getKey().equals("title") || property.getKey().equals("thumbnail") || - property.getKey().equals("author")) { - continue; - } else if (property.getKey().equals("pref")) { - res.append(XmlStringBuilder.createEmpty().wrap("pref", "value", property.getValue())); - } else { - res.append(XmlStringBuilder.createEmpty().wrap("state", - "name", property.getKey(), - "value", property.getValue())); - } - } - List<String> attributes = Lists.newArrayList("url", element.getProperty("url")); - if (element.getProperties().containsKey("author")) { - attributes.add("author"); - attributes.add(element.getProperty("author")); - } - if (element.getProperties().containsKey("ifr")) { - attributes.add("ifr"); - attributes.add(element.getProperty("ifr")); - } - String[] asArray = new String[attributes.size()]; - attributes.toArray(asArray); - return res.wrap("gadget", asArray); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - Gadget gadget = new Gadget(); - - gadget.setUrl(doc.getAttribute(element, "url")); - String author = doc.getAttribute(element, "author"); - if (author != null) { - gadget.setAuthor(author); - } - String ifr = doc.getAttribute(element, "ifr"); - if (ifr != null) { - gadget.setIframe(ifr); - } - - // TODO(user): Streamline this. Maybe use SchemaConstraints.java to - // get a list of child elements or attributes, then automate this. - E child = doc.asElement(doc.getFirstChild(element)); - while (child != null) { - if (doc.getTagName(child).equals("name")) { - gadget.setProperty("name", doc.getAttribute(child, "value")); - } else if (doc.getTagName(child).equals("title")) { - gadget.setProperty("title", doc.getAttribute(child, "value")); - } else if (doc.getTagName(child).equals("thumbnail")) { - gadget.setProperty("thumbnail", doc.getAttribute(child, "value")); - } else if (doc.getTagName(child).equals("pref")) { - gadget.setProperty("pref", doc.getAttribute(child, "value")); - } else if (doc.getTagName(child).equals("state")) { - gadget.setProperty(doc.getAttribute(child, "name"), doc.getAttribute(child, "value")); - } else if (doc.getTagName(child).equals("category")) { - gadget.setProperty("category", doc.getAttribute(child, "name")); - } - child = doc.asElement(doc.getNextSibling(child)); - } - - return gadget; - } - }); - - register(new ElementSerializer("img", ElementType.IMAGE) { - @Override - public XmlStringBuilder toXml(Element element) { - XmlStringBuilder res = XmlStringBuilder.createEmpty(); - List<String> attributes = Lists.newArrayList("src", element.getProperty("url")); - if (element.getProperty("width") != null) { - attributes.add("width"); - attributes.add(element.getProperty("width")); - } - if (element.getProperty("height") != null) { - attributes.add("height"); - attributes.add(element.getProperty("height")); - } - if (element.getProperty("caption") != null) { - attributes.add("alt"); - attributes.add(element.getProperty("caption")); - } - String[] asArray = new String[attributes.size()]; - attributes.toArray(asArray); - return res.wrap("img", asArray); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - Image image = new Image(); - - if (doc.getAttribute(element, "src") != null) { - image.setUrl(doc.getAttribute(element, "src")); - } - if (doc.getAttribute(element, "alt") != null) { - image.setCaption(doc.getAttribute(element, "alt")); - } - if (doc.getAttribute(element, "width") != null) { - image.setWidth(Integer.parseInt(doc.getAttribute(element, "width"))); - } - if (doc.getAttribute(element, "height") != null) { - image.setHeight(Integer.parseInt(doc.getAttribute(element, "height"))); - } - - return image; - } - }); - - register(new ElementSerializer("image", ElementType.ATTACHMENT) { - @Override - public XmlStringBuilder toXml(Element element) { - XmlStringBuilder res = XmlStringBuilder.createEmpty(); - if (element.getProperties().containsKey("attachmentId")) { - if (element.getProperty(CAPTION_STR) != null) { - res.append(XmlStringBuilder.createText(element.getProperty(CAPTION_STR)) - .wrap("caption")); - } - return res.wrap("image", ATTACHMENT_STR, element.getProperty("attachmentId")); - } - return res; - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - Map<String, String> properties = Maps.newHashMap(); - - String attachmentId = doc.getAttribute(element, ATTACHMENT_STR); - if (attachmentId != null) { - properties.put(Attachment.ATTACHMENT_ID, attachmentId); - } - String caption = getCaption(doc, element); - if (caption != null) { - properties.put(Attachment.CAPTION, caption); - } - if (wavelet != null && attachmentId != null) { - Document attachmentDataDoc = - wavelet.getDocument(IdConstants.ATTACHMENT_METADATA_PREFIX + "+" + attachmentId); - if (attachmentDataDoc != null) { - String dataDocument = attachmentDataDoc.toXmlString(); - if (dataDocument != null) { - properties.put(Attachment.MIME_TYPE, extractValue(dataDocument, MIME_TYPE_PATTERN)); - properties.put(Attachment.ATTACHMENT_URL, - ElementSerializer.attachmentDownloadHostUrl - + getAttachmentUrl(dataDocument)); - } - } - } - return new Attachment(properties, null); - } - - private String getCaption(Document doc, E element) { - N node = doc.getFirstChild(element); - - while (node != null) { - E cElement = doc.asElement(node); - if (cElement != null && doc.getTagName(cElement).equals(CAPTION_TAG) && - doc.getFirstChild(cElement) != null) { - return doc.getData(doc.asText(doc.getFirstChild(cElement))); - } - node = doc.getNextSibling(node); - } - return null; - } - }); - - register(new ElementSerializer(LineContainers.LINE_TAGNAME, ElementType.LINE) { - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - Line paragraph = new Line(); - if (doc.getAttribute(element, "t") != null) { - paragraph.setLineType(doc.getAttribute(element, "t")); - } - if (doc.getAttribute(element, "i") != null) { - paragraph.setIndent(doc.getAttribute(element, "i")); - } - if (doc.getAttribute(element, "a") != null) { - paragraph.setAlignment(doc.getAttribute(element, "a")); - } - if (doc.getAttribute(element, "d") != null) { - paragraph.setDirection(doc.getAttribute(element, "d")); - } - return paragraph; - } - - @Override - public XmlStringBuilder toXml(Element element) { - XmlStringBuilder res = XmlStringBuilder.createEmpty(); - // A cast would be nice here, but unfortunately the element - // gets deserialized as an actual Element - Line line = new Line(element.getProperties()); - - List<String> attributes = Lists.newArrayList(); - if (!isEmptyOrWhitespace(line.getLineType())) { - attributes.add("t"); - attributes.add(line.getLineType()); - } - if (!isEmptyOrWhitespace(line.getIndent())) { - attributes.add("i"); - attributes.add(line.getIndent()); - } - if (!isEmptyOrWhitespace(line.getAlignment())) { - attributes.add("a"); - attributes.add(line.getAlignment()); - } - if (!isEmptyOrWhitespace(line.getDirection())) { - attributes.add("d"); - attributes.add(line.getDirection()); - } - String[] asArray = new String[attributes.size()]; - attributes.toArray(asArray); - return res.wrap(LineContainers.LINE_TAGNAME, asArray); - } - - }); - - register(new ElementSerializer(Blips.THREAD_INLINE_ANCHOR_TAGNAME, ElementType.INLINE_BLIP) { - @Override - public XmlStringBuilder toXml(Element e) { - return XmlStringBuilder.createEmpty().wrap( - Blips.THREAD_INLINE_ANCHOR_TAGNAME, - Blips.THREAD_INLINE_ANCHOR_ID_ATTR, e.getProperty("id")); - } - - @Override - public Element fromXml(Document doc, E element, Wavelet wavelet) { - return new Element(ElementType.INLINE_BLIP, - ImmutableMap.of("id", doc.getAttribute(element, Blips.THREAD_INLINE_ANCHOR_ID_ATTR))); - } - }); - } - - private final String tagName; - private final ElementType elementType; - protected abstract XmlStringBuilder toXml(Element e); - protected abstract Element fromXml(Document doc, E element, Wavelet wavelet); - - public String getTagName() { - return tagName; - } - - public ElementType getElementType() { - return elementType; - } - - protected XmlStringBuilder wrap(String... attributes) { - return XmlStringBuilder.createEmpty().wrap(tagName, attributes); - } - - protected XmlStringBuilder wrapWithContent(String content, String... attributes) { - if (Strings.isNullOrEmpty(content)) { - return wrap(attributes); - } - return XmlStringBuilder.createText(content).wrap(tagName, attributes); - } - - /** - * Helper method to create a form element - * @return a form element of the right type and with the right name and - * optionally an initial value. - */ - - protected FormElement createFormElement(Document doc, E element, String initialValue) { - FormElement formElement = new FormElement(elementType, doc.getAttribute(element, "name")); - if (initialValue != null) { - formElement.setValue(initialValue); - formElement.setDefaultValue(initialValue); - } - return formElement; - } - - protected FormElement createFormElement(Document doc, E element) { - return createFormElement(doc, element, null); - } - - - public ElementSerializer(String tagName, ElementType elementType) { - this.tagName = tagName; - this.elementType = elementType; - } - - private static boolean isEmptyOrWhitespace(String value) { - return value == null || CharMatcher.WHITESPACE.matchesAllOf(value); - } - - private static String getAttachmentUrl(String dataDocument) { - String rawURL = extractValue(dataDocument, ATTACHMENT_URL_PATTERN); - return rawURL == null ? "" : rawURL.replace("&", "&"); - } - - // TODO(user): move away from REGEX - private static String extractValue(String dataDocument, Pattern pattern) { - Matcher matcher = pattern.matcher(dataDocument); - return matcher.find() ? matcher.group(1) : null; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/data/converter/ContextResolver.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/data/converter/ContextResolver.java b/wave/src/main/java/com/google/wave/api/data/converter/ContextResolver.java deleted file mode 100644 index 5320964..0000000 --- a/wave/src/main/java/com/google/wave/api/data/converter/ContextResolver.java +++ /dev/null @@ -1,151 +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 com.google.wave.api.data.converter; - -import com.google.wave.api.BlipData; -import com.google.wave.api.BlipThread; -import com.google.wave.api.Context; -import com.google.wave.api.impl.EventMessageBundle; -import com.google.wave.api.impl.WaveletData; - -import org.waveprotocol.wave.model.conversation.Conversation; -import org.waveprotocol.wave.model.conversation.ConversationBlip; -import org.waveprotocol.wave.model.conversation.ConversationBlip.LocatedReplyThread; -import org.waveprotocol.wave.model.conversation.ConversationThread; -import org.waveprotocol.wave.model.wave.Wavelet; - -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; -import java.util.Set; - -/** - * Class to resolve context for {@link EventMessageBundle}. - * - */ -public class ContextResolver { - - /** - * Resolve an {@link EventMessageBundle}'s context. Meaning that the - * {@link WaveletData}, {@link BlipData} and {@link BlipThread} will be - * resolved as dictated by the {@link EventMessageBundle}'s getRequiredBlips - * method. - * - * @param eventMessageBundle bundle to put the context in - * @param wavelet {@link Wavelet} to put in the {@link EventMessageBundle} - * @param conversation {@link Conversation} to put in the - * {@link EventMessageBundle} - * @param eventDataConverter {@link EventDataConverter} used to convert - * {@link Wavelet}s and {@link ConversationBlip}s. - */ - public static void resolveContext(EventMessageBundle eventMessageBundle, Wavelet wavelet, - Conversation conversation, EventDataConverter eventDataConverter) { - // TODO(user): Refactor. - WaveletData waveletData = - eventDataConverter.toWaveletData(wavelet, conversation, eventMessageBundle); - eventMessageBundle.setWaveletData(waveletData); - for (Map.Entry<String, Set<Context>> entry : eventMessageBundle.getRequiredBlips().entrySet()) { - Set<Context> contextSet = entry.getValue(); - ConversationBlip requiredBlip = conversation.getBlip(entry.getKey()); - if (contextSet.contains(Context.ALL)) { - ContextResolver.addAllBlipsToEventMessages( - eventMessageBundle, conversation, wavelet, eventDataConverter); - // We now have all blips so we're done. - break; - } - if (contextSet.contains(Context.ROOT)) { - ConversationBlip rootBlip = conversation.getRootThread().getFirstBlip(); - if (rootBlip != requiredBlip) { - ContextResolver.addBlipToEventMessages( - eventMessageBundle, rootBlip, wavelet, eventDataConverter); - } - } - - // Required blip might be null, for example, in a blip deleted event. - if (requiredBlip == null) { - continue; - } - - ContextResolver.addBlipToEventMessages( - eventMessageBundle, requiredBlip, wavelet, eventDataConverter); - if (contextSet.contains(Context.CHILDREN)) { - for (ConversationBlip child : eventDataConverter.findBlipChildren(requiredBlip)) { - ContextResolver.addBlipToEventMessages( - eventMessageBundle, child, wavelet, eventDataConverter); - } - } - ConversationThread containingThread = requiredBlip.getThread(); - if (contextSet.contains(Context.PARENT)) { - ConversationBlip parent = eventDataConverter.findBlipParent(requiredBlip); - if (parent != null) { - ContextResolver.addBlipToEventMessages( - eventMessageBundle, parent, wavelet, eventDataConverter); - } - } - if (contextSet.contains(Context.SIBLINGS)) { - for (ConversationBlip blip : containingThread.getBlips()) { - if (blip != requiredBlip) { - ContextResolver.addBlipToEventMessages( - eventMessageBundle, blip, wavelet, eventDataConverter); - } - } - } - } - } - - /** - * Adds a single {@link ConversationBlip} to the {@link EventMessageBundle}. - * - * @param eventMessageBundle to add the blip to - * @param blip {@link ConversationBlip} to add - * @param wavelet {@link Wavelet} that the blip is based on - * @param eventDataConverter {@link EventDataConverter} used for conversion - */ - private static void addBlipToEventMessages(EventMessageBundle eventMessageBundle, - ConversationBlip blip, Wavelet wavelet, EventDataConverter eventDataConverter) { - if (blip != null && !eventMessageBundle.hasBlipId(blip.getId())) { - eventMessageBundle.addBlip( - blip.getId(), eventDataConverter.toBlipData(blip, wavelet, eventMessageBundle)); - } - } - - /** - * Adds all blips in the given conversation to the {@link EventMessageBundle}. - * - * @param eventMessageBundle to add the blips to - * @param conversation {@link Conversation} to get all blips from - * @param wavelet {@link Wavelet} that the {@link Conversation} is based on - * @param eventDataConverter {@link EventDataConverter} used for conversion - */ - public static void addAllBlipsToEventMessages(EventMessageBundle eventMessageBundle, - Conversation conversation, Wavelet wavelet, EventDataConverter eventDataConverter) { - Queue<ConversationThread> threads = new LinkedList<ConversationThread>(); - threads.add(conversation.getRootThread()); - while (!threads.isEmpty()) { - ConversationThread thread = threads.remove(); - for (ConversationBlip blip : thread.getBlips()) { - addBlipToEventMessages(eventMessageBundle, blip, wavelet, eventDataConverter); - for (ConversationThread replyThread : blip.getReplyThreads()) { - threads.add(replyThread); - } - } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverter.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverter.java b/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverter.java deleted file mode 100644 index 3d8e91b..0000000 --- a/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverter.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 com.google.wave.api.data.converter; - -import com.google.wave.api.BlipData; -import com.google.wave.api.impl.EventMessageBundle; -import com.google.wave.api.impl.WaveletData; - -import org.waveprotocol.wave.model.conversation.Conversation; -import org.waveprotocol.wave.model.conversation.ConversationBlip; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.model.wave.Wavelet; - -import java.util.Collection; -import java.util.List; - -/** - * A utility that handles the conversion from server side model objects, for - * example, {@link Wavelet}, {@link ConversationBlip}, and so on, to the - * API model objects that are serializable to JSON. - * - */ -public interface EventDataConverter { - - /** - * Converts a {@link Wavelet} into a serializable {@link WaveletData} - * object so that it can be serialized into JSON, and sent to the robot. - * - * @param wavelet the wavelet to convert. - * @param conversation the conversation manifest. - * @param eventMessageBundle the event bundle where this {@link WaveletData} - * will be added to. - * @return the converted {@link WaveletData} object. - */ - WaveletData toWaveletData(Wavelet wavelet, - Conversation conversation, EventMessageBundle eventMessageBundle); - - /** - * Converts a {@link ConversationBlip} into a serializable {@link BlipData} - * object so that it can be serialized into JSON, and sent to the robot. - * - * @param blip the blip to convert. - * @param wavelet the wavelet that contains the blip. - * @param eventMessageBundle the event bundle where this {@link BlipData} - * will be added to. - * @return the converted {@link BlipData} object. - */ - BlipData toBlipData(ConversationBlip blip, Wavelet wavelet, - EventMessageBundle eventMessageBundle); - - /** - * Finds the parent of a blip. - * - * @param blip the blip. - * @return the blip's parent, or {@code null} if blip is the first blip in a - * conversation. - */ - ConversationBlip findBlipParent(ConversationBlip blip); - - /** - * Finds the children of a blip. - * - * @param blip the blip. - * @return a list of the blip's children. - */ - List<ConversationBlip> findBlipChildren(ConversationBlip 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. - */ - List<String> idsToParticipantIdList(Collection<ParticipantId> participantIds); - -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverterManager.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverterManager.java b/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverterManager.java deleted file mode 100644 index e23af85..0000000 --- a/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverterManager.java +++ /dev/null @@ -1,66 +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 com.google.wave.api.data.converter; - -import com.google.wave.api.ProtocolVersion; - -import java.util.Map.Entry; -import java.util.NavigableMap; - -/** - * A simple utility class that manages the {@link EventDataConverter} for - * various protocol versions. - * - */ -public class EventDataConverterManager { - - /** A map of protocol version to {@link EventDataConverter}. */ - private final NavigableMap<ProtocolVersion, EventDataConverter> eventDataConverters; - - /** - * Constructor. - * - * @param eventDataConverters a map of {@link EventDataConverter}. - */ - public EventDataConverterManager( - NavigableMap<ProtocolVersion, EventDataConverter> eventDataConverters) { - this.eventDataConverters = eventDataConverters; - } - - /** - * Returns an instance of an {@link EventDataConverter} for the given - * protocol version. - * - * @param protocolVersion the protocol version. - * @return an instance of an {@link EventDataConverter}, or {@code null} if - * there is no converter for the given version. - */ - public EventDataConverter getEventDataConverter(ProtocolVersion protocolVersion) { - // Get the latest instance of {@link EventDataConverter} for a protocol - // version that is less than or equal to the given version, as not every - // protocol version will have a versioned {@link EventDataConverter}. - Entry<ProtocolVersion, EventDataConverter> entry = eventDataConverters.floorEntry( - protocolVersion); - if (entry == null) { - return null; - } - return entry.getValue(); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverterModule.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverterModule.java b/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverterModule.java deleted file mode 100644 index 9916ec7..0000000 --- a/wave/src/main/java/com/google/wave/api/data/converter/EventDataConverterModule.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.google.wave.api.data.converter; - -import com.google.common.collect.Maps; -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.Singleton; -import com.google.wave.api.ProtocolVersion; -import com.google.wave.api.data.converter.v21.EventDataConverterV21; -import com.google.wave.api.data.converter.v22.EventDataConverterV22; - -import java.util.NavigableMap; - -/** - * Guice module for setting up the data conversion part of the {@link RobotSerializer}. - * - */ -public class EventDataConverterModule extends AbstractModule { - - /** - * @return A singleton instance of a {@link EventDataConverterManager}. - */ - @Singleton - @Provides - static EventDataConverterManager provideEventDataConverterManager() { - // v0.1 till v0.21 use the same event data converter. - NavigableMap<ProtocolVersion, EventDataConverter> converters = Maps.newTreeMap(); - EventDataConverterV21 eventDataConverterV21 = new EventDataConverterV21(); - converters.put(ProtocolVersion.V1, eventDataConverterV21); - converters.put(ProtocolVersion.V2, eventDataConverterV21); - converters.put(ProtocolVersion.V2_1, eventDataConverterV21); - converters.put(ProtocolVersion.V2_2, new EventDataConverterV22()); - return new EventDataConverterManager(converters); - } - - @Override - protected void configure() { - } -}