Updates DTRF to show the use of ServiceLocators and Locators.
- Added editors to modify person schedules
- Schedule is now a RF Entity and TimeSlot is now a VO
- ScheduleLocator interfaces with "non standard" getKey and getRevision methods
- ScheduleService provides a service method
Review at http://gwt-code-reviews.appspot.com/1299801
Review by: rjrjr@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9609 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java
index 51ce66f..51ad62c 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java
@@ -28,7 +28,10 @@
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.requestfactory.shared.Violation;
import com.google.gwt.sample.dynatablerf.client.events.EditPersonEvent;
+import com.google.gwt.sample.dynatablerf.client.widgets.MentorSelector;
import com.google.gwt.sample.dynatablerf.client.widgets.PersonEditor;
+import com.google.gwt.sample.dynatablerf.client.widgets.ScheduleEditor;
+import com.google.gwt.sample.dynatablerf.client.widgets.TimeSlotListWidget;
import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory.PersonRequest;
import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
@@ -88,7 +91,10 @@
this.requestFactory = requestFactory;
this.manager = manager;
this.person = person;
- personEditor = new PersonEditor(requestFactory);
+ TimeSlotListWidget timeSlotEditor = new TimeSlotListWidget(requestFactory);
+ ScheduleEditor scheduleEditor = new ScheduleEditor(timeSlotEditor);
+ MentorSelector mentorEditor = new MentorSelector(requestFactory);
+ personEditor = new PersonEditor(mentorEditor, scheduleEditor);
Binder.BINDER.createAndBindUi(this);
contents.addDomHandler(new KeyUpHandler() {
public void onKeyUp(KeyUpEvent event) {
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java
index 0ecdd4b..ddbfaf4 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java
@@ -20,7 +20,6 @@
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.editor.client.Editor;
import com.google.gwt.editor.ui.client.ValueBoxEditorDecorator;
-import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
@@ -52,9 +51,13 @@
@UiField
Focusable nameBox;
+
+ @UiField(provided = true)
+ ScheduleEditor classSchedule;
- public PersonEditor(DynaTableRequestFactory factory) {
- mentor = new MentorSelector(factory);
+ public PersonEditor(MentorSelector mentorEditor, ScheduleEditor scheduleEditor) {
+ classSchedule = scheduleEditor;
+ this.mentor = mentorEditor;
initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml
index 3b29ba3..40b32ce 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml
@@ -35,5 +35,8 @@
<dt:AddressEditor ui:field="address" stylePrimaryName="{style.editField}" />
Mentor:
<dt:MentorSelector ui:field="mentor" stylePrimaryName="{style.editField}" />
+ <br />
+ Schedule:
+ <dt:ScheduleEditor ui:field="classSchedule" stylePrimaryName="{style.editField}" />
</g:HTMLPanel>
</ui:UiBinder>
\ No newline at end of file
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/ScheduleEditor.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/ScheduleEditor.java
new file mode 100644
index 0000000..4d4d175
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/ScheduleEditor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011 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.dynatablerf.client.widgets;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.editor.client.Editor;
+import com.google.gwt.sample.dynatablerf.shared.ScheduleProxy;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Edits a persons's schedule.
+ */
+public class ScheduleEditor extends Composite implements Editor<ScheduleProxy> {
+
+ interface ScheduleEditorUiBinder extends UiBinder<Widget, ScheduleEditor> {
+ }
+
+ private static ScheduleEditorUiBinder uiBinder = GWT.create(
+ ScheduleEditorUiBinder.class);
+
+ @UiField(provided = true)
+ TimeSlotListWidget timeSlots;
+
+ public ScheduleEditor(TimeSlotListWidget timeSlotEditor) {
+ timeSlots = timeSlotEditor;
+ initWidget(uiBinder.createAndBindUi(this));
+ }
+
+}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/ScheduleEditor.ui.xml b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/ScheduleEditor.ui.xml
new file mode 100644
index 0000000..4a8771e
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/ScheduleEditor.ui.xml
@@ -0,0 +1,13 @@
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
+ xmlns:g="urn:import:com.google.gwt.user.client.ui"
+ xmlns:dt='urn:import:com.google.gwt.sample.dynatablerf.client.widgets' >
+ <ui:style>
+ .table {
+ width: 100%;
+ }
+ </ui:style>
+ <g:HTMLPanel>
+ <dt:TimeSlotListWidget ui:field="timeSlots" stylePrimaryName="{style.table}" />
+ </g:HTMLPanel>
+</ui:UiBinder>
\ No newline at end of file
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java
index 4024b61..78a0d9d 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java
@@ -34,6 +34,8 @@
import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory.PersonRequest;
import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
+import com.google.gwt.sample.dynatablerf.shared.ScheduleProxy;
+import com.google.gwt.sample.dynatablerf.shared.TimeSlotProxy;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
@@ -98,7 +100,7 @@
@Override
public String getValue(PersonProxy object) {
- return object.getSchedule();
+ return object.getScheduleDescription();
}
}
@@ -177,8 +179,11 @@
void onCreate(ClickEvent event) {
PersonRequest context = requestFactory.personRequest();
AddressProxy address = context.create(AddressProxy.class);
+ ScheduleProxy schedule = context.create(ScheduleProxy.class);
+ schedule.setTimeSlots(new ArrayList<TimeSlotProxy>());
PersonProxy person = context.edit(context.create(PersonProxy.class));
person.setAddress(address);
+ person.setClassSchedule(schedule);
context.persist().using(person);
eventBus.fireEvent(new EditPersonEvent(person, context));
}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/TimeSlotListWidget.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/TimeSlotListWidget.java
new file mode 100644
index 0000000..1d098f7
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/TimeSlotListWidget.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2011 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.dynatablerf.client.widgets;
+
+import com.google.gwt.cell.client.ClickableTextCell;
+import com.google.gwt.cell.client.FieldUpdater;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.editor.client.EditorDelegate;
+import com.google.gwt.editor.client.ValueAwareEditor;
+import com.google.gwt.requestfactory.shared.Receiver;
+import com.google.gwt.sample.dynatablerf.client.widgets.SummaryWidget.TableResources;
+import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
+import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory.ScheduleRequest;
+import com.google.gwt.sample.dynatablerf.shared.TimeSlotProxy;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.cellview.client.CellTable;
+import com.google.gwt.user.cellview.client.Column;
+import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Edits a list of time slots.
+ */
+public class TimeSlotListWidget extends Composite implements ValueAwareEditor<List<TimeSlotProxy>> {
+
+ interface TimeSlotListWidgetUiBinder extends UiBinder<Widget, TimeSlotListWidget> {
+ }
+
+ private class ScheduleRow {
+ int hour;
+
+ ScheduleRow(int hour) {
+ this.hour = hour;
+ }
+
+ public int getHour() {
+ return hour;
+ }
+
+ public boolean isInUse(WeekDay day) {
+ return currentSchedule.contains(new TimeSlotKey(day, hour));
+ }
+
+ public void toggleInUse(WeekDay day) {
+ final TimeSlotKey key = new TimeSlotKey(day, hour);
+ if (currentSchedule.contains(key)) {
+ currentSchedule.remove(key);
+ table.redraw();
+ } else if (!existingSlots.containsKey(key)) {
+ acceptClicks = false;
+ ScheduleRequest context = factory.scheduleRequest();
+ context.createTimeSlot(day.ordinal(), hour * 60, hour * 60 + 50).fire(
+ new Receiver<TimeSlotProxy>() {
+ public void onSuccess(TimeSlotProxy slot) {
+ existingSlots.put(key, slot);
+ backing.add(slot);
+ currentSchedule.add(key);
+ table.redraw();
+ acceptClicks = true;
+ }
+ });
+ } else {
+ currentSchedule.add(key);
+ table.redraw();
+ }
+ }
+ }
+
+ private static class TimeSlotKey {
+ private int hour;
+ private WeekDay day;
+
+ TimeSlotKey(WeekDay day, int hour) {
+ this.day = day;
+ this.hour = hour;
+ }
+
+ TimeSlotKey(TimeSlotProxy slot) {
+ day = WeekDay.fromInt(slot.getDayOfWeek());
+ hour = slot.getStartMinutes() / 60;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ TimeSlotKey other = (TimeSlotKey) obj;
+ if (day == null) {
+ if (other.day != null) {
+ return false;
+ }
+ } else if (!day.equals(other.day)) {
+ return false;
+ }
+ if (hour != other.hour) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * (31 + ((day == null) ? 0 : day.hashCode())) + hour;
+ }
+ }
+
+ private class WeekDayColumn extends Column<ScheduleRow, String> {
+ private WeekDay day;
+
+ public WeekDayColumn(WeekDay day) {
+ super(new ClickableTextCell());
+ this.day = day;
+ }
+
+ @Override
+ public String getValue(ScheduleRow row) {
+ if (day == null) {
+ int hour = row.getHour();
+ return Integer.toString(hour <= 12 ? hour : hour - 12) + ":00"
+ + ((hour < 12) ? "AM" : "PM");
+ }
+ return row.isInUse(day) ? "X" : ".";
+ }
+ }
+
+ private static final int ROWS_IN_A_DAY = 9;
+ private static final int FIRST_HOUR = 8;
+
+ private static TimeSlotListWidgetUiBinder uiBinder = GWT.create(
+ TimeSlotListWidgetUiBinder.class);
+
+ @UiField(provided = true)
+ CellTable<ScheduleRow> table;
+
+ private enum WeekDay {
+ SUNDAY("Su"), MONDAY("Mo"), TUESDAY("Tu"), WEDNESDAY("We"),
+ THURSDAY("Th"), FRIDAY("Fr"), SATURDAY("Sa");
+
+ public static WeekDay fromInt(int ordinal) {
+ return values()[ordinal];
+ }
+
+ private String shortName;
+
+ WeekDay(String shortName) {
+ this.shortName = shortName;
+ }
+
+ public String getShortName() {
+ return shortName;
+ }
+ }
+
+ private List<TimeSlotProxy> backing;
+ private HashSet<TimeSlotKey> currentSchedule;
+ private HashMap<TimeSlotKey, TimeSlotProxy> existingSlots;
+ private DynaTableRequestFactory factory;
+ private HashSet<TimeSlotKey> initialSchedule;
+ private boolean acceptClicks = true;
+
+ public TimeSlotListWidget(DynaTableRequestFactory factory) {
+ this.factory = factory;
+ table = new CellTable<TimeSlotListWidget.ScheduleRow>(ROWS_IN_A_DAY,
+ GWT.<TableResources> create(TableResources.class));
+ table.addColumn(new WeekDayColumn(null), "Hour");
+ for (WeekDay day : WeekDay.values()) {
+ WeekDayColumn col = new WeekDayColumn(day);
+
+ class Updater implements FieldUpdater<ScheduleRow, String> {
+ private WeekDay columnDay;
+
+ public Updater(WeekDay day) {
+ columnDay = day;
+ }
+
+ public void update(int index, ScheduleRow row, String value) {
+ if (acceptClicks) {
+ row.toggleInUse(columnDay);
+ }
+ }
+ }
+
+ FieldUpdater<ScheduleRow, String> fieldUpdater = new Updater(day);
+ col.setFieldUpdater(fieldUpdater);
+ table.addColumn(col, day.getShortName());
+ }
+
+ table.setRowCount(ROWS_IN_A_DAY, false);
+ table.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED);
+ initWidget(uiBinder.createAndBindUi(this));
+ }
+
+ public void flush() {
+ HashMap<TimeSlotProxy, TimeSlotKey> index = new HashMap<TimeSlotProxy, TimeSlotKey>();
+
+ for (TimeSlotProxy slot : backing) {
+ index.put(slot, new TimeSlotKey(slot));
+ }
+
+ // Compute slots that need to be removed from the backing
+ initialSchedule.removeAll(currentSchedule);
+
+ for (Iterator<TimeSlotProxy> iterator = backing.iterator(); iterator.hasNext();) {
+ TimeSlotProxy slot = iterator.next();
+ TimeSlotKey key = index.get(slot);
+ if (initialSchedule.contains(key)) {
+ iterator.remove();
+ }
+ }
+ }
+
+ public void onPropertyChange(String... paths) {
+ }
+
+ public void setDelegate(EditorDelegate<List<TimeSlotProxy>> delegate) {
+ }
+
+ public void setValue(List<TimeSlotProxy> value) {
+ backing = value;
+ currentSchedule = new HashSet<TimeSlotKey>();
+ existingSlots = new HashMap<TimeSlotKey, TimeSlotProxy>();
+
+ initialSchedule = new HashSet<TimeSlotKey>();
+
+ for (TimeSlotProxy slot : backing) {
+ TimeSlotKey key = new TimeSlotKey(slot);
+ currentSchedule.add(key);
+ existingSlots.put(key, slot);
+ initialSchedule.add(new TimeSlotKey(slot));
+ }
+
+ ArrayList<ScheduleRow> rows = new ArrayList<ScheduleRow>(ROWS_IN_A_DAY);
+ for (int i = 0; i < ROWS_IN_A_DAY; i++) {
+ rows.add(new ScheduleRow(FIRST_HOUR + i));
+ }
+ table.setRowData(rows);
+ }
+
+}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/TimeSlotListWidget.ui.xml b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/TimeSlotListWidget.ui.xml
new file mode 100644
index 0000000..6ae0e5b
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/TimeSlotListWidget.ui.xml
@@ -0,0 +1,13 @@
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
+ xmlns:g="urn:import:com.google.gwt.user.client.ui"
+ xmlns:cv='urn:import:com.google.gwt.user.cellview.client'>
+ <ui:style>
+ .table {
+ width: 100%;
+ }
+ </ui:style>
+ <g:HTMLPanel>
+ <cv:CellTable ui:field="table" stylePrimaryName="{style.table}" />
+ </g:HTMLPanel>
+</ui:UiBinder>
\ No newline at end of file
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 6f65c67..8a0a88c 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
@@ -127,8 +127,8 @@
public String getNote() {
return note;
}
-
- public String getSchedule() {
+
+ public String getScheduleDescription() {
return getScheduleWithFilter(daysFilters);
}
@@ -148,11 +148,6 @@
return new Person(this);
}
- /**
- * When this was written the 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);
}
@@ -160,6 +155,10 @@
public void setAddress(Address address) {
this.address = address;
}
+
+ public void setClassSchedule(Schedule schedule) {
+ this.classSchedule = schedule;
+ }
public void setDaysFilter(List<Boolean> daysFilter) {
assert daysFilter.size() == this.daysFilters.size();
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Schedule.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Schedule.java
index 14b6ddb..114c1f1 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Schedule.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Schedule.java
@@ -16,14 +16,23 @@
package com.google.gwt.sample.dynatablerf.domain;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
- * Hold the relevant data for a Schedule.
+ * Holds the relevant data for a Schedule entity.
+ * This entity does not follow the usual pattern of providing getId(), getVersion()
+ * and findSchedule() methods for RequestFactory's use.
+ * {@link com.google.gwt.sample.dynatablerf.server.ScheduleLocator} handles
+ * those responsibilities instead.
*/
public class Schedule {
private List<TimeSlot> timeSlots = new ArrayList<TimeSlot>();
+
+ private Integer key;
+
+ private Integer revision;
public Schedule() {
}
@@ -34,7 +43,9 @@
public String getDescription(List<Boolean> daysFilter) {
String s = null;
- for (TimeSlot timeSlot : timeSlots) {
+ ArrayList<TimeSlot> sortedSlots = new ArrayList<TimeSlot>(timeSlots);
+ Collections.sort(sortedSlots);
+ for (TimeSlot timeSlot : sortedSlots) {
if (daysFilter.get(timeSlot.getDayOfWeek())) {
if (s == null) {
s = timeSlot.getDescription();
@@ -51,6 +62,30 @@
}
}
+ public Integer getKey() {
+ return key;
+ }
+
+ public Integer getRevision() {
+ return revision;
+ }
+
+ public List<TimeSlot> getTimeSlots() {
+ return timeSlots;
+ }
+
+ public void setKey(Integer key) {
+ this.key = key;
+ }
+
+ public void setRevision(Integer revision) {
+ this.revision = revision;
+ }
+
+ public void setTimeSlots(List<TimeSlot> timeSlots) {
+ this.timeSlots = new ArrayList<TimeSlot>(timeSlots);
+ }
+
@Override
public String toString() {
return getDescription(null);
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/TimeSlot.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/TimeSlot.java
index c9ccec1..2b681c3 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/TimeSlot.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/TimeSlot.java
@@ -48,7 +48,11 @@
return -1;
} else if (startMinutes > o.startMinutes) {
return 1;
- }
+ } else if (endMinutes < o.endMinutes) {
+ return -1;
+ } else if (endMinutes > o.endMinutes) {
+ return 1;
+ }
}
return 0;
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonFuzzer.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonFuzzer.java
index 3a0c79b..251af9b 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonFuzzer.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonFuzzer.java
@@ -17,10 +17,8 @@
import com.google.gwt.sample.dynatablerf.domain.Person;
import com.google.gwt.sample.dynatablerf.domain.Schedule;
-import com.google.gwt.sample.dynatablerf.domain.TimeSlot;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Random;
@@ -29,6 +27,8 @@
*/
class PersonFuzzer {
+ public static final int MAX_PEOPLE = 100;
+
private static final String[] FIRST_NAMES = new String[] {
"Inman", "Sally", "Omar", "Teddy", "Jimmy", "Cathy", "Barney", "Fred",
"Eddie", "Carlos"};
@@ -42,16 +42,16 @@
"Basketball", "Computer Science", "Statistics", "Materials Engineering",
"English Literature", "Geology"};
- private static final int CLASS_LENGTH_MINS = 50;
-
- private static final int MAX_PEOPLE = 100;
-
- private static final int MAX_SCHED_ENTRIES = 5;
-
- private static final int MIN_SCHED_ENTRIES = 1;
-
private static final int STUDENTS_PER_PROF = 5;
+ public static List<Schedule> collectSchedules(List<Person> randomPeople) {
+ List<Schedule> toReturn = new ArrayList<Schedule>();
+ for (Person person : randomPeople) {
+ toReturn.add(person.getClassSchedule());
+ }
+ return toReturn;
+ }
+
public static Person generatePerson() {
Random rnd = new Random();
Person toReturn = generateRandomPerson(rnd);
@@ -71,9 +71,7 @@
}
private static Person generateRandomPerson(Random rnd) {
- // 1 out of every so many people is a prof.
- //
- if (rnd.nextInt(STUDENTS_PER_PROF) == 1) {
+ if (isChosenAsProfessor(rnd)) {
return generateRandomProfessor(rnd);
} else {
return generateRandomStudent(rnd);
@@ -90,35 +88,11 @@
String subject = pickRandomString(rnd, SUBJECTS);
prof.setDescription("Professor of " + subject);
- generateRandomSchedule(rnd, prof.getClassSchedule());
+ prof.setClassSchedule(ScheduleFuzzer.generateRandomSchedule(rnd));
return prof;
}
- private static void generateRandomSchedule(Random rnd, Schedule sched) {
- int range = MAX_SCHED_ENTRIES - MIN_SCHED_ENTRIES + 1;
- int howMany = MIN_SCHED_ENTRIES + rnd.nextInt(range);
-
- TimeSlot[] timeSlots = new TimeSlot[howMany];
-
- for (int i = 0; i < howMany; ++i) {
- int startHrs = 8 + rnd.nextInt(9); // 8 am - 5 pm
- int startMins = 15 * rnd.nextInt(4); // on the hour or some quarter
- int dayOfWeek = 1 + rnd.nextInt(5); // Mon - Fri
-
- int absStartMins = 60 * startHrs + startMins; // convert to minutes
- int absStopMins = absStartMins + CLASS_LENGTH_MINS;
-
- timeSlots[i] = new TimeSlot(dayOfWeek, absStartMins, absStopMins);
- }
-
- Arrays.sort(timeSlots);
-
- for (int i = 0; i < howMany; ++i) {
- sched.addTimeSlot(timeSlots[i]);
- }
- }
-
private static Person generateRandomStudent(Random rnd) {
Person student = new Person();
@@ -129,13 +103,18 @@
String subject = pickRandomString(rnd, SUBJECTS);
student.setDescription("Majoring in " + subject);
- generateRandomSchedule(rnd, student.getClassSchedule());
+ student.setClassSchedule(ScheduleFuzzer.generateRandomSchedule(rnd));
return student;
}
+ private static boolean isChosenAsProfessor(Random rnd) {
+ return rnd.nextInt(STUDENTS_PER_PROF + 1) == 0;
+ }
+
private static String pickRandomString(Random rnd, String[] a) {
int i = rnd.nextInt(a.length);
return a[i];
}
+
}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonSource.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonSource.java
index 1279342..e5e66ec 100644
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonSource.java
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/PersonSource.java
@@ -19,6 +19,7 @@
import static com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory.SchoolCalendarRequest.NO_DAYS;
import com.google.gwt.sample.dynatablerf.domain.Person;
+import com.google.gwt.sample.dynatablerf.domain.Schedule;
import java.util.ArrayList;
import java.util.Collections;
@@ -36,6 +37,11 @@
public abstract class PersonSource {
static class Backing extends PersonSource {
private Long serial = 0L;
+ private final ScheduleSource scheduleStore;
+
+ public Backing(ScheduleSource scheduleStore) {
+ this.scheduleStore = scheduleStore;
+ }
@Override
public int countPeople() {
@@ -94,6 +100,9 @@
person.setId(Long.toString(++serial));
}
person.setVersion(person.getVersion() + 1);
+ if (person.getClassSchedule() != null) {
+ scheduleStore.persist(person.getClassSchedule());
+ }
Person existing = people.get(person.getId());
if (existing != null) {
existing.copyFrom(person);
@@ -105,9 +114,11 @@
static class CopyOnRead extends PersonSource {
private final PersonSource backingStore;
+ private final ScheduleSource scheduleStore;
- public CopyOnRead(PersonSource backingStore) {
+ public CopyOnRead(PersonSource backingStore, ScheduleSource scheduleStore) {
this.backingStore = backingStore;
+ this.scheduleStore = scheduleStore;
}
@Override
@@ -122,6 +133,10 @@
toReturn = backingStore.findPerson(id);
if (toReturn != null) {
toReturn = toReturn.makeCopy();
+
+ Integer scheduleKey = toReturn.getClassSchedule().getKey();
+ Schedule scheduleCopy = scheduleStore.find(scheduleKey);
+ toReturn.setClassSchedule(scheduleCopy);
}
people.put(id, toReturn);
}
@@ -150,8 +165,8 @@
/**
* Create a PersonSource that will act directly on the given list.
*/
- public static PersonSource of(List<Person> people) {
- PersonSource backing = new Backing();
+ public static PersonSource of(List<Person> people, ScheduleSource schedules) {
+ PersonSource backing = new Backing(schedules);
for (Person person : people) {
backing.persist(person);
}
@@ -162,8 +177,8 @@
* Create a PersonSource that will read through to the given source and make
* copies of any objects that are requested.
*/
- public static PersonSource of(PersonSource backing) {
- return new CopyOnRead(backing);
+ public static PersonSource of(PersonSource backing, ScheduleSource scheduleBacking) {
+ return new CopyOnRead(backing, scheduleBacking);
}
final Map<String, Person> people = new LinkedHashMap<String, Person>();
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleFuzzer.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleFuzzer.java
new file mode 100644
index 0000000..148a55b
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleFuzzer.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011 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.dynatablerf.server;
+
+import com.google.gwt.sample.dynatablerf.domain.Schedule;
+import com.google.gwt.sample.dynatablerf.domain.TimeSlot;
+
+import java.util.ArrayList;
+import java.util.Random;
+import java.util.TreeSet;
+
+/**
+ * Generates a list of random schedules. To facilitate the UI
+ * TimeSlots are defined in whole hour blocks.
+ */
+public class ScheduleFuzzer {
+
+ private static final int MAX_SCHED_ENTRIES = 5;
+
+ private static final int MIN_SCHED_ENTRIES = 1;
+
+ private static final int CLASS_LENGTH_MINS = 50;
+
+ private static final int NUMBER_OF_SCHEDULES = PersonFuzzer.MAX_PEOPLE;
+
+ public static Schedule generateRandomSchedule(Random rnd) {
+ int range = MAX_SCHED_ENTRIES - MIN_SCHED_ENTRIES + 1;
+ int howMany = MIN_SCHED_ENTRIES + rnd.nextInt(range);
+
+ ArrayList<TimeSlot> timeSlots = generateTimeSlots(rnd, howMany);
+
+ Schedule sched = new Schedule();
+ for (TimeSlot timeSlot : timeSlots) {
+ sched.addTimeSlot(timeSlot);
+ }
+ return sched;
+ }
+
+ public static Schedule[] generateSchedules() {
+ Random rnd = new Random();
+ Schedule[] toReturn = new Schedule[NUMBER_OF_SCHEDULES];
+ for (int i = 0; i < NUMBER_OF_SCHEDULES; i++) {
+ Schedule sched = generateRandomSchedule(rnd);
+ toReturn[i] = sched;
+ }
+ return toReturn;
+ }
+
+ private static ArrayList<TimeSlot> generateTimeSlots(Random rnd, int howMany) {
+ TreeSet<TimeSlot> timeSlots = new TreeSet<TimeSlot>();
+
+ for (int i = 0; i < howMany; ++i) {
+ int startHrs = 8 + rnd.nextInt(9); // 8 am - 5 pm
+ int dayOfWeek = 1 + rnd.nextInt(5); // Mon - Fri
+
+ int absStartMins = 60 * startHrs; // convert to minutes
+ int absStopMins = absStartMins + CLASS_LENGTH_MINS;
+
+ timeSlots.add(new TimeSlot(dayOfWeek, absStartMins, absStopMins));
+ }
+
+ return new ArrayList<TimeSlot>(timeSlots);
+ }
+
+}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleLocator.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleLocator.java
new file mode 100644
index 0000000..5b3c666
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleLocator.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 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.dynatablerf.server;
+
+import com.google.gwt.requestfactory.shared.Locator;
+import com.google.gwt.sample.dynatablerf.domain.Schedule;
+
+/**
+ * This class serves as an example of implementing a Locator to allow
+ * RequestFactory to work with entities that don't conform to its expectations of
+ * static find*() methods, and getId() and getVersion() methods. In a production
+ * application such a Locator might be the bridge to your dependency injection
+ * framework, or a data access object.
+ * <p>
+ * There is a reference to this class in a {@literal @}Service annotation in
+ * {@link com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory}
+ */
+public class ScheduleLocator extends Locator<Schedule, String> {
+
+ public static ScheduleSource getThreadLocalObject() {
+ return SchoolCalendarService.SCHEDULE_SOURCE.get();
+ }
+
+ @Override
+ public Schedule create(Class<? extends Schedule> clazz) {
+ return getThreadLocalObject().create(clazz);
+ }
+
+ @Override
+ public Schedule find(Class<? extends Schedule> clazz, String id) {
+ return getThreadLocalObject().find(clazz, id);
+ }
+
+ @Override
+ public Class<Schedule> getDomainType() {
+ return getThreadLocalObject().getDomainType();
+ }
+
+ @Override
+ public String getId(Schedule domainObject) {
+ return getThreadLocalObject().getId(domainObject);
+ }
+
+ @Override
+ public Class<String> getIdType() {
+ return getThreadLocalObject().getIdType();
+ }
+
+ @Override
+ public Object getVersion(Schedule domainObject) {
+ return getThreadLocalObject().getVersion(domainObject);
+ }
+
+ public void persist(Schedule domainObject) {
+ getThreadLocalObject().persist(domainObject);
+ }
+}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleService.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleService.java
new file mode 100644
index 0000000..5b9117a
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleService.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2011 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.dynatablerf.server;
+
+import com.google.gwt.sample.dynatablerf.domain.TimeSlot;
+
+/**
+ * Service object for Schedule entities, used to demonstrate the use of non-static
+ * service objects with RequestFactory. RequestFactory finds this service via the
+ * {@link ScheduleServiceLocator}.
+ */
+public class ScheduleService {
+
+ public TimeSlot createTimeSlot(int zeroBasedDayOfWeek, int startMinutes, int endMinutes) {
+ return new TimeSlot(zeroBasedDayOfWeek, startMinutes, endMinutes);
+ }
+
+}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleServiceLocator.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleServiceLocator.java
new file mode 100644
index 0000000..92b82eb
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleServiceLocator.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011 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.dynatablerf.server;
+
+import com.google.gwt.requestfactory.shared.ServiceLocator;
+
+/**
+ * This class provides an example of implementing a ServiceLocator to allow
+ * RequestFactory to work with instances of service objects, instead of its default
+ * behavior of mapping service calls to static methods.
+ * <p>
+ * There is a reference to this class in an {@literal @}Service annotation in
+ * {@link com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory}
+ */
+public class ScheduleServiceLocator implements ServiceLocator {
+
+ public Object getInstance(Class<?> clazz) {
+ return clazz.equals(ScheduleService.class) ? new ScheduleService() : null;
+ }
+
+}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleSource.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleSource.java
new file mode 100644
index 0000000..46230a4
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/ScheduleSource.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2011 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.dynatablerf.server;
+
+import com.google.gwt.sample.dynatablerf.domain.Schedule;
+import com.google.gwt.sample.dynatablerf.domain.TimeSlot;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides a number of Schedule objects as a demonstration datasource. Many of
+ * the operations in this implementation would be much more efficient in a real
+ * database, but are implemented is a straightforward fashion because they're
+ * not really important for understanding the RequestFactory framework.
+ */
+public abstract class ScheduleSource {
+
+ private static int serial = 0;
+
+ /**
+ * Backing store of schedule entities.
+ */
+ static class Backing extends ScheduleSource {
+
+ @Override
+ public Schedule create(Class<? extends Schedule> clazz) {
+ return new Schedule();
+ }
+
+ @Override
+ public Schedule find(Class<? extends Schedule> clazz, String id) {
+ if (!Schedule.class.equals(clazz)) {
+ return null;
+ }
+ return schedules.get(makeKey(id));
+ }
+
+ @Override
+ public Class<Schedule> getDomainType() {
+ return Schedule.class;
+ }
+
+ @Override
+ public String getId(Schedule domainObject) {
+ return Integer.toString(domainObject.getKey());
+ }
+
+ @Override
+ public Class<String> getIdType() {
+ return String.class;
+ }
+
+ @Override
+ public Object getVersion(Schedule domainObject) {
+ return domainObject.getRevision();
+ }
+
+ @Override
+ public void persist(Schedule domainObject) {
+ if (domainObject.getKey() == null) {
+ domainObject.setKey(newSerial());
+ }
+ domainObject.setRevision(newSerial());
+ Schedule existing = schedules.get(domainObject.getKey());
+ if (existing == null) {
+ schedules.put(domainObject.getKey(), domainObject);
+ } else {
+ copyScheduleFields(domainObject, existing);
+ }
+ }
+ }
+
+ /**
+ * Provides copy-on-read access to a ScheduleLocator.
+ */
+ public static class CopyOnRead extends Backing {
+ private final ScheduleSource backingStore;
+
+ public CopyOnRead(ScheduleSource backingStore) {
+ this.backingStore = backingStore;
+ }
+
+ @Override
+ public Schedule find(Class<? extends Schedule> clazz, String id) {
+ if (!Schedule.class.equals(clazz)) {
+ return null;
+ }
+ Integer key = makeKey(id);
+ Schedule toReturn = schedules.get(key);
+ if (toReturn == null) {
+ Schedule original = backingStore.find(clazz, id);
+ if (original != null) {
+ toReturn = makeCopy(original);
+ }
+ schedules.put(key, toReturn);
+ }
+ return toReturn;
+ }
+
+ @Override
+ public void persist(Schedule domainObject) {
+ backingStore.persist(domainObject);
+ }
+
+ private Schedule makeCopy(Schedule source) {
+ Schedule destination = new Schedule();
+ copyScheduleFields(source, destination);
+ return destination;
+ }
+ }
+
+ static void copyScheduleFields(Schedule source, Schedule destination) {
+ destination.setKey(source.getKey());
+ destination.setRevision(source.getRevision());
+ destination.setTimeSlots(new ArrayList<TimeSlot>(source.getTimeSlots()));
+ }
+
+ public static Backing createBacking() {
+ return new Backing();
+ }
+
+ public static ScheduleSource getThreadLocalObject() {
+ return SchoolCalendarService.SCHEDULE_SOURCE.get();
+ }
+
+ /**
+ * Create a ScheduleLocator that will act directly on the given list.
+ */
+ public static ScheduleSource of(List<Schedule> schedules) {
+ ScheduleSource backing = createBacking();
+ for (Schedule schedule : schedules) {
+ backing.persist(schedule);
+ }
+ return backing;
+ }
+
+ /**
+ * Create a ScheduleLocator that will read through to the given source and make
+ * copies of any objects that are requested.
+ */
+ public static ScheduleSource of(ScheduleSource backing) {
+ return new CopyOnRead(backing);
+ }
+
+ private static Integer makeKey(String id) {
+ return Integer.valueOf(id);
+ }
+
+ private static int newSerial() {
+ return ++serial;
+ }
+
+ final Map<Integer, Schedule> schedules = new LinkedHashMap<Integer, Schedule>();
+
+ public abstract Schedule create(Class<? extends Schedule> clazz);
+
+ public Schedule find(Integer key) {
+ return find(Schedule.class, key.toString());
+ }
+
+ public abstract Schedule find(Class<? extends Schedule> clazz, String id);
+
+ public abstract Class<Schedule> getDomainType();
+
+ public abstract String getId(Schedule domainObject);
+
+ public abstract Class<String> getIdType();
+
+ public abstract Object getVersion(Schedule domainObject);
+
+ public abstract void persist(Schedule domainObject);
+
+}
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 b4097cf..a55935a 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
@@ -36,6 +36,7 @@
public class SchoolCalendarService implements Filter {
private static final ThreadLocal<PersonSource> PERSON_SOURCE = new ThreadLocal<PersonSource>();
+ static final ThreadLocal<ScheduleSource> SCHEDULE_SOURCE = new ThreadLocal<ScheduleSource>();
public static Person createPerson() {
checkPersonSource();
@@ -74,6 +75,7 @@
}
private PersonSource backingStore;
+ private ScheduleSource scheduleStore;
public void destroy() {
}
@@ -81,10 +83,13 @@
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
try {
- PERSON_SOURCE.set(PersonSource.of(backingStore));
+ ScheduleSource scheduleBacking = ScheduleSource.of(scheduleStore);
+ SCHEDULE_SOURCE.set(scheduleBacking);
+ PERSON_SOURCE.set(PersonSource.of(backingStore, scheduleBacking));
chain.doFilter(req, resp);
} finally {
PERSON_SOURCE.set(null);
+ SCHEDULE_SOURCE.set(null);
}
}
@@ -92,7 +97,9 @@
backingStore = (PersonSource) config.getServletContext().getAttribute(
SchoolCalendarService.class.getName());
if (backingStore == null) {
- backingStore = PersonSource.of(PersonFuzzer.generateRandomPeople());
+ List<Person> randomPeople = PersonFuzzer.generateRandomPeople();
+ scheduleStore = ScheduleSource.of(PersonFuzzer.collectSchedules(randomPeople));
+ backingStore = PersonSource.of(randomPeople, scheduleStore);
config.getServletContext().setAttribute(
SchoolCalendarService.class.getName(), backingStore);
}
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 ce18e88..5e6c34d 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
@@ -22,6 +22,8 @@
import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.Service;
import com.google.gwt.sample.dynatablerf.domain.Person;
+import com.google.gwt.sample.dynatablerf.server.ScheduleService;
+import com.google.gwt.sample.dynatablerf.server.ScheduleServiceLocator;
import com.google.gwt.sample.dynatablerf.server.SchoolCalendarService;
import java.util.Arrays;
@@ -57,9 +59,20 @@
Request<PersonProxy> getRandomPerson();
}
+ /**
+ * Source of request objects for Schedule entities.
+ */
+ @Service(value = ScheduleService.class, locator = ScheduleServiceLocator.class)
+ interface ScheduleRequest extends RequestContext {
+ Request<TimeSlotProxy> createTimeSlot(int zeroBasedDayOfWeek, int startMinutes,
+ int endMinutes);
+ }
+
LoggingRequest loggingRequest();
PersonRequest personRequest();
+
+ ScheduleRequest scheduleRequest();
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 bcd5dd9..ccec247 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
@@ -28,6 +28,8 @@
AddressProxy getAddress();
+ ScheduleProxy getClassSchedule();
+
String getDescription();
PersonProxy getMentor();
@@ -36,10 +38,12 @@
String getNote();
- String getSchedule();
-
+ String getScheduleDescription();
+
void setAddress(AddressProxy address);
+ void setClassSchedule(ScheduleProxy schedule);
+
void setDescription(String description);
void setMentor(PersonProxy mentor);
@@ -47,6 +51,6 @@
void setName(String name);
void setNote(String note);
-
+
EntityProxyId<PersonProxy> stableId();
}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/ScheduleProxy.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/ScheduleProxy.java
new file mode 100644
index 0000000..d7f4716
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/ScheduleProxy.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 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.dynatablerf.shared;
+
+import com.google.gwt.requestfactory.shared.EntityProxy;
+import com.google.gwt.requestfactory.shared.ProxyFor;
+import com.google.gwt.sample.dynatablerf.domain.Schedule;
+import com.google.gwt.sample.dynatablerf.server.ScheduleLocator;
+
+import java.util.List;
+
+/**
+ * Schedule DTO.
+ */
+@ProxyFor(value = Schedule.class, locator = ScheduleLocator.class)
+public interface ScheduleProxy extends EntityProxy {
+ List<TimeSlotProxy> getTimeSlots();
+ void setTimeSlots(List<TimeSlotProxy> slots);
+}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/TimeSlotProxy.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/TimeSlotProxy.java
new file mode 100644
index 0000000..ab2beec
--- /dev/null
+++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/TimeSlotProxy.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 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.dynatablerf.shared;
+
+import com.google.gwt.requestfactory.shared.ProxyFor;
+import com.google.gwt.requestfactory.shared.ValueProxy;
+import com.google.gwt.sample.dynatablerf.domain.TimeSlot;
+
+/**
+ * TimeSlot DTO.
+ */
+@ProxyFor(TimeSlot.class)
+public interface TimeSlotProxy extends ValueProxy {
+ int getDayOfWeek();
+
+ int getEndMinutes();
+
+ int getStartMinutes();
+
+ void setDayOfWeek(int zeroBasedDayOfWeek);
+
+ void setEndMinutes(int endMinutes);
+
+ void setStartMinutes(int startMinutes);
+}