Revision: 8526
Author: rj...@google.com
Date: Thu Aug 12 08:15:08 2010
Log: Extends DynaTableRF with a client call to Person#persist.
Review at http://gwt-code-reviews.appspot.com/755801
Review by: robertvaw...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=8526
Modified:
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/CalendarProvider.java
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableRf.java
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableWidget.java
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/SchoolCalendarWidget.java
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java
/trunk/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
/trunk/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
/trunk/user/src/com/google/gwt/valuestore/shared/SyncResult.java
=======================================
---
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml
Thu Jul 29 06:36:34 2010
+++
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml
Thu Aug 12 08:15:08 2010
@@ -18,6 +18,18 @@
<inherits name='com.google.gwt.user.User' />
<inherits name='com.google.gwt.requestfactory.RequestFactory' />
+
+ <inherits name='com.google.gwt.logging.Logging'/>
+ <set-property name="gwt.logging.enabled" value="TRUE"/>
+ <set-property name="gwt.logging.logLevel" value="INFO"/>
+ <set-property name="gwt.logging.consoleHandler" value="ENABLED" />
+ <set-property name="gwt.logging.developmentModeHandler" value="DISABLED"
/>
+ <set-property name="gwt.logging.firebugHandler" value="ENABLED" />
+ <set-property name="gwt.logging.hasWidgetsHandler" value="DISABLED" />
+ <set-property name="gwt.logging.popupHandler" value="DISABLED" />
+ <set-property name="gwt.logging.systemHandler" value="ENABLED" />
+ <set-property name="gwt.logging.simpleRemoteHandler" value="DISABLED" />
+
<entry-point
class='com.google.gwt.sample.dynatablerf.client.DynaTableRf' />
<set-configuration-property name="CssResource.obfuscationPrefix"
value="empty" />
=======================================
---
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/CalendarProvider.java
Mon Aug 2 18:09:28 2010
+++
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/CalendarProvider.java
Thu Aug 12 08:15:08 2010
@@ -18,6 +18,7 @@
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.requestfactory.shared.Receiver;
+import com.google.gwt.requestfactory.shared.RequestObject;
import com.google.gwt.sample.dynatablerf.client.events.DataAvailableEvent;
import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
@@ -25,12 +26,15 @@
import java.util.List;
import java.util.Set;
+import java.util.logging.Logger;
/**
* A data provider that bridges the provides row level updates from the
data
* available through a <@link SchoolCalendarService>.
*/
public class CalendarProvider {
+ private static final Logger log =
Logger.getLogger(CalendarProvider.class.getName());
+
private final HandlerManager eventBus = new HandlerManager(this);
private int lastMaxRows = -1;
@@ -69,12 +73,52 @@
lastMaxRows = maxRows;
lastPeople = response;
pushResults(startRow, response);
- }
+
+ if (response.size() > 0) {
+ demoPersist(response.get(0));
+ }
+ }
+
});
}
+
+ private void demoPersist(PersonProxy someone) {
+ /*
+ * Create a request to call someone's persist method.
+ */
+ RequestObject<Void> request =
requests.personRequest().persist(someone);
+
+ someone = request.edit(someone);
+ someone.setName("Ray Ryan");
+ someone.setDescription("Was here");
+
+ request.fire(new Receiver<Void>() {
+ public void onSuccess(Void isNull, /* syncResults going away very
soon */
+ Set<SyncResult> syncResults) {
+ /*
+ * A PersonProxyChanged should have fired. By M4, subtypes like
+ * PersonProxyChanged should go away and be replaced by a more
general
+ * ProxyUpdateEvent
+ */
+ log.info("The persist call worked, did you see an update event?");
+ }
+
+ /*
+ * Coming soon
+ *
+ * void onViolation(Set<ConstraintViolation> violations); void
onError(
+ * ... tbd ... );
+ *
+ * But likely this will come first, not sure who is dealing with
+ * serializing ConstraintViolation. Sorry.
+ *
+ * void onViolation(Set<SyncResult> syncResults) { ... }
+ */
+
+ });
+ }
private void pushResults(int startRow, List<PersonProxy> people) {
- // TODO(rjrjr) RequestFactory should probably provide this event.
eventBus.fireEvent(new DataAvailableEvent(startRow, people));
}
}
=======================================
---
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableRf.java
Mon Aug 2 18:09:28 2010
+++
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableRf.java
Thu Aug 12 08:15:08 2010
@@ -48,7 +48,7 @@
CalendarProvider provider = new CalendarProvider(requests);
- calendar = new SchoolCalendarWidget(provider, 15);
+ calendar = new SchoolCalendarWidget(new DynaTableWidget(eventBus,
provider, 15));
filter = new DayFilterWidget(eventBus);
RootLayoutPanel.get().add(
=======================================
---
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableWidget.java
Mon Aug 2 18:09:28 2010
+++
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableWidget.java
Thu Aug 12 08:15:08 2010
@@ -18,10 +18,12 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.sample.dynatablerf.client.events.NavigationEvent;
import com.google.gwt.sample.dynatablerf.client.events.DataAvailableEvent;
+import com.google.gwt.sample.dynatablerf.client.events.NavigationEvent;
import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
+import com.google.gwt.sample.dynatablerf.shared.PersonProxyChanged;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
@@ -34,13 +36,13 @@
import com.google.gwt.user.client.ui.Widget;
import java.util.List;
+import java.util.logging.Logger;
/**
* A composite Widget that implements the main interface for the dynamic
table,
* including the data table, status indicators, and paging buttons.
*/
public class DynaTableWidget extends Composite {
-
interface Binder extends UiBinder<Widget, DynaTableWidget> {
}
@@ -69,6 +71,8 @@
body.setHTML(html);
}
}
+
+ private static final Logger log =
Logger.getLogger(DynaTableWidget.class.getName());
// TODO: Re-add error handling
@SuppressWarnings("unused")
@@ -95,11 +99,30 @@
private HandlerRegistration rowDataRegistration;
- public DynaTableWidget(CalendarProvider provider, int rowCount) {
+ public DynaTableWidget(HandlerManager eventBus, CalendarProvider
provider,
+ int rowCount) {
this.provider = provider;
Binder binder = GWT.create(Binder.class);
initWidget(binder.createAndBindUi(this));
initTable(rowCount);
+
+ eventBus.addHandler(PersonProxyChanged.TYPE,
+ new PersonProxyChanged.Handler() {
+ public void onPersonChanged(PersonProxyChanged event) {
+ /*
+ * At the moment this proxy includes all the new property
values,
+ * but that's an accident. Only its id property should be
populated.
+ *
+ * The correct thing to do, and soon the only thing that will
work,
+ * is to fire an appropriate request to pick up the new
values. No,
+ * I'm not happy about the extra round trip. Still thinking
about
+ * that.
+ */
+ log.info("Look who changed, time to repaint some things: "
+ + event.getRecord());
+ }
+ });
+
}
public void clearStatusText() {
@@ -114,6 +137,25 @@
navbar.gotoNext.setEnabled(false);
setStatusText("Please wait...");
+
+ /*
+ * TODO the cell widgets reverse this relationship, to stay async
friendly.
+ *
+ * This widget would implement HasRows, and would not know directly
about
+ * its data provider. Instead, the provider would know about the
widget via
+ * something like
+ *
+ * dynaTableWidget.addRangeChangeHandler(calendarProvider)
+ *
+ * and on response would call
+ *
+ * dynaTableWidget.setRowValues( ... ) directly
+ *
+ * ListViewAdapter (soon to be renamed something like DataProvider)
exists
+ * to make this convenient when dealing with lists, and to allow one
+ * provider to serve multiple HasData clients
+ * (AbstractListViewAdapter#addView(HasData<T>))
+ */
provider.updateRowData(startRow, grid.getRowCount() - 1);
}
@@ -167,6 +209,7 @@
int srcRowIndex = 0;
int srcRowCount = people.size();
int destRowIndex = 1; // skip navbar row
+
for (; srcRowIndex < srcRowCount; ++srcRowIndex, ++destRowIndex) {
PersonProxy p = people.get(srcRowIndex);
grid.setText(destRowIndex, 0, p.getName());
=======================================
---
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/SchoolCalendarWidget.java
Mon Aug 2 18:09:28 2010
+++
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/SchoolCalendarWidget.java
Thu Aug 12 08:15:08 2010
@@ -31,8 +31,8 @@
private ScheduledCommand pendingRefresh;
- public SchoolCalendarWidget(CalendarProvider provider, int visibleRows) {
- dynaTable = new DynaTableWidget(provider, visibleRows);
+ public SchoolCalendarWidget(DynaTableWidget dynaTable) {
+ this.dynaTable = dynaTable;
initWidget(dynaTable);
}
=======================================
---
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java
Mon Aug 2 10:03:54 2010
+++
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java
Thu Aug 12 08:15:08 2010
@@ -15,30 +15,46 @@
*/
package com.google.gwt.sample.dynatablerf.domain;
+import com.google.gwt.sample.dynatablerf.server.SchoolCalendarService;
+
/**
* Hold relevant data for Person.
*/
public abstract class Person {
- private static Long serial = 1L;
+ /**
+ * The {...@link RequestFactory} requires a static finder method for each
proxied type.
+ * Soon it should allow you to customize how instances are found.
+ */
+ public static Person findPerson(Long id) {
+ return SchoolCalendarService.findPerson(id);
+ }
private String description = "DESC";
private String name;
-
- private final Long id;
+
+ private Long id;
+
+ private Integer version = 0;
public Person() {
- id = serial++;
}
public String getDescription() {
return description;
}
-
+
+ /**
+ * The {...@link RequestFactory} requires a Long id property for each
proxied type.
+ * <p>
+ * The requirement for some kind of id object with proper hash / equals
+ * semantics is not going away, but it should become possible to use
types
+ * other than Long, and properties other than "id".
+ */
public Long getId() {
return id;
}
-
+
public String getName() {
return name;
}
@@ -49,15 +65,42 @@
public abstract String getSchedule(boolean[] daysFilter);
+ /**
+ * The {...@link RequestFactory} requires an Integer version property for
each proxied
+ * type, but makes no good use of it. This requirement will be removed
soon.
+ */
public Integer getVersion() {
- return 1;
+ return version;
+ }
+
+ /**
+ * When this was written the {...@link RequestFactory} required a persist
method per type.
+ * That requirement should be relaxed very soon (and may well have been
already
+ * if we forget to update this comment).
+ */
+ public void persist() {
+ SchoolCalendarService.persist(this);
}
public void setDescription(String description) {
this.description = description;
}
+
+ public void setId(Long id) {
+ this.id = id;
+ }
public void setName(String name) {
this.name = name;
}
-}
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
+
+ @Override
+ public String toString() {
+ return "Person [description=" + description + ", id=" + id + ", name="
+ + name + ", version=" + version + "]";
+ }
+}
=======================================
---
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java
Fri Jul 23 15:42:40 2010
+++
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java
Thu Aug 12 08:15:08 2010
@@ -24,13 +24,16 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.Random;
/**
* The server side service class.
*/
public class SchoolCalendarService {
+ private static Long serial = 0L;
private static final String[] FIRST_NAMES = new String[] {
"Inman", "Sally", "Omar", "Teddy", "Jimmy", "Cathy", "Barney", "Fred",
@@ -55,7 +58,7 @@
private static final int STUDENTS_PER_PROF = 5;
- private static final List<Person> people = new ArrayList<Person>();
+ private static final Map<Long, Person> people = new LinkedHashMap<Long,
Person>();
private static final Random rnd = new Random(3);
@@ -74,16 +77,28 @@
return Collections.emptyList();
}
- return people.subList(startIndex, end);
+ return new ArrayList<Person>(people.values()).subList(startIndex, end);
}
private static void generateRandomPeople() {
if (people.isEmpty())
for (int i = 0; i < MAX_PEOPLE; ++i) {
Person person = generateRandomPerson();
- people.add(person);
+ persist(person);
}
}
+
+ public static Person findPerson(Long id) {
+ return people.get(id);
+ }
+
+ public static void persist(Person person) {
+ if (person.getId() == null) {
+ person.setId(++serial);
+ }
+ person.setVersion(person.getVersion() + 1);
+ people.put(person.getId(), person);
+ }
private static Person generateRandomPerson() {
// 1 out of every so many people is a prof.
=======================================
---
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java
Fri Jul 23 15:42:40 2010
+++
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java
Thu Aug 12 08:15:08 2010
@@ -15,9 +15,12 @@
*/
package com.google.gwt.sample.dynatablerf.shared;
+import com.google.gwt.requestfactory.shared.Instance;
import com.google.gwt.requestfactory.shared.RecordListRequest;
import com.google.gwt.requestfactory.shared.RequestFactory;
+import com.google.gwt.requestfactory.shared.RequestObject;
import com.google.gwt.requestfactory.shared.Service;
+import com.google.gwt.sample.dynatablerf.domain.Person;
import com.google.gwt.sample.dynatablerf.server.SchoolCalendarService;
/**
@@ -26,13 +29,25 @@
*/
public interface DynaTableRequestFactory extends RequestFactory {
+ /**
+ * Source of request objects for the Person class.
+ */
+ @Service(Person.class)
+ interface PersonRequest {
+ @Instance
+ RequestObject<Void> persist(PersonProxy person);
+ }
+
/**
* Source of request objects for the SchoolCalendarService.
*/
@Service(SchoolCalendarService.class)
interface SchoolCalendarRequest {
+ // TODO(amitmanjhi, cromwellian) RequestObject<List<PersonProxy>>
RecordListRequest<PersonProxy> getPeople(int startIndex, int maxCount);
}
-
+
+ PersonRequest personRequest();
+
SchoolCalendarRequest schoolCalendarRequest();
}
=======================================
---
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java
Thu Jul 29 12:54:53 2010
+++
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java
Thu Aug 12 08:15:08 2010
@@ -33,9 +33,13 @@
Property<String> description = new
Property<String>("description", "Description", String.class);
Property<String> schedule = new Property<String>("schedule", "Schedule",
String.class);
- String getSchedule();
-
String getDescription();
String getName();
-}
+
+ String getSchedule();
+
+ void setDescription(String description);
+
+ void setName(String name);
+}
=======================================
---
/trunk/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
Thu Aug 5 15:15:34 2010
+++
/trunk/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
Thu Aug 12 08:15:08 2010
@@ -52,6 +52,9 @@
* An implementation of RequestProcessor for JSON encoded payloads.
*/
public class JsonRequestProcessor implements RequestProcessor<String> {
+
+ private static final Logger log =
Logger.getLogger(JsonRequestProcessor.class.getName());
+
// TODO should we consume String, InputStream, or JSONObject?
/**
* A class representing the pair of a domain entity and its corresponding
@@ -71,7 +74,7 @@
public static Set<String> initBlackList() {
Set<String> blackList = new HashSet<String>();
- for (String str : new String[]{"password"}) {
+ for (String str : new String[] {"password"}) {
blackList.add(str);
}
return Collections.unmodifiableSet(blackList);
@@ -158,8 +161,7 @@
int ordinal = Integer.parseInt(parameterValue);
Method valuesMethod = parameterType.getDeclaredMethod("values",
new Class[0]);
- Logger.getLogger(this.getClass().getName()).severe(
- "Type is " + parameterType + " valuesMethod " + valuesMethod);
+ log.severe("Type is " + parameterType + " valuesMethod " +
valuesMethod);
if (valuesMethod != null) {
valuesMethod.setAccessible(true);
@@ -612,7 +614,9 @@
recordObject.get("id"), propertiesInRecord.get("id"));
// persist
- Set<ConstraintViolation<Object>> violations = null;
+
+ Set<ConstraintViolation<Object>> violations = Collections.emptySet();
+
if (writeOperation == WriteOperation.DELETE) {
entity.getMethod("remove").invoke(entityInstance);
} else {
@@ -635,10 +639,24 @@
}
// validations check..
- ValidatorFactory validatorFactory =
Validation.buildDefaultValidatorFactory();
- Validator validator = validatorFactory.getValidator();
-
- violations = validator.validate(entityInstance);
+ Validator validator = null;
+ try {
+ ValidatorFactory validatorFactory =
Validation.buildDefaultValidatorFactory();
+ validator = validatorFactory.getValidator();
+ } catch (Exception e) {
+ /*
+ * This is JBoss's clumsy way of telling us that the system has
not
+ * been configured.
+ */
+ log.info(String.format(
+ "Ingnoring exception caught initializing bean validation
framework. "
+ + "It is probably unconfigured or misconfigured.
[%s] %s ",
+ e.getClass().getName(), e.getLocalizedMessage()));
+ }
+
+ if (validator != null) {
+ violations = validator.validate(entityInstance);
+ }
if (violations.isEmpty()) {
entity.getMethod("persist").invoke(entityInstance);
}
@@ -648,6 +666,8 @@
return getReturnRecord(writeOperation, entityInstance, recordObject,
violations);
} catch (Exception ex) {
+ log.severe(String.format("Caught exception [%s] %s",
+ ex.getClass().getName(), ex.getLocalizedMessage()));
return getReturnRecordForException(writeOperation, recordObject, ex);
}
}
=======================================
---
/trunk/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
Thu Aug 5 15:15:34 2010
+++
/trunk/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
Thu Aug 12 08:15:08 2010
@@ -58,7 +58,6 @@
private static final String JSON_CHARSET = "UTF-8";
private static final String JSON_CONTENT_TYPE = "application/json";
- @SuppressWarnings("unchecked")
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response)
throws IOException, ServletException {
=======================================
--- /trunk/user/src/com/google/gwt/valuestore/shared/SyncResult.java Thu
Aug 5 10:04:19 2010
+++ /trunk/user/src/com/google/gwt/valuestore/shared/SyncResult.java Thu
Aug 12 08:15:08 2010
@@ -29,6 +29,7 @@
// TODO: move violations out of the SyncResult...
boolean hasViolations();
+ // TODO: futureId isn't working out so well, leaving soon
Long getFutureId();
Record getRecord();
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors