http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/ProtocolVersion.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/ProtocolVersion.java b/wave/src/main/java/com/google/wave/api/ProtocolVersion.java deleted file mode 100644 index c6fc14a..0000000 --- a/wave/src/main/java/com/google/wave/api/ProtocolVersion.java +++ /dev/null @@ -1,127 +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 java.util.HashMap; -import java.util.Map; -import java.util.logging.Logger; - -/** - * An enumeration that represents the robot API wire protocol versions. - * - * @author [email protected] (Marcel Prasetya) - */ -public enum ProtocolVersion { - V1("0.1"), - V2("0.2"), - V2_1("0.21"), - V2_2("0.22"); - - /** The default protocol version. */ - public static final ProtocolVersion DEFAULT = ProtocolVersion.V2_2; - - /** Logger. */ - private static final Logger LOG = Logger.getLogger(ProtocolVersion.class.getName()); - - /** Reverse mapping from version string to {@link ProtocolVersion} enum. */ - private static final Map<String, ProtocolVersion> REVERSE_LOOKUP_MAP = - new HashMap<String, ProtocolVersion>(ProtocolVersion.values().length); - - static { - for (ProtocolVersion protocolVersion : ProtocolVersion.values()) { - String versionString = protocolVersion.versionString; - if (REVERSE_LOOKUP_MAP.containsKey(versionString)) { - LOG.warning("There are more than one ProtocolVersions that have the same version string " + - versionString); - } - REVERSE_LOOKUP_MAP.put(versionString, protocolVersion); - } - } - - /** The version string, for example, 0.1. */ - private final String versionString; - - /** - * Constructor. - * - * @param versionString the version string, for example, 0.1. - */ - private ProtocolVersion(String versionString) { - this.versionString = versionString; - } - - /** - * @return the version string. - */ - public String getVersionString() { - return versionString; - } - - /** - * @param other the other {@link ProtocolVersion} to compare to. - * @return {@code true} if {@code this} version is less than the {@code other} - * version. - */ - public boolean isLessThan(ProtocolVersion other) { - return versionString.compareTo(other.versionString) < 0; - } - - /** - * @param other the other {@link ProtocolVersion} to compare to. - * @return {@code true} if {@code this} version is less than or equal to the - * {@code other} version. - */ - public boolean isLessThanOrEqual(ProtocolVersion other) { - return versionString.compareTo(other.versionString) <= 0; - } - - /** - * @param other the other {@link ProtocolVersion} to compare to. - * @return {@code true} if {@code this} version is greater than or equal to - * the {@code other} version. - */ - public boolean isGreaterThanOrEqual(ProtocolVersion other) { - return versionString.compareTo(other.versionString) >= 0; - } - - /** - * @param other the other {@link ProtocolVersion} to compare to. - * @return {@code true} if {@code this} version is greater than the - * {@code other} version. - */ - public boolean isGreaterThan(ProtocolVersion other) { - return versionString.compareTo(other.versionString) > 0; - } - - /** - * Returns a {@link ProtocolVersion} that represents the given version string, - * or {@link ProtocolVersion#DEFAULT} if the version string is invalid. - * - * @param versionString the version string. - * @return a {@link ProtocolVersion}. - */ - public static ProtocolVersion fromVersionString(String versionString) { - ProtocolVersion protocolVersion = REVERSE_LOOKUP_MAP.get(versionString); - if (protocolVersion == null) { - return DEFAULT; - } - return protocolVersion; - } -}
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/Range.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/Range.java b/wave/src/main/java/com/google/wave/api/Range.java deleted file mode 100644 index 53cf0b6..0000000 --- a/wave/src/main/java/com/google/wave/api/Range.java +++ /dev/null @@ -1,95 +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 java.io.Serializable; - -/** - * A class that models a range, that contains a start and end index. - */ -public class Range implements Serializable { - - /** Start of the range. */ - private final int start; - - /** End of the range. */ - private final int end; - - /** - * Constructs a range object given a start and end index into the document. - * - * @param start the start of the range. - * @param end the end of the range. - */ - public Range(int start, int end) { - this.start = start; - this.end = end; - } - - /** - * Returns the starting index of the range. - * - * @return the starting index. - */ - public int getStart() { - return start; - } - - /** - * Returns the ending index of the range. - * - * @return the ending index. - */ - public int getEnd() { - return end; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + end; - result = prime * result + start; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj == null) { - return false; - } - - if (getClass() != obj.getClass()) { - return false; - } - - Range other = (Range) obj; - return start == other.start && end == other.end; - } - - @Override - public String toString() { - return "Range(" + start + ',' + end + ')'; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/Restriction.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/Restriction.java b/wave/src/main/java/com/google/wave/api/Restriction.java deleted file mode 100644 index 9bc7e7f..0000000 --- a/wave/src/main/java/com/google/wave/api/Restriction.java +++ /dev/null @@ -1,70 +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; - -/** - * A class that represents a property filter for element, that can be used when - * when searching for an element inside a blip. - */ -public class Restriction { - - /** The key of the property. */ - private final String key; - - /** The value of the property. */ - private final String value; - - /** - * Creates an instance of {@link Restriction} for a property with the given - * key and value. - * - * @param key the key of the property to restrict. - * @param value the value of the property to restrict. - * @return an instance of {@link Restriction}. - */ - public static Restriction of(String key, String value) { - return new Restriction(key, value); - } - - /** - * Constructor. - * - * @param key the key of the property to restrict. - * @param value the value of the property to restrict. - */ - private Restriction(String key, String value) { - this.key = key; - this.value = value; - } - - /** - * @return the key of the property to restrict. - */ - public String getKey() { - return key; - } - - /** - * @return the value of the property to restrict. - */ - public String getValue() { - return value; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/RobotSerializer.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/RobotSerializer.java b/wave/src/main/java/com/google/wave/api/RobotSerializer.java deleted file mode 100644 index 9bcbf76..0000000 --- a/wave/src/main/java/com/google/wave/api/RobotSerializer.java +++ /dev/null @@ -1,345 +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 static com.google.wave.api.OperationType.ROBOT_NOTIFY; -import static com.google.wave.api.OperationType.ROBOT_NOTIFY_CAPABILITIES_HASH; - -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonParser; -import com.google.wave.api.JsonRpcConstant.ParamsProperty; -import com.google.wave.api.JsonRpcConstant.RequestProperty; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.NavigableMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Logger; - -/** - * Utility class to serialize and deserialize Events and Operations to and from - * JSON string for V2.* of the protocol. - * - * @author [email protected] (Marcel Prasetya) - * @author [email protected] (Lennard de Rijk) - */ -public class RobotSerializer { - - /** The counter for protocol versions. */ - public static final Map<ProtocolVersion, AtomicInteger> PROTOCOL_VERSION_COUNTERS; - - static { - PROTOCOL_VERSION_COUNTERS = new HashMap<ProtocolVersion, AtomicInteger>(); - // Put in the V2 protocols that are used in this serializer - for (ProtocolVersion protcolVersion : ProtocolVersion.values()) { - if (protcolVersion.isGreaterThanOrEqual(ProtocolVersion.V2)) { - PROTOCOL_VERSION_COUNTERS.put(protcolVersion, new AtomicInteger()); - } - } - } - - private static final Logger LOG = Logger.getLogger(RobotSerializer.class.getName()); - - /** An map of {@link Gson}s for serializing and deserializing JSON. */ - private final NavigableMap<ProtocolVersion, Gson> gsons; - - /** The default protocol version. */ - private final ProtocolVersion defaultProtocolVersion; - - /** - * An instance of {@link JsonParser} to parse JSON string into - * {@link JsonElement}. - */ - private final JsonParser jsonParser; - - /** - * Constructor. Note that the defaultprotocol version must occur in the map - * of {@link Gson}s. - * - * @param gsons an map of {@link Gson}s for serializing and deserializing - * JSON, keyed by protocol version. - * @param defaultProtocolVersion the default protocol version. - */ - public RobotSerializer(NavigableMap<ProtocolVersion, Gson> gsons, - ProtocolVersion defaultProtocolVersion) { - if (!gsons.containsKey(defaultProtocolVersion)) { - throw new IllegalArgumentException( - "The serializer map does not contain a serializer for the default protocol version"); - } - this.gsons = gsons; - this.defaultProtocolVersion = defaultProtocolVersion; - this.jsonParser = new JsonParser(); - } - - /** - * Deserializes the given JSON string into an instance of the given type. - * - * @param <T> the generic type of the given class. - * @param jsonString the JSON string to deserialize. - * @param type the type to deserialize the JSON string into. - * @param protocolVersion the wire protocol version of the given JSON string. - * @return an instance of {@code type}, that is constructed by deserializing - * the given {@code jsonString} - */ - public <T> T deserialize(String jsonString, Type type, ProtocolVersion protocolVersion) { - return getGson(protocolVersion).<T>fromJson(jsonString, type); - } - - /** - * Serializes the given object into a JSON string. - * - * @param <T> the generic type of the given object. - * @param object the object to serialize. - * @return a JSON string representation of {@code object}. - */ - public <T> String serialize(T object) { - return serialize(object, defaultProtocolVersion); - } - - /** - * Serializes the given object into a JSON string. - * - * @param <T> the generic type of the given object. - * @param object the object to serialize. - * @param type the specific genericized type of {@code object}. - * @return a JSON string representation of {@code object}. - */ - public <T> String serialize(T object, Type type) { - return serialize(object, type, defaultProtocolVersion); - } - - /** - * Serializes the given object into a JSON string. - * - * @param <T> the generic type of the given object. - * @param object the object to serialize. - * @param protocolVersion the version of the serializer to use. - * @return a JSON string representation of {@code object}. - */ - public <T> String serialize(T object, ProtocolVersion protocolVersion) { - return getGson(protocolVersion).toJson(object); - } - - /** - * Serializes the given object into a JSON string. - * - * @param <T> the generic type of the given object. - * @param object the object to serialize. - * @param type the specific genericized type of {@code object}. - * @param protocolVersion the version of the serializer to use. - * @return a JSON string representation of {@code object}. - */ - public <T> String serialize(T object, Type type, ProtocolVersion protocolVersion) { - return getGson(protocolVersion).toJson(object, type); - } - - /** - * Parses the given JSON string into a {@link JsonElement}. - * - * @param jsonString the string to parse. - * @return a {@link JsonElement} representation of the input - * {@code jsonString}. - */ - public JsonElement parse(String jsonString) { - return jsonParser.parse(jsonString); - } - - /** - * Deserializes operations. This method supports only the new JSON-RPC style - * operations. - * - * @param jsonString the operations JSON string to deserialize. - * @return a list of {@link OperationRequest},that represents the operations. - * @throws InvalidRequestException if there is a problem deserializing the - * operations. - */ - public List<OperationRequest> deserializeOperations(String jsonString) - throws InvalidRequestException { - if (Util.isEmptyOrWhitespace(jsonString)) { - return Collections.emptyList(); - } - - // Parse incoming operations. - JsonArray requestsAsJsonArray = null; - - JsonElement json = null; - try { - json = jsonParser.parse(jsonString); - } catch (JsonParseException e) { - throw new InvalidRequestException("Couldn't deserialize incoming operations: " + - jsonString, null, e); - } - - if (json.isJsonArray()) { - requestsAsJsonArray = json.getAsJsonArray(); - } else { - requestsAsJsonArray = new JsonArray(); - requestsAsJsonArray.add(json); - } - - // Convert incoming operations into a list of JsonRpcRequest. - ProtocolVersion protocolVersion = determineProtocolVersion(requestsAsJsonArray); - PROTOCOL_VERSION_COUNTERS.get(protocolVersion).incrementAndGet(); - List<OperationRequest> requests = new ArrayList<OperationRequest>(requestsAsJsonArray.size()); - for (JsonElement requestAsJsonElement : requestsAsJsonArray) { - validate(requestAsJsonElement); - requests.add(getGson(protocolVersion).fromJson(requestAsJsonElement, - OperationRequest.class)); - } - return requests; - } - - /** - * Determines the protocol version of a given operation bundle JSON by - * inspecting the first operation in the bundle. If it is a - * {@code robot.notify} operation, and contains {@code protocolVersion} - * parameter, then this method will return the value of that parameter. - * Otherwise, this method will return the default version. - * - * @param operationBundle the operation bundle to check. - * @return the wire protocol version of the given operation bundle. - */ - private ProtocolVersion determineProtocolVersion(JsonArray operationBundle) { - if (operationBundle.size() == 0 || !operationBundle.get(0).isJsonObject()) { - return defaultProtocolVersion; - } - - JsonObject firstOperation = operationBundle.get(0).getAsJsonObject(); - if (!firstOperation.has(RequestProperty.METHOD.key())) { - return defaultProtocolVersion; - } - - String method = firstOperation.get(RequestProperty.METHOD.key()).getAsString(); - if (isRobotNotifyOperationMethod(method)) { - JsonObject params = firstOperation.get(RequestProperty.PARAMS.key()).getAsJsonObject(); - if (params.has(ParamsProperty.PROTOCOL_VERSION.key())) { - JsonElement protocolVersionElement = params.get(ParamsProperty.PROTOCOL_VERSION.key()); - if (!protocolVersionElement.isJsonNull()) { - return ProtocolVersion.fromVersionString(protocolVersionElement.getAsString()); - } - } - } - return defaultProtocolVersion; - } - - /** - * Determines the protocol version of a given operation bundle by inspecting - * the first operation in the bundle. If it is a {@code robot.notify} - * operation, and contains {@code protocolVersion} parameter, then this method - * will return the value of that parameter. Otherwise, this method will return - * the default version. - * - * @param operationBundle the operation bundle to check. - * @return the wire protocol version of the given operation bundle. - */ - private ProtocolVersion determineProtocolVersion(List<OperationRequest> operationBundle) { - if (operationBundle.size() == 0) { - return defaultProtocolVersion; - } - - OperationRequest firstOperation = operationBundle.get(0); - if (isRobotNotifyOperationMethod(firstOperation.getMethod())) { - String versionString = (String) firstOperation.getParameter(ParamsProperty.PROTOCOL_VERSION); - if (versionString != null) { - return ProtocolVersion.fromVersionString(versionString); - } - } - return defaultProtocolVersion; - } - - /** - * Serializes a list of {@link OperationRequest} objects into a JSON string. - * - * @param operations List of operations to serialize. - * @return A JSON string representing the serialized operations. - */ - public String serializeOperations(List<OperationRequest> operations) - throws JsonParseException { - ProtocolVersion protocolVersion = determineProtocolVersion(operations); - return getGson(protocolVersion).toJson(operations); - } - - /** - * Returns an instance of Gson for the given protocol version. - * - * @param protocolVersion the protocol version. - * @return an instance of {@link Gson}. - */ - private Gson getGson(ProtocolVersion protocolVersion) { - // Returns the last entry which protocol version is less than or equal to - // the given protocol version. - Entry<ProtocolVersion, Gson> entry = gsons.floorEntry(protocolVersion); - if (entry == null) { - LOG.severe("Could not find the proper Gson for protocol version " + protocolVersion); - return null; - } - return entry.getValue(); - } - - /** - * Validates that the incoming JSON is a JSON object that represents a - * JSON-RPC request. - * - * @param jsonElement the incoming JSON. - * @throws InvalidRequestException if the incoming JSON does not have the - * required properties. - */ - private static void validate(JsonElement jsonElement) throws InvalidRequestException { - if (!jsonElement.isJsonObject()) { - throw new InvalidRequestException("The incoming JSON is not a JSON object: " + jsonElement); - } - - JsonObject jsonObject = jsonElement.getAsJsonObject(); - - StringBuilder missingProperties = new StringBuilder(); - for (RequestProperty requestProperty : RequestProperty.values()) { - if (!jsonObject.has(requestProperty.key())) { - missingProperties.append(requestProperty.key()); - } - } - - if (missingProperties.length() > 0) { - throw new InvalidRequestException("Missing required properties " + missingProperties + - "operation: " + jsonObject); - } - } - - /** - * Checks whether the given operation method is of a robot notify operation. - * - * @param method the method to check. - * @return {@code true} if the given method is a robot notify operation's - * method. - */ - @SuppressWarnings("deprecation") - private static boolean isRobotNotifyOperationMethod(String method) { - return ROBOT_NOTIFY_CAPABILITIES_HASH.method().equals(method) || - ROBOT_NOTIFY.method().equals(method); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/SearchResult.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/SearchResult.java b/wave/src/main/java/com/google/wave/api/SearchResult.java deleted file mode 100644 index 2b38393..0000000 --- a/wave/src/main/java/com/google/wave/api/SearchResult.java +++ /dev/null @@ -1,127 +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 java.util.ArrayList; -import java.util.List; - -/** - * SearchResult is returned from a search request. - * - */ -public class SearchResult { - - /** - * Digest contains the digest information for one 'hit' in the result. - */ - public static class Digest { - private final String title; - private final String snippet; - private final String waveId; - private final long lastModified; - private final long created; - private final int unreadCount; - private final int blipCount; - private final List<String> participants; - - public Digest(String title, String snippet, String waveId, List<String> participants, - long lastModified, long created, int unreadCount, int blipCount) { - this.title = title; - this.snippet = snippet; - this.waveId = waveId; - this.participants = new ArrayList<String>(participants); - this.lastModified = lastModified; - this.created = created; - this.unreadCount = unreadCount; - this.blipCount = blipCount; - } - - public String getTitle() { - return title; - } - - public String getSnippet() { - return snippet; - } - - public String getWaveId() { - return waveId; - } - - public List<String> getParticipants() { - return participants; - } - - public long getLastModified() { - return lastModified; - } - - public long getCreated() { - return created; - } - - public int getUnreadCount() { - return unreadCount; - } - - public int getBlipCount() { - return blipCount; - } - } - - private final String query; - private int numResults; - private final List<Digest> digests = new ArrayList<Digest>(10); - - public SearchResult(String query) { - this.query = query; - this.numResults = 0; - } - - /** - * Add a result to the set - * @param digest to add - */ - public void addDigest(Digest digest) { - numResults += 1; - digests.add(digest); - } - - /** - * @returns the query associated with this result - */ - public String getQuery() { - return query; - } - - /** - * @returns the number of results - */ - public int getNumResults() { - return numResults; - } - - /** - * @returns the digests for the result - */ - public List<Digest> getDigests() { - return digests; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/Tags.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/Tags.java b/wave/src/main/java/com/google/wave/api/Tags.java deleted file mode 100644 index a9c92e4..0000000 --- a/wave/src/main/java/com/google/wave/api/Tags.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; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; - -/** - * A class that represents wavelet's tags. This class supports various - * tag related operations, such as, adding or removing tag from a wavelet. - */ -public class Tags implements Iterable<String>, Serializable { - - /** A set of string that represents wavelet tags. */ - private final Set<String> tags; - - /** The wavelet that this tag list represents. */ - private final Wavelet wavelet; - - /** The operation queue to queue operation to the robot proxy. */ - private final OperationQueue operationQueue; - - /** - * Constructor. - * - * @param tags a collection of initial tags of the wavelet. - * @param wavelet the wavelet that this tag list represents. - * @param operationQueue the operation queue to queue operation to the robot - * proxy. - */ - public Tags(Collection<String> tags, Wavelet wavelet, OperationQueue operationQueue) { - this.tags = new LinkedHashSet<String>(tags); - this.wavelet = wavelet; - this.operationQueue = operationQueue; - } - - /** - * Adds the given tag id if it doesn't exist. - * - * @param tag the tag that will be added. - * @return {@code true} if the given tag does not exist yet - * in the owning wavelet, which means that a new - * {@code wavelet.modifyTag()} has been queued. Otherwise, returns - * {@code false}. - */ - public boolean add(String tag) { - if (tags.contains(tag)) { - return false; - } - - operationQueue.modifyTagOfWavelet(wavelet, tag, "add"); - tags.add(tag); - return true; - } - - /** - * Removes the given tag id if it exists. - * - * @param tag the tag that will be removed. - * @return {@code true} if the given tag exists in the owning wavelet, which - * means that a new {@code wavelet.modifyTag()} has been queued. - * Otherwise, returns {@code false}. - */ - public boolean remove(String tag) { - if (!tags.contains(tag)) { - return false; - } - - operationQueue.modifyTagOfWavelet(wavelet, tag, "remove"); - tags.remove(tag); - return true; - } - - /** - * Checks whether the owning wavelet has the given tag or not. - * - * @param tag the name of the tag to check. - * @return {@code true} if the wavelet has the given tag. - * Otherwise, returns {@code false}. - */ - public boolean contains(String tag) { - return tags.contains(tag); - } - - /** - * Returns the number of tags in the owning wavelet. - * - * @return the number of tags. - */ - public int size() { - return tags.size(); - } - - /** - * Checks whether the owning wavelet has any tag or not. - * - * @return {@code true} if the owning wavelet has at least one tag. Otherwise, - * returns {@code false}. - */ - public boolean isEmpty() { - return tags.isEmpty(); - } - - @Override - public Iterator<String> iterator() { - return new TagsIterator(); - } - - /** - * An iterator for {@link Tags}. - */ - private class TagsIterator implements Iterator<String> { - - /** The iterator of the underlying tag store. */ - private final Iterator<String> storeIterator; - - /** The pointer to the current tag. */ - private String currentTag; - - /** A flag that denotes whether {@link #remove} has been called or not. */ - private boolean removeCalled; - - /** - * Constructor. - */ - private TagsIterator() { - this.storeIterator = tags.iterator(); - } - - @Override - public boolean hasNext() { - return storeIterator.hasNext(); - } - - @Override - public String next() { - removeCalled = false; - currentTag = storeIterator.next(); - return currentTag; - } - - @Override - public void remove() { - if (removeCalled) { - throw new IllegalStateException("remove() has been called after the last call to next()."); - } - - if (currentTag == null) { - throw new IllegalStateException("Please call next() first before calling remove()."); - } - - removeCalled = true; - operationQueue.modifyTagOfWavelet(wavelet, currentTag, "remove"); - storeIterator.remove(); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/Util.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/Util.java b/wave/src/main/java/com/google/wave/api/Util.java deleted file mode 100644 index 311af50..0000000 --- a/wave/src/main/java/com/google/wave/api/Util.java +++ /dev/null @@ -1,94 +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 org.apache.commons.codec.binary.Base64; - -import java.net.URLEncoder; -import java.util.regex.Pattern; - -import javax.annotation.Nullable; - -/** - * A class that contains various utility methods. - */ -public final class Util { - - /** - * A regular expression that defines reserved {@code proxy_for} id. - */ - private static final Pattern RESERVED_PROXY_FOR_CHARS_REGEX = - Pattern.compile("[\\s\u0000-\u001F@,:<>\u007F]"); - - /** - * Checks if the given string is a valid proxy id, by asserting whether the - * string contains reserved characters or not. This check is to ensure that - * when we concatenate the robot id and the proxy id, it doesn't result in an - * invalid participant id. - * - * The reserved characters are: - * <ul> - * <li>whitespaces</li> - * <li>non-printing characters: decimal 0 - 31 (hex 00 - 1F), and decimal - * 127 (hex 7F)</li> - * <li>{@code @}, {@code ,}, {@code :}, {@code <}, {@code >}</li> - * </ul> - * - * If you need to pass in an arbitrary string as the proxy id, please consider - * encoding the string with a Base64 encoder (for example, {@link Base64}) or - * a URL encoder (for example, {@link URLEncoder}). - * - * @param string the string to be checked. - * @return {@code true} if the string doesn't contain any reserved characters. - */ - public static boolean isValidProxyForId(String string) { - return !RESERVED_PROXY_FOR_CHARS_REGEX.matcher(string).find(); - } - - /** - * Checks if the given string is a valid proxy id. Please see - * {@link #isValidProxyForId(String)} for more details on the assertion. This - * method throws an {@link IllegalArgumentException} if the input string is - * not a valid proxy id. - * - * @param string the string to check. - * @throws IllegalArgumentException if the input string is not a valid proxy - * id. - */ - public static void checkIsValidProxyForId(String string) { - if (string != null && !isValidProxyForId(string)) { - throw new IllegalArgumentException("The input string \"" + string + "\" is not a valid " + - "proxy id. A valid proxy id may not contain whitespace characters, non-printing" + - "characters (decimal 0 - 31, and decimal 127), @, :, <, >, and comma."); - } - } - - /** - * Returns {@code true} if the given string is null, empty, or comprises only - * whitespace characters. - * - * @param string the string reference to check - * @return {@code true} if {@code string} is null, empty, or consists of - * whitespace characters only - */ - public static boolean isEmptyOrWhitespace(@Nullable String string) { - return string == null || string.matches("\\s*"); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/com/google/wave/api/WaveService.java ---------------------------------------------------------------------- diff --git a/wave/src/main/java/com/google/wave/api/WaveService.java b/wave/src/main/java/com/google/wave/api/WaveService.java deleted file mode 100644 index 4277fa2..0000000 --- a/wave/src/main/java/com/google/wave/api/WaveService.java +++ /dev/null @@ -1,1011 +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.gson.Gson; -import com.google.wave.api.JsonRpcConstant.ParamsProperty; -import com.google.wave.api.impl.RawAttachmentData; -import com.google.wave.api.impl.GsonFactory; -import com.google.wave.api.impl.RawDeltasListener; -import com.google.wave.api.impl.WaveletData; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.digest.DigestUtils; -import org.waveprotocol.wave.model.id.InvalidIdException; -import org.waveprotocol.wave.model.id.WaveId; -import org.waveprotocol.wave.model.id.WaveletId; -import org.waveprotocol.wave.media.model.AttachmentId; - -import net.oauth.OAuth; -import net.oauth.OAuthAccessor; -import net.oauth.OAuthConsumer; -import net.oauth.OAuthException; -import net.oauth.OAuthMessage; -import net.oauth.OAuthValidator; -import net.oauth.SimpleOAuthValidator; -import net.oauth.client.OAuthClient; -import net.oauth.http.HttpClient; -import net.oauth.http.HttpMessage; -import net.oauth.http.HttpResponseMessage; -import net.oauth.signature.OAuthSignatureMethod; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLEncoder; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.AbstractMap.SimpleEntry; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Utility class for using OAuth to talk to Wave service. - */ -public class WaveService { - - /** Infinite {@code urlfetch} fetch timeout. */ - public static final int FETCH_INFINITE_TIMEOUT = 0; - - /** Default {@code urlfetch} fetch timeout in ms. */ - public static final int FETCH_DEFAILT_TIMEOUT_IN_MS = 10 * 1000; - - /** - * Helper class to make outgoing OAuth HTTP requests. - */ - static class HttpFetcher implements HttpClient { - - private static final String HTTP_POST_METHOD = "POST"; - private static final String HTTP_PUT_METHOD = "PUT"; - - private int fetchTimeout = FETCH_DEFAILT_TIMEOUT_IN_MS; - - @Override - public HttpResponseMessage execute(HttpMessage request, Map<String, Object> stringObjectMap) - throws IOException { - String body = readInputStream(request.getBody()); - OutputStreamWriter out = null; - HttpURLConnection conn = null; - // Open the connection. - conn = (HttpURLConnection) request.url.openConnection(); - conn.setReadTimeout(fetchTimeout); - conn.setRequestMethod(request.method); - // Add the headers - if (request.headers != null) { - for (java.util.Map.Entry<String, String> header : request.headers) { - conn.setRequestProperty(header.getKey(), header.getValue()); - } - } - - boolean doOutput = - body != null && (HTTP_POST_METHOD.equalsIgnoreCase(request.method) - || HTTP_PUT_METHOD.equalsIgnoreCase(request.method)); - - if (doOutput) { - conn.setDoOutput(true); - } - - conn.connect(); - - if (doOutput) { - // Send the request body. - out = new OutputStreamWriter(conn.getOutputStream(), UTF_8); - try { - out.write(body); - out.flush(); - } finally { - out.close(); - } - } - - // Return the response stream. - return new HttpResponse( - request.method, request.url, conn.getResponseCode(), conn.getInputStream()); - } - - /** - * Reads the given {@link java.io.InputStream} into a {@link String} - * - * @param inputStream the {@link java.io.InputStream} to be read. - * @return a string content of the {@link java.io.InputStream}. - * @throws IOException if there is a problem reading the stream. - */ - static String readInputStream(InputStream inputStream) throws IOException { - if (inputStream == null) { - return null; - } - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); - StringBuilder result = new StringBuilder(); - String s; - while ((s = reader.readLine()) != null) { - result.append(s); - } - return result.toString(); - } - - /** - * Sets the fetch timeout to a specified timeout, in milliseconds. - * A timeout of zero is interpreted as an infinite timeout. - * - * @param fetchTimeout - */ - void setTimeout(int fetchTimeout) { - this.fetchTimeout = fetchTimeout; - } - } - - /** - * A simple implementation of {@link HttpResponseMessage} that gets the - * response from {@link HttpURLConnection#getInputStream()}. - */ - static class HttpResponse extends HttpResponseMessage { - - /** The HTTP response code. */ - private final int statusCode; - - /** The response stream. */ - private final InputStream responseStream; - - /** - * Constructor. - * - * @param method the HTTP method, for example, GET or POST. - * @param url the URL where the response comes from. - * @param statusCode the HTTP response code. - * @param responseStream the response stream. - */ - public HttpResponse(String method, URL url, int statusCode, InputStream responseStream) { - super(method, url); - this.statusCode = statusCode; - this.responseStream = responseStream; - } - - @Override - public int getStatusCode() { - return statusCode; - } - - @Override - public InputStream openBody() { - return responseStream; - } - } - - /** - * Helper class that contains various OAuth credentials. - */ - static class ConsumerData { - - /** Consumer key used to sign the operations in the active mode. */ - private final String consumerKey; - - /** Consumer secret used to sign the operations in the active mode. */ - private final String consumerSecret; - - /** The URL that handles the JSON-RPC request in the active mode. */ - private final String rpcServerUrl; - - /** Whether this session is user authenticated */ - private final boolean userAuthenticated; - - /** The OAuth Accessor contains authentication data used to make requests */ - private final OAuthAccessor accessor; - - /** - * Constructor. - * - * @param consumerKey the consumer key. - * @param consumerSecret the consumer secret - * @param rpcServerUrl the URL of the JSON-RPC request handler - */ - public ConsumerData(String consumerKey, String consumerSecret, String rpcServerUrl) { - String consumerKeyPrefix = ""; - // NOTE(ljvderijk): Present for backwards capability. - if (RPC_URL.equals(rpcServerUrl) || SANDBOX_RPC_URL.equals(rpcServerUrl)) { - consumerKeyPrefix = "google.com:"; - } - this.consumerKey = consumerKeyPrefix + consumerKey; - this.consumerSecret = consumerSecret; - this.rpcServerUrl = rpcServerUrl; - - userAuthenticated = false; - OAuthConsumer consumer = new OAuthConsumer(null, consumerKey, consumerSecret, null); - consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.HMAC_SHA1); - accessor = new OAuthAccessor(consumer); - } - - public ConsumerData(OAuthAccessor accessor, String rpcServerUrl) { - this.consumerKey = accessor.consumer.consumerKey; - this.consumerSecret = accessor.consumer.consumerSecret; - this.accessor = accessor; - this.rpcServerUrl = rpcServerUrl; - userAuthenticated = true; - } - - /** - * @return the consumer key used to sign the operations in the active mode. - */ - public String getConsumerKey() { - return consumerKey; - } - - /** - * @return the consumer secret used to sign the operations in the active mode. - */ - public String getConsumerSecret() { - return consumerSecret; - } - - /** - * @return the URL of the JSON-RPC request handler. - */ - public String getRpcServerUrl() { - return rpcServerUrl; - } - - public boolean isUserAuthenticated() { - return userAuthenticated; - } - - public OAuthAccessor getAccessor() { - return accessor; - } - - } - - /** The wire protocol version. */ - public static final ProtocolVersion PROTOCOL_VERSION = ProtocolVersion.DEFAULT; - - private static final String JSON_MIME_TYPE = "application/json; charset=utf-8"; - private static final String OAUTH_BODY_HASH = "oauth_body_hash"; - private static final String POST = "POST"; - private static final String SHA_1 = "SHA-1"; - private static final String UTF_8 = "UTF-8"; - - /** Wave RPC URLs. */ - public static final String RPC_URL = "https://www-opensocial.googleusercontent.com/api/rpc"; - public static final String SANDBOX_RPC_URL = - "https://www-opensocial-sandbox.googleusercontent.com/api/rpc"; - - private static final Logger LOG = Logger.getLogger(WaveService.class.getName()); - - /** Namespace to prefix all active api operation calls. */ - private static final String OPERATION_NAMESPACE = "wave"; - - /** Serializer to serialize events and operations in active mode. */ - private static final Gson SERIALIZER = new GsonFactory().create(OPERATION_NAMESPACE); - - /** OAuth request validator. */ - private static final OAuthValidator VALIDATOR = new SimpleOAuthValidator(); - - /** A map of RPC server URL to its consumer data object. */ - private final Map<String, ConsumerData> consumerDataMap = new HashMap<String, ConsumerData>(); - - /** A version number. */ - private final String version; - - /** A utility to make HTTP requests. */ - private final HttpFetcher httpFetcher; - - /** - * Constructor. - */ - public WaveService() { - this(new HttpFetcher(), null); - } - - /** - * Constructor. - * - * @param version the version number. - */ - public WaveService(String version) { - this(new HttpFetcher(), version); - } - - /** - * Constructor. - * - * @param httpFetcher the fetcher to make HTTP calls. - * @param version the version number. - */ - public WaveService(HttpFetcher httpFetcher, String version) { - this.httpFetcher = httpFetcher; - this.version = version; - } - - /** - * Sets the OAuth related properties, including the consumer key and secret - * that are used to sign the outgoing operations. - * - * <p> - * This version of the method is for 2-legged OAuth, where the robot is not - * acting on behalf of a user. - * - * <p> - * For the rpcServerUrl you can use: - * <ul> - * <li>https://www-opensocial.googleusercontent.com/api/rpc - for wave - * preview. - * <li> - * https://www-opensocial-sandbox.googleusercontent.com/api/rpc - for wave - * sandbox. - * </ul> - * - * @param consumerKey the consumer key. - * @param consumerSecret the consumer secret. - * @param rpcServerUrl the URL of the server that serves the JSON-RPC request. - */ - public void setupOAuth(String consumerKey, String consumerSecret, String rpcServerUrl) { - if (consumerKey == null || consumerSecret == null || rpcServerUrl == null) { - throw new IllegalArgumentException( - "Consumer Key, Consumer Secret and RPCServerURL " + "have to be non-null"); - } - consumerDataMap.put(rpcServerUrl, new ConsumerData(consumerKey, consumerSecret, rpcServerUrl)); - } - - /** - * Sets the OAuth related properties that are used to sign the outgoing - * operations for 3-legged OAuth. - * - * <p> - * Performing the OAuth dance is not part of this interface - once you've done - * the dance, pass the constructed accessor and rpc endpoint into this method. - * - * <p> - * Ensure that the endpoint URL you pass in matches exactly the URL used to - * request an access token (including https vs http). - * - * For the rpcServerUrl you can use: - * <ul> - * <li>https://www-opensocial.googleusercontent.com/api/rpc - for wave - * preview. - * <li> - * https://www-opensocial-sandbox.googleusercontent.com/api/rpc - for wave - * sandbox. - * </ul> - * - * @param accessor the {@code OAuthAccessor} with access token and secret - * @param rpcServerUrl the endpoint URL of the server that serves the JSON-RPC - * request. - */ - public void setupOAuth(OAuthAccessor accessor, String rpcServerUrl) { - if (accessor == null || rpcServerUrl == null) { - throw new IllegalArgumentException("Accessor and RPCServerURL have to be non-null"); - } - consumerDataMap.put(rpcServerUrl, new ConsumerData(accessor, rpcServerUrl)); - } - - /** - * Validates the incoming HTTP request. - * - * @param requestUrl the URL of the request. - * @param jsonBody the request body to be validated. - * @param rpcServerUrl the RPC server URL. - * - * @throws OAuthException if it can't validate the request. - */ - public void validateOAuthRequest( - String requestUrl, Map<String, String[]> requestParams, String jsonBody, String rpcServerUrl) - throws OAuthException { - ConsumerData consumerData = consumerDataMap.get(rpcServerUrl); - if (consumerData == null) { - throw new IllegalArgumentException( - "There is no consumer key and secret associated " + "with the given RPC URL " - + rpcServerUrl); - } - - List<OAuth.Parameter> params = new ArrayList<OAuth.Parameter>(); - for (Map.Entry<String, String[]> entry : requestParams.entrySet()) { - for (String value : entry.getValue()) { - params.add(new OAuth.Parameter(entry.getKey(), value)); - } - } - OAuthMessage message = new OAuthMessage(POST, requestUrl, params); - - // Compute and check the hash of the body. - try { - MessageDigest md = MessageDigest.getInstance(SHA_1); - byte[] hash = md.digest(jsonBody.getBytes(UTF_8)); - String encodedHash = new String(Base64.encodeBase64(hash, false), UTF_8); - if (!encodedHash.equals(message.getParameter(OAUTH_BODY_HASH))) { - throw new IllegalArgumentException( - "Body hash does not match. Expected: " + encodedHash + ", provided: " - + message.getParameter(OAUTH_BODY_HASH)); - } - - OAuthAccessor accessor = consumerData.getAccessor(); - if (LOG.isLoggable(Level.FINE)) { - LOG.fine("Signature base string: " + OAuthSignatureMethod.getBaseString(message)); - } - VALIDATOR.validateMessage(message, accessor); - } catch (NoSuchAlgorithmException e) { - throw new OAuthException("Error validating OAuth request", e); - } catch (URISyntaxException e) { - throw new OAuthException("Error validating OAuth request", e); - } catch (OAuthException e) { - throw new OAuthException("Error validating OAuth request", e); - } catch (IOException e) { - throw new OAuthException("Error validating OAuth request", e); - } - } - - /** - * Submits the pending operations associated with this {@link Wavelet}. - * - * @param wavelet the bundle that contains the operations to be submitted. - * @param rpcServerUrl the active gateway to send the operations to. - * @return a list of {@link JsonRpcResponse} that represents the responses - * from the server for all operations that were submitted. - * - * @throws IllegalStateException if this method is called prior to setting the - * proper consumer key, secret, and handler URL. - * @throws IOException if there is a problem submitting the operations. - */ - public List<JsonRpcResponse> submit(Wavelet wavelet, String rpcServerUrl) throws IOException { - List<JsonRpcResponse> responses = makeRpc(wavelet.getOperationQueue(), rpcServerUrl); - wavelet.getOperationQueue().clear(); - return responses; - } - - /** - * Returns an empty/blind stub of a wavelet with the given wave id and wavelet - * id. - * - * <p> - * Call this method if you would like to apply wavelet-only operations - * without fetching the wave first. - * - * The returned wavelet has its own {@link OperationQueue}. It is the - * responsibility of the caller to make sure this wavelet gets submitted to - * the server, either by calling {@link AbstractRobot#submit(Wavelet, String)} - * or by calling {@link Wavelet#submitWith(Wavelet)} on the new wavelet, to - * join its queue with another wavelet, for example, the event wavelet. - * - * @param waveId the id of the wave. - * @param waveletId the id of the wavelet. - * @return a stub of a wavelet. - */ - public Wavelet blindWavelet(WaveId waveId, WaveletId waveletId) { - return blindWavelet(waveId, waveletId, null); - } - - /** - * @see #blindWavelet(WaveId, WaveletId) - * - * @param proxyForId the proxying information that should be set on the - * operation queue. 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). - */ - public Wavelet blindWavelet(WaveId waveId, WaveletId waveletId, String proxyForId) { - return blindWavelet(waveId, waveletId, proxyForId, new HashMap<String, Blip>()); - } - - /** - * @see #blindWavelet(WaveId, WaveletId, String) - * - * @param blips a collection of blips that belong to this wavelet. - */ - public Wavelet blindWavelet( - WaveId waveId, WaveletId waveletId, String proxyForId, Map<String, Blip> blips) { - return blindWavelet(waveId, waveletId, proxyForId, blips, new HashMap<String, BlipThread>()); - } - - /** - * @see #blindWavelet(WaveId, WaveletId, String, Map) - * - * @param threads a collection of threads that belong to this wavelet. - */ - public Wavelet blindWavelet(WaveId waveId, WaveletId waveletId, String proxyForId, - Map<String, Blip> blips, Map<String, BlipThread> threads) { - Util.checkIsValidProxyForId(proxyForId); - Map<String, String> roles = new HashMap<String, String>(); - return new Wavelet(waveId, waveletId, null, - new BlipThread("", -1, new ArrayList<String>(), blips), Collections.<String>emptySet(), - roles, blips, threads, new OperationQueue(proxyForId)); - } - - /** - * Creates a new wave with a list of participants on it. - * - * The root wavelet of the new wave is returned with its own - * {@link OperationQueue}. It is the responsibility of the caller to make sure - * this wavelet gets submitted to the server, either by calling - * {@link AbstractRobot#submit(Wavelet, String)} or by calling - * {@link Wavelet#submitWith(Wavelet)} on the new wavelet. - * - * @param domain the domain to create the wavelet on. In general, this should - * correspond to the domain of the incoming event wavelet, except when - * the robot is calling this method outside of an event or when the - * server is handling multiple domains. - * @param participants the initial participants on the wave. The robot, as the - * creator of the wave, will be added by default. The order of the - * participants will be preserved. - */ - public Wavelet newWave(String domain, Set<String> participants) { - return newWave(domain, participants, null); - } - - /** - * @see #newWave(String, Set) - * - * @param proxyForId the proxy id that should be used to create the new wave. - * If specified, the creator of the wave would be - * robotid+<proxyForId>@appspot.com. 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). - */ - public Wavelet newWave(String domain, Set<String> participants, String proxyForId) { - return newWave(domain, participants, "", proxyForId); - } - - /** - * @see #newWave(String, Set, String) - * - * @param msg the message that will be passed back to the robot when - * WAVELET_CREATED event is fired as a result of this operation. - */ - public Wavelet newWave(String domain, Set<String> participants, String msg, String proxyForId) { - Util.checkIsValidProxyForId(proxyForId); - return new OperationQueue(proxyForId).createWavelet(domain, participants, msg); - } - - /** - * @see #newWave(String, Set, String, String) - * - * @param rpcServerUrl if specified, this operation will be submitted - * immediately to this active gateway, that will return immediately the - * actual wave id, the id of the root wavelet, and id of the root blip. - * - * @throws IOException if there is a problem submitting the operation to the - * server, when {@code submit} is {@code true}. - * @throws InvalidIdException - */ - public Wavelet newWave( - String domain, Set<String> participants, String msg, String proxyForId, String rpcServerUrl) - throws IOException, InvalidIdException { - Util.checkIsValidProxyForId(proxyForId); - OperationQueue opQueue = new OperationQueue(proxyForId); - Wavelet newWavelet = opQueue.createWavelet(domain, participants, msg); - - if (rpcServerUrl != null && !rpcServerUrl.isEmpty()) { - // Get the response for the robot.fetchWavelet() operation, which is the - // second operation, since makeRpc prepends the robot.notify() operation. - JsonRpcResponse response = this.submit(newWavelet, rpcServerUrl).get(1); - if (response.isError()) { - throw new IOException(response.getErrorMessage()); - } - WaveId waveId = ApiIdSerializer.instance().deserialiseWaveId( - (String) response.getData().get(ParamsProperty.WAVE_ID)); - WaveletId waveletId = ApiIdSerializer.instance().deserialiseWaveletId( - (String) response.getData().get(ParamsProperty.WAVELET_ID)); - String rootBlipId = (String) response.getData().get(ParamsProperty.BLIP_ID); - - Map<String, Blip> blips = new HashMap<String, Blip>(); - Map<String, BlipThread> threads = new HashMap<String, BlipThread>(); - Map<String, String> roles = new HashMap<String, String>(); - - List<String> blipIds = new ArrayList<String>(); - blipIds.add(rootBlipId); - BlipThread rootThread = new BlipThread("", -1, blipIds, blips); - - newWavelet = new Wavelet(waveId, waveletId, rootBlipId, rootThread, participants, - roles, blips, threads, opQueue); - blips.put(rootBlipId, new Blip(rootBlipId, "", null, "", newWavelet)); - } - return newWavelet; - } - - /** - * Requests SearchResult for a query. - * - * @param query the query to execute. - * @param index the index from which to return results. - * @param numresults the number of results to return. - * @param rpcServerUrl the active gateway. - * - * @throws IOException if remote server returns error. - */ - public SearchResult search(String query, Integer index, Integer numResults, String rpcServerUrl) - throws IOException { - OperationQueue opQueue = new OperationQueue(); - opQueue.search(query, index, numResults); - Map<ParamsProperty, Object> response = makeSingleOperationRpc(opQueue, rpcServerUrl); - return (SearchResult) response.get(ParamsProperty.SEARCH_RESULTS); - } - - /** - * Fetches a wavelet using the active API. - * - * The returned wavelet contains a snapshot of the state of the wavelet at - * that point. It can be used to modify the wavelet, but the wavelet might - * change in between, so treat carefully. - * - * Also, the returned wavelet has its own {@link OperationQueue}. It is the - * responsibility of the caller to make sure this wavelet gets submitted to - * the server, either by calling {@link AbstractRobot#submit(Wavelet, String)} - * or by calling {@link Wavelet#submitWith(Wavelet)} on the new wavelet. - * - * @param waveId the id of the wave to fetch. - * @param waveletId the id of the wavelet to fetch. - * @param rpcServerUrl the active gateway that is used to fetch the wavelet. - * - * @throws IOException if there is a problem fetching the wavelet. - */ - public Wavelet fetchWavelet(WaveId waveId, WaveletId waveletId, String rpcServerUrl) - throws IOException { - return fetchWavelet(waveId, waveletId, null, rpcServerUrl); - } - - /** - * @see #fetchWavelet(WaveId, WaveletId, String) - * - * @param proxyForId the proxy id that should be used to fetch this wavelet. - * 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). - */ - public Wavelet fetchWavelet( - WaveId waveId, WaveletId waveletId, String proxyForId, String rpcServerUrl) - throws IOException { - Util.checkIsValidProxyForId(proxyForId); - OperationQueue opQueue = new OperationQueue(proxyForId); - opQueue.fetchWavelet(waveId, waveletId); - - Map<ParamsProperty, Object> response = makeSingleOperationRpc(opQueue, rpcServerUrl); - - // Deserialize wavelet. - opQueue.clear(); - WaveletData waveletData = (WaveletData) response.get(ParamsProperty.WAVELET_DATA); - Map<String, Blip> blips = new HashMap<String, Blip>(); - Map<String, BlipThread> threads = new HashMap<String, BlipThread>(); - Wavelet wavelet = Wavelet.deserialize(opQueue, blips, threads, waveletData); - - // Deserialize threads. - @SuppressWarnings("unchecked") - Map<String, BlipThread> tempThreads = - (Map<String, BlipThread>) response.get(ParamsProperty.THREADS); - for (Map.Entry<String, BlipThread> entry : tempThreads.entrySet()) { - BlipThread thread = entry.getValue(); - threads.put(entry.getKey(), - new BlipThread(thread.getId(), thread.getLocation(), thread.getBlipIds(), blips)); - } - - // Deserialize blips. - @SuppressWarnings("unchecked") - Map<String, BlipData> blipDatas = - (Map<String, BlipData>) response.get(ParamsProperty.BLIPS); - for (Map.Entry<String, BlipData> entry : blipDatas.entrySet()) { - blips.put(entry.getKey(), Blip.deserialize(opQueue, wavelet, entry.getValue())); - } - - return wavelet; - } - - /** - * Retrieves wavelets ids of the specified wave. - * - * @param waveId the id of the wave. - * @param rpcServerUrl the URL of the JSON-RPC request handler. - * @return list of wavelets ids. - * @throws IOException if there is a problem fetching the wavelet. - */ - public List<WaveletId> retrieveWaveletIds(WaveId waveId, String rpcServerUrl) - throws IOException { - OperationQueue opQueue = new OperationQueue(); - opQueue.retrieveWaveletIds(waveId); - - Map<ParamsProperty, Object> response = makeSingleOperationRpc(opQueue, rpcServerUrl); - @SuppressWarnings("unchecked") - List<WaveletId> list = (List<WaveletId>)response.get(ParamsProperty.WAVELET_IDS); - return list; - } - - /** - * Exports wavelet deltas history. - * - * @param waveId the id of the wave to export. - * @param waveletId the id of the wavelet to export. - * @param rpcServerUrl the URL of the JSON-RPC request handler. - * @return WaveletSnapshot in Json. - * @throws IOException if there is a problem fetching the wavelet. - */ - public String exportRawSnapshot(WaveId waveId, WaveletId waveletId, String rpcServerUrl) throws IOException { - OperationQueue opQueue = new OperationQueue(); - opQueue.exportSnapshot(waveId, waveletId); - - Map<ParamsProperty, Object> response = makeSingleOperationRpc(opQueue, rpcServerUrl); - return (String)response.get(ParamsProperty.RAW_SNAPSHOT); - } - - /** - * Exports wavelet deltas history. - * - * @param waveId the id of the wave to export. - * @param waveletId the id of the wavelet to export. - * @param fromVersion start ProtocolHashedVersion. - * @param toVersion end ProtocolHashedVersion. - * @param rpcServerUrl the URL of the JSON-RPC request handler. - * @return history of deltas. - * @throws IOException if there is a problem fetching the deltas. - */ - public void exportRawDeltas(WaveId waveId, WaveletId waveletId, - byte[] fromVersion, byte[] toVersion, String rpcServerUrl, - RawDeltasListener listener) throws IOException { - OperationQueue opQueue = new OperationQueue(); - opQueue.exportRawDeltas(waveId, waveletId, fromVersion, toVersion); - - Map<ParamsProperty, Object> response = makeSingleOperationRpc(opQueue, rpcServerUrl); - @SuppressWarnings("unchecked") - List<byte[]> rawHistory = (List<byte[]>)response.get(ParamsProperty.RAW_DELTAS); - byte[] rawTargetVersion = (byte[])response.get(ParamsProperty.TARGET_VERSION); - listener.onSuccess(rawHistory, rawTargetVersion); - } - - /** - * Exports attachment. - * - * @param attachmentId the id of attachment. - * @param rpcServerUrl the URL of the JSON-RPC request handler. - * @return the data of attachment. - * @throws IOException if there is a problem fetching the wavelet. - */ - public RawAttachmentData exportAttachment(AttachmentId attachmentId, - String rpcServerUrl) throws IOException { - OperationQueue opQueue = new OperationQueue(); - opQueue.exportAttachment(attachmentId); - - Map<ParamsProperty, Object> response = makeSingleOperationRpc(opQueue, rpcServerUrl); - return (RawAttachmentData)response.get(ParamsProperty.ATTACHMENT_DATA); - } - - /** - * Imports deltas to wavelet. - * - * @param waveId the id of the wave to import. - * @param waveletId the id of the wavelet to import. - * @param history the history of deltas. - * @param rpcServerUrl the URL of the JSON-RPC request handler. - * @return the version from which importing started. - * @throws IOException if there is a problem fetching the wavelet. - */ - public long importRawDeltas(WaveId waveId, WaveletId waveletId, - List<byte[]> history, String rpcServerUrl) throws IOException { - OperationQueue opQueue = new OperationQueue(); - opQueue.importRawDeltas(waveId, waveletId, history); - - Map<ParamsProperty, Object> response = makeSingleOperationRpc(opQueue, rpcServerUrl); - return (Long)response.get(ParamsProperty.IMPORTED_FROM_VERSION); - } - - /** - * Imports attachment. - * - * @param waveId the id of the wave to import. - * @param waveletId the id of the wavelet to import. - * @param attachmentId the id of attachment. - * @param attachmentData the data of attachment. - * @param rpcServerUrl the URL of the JSON-RPC request handler. - * @throws IOException if there is a problem fetching the wavelet. - */ - public void importAttachment(WaveId waveId, WaveletId waveletId, AttachmentId attachmentId, - RawAttachmentData attachmentData, String rpcServerUrl) throws IOException { - OperationQueue opQueue = new OperationQueue(); - opQueue.importAttachment(waveId, waveletId, attachmentId, attachmentData); - - makeSingleOperationRpc(opQueue, rpcServerUrl); - } - - /** - * @return the map of consumer key and secret. - */ - protected Map<String, ConsumerData> getConsumerDataMap() { - return consumerDataMap; - } - - /** - * @return {@code true} if this service object contains a consumer key and - * secret for the given RPC server URL. - */ - protected boolean hasConsumerData(String rpcServerUrl) { - return consumerDataMap.containsKey(rpcServerUrl); - } - - /** - * Submits the given operation. - * - * @param opQueue the operation queue with operation to be submitted. - * @param rpcServerUrl the active gateway to send the operations to. - * @return the data of response. - * @throws IllegalStateException if this method is called prior to setting the - * proper consumer key, secret, and handler URL. - * @throws IOException if there is a problem submitting the operations, or error response. - */ - private Map<ParamsProperty, Object> makeSingleOperationRpc(OperationQueue opQueue, String rpcServerUrl) - throws IOException { - JsonRpcResponse response = makeRpc(opQueue, rpcServerUrl).get(0); - if (response.isError()) { - throw new IOException(response.getErrorMessage()); - } - return response.getData(); - } - - /** - * Submits the given operations. - * - * @param opQueue the operation queue to be submitted. - * @param rpcServerUrl the active gateway to send the operations to. - * @return a list of {@link JsonRpcResponse} that represents the responses - * from the server for all operations that were submitted. - * - * @throws IllegalStateException if this method is called prior to setting the - * proper consumer key, secret, and handler URL. - * @throws IOException if there is a problem submitting the operations. - */ - private List<JsonRpcResponse> makeRpc(OperationQueue opQueue, String rpcServerUrl) - throws IOException { - if (rpcServerUrl == null) { - throw new IllegalStateException("RPC Server URL is not set up."); - } - - ConsumerData consumerDataObj = consumerDataMap.get(rpcServerUrl); - if (consumerDataObj == null) { - throw new IllegalStateException("Consumer key, consumer secret, and JSON-RPC server URL " - + "have to be set first, by calling AbstractRobot.setupOAuth(), before invoking " - + "AbstractRobot.submit()."); - } - - opQueue.notifyRobotInformation(PROTOCOL_VERSION, version); - String json = - SERIALIZER.toJson(opQueue.getPendingOperations(), GsonFactory.OPERATION_REQUEST_LIST_TYPE); - - try { - InputStream bodyStream; - InputStream responseStream; - try { - bodyStream = new ByteArrayInputStream(json.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException(e); - } - if (!consumerDataObj.isUserAuthenticated()) { - String url = createOAuthUrlString( - json, consumerDataObj.getRpcServerUrl(), consumerDataObj.getAccessor()); - if (LOG.isLoggable(Level.FINE)) { - LOG.fine("JSON request to be sent: " + json); - } - HttpMessage request = new HttpMessage("POST", new URL(url), bodyStream); - request.headers.add( - new SimpleEntry<String, String>(HttpMessage.CONTENT_TYPE, JSON_MIME_TYPE)); - request.headers.add(new SimpleEntry<String, String>("oauth_version", "1.0")); - responseStream = - httpFetcher.execute(request, Collections.<String, Object>emptyMap()).getBody(); - } else { - OAuthAccessor accessor = consumerDataObj.getAccessor(); - OAuthMessage message = accessor.newRequestMessage("POST", rpcServerUrl, null, bodyStream); - message.getHeaders().add( - new SimpleEntry<String, String>(HttpMessage.CONTENT_TYPE, JSON_MIME_TYPE)); - message.getHeaders().add(new SimpleEntry<String, String>("oauth_version", "1.0")); - OAuthClient client = new OAuthClient(httpFetcher); - responseStream = client.invoke(message, net.oauth.ParameterStyle.BODY).getBodyAsStream(); - } - - String responseString = HttpFetcher.readInputStream(responseStream); - if (LOG.isLoggable(Level.FINE)) { - LOG.fine("Response returned: " + responseString); - } - - List<JsonRpcResponse> responses = null; - if (responseString.startsWith("[")) { - responses = SERIALIZER.fromJson(responseString, GsonFactory.JSON_RPC_RESPONSE_LIST_TYPE); - } else { - responses = new ArrayList<JsonRpcResponse>(1); - responses.add(SERIALIZER.fromJson(responseString, JsonRpcResponse.class)); - } - responses.remove(0); // removes response to the notify operation. - return responses; - } catch (OAuthException e) { - LOG.warning("OAuthException when constructing the OAuth parameters: " + e); - throw new IOException(e); - } catch (URISyntaxException e) { - LOG.warning("URISyntaxException when constructing the OAuth parameters: " + e); - throw new IOException(e); - } - } - - /** - * Creates a URL that contains the necessary OAuth query parameters for the - * given JSON string. - * - * The required OAuth parameters are: - * <ul> - * <li>oauth_body_hash</li> - * <li>oauth_consumer_key</li> - * <li>oauth_signature_method</li> - * <li>oauth_timestamp</li> - * <li>oauth_nonce</li> - * <li>oauth_version</li> - * <li>oauth_signature</li> - * </ul> - * - * @param jsonBody the JSON string to construct the URL from. - * @param rpcServerUrl the URL of the handler that services the JSON-RPC - * request. - * @param accessor the OAuth accessor used to create the signed string. - * @return a URL for the given JSON string, and the required OAuth parameters. - */ - public static String createOAuthUrlString( - String jsonBody, String rpcServerUrl, OAuthAccessor accessor) - throws IOException, URISyntaxException, OAuthException { - OAuthMessage message = - new OAuthMessage(POST, rpcServerUrl, Collections.<SimpleEntry<String, String>>emptyList()); - - // Compute the hash of the body. - byte[] rawBody = jsonBody.getBytes(UTF_8); - byte[] hash = DigestUtils.sha(rawBody); - byte[] encodedHash = Base64.encodeBase64(hash); - message.addParameter(OAUTH_BODY_HASH, new String(encodedHash, UTF_8)); - - // Add other parameters. - - message.addRequiredParameters(accessor); - if (LOG.isLoggable(Level.FINE)) { - LOG.fine("Signature base string: " + OAuthSignatureMethod.getBaseString(message)); - } - - // Construct the resulting URL. - StringBuilder sb = new StringBuilder(rpcServerUrl); - char connector = '?'; - for (Map.Entry<String, String> p : message.getParameters()) { - if (!p.getKey().equals(jsonBody)) { - sb.append(connector); - sb.append(URLEncoder.encode(p.getKey(), UTF_8)); - sb.append('='); - sb.append(URLEncoder.encode(p.getValue(), UTF_8)); - connector = '&'; - } - } - return sb.toString(); - } - - /** - * Sets the fetch timeout to a specified timeout, in milliseconds. - * A timeout of zero is interpreted as an infinite timeout. - * - * @param fetchTimeout - */ - public void setFetchFimeout(int fetchTimeout) { - httpFetcher.setTimeout(fetchTimeout); - } -}
