-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbackup.txt
More file actions
292 lines (273 loc) · 10.4 KB
/
backup.txt
File metadata and controls
292 lines (273 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
// Copyright 2011 Google Inc. All Rights Reserved.
package com.google.appengine.demos.search;
import com.google.appengine.api.search.Document;
import com.google.appengine.api.search.Field;
import com.google.appengine.api.search.Index;
import com.google.appengine.api.search.IndexSpec;
import com.google.appengine.api.search.OperationResult;
import com.google.appengine.api.search.Query;
import com.google.appengine.api.search.QueryOptions;
import com.google.appengine.api.search.Results;
import com.google.appengine.api.search.DeleteException;
import com.google.appengine.api.search.ScoredDocument;
import com.google.appengine.api.search.SearchServiceFactory;
import com.google.appengine.api.search.StatusCode;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A demo servlet showing basic text search capabilities. This servlet
* has a single index shared between all users. It illustrates how to
* add, search for and remove documents from the shared index.
*
*/
public class TextSearchServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String VOID_REMOVE =
"Remove failed due to a null doc ID";
private static final String VOID_ADD =
"Document not added due to empty content";
/**
* The index used by this application. Since we only have one index
* we create one instance only. We build an index with the default
* consistency, which is Consistency.PER_DOCUMENT. These types of
* indexes are most suitable for streams and feeds, and can cope with
* a high rate of updates.
*/
private static final Index INDEX = SearchServiceFactory.getSearchService()
.getIndex(IndexSpec.newBuilder().setName("shared_index"));
enum Action {
ADD, REMOVE, DEFAULT;
}
private static final Logger LOG = Logger.getLogger(
TextSearchServlet.class.getName());
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
User currentUser = setupUser(req);
String outcome = null;
switch (getAction(req)) {
case ADD:
outcome = add(req, currentUser);
break;
case REMOVE:
outcome = remove(req);
break;
// On DEFAULT we fall through and just execute search below.
}
String searchOutcome = search(req);
if (outcome == null) {
outcome = searchOutcome;
}
req.setAttribute("outcome", outcome);
req.getRequestDispatcher("display.jsp").forward(req, resp);
}
private User setupUser(HttpServletRequest req) {
UserService userService = UserServiceFactory.getUserService();
User currentUser = userService.getCurrentUser();
if (currentUser != null) {
req.setAttribute("authAction", "sign out");
req.setAttribute("authUrl",
userService.createLogoutURL(req.getRequestURI()));
} else {
currentUser = new User("nobody@example.com", "example.com");
req.setAttribute("authAction", "sign in");
req.setAttribute("authUrl",
userService.createLoginURL(req.getRequestURI()));
}
req.setAttribute("nickname", currentUser.getNickname());
return currentUser;
}
/**
* Indexes a document built from the current request on behalf of the
* specified user. Each document has three fields in it. The content
* field stores used entered text. The email, and domain are extracted
* from the current user.
*/
private String add(HttpServletRequest req, User currentUser) {
String content = req.getParameter("doc");
if (content == null || content.isEmpty()) {
LOG.warning(VOID_ADD);
return VOID_ADD;
}
String ratingStr = req.getParameter("rating");
int rating = 1;
if (ratingStr != null) {
rating = Integer.parseInt(ratingStr);
}
Document.Builder docBuilder = Document.newBuilder()
.addField(Field.newBuilder().setName("content").setText(content))
.addField(Field.newBuilder().setName("email")
.setText(currentUser.getEmail()))
.addField(Field.newBuilder().setName("domain")
.setText(currentUser.getAuthDomain()))
.addField(Field.newBuilder().setName("published").setDate(
new Date()))
.addField(Field.newBuilder().setName("rating")
.setNumber(rating));
String tagStr = req.getParameter("tags");
if (tagStr != null) {
StringTokenizer tokenizer = new StringTokenizer(tagStr, ",");
while (tokenizer.hasMoreTokens()) {
docBuilder.addField(Field.newBuilder().setName("tag")
.setAtom(tokenizer.nextToken()));
}
}
Document doc = docBuilder.build();
LOG.info("Adding document:\n" + doc.toString());
try {
INDEX.put(doc);
return "Document added";
} catch (RuntimeException e) {
LOG.log(Level.SEVERE, "Failed to add " + doc, e);
return "Document not added due to an error " + e.getMessage();
}
}
private String getOnlyField(Document doc, String fieldName, String defaultValue) {
if (doc.getFieldCount(fieldName) == 1) {
return doc.getOnlyField(fieldName).getText();
}
LOG.severe("Field " + fieldName + " present " + doc.getFieldCount(fieldName));
return defaultValue;
}
/**
* Searches the index for matching documents. If the query is not specified
* in the request, we search for any documents.
*/
private String search(HttpServletRequest req) {
String queryStr = req.getParameter("query");
if (queryStr == null) {
queryStr = "";
}
String limitStr = req.getParameter("limit");
int limit = 10;
if (limitStr != null) {
try {
limit = Integer.parseInt(limitStr);
} catch (NumberFormatException e) {
LOG.severe("Failed to parse " + limitStr);
}
}
List<Document> found = new ArrayList<Document>();
String outcome = null;
try {
// Rather than just using a query we build a search request.
// This allows us to specify other attributes, such as the
// number of documents to be returned by search.
Query query = Query.newBuilder()
.setOptions(QueryOptions.newBuilder()
.setLimit(limit).
// for deployed apps, uncomment the line below to demo snippeting.
// This will not work on the dev_appserver.
// setFieldsToSnippet("content").
build())
.build(queryStr);
LOG.info("Sending query " + query);
Results<ScoredDocument> results = INDEX.search(query);
for (ScoredDocument scoredDoc : results) {
User author = new User(
getOnlyField(scoredDoc, "email", "user"),
getOnlyField(scoredDoc, "domain", "example.com"));
// Rather than presenting the original document to the
// user, we build a derived one that holds author's nickname.
List<Field> expressions = scoredDoc.getExpressions();
String content = null;
if (expressions != null) {
for (Field field : expressions) {
if ("content".equals(field.getName())) {
content = field.getHTML();
break;
}
}
}
if (content == null) {
content = getOnlyField(scoredDoc, "content", "");
}
Document derived = Document.newBuilder()
.setId(scoredDoc.getId())
.addField(Field.newBuilder().setName("content").setText(content))
.addField(Field.newBuilder().setName("nickname").setText(
author.getNickname()))
.addField(Field.newBuilder().setName("published").setDate(
scoredDoc.getOnlyField("published").getDate()))
.build();
found.add(derived);
}
} catch (RuntimeException e) {
LOG.log(Level.SEVERE, "Search with query '" + queryStr + "' failed", e);
outcome = "Search failed due to an error: " + e.getMessage();
}
req.setAttribute("found", found);
return outcome;
}
/**
* Removes documents with IDs specified in the given request. In the demo
* application we do not perform any authorization checks, thus no user
* information is necessary.
*/
private String remove(HttpServletRequest req) {
String[] docIds = req.getParameterValues("docid");
if (docIds == null) {
LOG.warning(VOID_REMOVE);
return VOID_REMOVE;
}
List<String> docIdList = Arrays.asList(docIds);
try {
INDEX.delete(docIdList);
return "Documents " + docIdList + " removed";
} catch (DeleteException e) {
List<String> failedIds = findFailedIds(docIdList, e.getResults());
LOG.log(Level.SEVERE, "Failed to remove documents " + failedIds, e);
return "Remove failed for " + failedIds;
}
}
/**
* A convenience method that correlates document status to the document ID.
*/
private List<String> findFailedIds(List<String> docIdList,
List<OperationResult> results) {
List<String> failedIds = new ArrayList<String>();
Iterator<OperationResult> opIter = results.iterator();
Iterator<String> idIter = docIdList.iterator();
while (opIter.hasNext() && idIter.hasNext()) {
OperationResult result = opIter.next();
String docId = idIter.next();
if (!StatusCode.OK.equals(result.getCode())) {
failedIds.add(docId);
}
}
return failedIds;
}
/**
* Extracts the type of action stored in the request. We have only three
* types of actions: ADD, REMOVE and DEFAULT. The DEFAULT is included
* to indicate action other than ADD or REMOVE. We do not have a special
* acton for search, as we always execute search. This way we show documents
* that match terms entered in the search box, regardless of the operation.
*
* @param HTTP request received by the servlet
* @return the requested user action, as inferred from the request
*/
private Action getAction(HttpServletRequest req) {
if (req.getParameter("index") != null) {
return Action.ADD;
}
if (req.getParameter("delete") != null) {
return Action.REMOVE;
}
return Action.DEFAULT;
}
}