1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.kuali.student.common.ui.client.mvc;
20
21 import java.util.Date;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26
27 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
28 import org.kuali.student.common.ui.client.mvc.ModelChangeEvent.Action;
29 import org.kuali.student.common.ui.client.validator.ClientDateParser;
30 import org.kuali.student.common.ui.client.validator.DataModelValidator;
31 import org.kuali.student.common.validator.DateParser;
32 import org.kuali.student.core.assembly.data.Data;
33 import org.kuali.student.core.assembly.data.Metadata;
34 import org.kuali.student.core.assembly.data.ModelDefinition;
35 import org.kuali.student.core.assembly.data.QueryPath;
36 import org.kuali.student.core.assembly.data.Data.DataType;
37 import org.kuali.student.core.assembly.data.Data.DataValue;
38 import org.kuali.student.core.assembly.data.Data.Key;
39 import org.kuali.student.core.assembly.data.Data.Property;
40 import org.kuali.student.core.assembly.data.Data.Value;
41 import org.kuali.student.core.assembly.data.HasChangeCallbacks.ChangeCallback;
42 import org.kuali.student.core.assembly.data.HasChangeCallbacks.ChangeCallbackRegistration;
43 import org.kuali.student.core.assembly.data.HasChangeCallbacks.ChangeType;
44 import org.kuali.student.core.validation.dto.ValidationResultInfo;
45
46 import com.google.gwt.core.client.GWT;
47 import com.google.gwt.event.shared.HandlerManager;
48 import com.google.gwt.event.shared.HandlerRegistration;
49
50
51
52
53
54
55
56
57
58
59
60 @SuppressWarnings("unchecked")
61 public class DataModel implements Model {
62 public interface QueryCallback<T> {
63 void onResult(QueryPath path, T result);
64 }
65
66 private static final long serialVersionUID = 1L;
67
68 private String modelName = "";
69 private ModelDefinition definition;
70 private DataModelValidator validator = new DataModelValidator();
71
72 private HandlerManager handlers = new HandlerManager(this);
73 private ChangeCallbackRegistration bridgeCallbackReg;
74
75 private Data root;
76
77 private String parentPath;
78
79 public DataModel() {
80
81 }
82
83 public DataModel(String name) {
84 this.modelName = name;
85 }
86
87 public DataModel(final ModelDefinition definition, final Data root) {
88 this.definition = definition;
89 this.root = root;
90 validator.setDateParser((DateParser) GWT.create(ClientDateParser.class));
91 }
92
93 public String getModelName() {
94 return modelName;
95 }
96
97 public void setModelName(String modelName) {
98 this.modelName = modelName;
99 }
100
101 public <T> T get(final QueryPath path) {
102 return (T) root.query(path);
103 }
104
105 public <T> T get(final String path) {
106 return (T) get(QueryPath.parse(path));
107 }
108
109
110
111
112 public Data getRoot() {
113 return root;
114 }
115
116 public void resetRoot() {
117 root = null;
118 }
119
120 public void remove(final QueryPath path) {
121 QueryPath parent = null;
122 QueryPath leavePath = null;
123 if (path != null && path.size() >= 2) {
124 parent = path.subPath(0, path.size() - 1);
125 leavePath = path.subPath(path.size() - 1, path.size());
126 Object parentData = this.get(parent);
127 if (parentData != null && parentData instanceof Data) {
128 ((Data) parentData).remove(
129 new Data.StringKey(leavePath.toString()));
130 }
131
132 } else if (path != null) {
133 root.remove(new Data.StringKey(path.toString()));
134 }
135 }
136
137
138
139
140
141
142 public Map<QueryPath, Object> query(final QueryPath path) {
143 Map<QueryPath, Object> result = new HashMap<QueryPath, Object>();
144 queryRelative(root, path, result);
145 return result;
146 }
147
148
149
150
151
152
153 public Map<QueryPath, Object> query(final String path) {
154 return query(QueryPath.parse(path));
155 }
156
157
158
159
160
161
162
163
164
165 private void queryRelative(final Data branch, final QueryPath path, Map<QueryPath, Object> result) {
166
167
168 Data d = branch;
169
170 for (int i = 0; i < path.size(); i++) {
171 if (d == null) {
172
173 break;
174 }
175 final Key key = path.get(i);
176 if (key.equals(Data.WILDCARD_KEY)) {
177 final QueryPath relative = path.subPath(i + 1, path.size());
178 if (!relative.isEmpty()) {
179
180 for (final Property p : d) {
181 if (p.getValueType().equals(Data.class)) {
182 queryRelative((Data) p.getValue(), relative, result);
183 }
184 }
185 } else {
186
187
188 Set<Key> keys = d.keySet();
189 for (Key wildcardKey : keys) {
190 if (!("_runtimeData".equals(wildcardKey.get()))) {
191 QueryPath wildcardPath = path.subPath(0, path.size() - 1);
192 wildcardPath.add(wildcardKey);
193 result.put(wildcardPath, d.get(wildcardKey));
194 }
195 }
196 }
197 break;
198 } else if (i < path.size() - 1) {
199 d = d.get(key);
200 } else {
201 final QueryPath resultPath = d.getQueryPath();
202 resultPath.add(key);
203
204 Object resultValue = d.get(key);
205
206
207
208 if (parentPath != null) {
209 String relativePath = resultPath.toString();
210 if (relativePath.contains("/")) {
211 relativePath = relativePath.substring(parentPath.length());
212 result.put(QueryPath.parse(relativePath), resultValue);
213 }else{
214 result.put(resultPath, resultValue);
215 }
216 } else {
217 result.put(resultPath, resultValue);
218 }
219 }
220 }
221 }
222
223 public void set(final QueryPath path, final Data value) {
224 set(path, new Data.DataValue(value));
225 }
226
227 public void set(final QueryPath path, final Integer value) {
228 set(path, new Data.IntegerValue(value));
229 }
230
231 public void set(final QueryPath path, final String value) {
232 set(path, new Data.StringValue(value));
233 }
234
235 public void set(final QueryPath path, final Long value) {
236 set(path, new Data.LongValue(value));
237 }
238
239 public void set(final QueryPath path, final Short value) {
240 set(path, new Data.ShortValue(value));
241 }
242
243 public void set(final QueryPath path, final Double value) {
244 set(path, new Data.DoubleValue(value));
245 }
246
247 public void set(final QueryPath path, final Float value) {
248 set(path, new Data.FloatValue(value));
249 }
250
251 public void set(final QueryPath path, final Boolean value) {
252 set(path, new Data.BooleanValue(value));
253 }
254
255 public void set(final QueryPath path, final Date value) {
256 set(path, new Data.DateValue(value));
257 }
258
259 public void set(final QueryPath path, final Value value) {
260 definition.ensurePath(root, path, value instanceof DataValue);
261 if (path.size() > 1) {
262 final QueryPath q = path.subPath(0, path.size() - 1);
263 final Data d = root.query(q);
264 d.set(path.get(path.size() - 1), value);
265 } else {
266 root.set(path.get(0), value);
267 }
268 }
269
270 public DataType getType(final QueryPath path) {
271 return definition.getType(path);
272 }
273
274 public Metadata getMetadata(final QueryPath path) {
275 return definition.getMetadata(path);
276 }
277
278
279
280
281
282 public void setRoot(final Data root) {
283 if (bridgeCallbackReg != null) {
284 bridgeCallbackReg.remove();
285 }
286 this.root = root;
287 bridgeCallbackReg = root.addChangeCallback(new ChangeCallback() {
288 @Override
289 public void onChange(ChangeType type, QueryPath path) {
290 Action action = null;
291 if (type == ChangeType.ADD) {
292 action = Action.ADD;
293 } else if (type == ChangeType.REMOVE) {
294 action = Action.REMOVE;
295 } else if (type == ChangeType.UPDATE) {
296 action = Action.UPDATE;
297 }
298 handlers.fireEvent(new DataModelChangeEvent(action, DataModel.this, path));
299 }
300 });
301 handlers.fireEvent(new DataModelChangeEvent(Action.RELOAD, this, new QueryPath()));
302 }
303
304 @Override
305 public HandlerRegistration addModelChangeHandler(ModelChangeHandler handler) {
306 return handlers.addHandler(ModelChangeEvent.TYPE, handler);
307 }
308
309 public ModelDefinition getDefinition() {
310 return definition;
311 }
312
313 public void setDefinition(ModelDefinition definition) {
314 this.definition = definition;
315 }
316
317
318 public String getParentPath() {
319 return parentPath;
320 }
321
322
323
324
325
326
327
328
329 public void setParentPath(String parentPath) {
330 this.parentPath = parentPath;
331 }
332
333
334
335
336
337
338 public void validate(final Callback<List<ValidationResultInfo>> callback) {
339 List<ValidationResultInfo> result = validator.validate(this);
340 callback.exec(result);
341 }
342
343
344
345
346
347
348 public void validateNextState(final Callback<List<ValidationResultInfo>> callback) {
349 List<ValidationResultInfo> result = validator.validateNextState(this);
350 callback.exec(result);
351 }
352
353
354
355
356
357
358 public void validateField(FieldDescriptor fd, final Callback<List<ValidationResultInfo>> callback) {
359 List<ValidationResultInfo> result = validator.validate(fd, this);
360 callback.exec(result);
361 }
362
363
364
365
366
367
368 public boolean isValidPath(String sPath) {
369 QueryPath path = QueryPath.parse(sPath);
370 boolean result = false;
371 Data root = this.getRoot();
372 for (int i = 0; i < path.size(); i++) {
373 Data.Key key = path.get(i);
374 if (!root.containsKey(key)) {
375 result = false;
376 break;
377 } else if (i < path.size() - 1) {
378 root = (Data) root.get(key);
379 } else {
380 result = true;
381 break;
382 }
383 }
384 return result;
385 }
386
387 }