Config class no longer so monolithic.
Review at http://gwt-code-reviews.appspot.com/310802
Review by: amitmanjhi@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7882 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java b/bikeshed/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
index b78b6fc..5d5a3de 100644
--- a/bikeshed/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
@@ -16,6 +16,7 @@
package com.google.gwt.requestfactory.server;
import com.google.gwt.requestfactory.shared.RequestFactory;
+import com.google.gwt.requestfactory.shared.RequestFactory.Config;
import com.google.gwt.requestfactory.shared.RequestFactory.RequestDefinition;
import com.google.gwt.requestfactory.shared.impl.RequestDataManager;
import com.google.gwt.valuestore.shared.Property;
@@ -43,15 +44,16 @@
import javax.servlet.http.HttpServletResponse;
/**
- * Handles GWT RequestFactory requests. Configured via servlet context param
- * servlet.serverOperation, which must be set to the fully qualified name of an
- * enum implementing {@link RequestDefinition}.
+ * Handles GWT RequestFactory JSON requests. Configured via servlet context
+ * param <code>servlet.serverOperation</code>, which must be set to the name of a default
+ * instantiable class implementing
+ * com.google.gwt.requestfactory.shared.RequestFactory.Config.
* <p>
* e.g.
*
* <pre> <context-param>
<param-name>servlet.serverOperation</param-name>
- <param-value>com.google.gwt.sample.expenses.shared.ExpenseRequestFactory$ServerSideOperation</param-value>
+ <param-value>com.myco.myapp.MyAppServerSideOperations</param-value>
</context-param>
* </pre>
@@ -69,6 +71,8 @@
}
}
+ private Config config;
+
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
@@ -83,8 +87,7 @@
sync(topLevelJsonObject.getString(RequestDataManager.CONTENT_TOKEN),
writer);
} else {
-
- operation = getOperationFromName(operationName, getConfigClass());
+ operation = getOperation(operationName);
Class<?> domainClass = Class.forName(operation.getDomainClassName());
Method domainMethod = domainClass.getMethod(
operation.getDomainMethodName(), operation.getParameterTypes());
@@ -122,8 +125,9 @@
}
/**
- * Allows subclass to provide hack implementation. TODO real reflection based
- * implsementation.
+ * Allows subclass to provide hack implementation.
+ * <p>
+ * TODO real reflection based implementation.
*/
@SuppressWarnings("unused")
protected void sync(String content, PrintWriter writer) {
@@ -131,26 +135,50 @@
}
@SuppressWarnings("unchecked")
- private Class<? extends RequestDefinition> getConfigClass() {
- try {
- final String serverOperation = getServletContext().getInitParameter(
- SERVER_OPERATION_CONTEXT_PARAM);
- if (null == serverOperation) {
- throw new IllegalStateException(String.format(
- "Context parameter \"%s\" must name an enum implementing %s",
- SERVER_OPERATION_CONTEXT_PARAM, RequestDefinition.class.getName()));
+ private void ensureConfig() {
+ if (config == null) {
+ synchronized (this) {
+ if (config != null) {
+ return;
+ }
+ try {
+ final String serverOperation = getServletContext().getInitParameter(
+ SERVER_OPERATION_CONTEXT_PARAM);
+ if (null == serverOperation) {
+ failConfig();
+ }
+ Class<?> clazz = Class.forName(serverOperation);
+ if (Config.class.isAssignableFrom(clazz)) {
+ config = ((Class<? extends Config>) clazz).newInstance();
+ }
+
+ } catch (ClassNotFoundException e) {
+ failConfig(e);
+ } catch (InstantiationException e) {
+ failConfig(e);
+ } catch (IllegalAccessException e) {
+ failConfig(e);
+ } catch (SecurityException e) {
+ failConfig(e);
+ } catch (ClassCastException e) {
+ failConfig(e);
+ }
}
- Class<?> clazz = Class.forName(serverOperation);
- if (!RequestDefinition.class.isAssignableFrom(clazz)) {
- throw new RuntimeException(serverOperation + " must implement "
- + RequestDefinition.class.getName());
- }
- return (Class<? extends RequestDefinition>) clazz;
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(e);
}
}
+ private void failConfig() {
+ failConfig(null);
+ }
+
+ private void failConfig(Throwable e) {
+ final String message = String.format("Context parameter \"%s\" must name "
+ + "a default instantiable configuration class implementing %s",
+ SERVER_OPERATION_CONTEXT_PARAM, RequestFactory.Config.class.getName());
+
+ throw new IllegalStateException(message, e);
+ }
+
private String getContent(HttpServletRequest request) throws IOException {
int contentLength = request.getContentLength();
byte contentBytes[] = new byte[contentLength];
@@ -211,16 +239,15 @@
return methodName.toString();
}
- private RequestDefinition getOperationFromName(String operationName,
- Class<? extends RequestDefinition> enumClass) throws SecurityException,
- IllegalAccessException, InvocationTargetException, NoSuchMethodException {
- for (RequestDefinition operation : ((RequestDefinition[]) enumClass.getMethod(
- "values").invoke(null))) {
- if (operation.name().equals(operationName)) {
- return operation;
- }
+ private RequestDefinition getOperation(String operationName) {
+ RequestDefinition operation;
+ ensureConfig();
+ operation = config.requestDefinitions().get(operationName);
+ if (null == operation) {
+ throw new IllegalArgumentException("Unknown operation "
+ + operationName);
}
- throw new IllegalArgumentException("Unknown operation " + operationName);
+ return operation;
}
/**
diff --git a/bikeshed/src/com/google/gwt/requestfactory/shared/RequestFactory.java b/bikeshed/src/com/google/gwt/requestfactory/shared/RequestFactory.java
index 1cdb8bd..d5bdf28 100644
--- a/bikeshed/src/com/google/gwt/requestfactory/shared/RequestFactory.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/shared/RequestFactory.java
@@ -16,50 +16,32 @@
package com.google.gwt.requestfactory.shared;
import com.google.gwt.event.shared.HandlerManager;
+import com.google.gwt.requestfactory.server.RequestFactoryServlet;
import com.google.gwt.valuestore.shared.DeltaValueStore;
import com.google.gwt.valuestore.shared.ValueStore;
import com.google.gwt.valuestore.shared.ValuesKey;
+import java.util.Map;
+
/**
* Marker interface for the RequestFactory code generator.
*/
public interface RequestFactory {
- String URL = "/expenses/data";
-
- /*
- * eventually, this will become an enum of update operations.
- */
- String UPDATE_STRING = "SYNC";
-
/**
- * Implemented by the request objects created by this factory.
+ * Implemented by the configuration class used by
+ * {@link RequestFactoryServlet}.
*/
- interface RequestObject {
- void fire();
-
- String getRequestData();
-
- void handleResponseText(String responseText);
+ interface Config {
+ Map<String, RequestDefinition> requestDefinitions();
}
- ValueStore getValueStore();
-
- void init(HandlerManager handlerManager);
-
- SyncRequest syncRequest(DeltaValueStore deltaValueStore);
-
/**
- * Implemented by the enum that defines the mapping between request objects
- * and service methods.
+ * Implemented by enums that defines the mapping between request objects and
+ * service methods.
*/
interface RequestDefinition {
/**
- * Returns the name.
- */
- String name();
-
- /**
* Returns the name of the (domain) class that contains the method to be
* invoked on the server.
*/
@@ -79,5 +61,34 @@
* Returns the return type of the method to be invoked on the server.
*/
Class<? extends ValuesKey<?>> getReturnType();
+
+ /**
+ * Returns the name.
+ */
+ String name();
}
+
+ /**
+ * Implemented by the request objects created by this factory.
+ */
+ interface RequestObject {
+ void fire();
+
+ String getRequestData();
+
+ void handleResponseText(String responseText);
+ }
+
+ String URL = "/expenses/data";
+
+ /*
+ * eventually, this will become an enum of update operations.
+ */
+ String UPDATE_STRING = "SYNC";
+
+ ValueStore getValueStore();
+
+ void init(HandlerManager handlerManager);
+
+ SyncRequest syncRequest(DeltaValueStore deltaValueStore);
}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java
index f84426c..b8b3b7e 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java
@@ -16,12 +16,33 @@
package com.google.gwt.sample.expenses.gwt.request;
import com.google.gwt.requestfactory.shared.EntityListRequest;
+import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.ServerOperation;
+import com.google.gwt.valuestore.shared.ValuesKey;
/**
* Request selector.
*/
public interface EmployeeRequest {
+ public enum ServerOperations implements RequestFactory.RequestDefinition {
+ FIND_ALL_EMPLOYEES {
+ public String getDomainMethodName() {
+ return "findAllEmployees";
+ }
+
+ public Class<? extends ValuesKey<?>> getReturnType() {
+ return com.google.gwt.sample.expenses.gwt.request.EmployeeKey.class;
+ }
+ };
+
+ public String getDomainClassName() {
+ return "com.google.gwt.sample.expenses.server.domain.Employee";
+ }
+
+ public Class<?>[] getParameterTypes() {
+ return null;
+ }
+ }
/**
* @return a request object
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ExpensesServerSideOperations.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ExpensesServerSideOperations.java
index 7f10ff6..03f4718 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ExpensesServerSideOperations.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ExpensesServerSideOperations.java
@@ -15,67 +15,38 @@
*/
package com.google.gwt.sample.expenses.gwt.request;
+import com.google.gwt.requestfactory.shared.RequestFactory.Config;
import com.google.gwt.requestfactory.shared.RequestFactory.RequestDefinition;
-import com.google.gwt.valuestore.shared.ValuesKey;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
/**
- * Represents the server side operation to be carried out. This enum will be
- * generated by the JPA-aware tool.
+ * Configuration class for
+ * {@link com.google.gwt.requestfactory.server.RequestFactoryServlet
+ * RequestFactoryServlet}
*/
-public enum ExpensesServerSideOperations implements RequestDefinition {
- FIND_ALL_EMPLOYEES("com.google.gwt.sample.expenses.server.domain.Employee",
- "findAllEmployees", null,
- com.google.gwt.sample.expenses.gwt.request.EmployeeKey.class), //
- FIND_ALL_REPORTS("com.google.gwt.sample.expenses.server.domain.Report",
- "findAllReports", null,
- com.google.gwt.sample.expenses.gwt.request.ReportKey.class), //
- FIND_REPORTS_BY_EMPLOYEE(
- "com.google.gwt.sample.expenses.server.domain.Report",
- "findReportsByEmployee", new Class[] {java.lang.Long.class},
- com.google.gwt.sample.expenses.gwt.request.ReportKey.class); //
+public class ExpensesServerSideOperations implements Config {
- /**
- * the server side domain class.
- */
- private final String domainClassName;
-
- /**
- * the methodName of the domain class that is to be invoked.
- */
- private final String domainMethodName;
-
- /**
- * the parameterTypes of the parameters the domain method requires.
- */
- private final Class<?>[] parameterTypes;
-
- /**
- * for "READ" methods, the methods return a List. This class denotes the types
- * of the elements of the list.
- */
- private final Class<? extends ValuesKey<?>> returnType;
-
- private ExpensesServerSideOperations(String domainClassName, String domainMethodName,
- Class<?> parameterTypes[], Class<? extends ValuesKey<?>> entryReturnType) {
- this.domainClassName = domainClassName;
- this.domainMethodName = domainMethodName;
- this.parameterTypes = parameterTypes;
- this.returnType = entryReturnType;
+ private static void putAll(RequestDefinition[] values,
+ Map<String, RequestDefinition> newMap) {
+ for (RequestDefinition def : values) {
+ newMap.put(def.name(), def);
+ }
}
- public String getDomainClassName() {
- return domainClassName;
+ private final Map<String, RequestDefinition> map;
+
+ public ExpensesServerSideOperations() {
+ Map<String, RequestDefinition> newMap = new HashMap<String, RequestDefinition>();
+ putAll(EmployeeRequest.ServerOperations.values(), newMap);
+ putAll(ReportRequest.ServerOperations.values(), newMap);
+ map = Collections.unmodifiableMap(newMap);
}
- public String getDomainMethodName() {
- return domainMethodName;
+ public Map<String, RequestDefinition> requestDefinitions() {
+ return map;
}
- public Class<?>[] getParameterTypes() {
- return parameterTypes;
- }
-
- public Class<? extends ValuesKey<?>> getReturnType() {
- return returnType;
- }
-}
\ No newline at end of file
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ReportRequest.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ReportRequest.java
index 4be2dab..75857ec 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ReportRequest.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ReportRequest.java
@@ -17,13 +17,48 @@
import com.google.gwt.requestfactory.shared.EntityListRequest;
import com.google.gwt.requestfactory.shared.LongString;
+import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.ServerOperation;
import com.google.gwt.valuestore.shared.ValueRef;
+import com.google.gwt.valuestore.shared.ValuesKey;
/**
* Request selector.
*/
public interface ReportRequest {
+ public enum ServerOperations implements RequestFactory.RequestDefinition {
+ FIND_REPORTS_BY_EMPLOYEE {
+ public String getDomainMethodName() {
+ return "findReportsByEmployee";
+ }
+
+ public Class<?>[] getParameterTypes() {
+ return new Class[] { java.lang.Long.class };
+ }
+
+ public Class<? extends ValuesKey<?>> getReturnType() {
+ return com.google.gwt.sample.expenses.gwt.request.ReportKey.class;
+ }
+ },
+
+ FIND_ALL_REPORTS {
+ public String getDomainMethodName() {
+ return "findAllReports";
+ }
+
+ public Class<? extends ValuesKey<?>> getReturnType() {
+ return com.google.gwt.sample.expenses.gwt.request.ReportKey.class;
+ }
+ };
+
+ public String getDomainClassName() {
+ return "com.google.gwt.sample.expenses.server.domain.Report";
+ }
+
+ public Class<?>[] getParameterTypes() {
+ return null;
+ }
+ }
/**
* @return a request object
diff --git a/bikeshed/war/WEB-INF/web.xml b/bikeshed/war/WEB-INF/web.xml
index bb3088e..17718a8 100644
--- a/bikeshed/war/WEB-INF/web.xml
+++ b/bikeshed/war/WEB-INF/web.xml
@@ -8,7 +8,7 @@
<!-- Configures expensesData servlet -->
<context-param>
<param-name>servlet.serverOperation</param-name>
- <param-value>com.google.gwt.sample.expenses.gwt.request.ExpensesRequests</param-value>
+ <param-value>com.google.gwt.sample.expenses.gwt.request.ExpensesServerSideOperations</param-value>
</context-param>
<!-- Servlets -->