Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / prospectivesearch / ProspectiveSearchServiceImpl.java
blob43196e328cab9c395249e33639f8f0069e09ddd4
1 // Copyright 2011 Google Inc. All Rights Reserved.
3 package com.google.appengine.api.prospectivesearch;
5 import com.google.appengine.api.datastore.Entity;
6 import com.google.appengine.api.datastore.EntityTranslator;
7 import com.google.appengine.api.prospectivesearch.ProspectiveSearchPb.*;
8 import com.google.apphosting.api.ApiProxy;
9 import com.google.common.base.CharMatcher;
10 import com.google.common.io.BaseEncoding;
11 import com.google.io.protocol.ProtocolMessage;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.logging.Level;
17 import java.util.logging.Logger;
19 import javax.servlet.http.HttpServletRequest;
21 /**
22 * The ProspectiveSearchServiceImpl class is a proxy to a remote
23 * Prospective Search service. Calls are dispatched via AppEngine's
24 * ApiProxy system. All responses are checked for validity or a
25 * RuntimeException is thrown.
28 class ProspectiveSearchServiceImpl implements ProspectiveSearchService {
30 static final String PACKAGE = "matcher";
32 static final Logger logger = Logger.getLogger(ProspectiveSearchServiceImpl.class.getName());
34 @Override
35 public void subscribe(String topic,
36 String subId,
37 long leaseDurationSeconds,
38 String query,
39 Map<String, FieldType> schema)
40 throws QuerySyntaxException {
41 SubscribeRequest req = new SubscribeRequest();
42 req.setTopic(topic);
43 req.setSubId(subId);
44 if (leaseDurationSeconds < 0) {
45 throw new IllegalArgumentException("Lease duration must be non-negative: "
46 + leaseDurationSeconds);
48 req.setLeaseDurationSec(leaseDurationSeconds);
49 req.setVanillaQuery(query);
51 for (Map.Entry<String, FieldType> entries : schema.entrySet()) {
52 SchemaEntry entry = new SchemaEntry();
53 entry.setName(entries.getKey());
54 entry.setType(entries.getValue().internalType);
55 req.addSchemaEntry(entry);
58 try {
59 doCall("Subscribe", req, new SubscribeResponse());
60 } catch (ApiProxy.ApplicationException e) {
61 switch (ErrorPb.Error.ErrorCode.valueOf(e.getApplicationError())) {
62 case BAD_REQUEST:
63 throw new QuerySyntaxException(subId, topic, query, e.getErrorDetail());
64 default:
65 throw e;
70 @Override
71 public void unsubscribe(String topic, String subId) {
72 UnsubscribeRequest req = new UnsubscribeRequest();
73 req.setTopic(topic);
74 req.setSubId(subId);
76 try {
77 doCall("Unsubscribe", req, new UnsubscribeResponse());
78 } catch (ApiProxy.ApplicationException e) {
79 switch (ErrorPb.Error.ErrorCode.valueOf(e.getApplicationError())) {
80 case BAD_REQUEST:
81 throw new IllegalArgumentException(e.getErrorDetail());
82 default:
83 throw e;
88 @Override
89 public void match(Entity entity, String topic) {
90 match(entity, topic, "");
93 @Override
94 public void match(Entity entity, String topic, String resultKey) {
95 match(entity, topic, resultKey,
96 DEFAULT_RESULT_RELATIVE_URL,
97 DEFAULT_RESULT_TASK_QUEUE_NAME,
98 DEFAULT_RESULT_BATCH_SIZE,
99 true);
102 @Override
103 public void match(Entity entity,
104 String topic,
105 String resultKey,
106 String relativeUrl,
107 String taskQueueName,
108 int batchSize,
109 boolean resultReturnDocument) {
110 MatchRequest req = new MatchRequest();
111 req.setDocument(EntityTranslator.convertToPb(entity));
112 req.setTopic(topic);
113 req.setResultKey(resultKey);
114 req.setResultRelativeUrl(relativeUrl);
115 req.setResultTaskQueue(taskQueueName);
116 req.setResultBatchSize(batchSize);
117 if (resultReturnDocument) {
118 req.setResultPythonDocumentClass(MatchRequest.PythonDocumentClass.ENTITY);
121 doCall("Match", req, new MatchResponse());
124 @Override
125 public List<Subscription> listSubscriptions(String topic) {
126 return listSubscriptions(topic, "",
127 DEFAULT_LIST_SUBSCRIPTIONS_MAX_RESULTS,
131 @Override
132 public List<Subscription> listSubscriptions(String topic,
133 String subIdStart,
134 int maxResults,
135 long expiresBefore) {
136 ListSubscriptionsRequest req = new ListSubscriptionsRequest();
137 req.setTopic(topic);
138 req.setSubscriptionIdStart(subIdStart);
139 req.setMaxResults(maxResults);
140 if (expiresBefore > 0) {
141 req.setExpiresBefore(expiresBefore);
143 ListSubscriptionsResponse rsp = new ListSubscriptionsResponse();
145 doCall("ListSubscriptions", req, rsp);
146 return convertSubscriptionList(rsp.subscriptions());
149 @Override
150 public Subscription getSubscription(String topic, String subId) {
151 List<Subscription> subs = listSubscriptions(topic, subId, 1, 0);
152 if (!subs.isEmpty()) {
153 Subscription sub = subs.get(0);
154 if (sub.getId().equals(subId)) {
155 return sub;
158 throw new IllegalArgumentException(String.format("No such subscription topic: %s, id: %s",
159 topic, subId));
162 @Override
163 public List<String> listTopics(String topicStart, long maxResults) {
164 ListTopicsRequest req = new ListTopicsRequest();
165 if (!topicStart.equals("")) {
166 req.setTopicStart(topicStart);
168 req.setMaxResults(maxResults);
169 ListTopicsResponse rsp = new ListTopicsResponse();
170 doCall("ListTopics", req, rsp);
171 return rsp.topics();
174 @Override
175 public Entity getDocument(HttpServletRequest matchCallbackPost) {
176 try {
177 String docStr = matchCallbackPost.getParameter("document");
178 byte[] docBuf = BaseEncoding.base64Url().decode(CharMatcher.WHITESPACE.removeFrom(docStr));
179 return EntityTranslator.createFromPbBytes(docBuf);
180 } catch (IllegalArgumentException e) {
181 logger.log(Level.SEVERE, "Could not decode returned matching message.", e);
182 return null;
186 static void doCall(String name, ProtocolMessage<?> request, ProtocolMessage<?> response) {
187 byte[] serializedResponse = ApiProxy.makeSyncCall(PACKAGE, name, request.toByteArray());
188 if (!response.mergeFrom(serializedResponse)) {
189 throw new ApiProxy.ArgumentException(PACKAGE, name);
194 * Converts List<SubscriptionRecord> to List<Subscription>.
196 static List<Subscription> convertSubscriptionList(List<SubscriptionRecord> from) {
197 List<Subscription> to = new ArrayList<Subscription>();
198 for (SubscriptionRecord internal : from) {
199 to.add(new Subscription(internal));
201 return to;