Revision: 8178
Author: gwt.mirror...@gmail.com
Date: Tue May 18 14:43:14 2010
Log: Added an AppCacheWarmer that warms the AppEngine cache so that
subsequent requests do not suffer from a cold startup.
Review by: rj...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=8178
Added:
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/server/AppCacheWarmer.java
Modified:
/branches/2.1/bikeshed/war/WEB-INF/appengine-web.xml
=======================================
--- /dev/null
+++
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/server/AppCacheWarmer.java
Tue May 18 14:43:14 2010
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * 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.google.gwt.sample.expenses.server;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Warm an App-Engine App.
+ */
+public class AppCacheWarmer {
+
+ static class CountEmployees extends RequestObject {
+ CountEmployees() {
+ super("COUNT_EMPLOYEES", new String[0]);
+ }
+ }
+
+ static class CountEmployeesByDepartment extends RequestObject {
+ CountEmployeesByDepartment(String department) {
+ super("COUNT_EMPLOYEES_BY_DEPARTMENT", new String[] {department});
+ }
+ }
+
+ static class CountReports extends RequestObject {
+ CountReports() {
+ super("COUNT_REPORTS", new String[0]);
+ }
+ }
+
+ static class CountReportsBySearch extends RequestObject {
+ CountReportsBySearch(long reporterKey, String department, String
startsWith) {
+ super("COUNT_REPORTS_BY_SEARCH", new String[] {
+ reporterKey + "", department, startsWith});
+ }
+ }
+
+ static class FindAllEmployees extends RequestObject {
+ FindAllEmployees() {
+ super("FIND_ALL_EMPLOYEES", new String[0]);
+ }
+ }
+
+ static class FindAllExpenses extends RequestObject {
+ FindAllExpenses() {
+ super("FIND_ALL_EXPENSES", new String[0]);
+ }
+ }
+
+ static class FindAllReports extends RequestObject {
+ FindAllReports() {
+ super("FIND_ALL_REPORTS", new String[0]);
+ }
+ }
+
+ static class FindEmployeeEntries extends RequestObject {
+ FindEmployeeEntries(int firstResult, int maxResults) {
+ super("FIND_EMPLOYEE_ENTRIES", new String[] {
+ "" + firstResult, "" + maxResults});
+ }
+ }
+
+ static class FindEmployeeEntriesByDepartment extends RequestObject {
+ FindEmployeeEntriesByDepartment(String department, int firstResult,
+ int maxResults) {
+ super("FIND_EMPLOYEE_ENTRIES_BY_DEPARTMENT", new String[] {
+ department, "" + firstResult, "" + maxResults});
+ }
+ }
+
+ static class FindExpense extends RequestObject {
+ FindExpense(String id) {
+ super("FIND_EXPENSE", new String[] {id});
+ }
+ }
+
+ static class FindExpensesByReport extends RequestObject {
+ FindExpensesByReport(String reportId) {
+ super("FIND_EXPENSES_BY_REPORT", new String[] {reportId});
+ }
+ }
+
+ static class FindReport extends RequestObject {
+ FindReport(String id) {
+ super("FIND_REPORT", new String[] {id});
+ }
+ }
+
+ static class FindReportEntries extends RequestObject {
+ FindReportEntries(int firstResult, int maxResults) {
+ super("FIND_REPORT_ENTRIES", new String[] {
+ "" + firstResult, "" + maxResults});
+ }
+ }
+
+ static class FindReportEntriesBySearch extends RequestObject {
+ FindReportEntriesBySearch(Long employeeId, String department,
+ String startsWith, String orderBy, int firstResult, int
maxResults) {
+ super("FIND_REPORT_ENTRIES_BY_SEARCH", new String[] {
+ "" + employeeId, department, startsWith, orderBy, "" +
firstResult,
+ "" + maxResults});
+ }
+ }
+
+ static class FindReportsByEmployee extends RequestObject {
+ FindReportsByEmployee(Long id) {
+ super("FIND_REPORTS_BY_EMPLOYEE", new String[] {"" + id});
+ }
+ }
+
+ /*
+ * Each subclass of the RequestObject represents a type of post request.
+ */
+ static class RequestObject {
+ static int fetchedRequests = 0;
+ final String operation;
+ final String parameters[];
+
+ RequestObject(String operation, String parameters[]) {
+ this.operation = operation;
+ this.parameters = parameters;
+ }
+
+ public String toString() {
+ String returnStr = "[" + operation;
+ returnStr += "{";
+ for (String parameter : parameters) {
+ returnStr = returnStr + parameter + ",";
+ }
+ return returnStr + "}" + "]";
+ }
+
+ String getResponseString(String urlString) throws JSONException,
+ IOException {
+ fetchedRequests++;
+ System.out.println("fetching " + this);
+ URL url = new URL(urlString);
+ HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("operation", operation);
+ int count = 0;
+ for (String param : parameters) {
+ jsonObject.put("param" + count, param);
+ count++;
+ }
+ } catch (JSONException ex) {
+ System.err.println("AppCacheWarmer ERROR: caught a JSON exception
trying to construct a "
+ + this + " request, quitting");
+ throw ex;
+ }
+ OutputStreamWriter writer = new OutputStreamWriter(
+ connection.getOutputStream());
+ writer.write(jsonObject.toString());
+ writer.close();
+
+ if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
+ // read the response
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ connection.getInputStream()));
+ String responseString = "";
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ responseString = responseString + line;
+ }
+ reader.close();
+ try {
+ Thread.currentThread().sleep(SLEEP_INTERVAL);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
+ return responseString;
+ }
+ throw new IOException("AppCacheWarmer ERROR: returned "
+ + connection.getResponseCode() + " from " + this + " request");
+ }
+ }
+
+ static final boolean GET_REPORTS_FOR_SORTED_LISTS = false; //
CONFIGURABLEì
+
+ static final long SLEEP_INTERVAL = 0L;
+
+ static final String BASE_URL = "http://gwt-bikeshed.appspot.com";
+
+ static final String POST_URL = BASE_URL + "/gwtRequest";
+
+ public static void exhaustiveRun() throws IOException, JSONException {
+
+ readStaticResources(BASE_URL);
+
+ String departments[] = new String[] {
+ "Engineering", "Finance", "Marketing", "Operations", "Sales"};
+ List<RequestObject> queuedRequestObjects = new
ArrayList<RequestObject>();
+
+ // get "ALL"
+ queuedRequestObjects.add(new CountReportsBySearch(-1, "", ""));
+ for (String department : departments) {
+ // click on the department
+ for (int lastIndex : new int[] {25, 50, 75}) { // CONFIGURABLE
+ RequestObject employeeEntries = new
FindEmployeeEntriesByDepartment(
+ department, 0, lastIndex);
+ JSONArray employees = new JSONArray(
+ employeeEntries.getResponseString(POST_URL));
+ for (int i = 0; i < employees.length(); i++) {
+ // click on the employee -- get Reports for each employee..
+ JSONObject employee = (JSONObject) employees.get(i);
+ RequestObject reportsForAnEmployee = new
FindReportEntriesBySearch(
+ Long.parseLong(employee.getString("id")), "", "", "created
DESC",
+ 0, 20);
+ JSONArray expenses = new JSONArray(
+ reportsForAnEmployee.getResponseString(POST_URL));
+ if (GET_REPORTS_FOR_SORTED_LISTS) {
+ for (int j = 0; j < expenses.length(); j++) {
+ // click on the report -- get expenses for report
+ JSONObject expense = (JSONObject) expenses.get(j);
+ RequestObject expensesForReport = new FindExpensesByReport(
+ expense.getString("id"));
+ expensesForReport.getResponseString(POST_URL);
+ }
+ }
+ }
+ }
+ queuedRequestObjects.add(new CountEmployeesByDepartment(department));
+ queuedRequestObjects.add(new CountReportsBySearch(-1,
department, ""));
+ }
+
+ String searchText = "";
+ // count_reports_by_search
+ for (String field : new String[] {
+ "purpose", "notes", "department", "created"}) {
+ for (String sortOrder : new String[] {"asc", "desc"}) {
+ // first 2 pages
+ for (int startIndex : new int[] {0, 20}) { // CONFIGURABLE
+ RequestObject reportsBySearch = new
FindReportEntriesBySearch(-1L,
+ "", searchText, field + " " + sortOrder.toUpperCase(),
+ startIndex, 20);
+ JSONArray expenses = new JSONArray(
+ reportsBySearch.getResponseString(POST_URL));
+ if (GET_REPORTS_FOR_SORTED_LISTS) {
+ for (int j = 0; j < expenses.length(); j++) {
+ // click on the report -- get expenses for report
+ JSONObject expense = (JSONObject) expenses.get(j);
+ RequestObject expensesForReport = new FindExpensesByReport(
+ expense.getString("id"));
+ expensesForReport.getResponseString(POST_URL);
+ }
+ }
+ }
+ }
+ }
+
+ for (RequestObject requestObject : queuedRequestObjects) {
+ requestObject.getResponseString(POST_URL);
+ }
+ }
+
+ public static void main(String args[]) {
+ long startTime = System.currentTimeMillis();
+
+ try {
+ testRun();
+ // exhaustiveRun();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.err.println("Exception message: " + ex.getMessage());
+ }
+ System.out.println("AppCacheWarmer: ran at " + new Date() + " for "
+ + (System.currentTimeMillis() - startTime) + "ms, #Requests
fetched: "
+ + RequestObject.fetchedRequests);
+ }
+
+ public static void testRun() throws IOException, JSONException {
+ // get "ALL"
+ RequestObject allReportsCount = new CountReportsBySearch(-1, "", "");
+ allReportsCount.getResponseString(POST_URL);
+ RequestObject allReports = new FindReportEntriesBySearch(-1L, "", "",
+ "created DESC", 0, 20);
+ allReports.getResponseString(POST_URL);
+
+ String engineerList = null;
+ // Expand the Engineering and Finance departments
+ for (String department : new String[] {"Engineering", "Finance"}) {
+ RequestObject countEmployeeEntries = new CountEmployeesByDepartment(
+ department);
+ countEmployeeEntries.getResponseString(POST_URL);
+ for (int lastIndex : new int[] {25}) {
+ RequestObject employeeEntries = new
FindEmployeeEntriesByDepartment(
+ department, 0, lastIndex);
+ String tempList = employeeEntries.getResponseString(POST_URL);
+ if (department.equals("Engineering")) {
+ engineerList = tempList;
+ }
+ }
+ }
+
+ assert engineerList != null;
+ JSONArray engineers = new JSONArray(engineerList);
+ JSONObject firstEngineer = (JSONObject) engineers.get(0);
+ RequestObject countReportsForAnEmployee = new CountReportsBySearch(
+ Long.parseLong(firstEngineer.getString("id")), "", "");
+ countReportsForAnEmployee.getResponseString(POST_URL);
+
+ RequestObject reportsForAnEmployee = new FindReportEntriesBySearch(
+ Long.parseLong(firstEngineer.getString("id")), "", "", "created
DESC",
+ 0, 20);
+ JSONArray expenses = new JSONArray(
+ reportsForAnEmployee.getResponseString(POST_URL));
+ // open first 5 reports
+ int range = Math.min(5, expenses.length());
+ for (int j = 0; j < range; j++) {
+ // click on the report -- get expenses for report
+ JSONObject expense = (JSONObject) expenses.get(j);
+ RequestObject expensesForReport = new FindExpensesByReport(
+ expense.getString("id"));
+ expensesForReport.getResponseString(POST_URL);
+ }
+
+ // get count for "ALL", get "ALL", page next, page next
+ allReportsCount = new CountReportsBySearch(-1, "", "");
+ allReportsCount.getResponseString(POST_URL);
+ for (int startIndex : new int[] {0, 20, 40}) {
+ allReports = new FindReportEntriesBySearch(-1L, "", "",
+ "created DESC", startIndex, 20);
+ allReports.getResponseString(POST_URL);
+ }
+
+ // select "ALL" i.e. "created DESC", sort by "purpose DESC", sort by
+ // "created ASC", sort by "created DESC"
+ allReportsCount = new CountReportsBySearch(-1, "", "");
+ allReportsCount.getResponseString(POST_URL);
+ for (String sortOrder : new String[] {
+ "created DESC", "purpose DESC", "created ASC", "created DESC"}) {
+ RequestObject sortOrderReports = new
FindReportEntriesBySearch(-1L, "", "", sortOrder, 0, 20);
+ sortOrderReports.getResponseString(POST_URL);
+ }
+
+ // search for "..."
+ String searchString = "Seattle dinner";
+ RequestObject searchReportsCount = new CountReportsBySearch(-1, "",
searchString);
+ searchReportsCount.getResponseString(POST_URL);
+ RequestObject searchReports = new FindReportEntriesBySearch(-1L, "",
searchString, "created DESC", 0, 20);
+ searchReports.getResponseString(POST_URL);
+ }
+
+ private static void readStaticResources(String baseUrl) throws
IOException {
+ URL url = new URL((baseUrl + "/Expenses.html"));
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ url.openStream()));
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ // ...
+ }
+ reader.close();
+ }
+}
=======================================
--- /branches/2.1/bikeshed/war/WEB-INF/appengine-web.xml Mon May 17
08:54:17 2010
+++ /branches/2.1/bikeshed/war/WEB-INF/appengine-web.xml Tue May 18
14:43:14 2010
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>gwt-bikeshed</application>
- <version>23</version>
+ <version>24</version>
<static-files>
<include path="**.nocache.*" expiration="1s"/>
<include path="**.cache.html" expiration="365d"/>
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors