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