Skip to content

Commit

Permalink
Add Query Cursor Datastore sample.
Browse files Browse the repository at this point in the history
  • Loading branch information
tswast committed Apr 27, 2016
1 parent d20f66f commit 902723a
Show file tree
Hide file tree
Showing 5 changed files with 499 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed 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.example.appengine;

// [START cursors]
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.datastore.QueryResultList;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ListPeopleServlet extends HttpServlet {
static final int PAGE_SIZE = 15;
private final DatastoreService datastore;

public ListPeopleServlet() {
datastore = DatastoreServiceFactory.getDatastoreService();
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
FetchOptions fetchOptions = FetchOptions.Builder.withLimit(PAGE_SIZE);

// If this servlet is passed a cursor parameter, let's use it.
String startCursor = req.getParameter("cursor");
if (startCursor != null) {
fetchOptions.startCursor(Cursor.fromWebSafeString(startCursor));
}

Query q = new Query("Person").addSort("name", SortDirection.ASCENDING);
PreparedQuery pq = datastore.prepare(q);

QueryResultList<Entity> results;
try {
results = pq.asQueryResultList(fetchOptions);
} catch (IllegalArgumentException e) {
// IllegalArgumentException happens when an invalid cursor is used.
// A user could have manually entered a bad cursor in the URL or there
// may have been an internal implementation detail change in App Engine.
// Redirect to the page without the cursor parameter to show something
// rather than an error.
resp.sendRedirect("/people");
return;
}

resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
PrintWriter w = resp.getWriter();
w.println("<!DOCTYPE html>");
w.println("<meta charset=\"utf-8\">");
w.println("<title>Cloud Datastore Cursor Sample</title>");
w.println("<ul>");
for (Entity entity : results) {
w.println("<li>" + entity.getProperty("name") + "</li>");
}
w.println("</ul>");

String cursorString = results.getCursor().toWebSafeString();

// This servlet lives at '/people'.
w.println("<a href='/people?cursor=" + cursorString + "'>Next page</a>");
}
}
// [END cursors]
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed 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.example.appengine;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.common.collect.ImmutableList;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* A startup handler to populate the datastore with example entities.
*/
public class StartupServlet extends HttpServlet {
static final String IS_POPULATED_ENTITY = "IsPopulated";
static final String IS_POPULATED_KEY_NAME = "is-populated";

private static final String PERSON_ENTITY = "Person";
private static final String NAME_PROPERTY = "name";
private static final ImmutableList<String> US_PRESIDENTS =
ImmutableList.<String>builder()
.add("George Washington")
.add("John Adams")
.add("Thomas Jefferson")
.add("James Madison")
.add("James Monroe")
.add("John Quincy Adams")
.add("Andrew Jackson")
.add("Martin Van Buren")
.add("William Henry Harrison")
.add("John Tyler")
.add("James K. Polk")
.add("Zachary Taylor")
.add("Millard Fillmore")
.add("Franklin Pierce")
.add("James Buchanan")
.add("Abraham Lincoln")
.add("Andrew Johnson")
.add("Ulysses S. Grant")
.add("Rutherford B. Hayes")
.add("James A. Garfield")
.add("Chester A. Arthur")
.add("Grover Cleveland")
.add("Benjamin Harrison")
.add("Grover Cleveland")
.add("William McKinley")
.add("Theodore Roosevelt")
.add("William Howard Taft")
.add("Woodrow Wilson")
.add("Warren G. Harding")
.add("Calvin Coolidge")
.add("Herbert Hoover")
.add("Franklin D. Roosevelt")
.add("Harry S. Truman")
.add("Dwight D. Eisenhower")
.add("John F. Kennedy")
.add("Lyndon B. Johnson")
.add("Richard Nixon")
.add("Gerald Ford")
.add("Jimmy Carter")
.add("Ronald Reagan")
.add("George H. W. Bush")
.add("Bill Clinton")
.add("George W. Bush")
.add("Barack Obama")
.build();

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain");
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Key isPopulatedKey = KeyFactory.createKey(IS_POPULATED_ENTITY, IS_POPULATED_KEY_NAME);
boolean isAlreadyPopulated;
try {
datastore.get(isPopulatedKey);
isAlreadyPopulated = true;
} catch (EntityNotFoundException expected) {
isAlreadyPopulated = false;
}
if (isAlreadyPopulated) {
resp.getWriter().println("ok");
return;
}

ImmutableList.Builder<Entity> people = ImmutableList.builder();
for (String name : US_PRESIDENTS) {
Entity person = new Entity(PERSON_ENTITY);
person.setProperty(NAME_PROPERTY, name);
people.add(person);
}
datastore.put(people.build());
datastore.put(new Entity(isPopulatedKey));
resp.getWriter().println("ok");
}
}
20 changes: 19 additions & 1 deletion appengine/datastore/src/main/webapp/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</servlet>
<servlet-mapping>
<servlet-name>guestbook-strong</servlet-name>
<url-pattern>/guestbook-strong</url-pattern>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>guestbook</servlet-name>
Expand All @@ -34,6 +34,14 @@
<servlet-name>guestbook</servlet-name>
<url-pattern>/guestbook</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>people</servlet-name>
<servlet-class>com.example.appengine.ListPeopleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>people</servlet-name>
<url-pattern>/people</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>projection</servlet-name>
<servlet-class>com.example.appengine.ProjectionServlet</servlet-class>
Expand All @@ -43,6 +51,16 @@
<url-pattern>/projection</url-pattern>
</servlet-mapping>

<!-- Special handler to populate Datastore with default values. -->
<servlet>
<servlet-name>startup</servlet-name>
<servlet-class>com.example.appengine.StartupServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>startup</servlet-name>
<url-pattern>/_ah/start</url-pattern>
</servlet-mapping>

<security-constraint>
<web-resource-collection>
<web-resource-name>profile</web-resource-name>
Expand Down
Loading

0 comments on commit 902723a

Please sign in to comment.