Extends DynaTableRF with a client call to Person#persist. Review at http://gwt-code-reviews.appspot.com/755801 Review by: robertvawter@google.com git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8526 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml index f7d3f56..61d5ea2 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/DynaTableRf.gwt.xml
@@ -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" />
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/CalendarProvider.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/CalendarProvider.java index 3760c43..23f5118 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/CalendarProvider.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/CalendarProvider.java
@@ -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)); } }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableRf.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableRf.java index 33c6836..5c4e058 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableRf.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableRf.java
@@ -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(
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableWidget.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableWidget.java index 1628b9b..59326f7 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableWidget.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/DynaTableWidget.java
@@ -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> { } @@ -70,6 +72,8 @@ } } + private static final Logger log = Logger.getLogger(DynaTableWidget.class.getName()); + // TODO: Re-add error handling @SuppressWarnings("unused") private static final String NO_CONNECTION_MESSAGE = "<p>The DynaTableRf example uses a " @@ -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());
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/SchoolCalendarWidget.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/SchoolCalendarWidget.java index e7c45bc..97b9b42 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/SchoolCalendarWidget.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/SchoolCalendarWidget.java
@@ -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); }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java index a914982..75ee22a 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java
@@ -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 + "]"; + } }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java index 1787f9e..dc7538c 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java
@@ -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.
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java index 3769203..e2a9c99 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java
@@ -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; /** @@ -27,12 +30,24 @@ 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(); }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java index 186ceb1..76a065c 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java
@@ -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); }
diff --git a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java index f3a6b27..d017f36 100644 --- a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java +++ b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
@@ -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(); + 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())); + } - violations = validator.validate(entityInstance); + 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); } }
diff --git a/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java b/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java index ef3be44..a52862d 100644 --- a/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java +++ b/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
@@ -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 {
diff --git a/user/src/com/google/gwt/valuestore/shared/SyncResult.java b/user/src/com/google/gwt/valuestore/shared/SyncResult.java index 7161c32..6c2e6cc 100644 --- a/user/src/com/google/gwt/valuestore/shared/SyncResult.java +++ b/user/src/com/google/gwt/valuestore/shared/SyncResult.java
@@ -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();