~mnml/play/crud

« back to all changes in this revision

Viewing changes to modules/crud/app/views/CRUD/CRUD.java

  • Committer: mnml
  • Date: 2010-04-13 22:38:26 UTC
  • Revision ID: mnml@mnml-20100413223826-6pr822ctltxk0ii6
adding byte type

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package controllers;
 
2
 
 
3
import play.Logger;
 
4
import play.Play;
 
5
import play.data.validation.MaxSize;
 
6
import play.data.validation.Password;
 
7
import play.data.validation.Required;
 
8
import play.db.jpa.FileAttachment;
 
9
import play.db.jpa.JPA;
 
10
import play.db.jpa.JPASupport;
 
11
import play.exceptions.TemplateNotFoundException;
 
12
import play.i18n.Messages;
 
13
import play.mvc.Before;
 
14
import play.mvc.Controller;
 
15
import play.mvc.Router;
 
16
 
 
17
import javax.persistence.*;
 
18
import java.lang.annotation.ElementType;
 
19
import java.lang.annotation.Retention;
 
20
import java.lang.annotation.RetentionPolicy;
 
21
import java.lang.annotation.Target;
 
22
import java.lang.reflect.Field;
 
23
import java.lang.reflect.Modifier;
 
24
import java.lang.reflect.ParameterizedType;
 
25
import java.util.*;
 
26
 
 
27
public abstract class CRUD extends Application {
 
28
 
 
29
    @Before
 
30
    static void addType() {
 
31
        ObjectType type = ObjectType.get(getControllerClass());
 
32
        renderArgs.put("type", type);
 
33
    }
 
34
 
 
35
    public static void index() {
 
36
        try {
 
37
            render();
 
38
        } catch (TemplateNotFoundException e) {
 
39
            render("CRUD/index.html");
 
40
        }
 
41
    }
 
42
 
 
43
    public static void autocomplete(String oType, String q, String searchFields) throws ClassNotFoundException {
 
44
        ObjectType type = new ObjectType(oType);
 
45
        notFoundIfNull(type);
 
46
        int page = 1;
 
47
        String orderBy = null, order = null;
 
48
        List<JPASupport> objects = type.findPage(page, q, searchFields, orderBy, order, (String) request.args.get("where"));
 
49
        Long count = type.count(q, searchFields, (String) request.args.get("where"));
 
50
        Long totalCount = type.count(null, null, (String) request.args.get("where"));
 
51
        try {
 
52
            render(type, objects, count, totalCount, page, orderBy, order);
 
53
        } catch (TemplateNotFoundException e) {
 
54
            render("CRUD/autocomplete.html", type, objects, count, totalCount, page, orderBy, order);
 
55
        }
 
56
    }
 
57
 
 
58
    public static void list(int page, String search, String searchFields, String orderBy, String order) {
 
59
        ObjectType type = ObjectType.get(getControllerClass());
 
60
        notFoundIfNull(type);
 
61
        if (page < 1) {
 
62
            page = 1;
 
63
        }
 
64
        List<JPASupport> objects = type.findPage(page, search, searchFields, orderBy, order, (String) request.args.get("where"));
 
65
        Long count = type.count(search, searchFields, (String) request.args.get("where"));
 
66
        Long totalCount = type.count(null, null, (String) request.args.get("where"));
 
67
        try {
 
68
            render(type, objects, count, totalCount, page, orderBy, order);
 
69
        } catch (TemplateNotFoundException e) {
 
70
            render("CRUD/list.html", type, objects, count, totalCount, page, orderBy, order);
 
71
        }
 
72
    }
 
73
 
 
74
    public static void show(String id) {
 
75
        ObjectType type = ObjectType.get(getControllerClass());
 
76
        notFoundIfNull(type);
 
77
        JPASupport object = type.findById(id);
 
78
        try {
 
79
            render(type, object);
 
80
        } catch (TemplateNotFoundException e) {
 
81
            render("CRUD/show.html", type, object);
 
82
        }
 
83
    }
 
84
 
 
85
    public static void attachment(String id, String field) throws Exception {
 
86
        ObjectType type = ObjectType.get(getControllerClass());
 
87
        notFoundIfNull(type);
 
88
        JPASupport object = type.findById(id);
 
89
        FileAttachment attachment = (FileAttachment) object.getClass().getField(field).get(object);
 
90
        if (attachment == null) {
 
91
            notFound();
 
92
        }
 
93
        renderBinary(attachment.get(), attachment.filename);
 
94
    }
 
95
 
 
96
    public static void save(String id) throws Exception {
 
97
        ObjectType type = ObjectType.get(getControllerClass());
 
98
        notFoundIfNull(type);
 
99
        JPASupport object = type.findById(id);
 
100
        object = object.edit("object", params);
 
101
        // Look if we need to deserialize
 
102
        for (ObjectType.ObjectField field : type.getFields()) {
 
103
            if (field.type.equals("serializedText") && params.get("object." + field.name) != null) {
 
104
                Field f = object.getClass().getDeclaredField(field.name);
 
105
                f.set(object, CRUD.collectionDeserializer(params.get("object." + field.name),(Class)((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0]));
 
106
            }
 
107
        }
 
108
               
 
109
        validation.valid(object);
 
110
        if (validation.hasErrors()) {
 
111
            renderArgs.put("error", Messages.get("crud.hasErrors"));
 
112
            try {
 
113
                render(request.controller.replace(".", "/") + "/show.html", type, object);
 
114
            } catch (TemplateNotFoundException e) {
 
115
                render("CRUD/show.html", type, object);
 
116
            }
 
117
        }
 
118
        object.save();
 
119
        flash.success(Messages.get("crud.saved", type.modelName, object.getEntityId()));
 
120
        if (params.get("_save") != null) {
 
121
            redirect(request.controller + ".list");
 
122
        }
 
123
        redirect(request.controller + ".show", object.getEntityId());
 
124
    }
 
125
 
 
126
    public static void blank() {
 
127
        ObjectType type = ObjectType.get(getControllerClass());
 
128
        notFoundIfNull(type);
 
129
        try {
 
130
            render(type);
 
131
        } catch (TemplateNotFoundException e) {
 
132
            render("CRUD/blank.html", type);
 
133
        }
 
134
    }
 
135
 
 
136
    public static void create() throws Exception {
 
137
        ObjectType type = ObjectType.get(getControllerClass());
 
138
        notFoundIfNull(type);
 
139
        JPASupport object = type.entityClass.newInstance();
 
140
        validation.valid(object.edit("object", params));
 
141
        if (validation.hasErrors()) {
 
142
            renderArgs.put("error", Messages.get("crud.hasErrors"));
 
143
            try {
 
144
                render(request.controller.replace(".", "/") + "/blank.html", type);
 
145
            } catch (TemplateNotFoundException e) {
 
146
                render("CRUD/blank.html", type);
 
147
            }
 
148
        }
 
149
        object.save();
 
150
        flash.success(Messages.get("crud.created", type.modelName, object.getEntityId()));
 
151
        if (params.get("_save") != null) {
 
152
            redirect(request.controller + ".list");
 
153
        }
 
154
        if (params.get("_saveAndAddAnother") != null) {
 
155
            redirect(request.controller + ".blank");
 
156
        }
 
157
        redirect(request.controller + ".show", object.getEntityId());
 
158
    }
 
159
 
 
160
    public static void delete(String id) {
 
161
        ObjectType type = ObjectType.get(getControllerClass());
 
162
        notFoundIfNull(type);
 
163
        JPASupport object = type.findById(id);
 
164
        try {
 
165
            object.delete();
 
166
        } catch (Exception e) {
 
167
            flash.error(Messages.get("crud.delete.error", type.modelName, object.getEntityId()));
 
168
            redirect(request.controller + ".show", object.getEntityId());
 
169
        }
 
170
        flash.success(Messages.get("crud.deleted", type.modelName, object.getEntityId()));
 
171
        redirect(request.controller + ".list");
 
172
    }
 
173
 
 
174
    // ~~~~~~~~~~~~~
 
175
    @Retention(RetentionPolicy.RUNTIME)
 
176
    @Target(ElementType.TYPE)
 
177
    public @interface For {
 
178
 
 
179
        Class value();
 
180
    }
 
181
 
 
182
    // ~~~~~~~~~~~~~
 
183
    static int getPageSize() {
 
184
        return Integer.parseInt(Play.configuration.getProperty("crud.pageSize", "30"));
 
185
    }
 
186
 
 
187
    public static class ObjectType implements Comparable<ObjectType> {
 
188
 
 
189
        public Class<? extends CRUD> controllerClass;
 
190
        public Class<? extends JPASupport> entityClass;
 
191
        public String name;
 
192
        public String modelName;
 
193
        public String controllerName;
 
194
 
 
195
        public ObjectType(Class modelClass) {
 
196
            this.modelName = modelClass.getSimpleName();
 
197
            this.entityClass = modelClass;
 
198
        }
 
199
 
 
200
        public ObjectType(String modelClass) throws ClassNotFoundException {
 
201
            this(Play.classloader.loadClass(modelClass));
 
202
        }
 
203
 
 
204
        public static ObjectType forClass(String modelClass) throws ClassNotFoundException {
 
205
            return new ObjectType(modelClass);
 
206
        }
 
207
 
 
208
        public static ObjectType get(Class controllerClass) {
 
209
            Class entityClass = getEntityClassForController(controllerClass);
 
210
            if (entityClass == null || !JPASupport.class.isAssignableFrom(entityClass)) {
 
211
                return null;
 
212
            }
 
213
            ObjectType type = new ObjectType(entityClass);
 
214
            type.name = controllerClass.getSimpleName();
 
215
            type.controllerName = controllerClass.getSimpleName().toLowerCase();
 
216
            type.controllerClass = controllerClass;
 
217
            return type;
 
218
        }
 
219
 
 
220
        public static Class getEntityClassForController(Class controllerClass) {
 
221
            if (controllerClass.isAnnotationPresent(For.class)) {
 
222
                return ((For) (controllerClass.getAnnotation(For.class))).value();
 
223
            }
 
224
            String name = controllerClass.getSimpleName();
 
225
            name = "models." + name.substring(0, name.length() - 1);
 
226
            try {
 
227
                return Play.classloader.loadClass(name);
 
228
            } catch (ClassNotFoundException e) {
 
229
                return null;
 
230
            }
 
231
        }
 
232
 
 
233
        public Object getListAction() {
 
234
            return Router.reverse(controllerClass.getName() + ".list");
 
235
        }
 
236
 
 
237
        public Object getBlankAction() {
 
238
            return Router.reverse(controllerClass.getName() + ".blank");
 
239
        }
 
240
 
 
241
        public Long count(String search, String searchFields, String where) {
 
242
            String q = "select count(e) from " + entityClass.getName() + " e";
 
243
            if (search != null && !search.equals("")) {
 
244
                String searchQuery = getSearchQuery(searchFields);
 
245
                if (!searchQuery.equals("")) {
 
246
                    q += " where (" + searchQuery + ")";
 
247
                }
 
248
                q += (where != null ? " and " + where : "");
 
249
            } else {
 
250
                q += (where != null ? " where " + where : "");
 
251
            }
 
252
            Query query = JPA.em().createQuery(q);
 
253
            if (search != null && !search.equals("") && q.indexOf("?1") != -1) {
 
254
                query.setParameter(1, "%" + search.toLowerCase() + "%");
 
255
            }
 
256
            return Long.decode(query.getSingleResult().toString());
 
257
        }
 
258
 
 
259
        public List findPage(int page, String search, String searchFields, String orderBy, String order, String where) {
 
260
            int pageLength = getPageSize();
 
261
            String q = "from " + entityClass.getName();
 
262
            if (search != null && !search.equals("")) {
 
263
                String searchQuery = getSearchQuery(searchFields);
 
264
                if (!searchQuery.equals("")) {
 
265
                    q += " where (" + searchQuery + ")";
 
266
                }
 
267
                q += (where != null ? " and " + where : "");
 
268
            } else {
 
269
                q += (where != null ? " where " + where : "");
 
270
            }
 
271
            if (orderBy == null && order == null) {
 
272
                orderBy = "id";
 
273
                order = "ASC";
 
274
            }
 
275
            if (orderBy == null && order != null) {
 
276
                orderBy = "id";
 
277
            }
 
278
            if (order == null || (!order.equals("ASC") && !order.equals("DESC"))) {
 
279
                order = "ASC";
 
280
            }
 
281
            q += " order by " + orderBy + " " + order;
 
282
            Query query = JPA.em().createQuery(q);
 
283
            if (search != null && !search.equals("") && q.indexOf("?1") != -1) {
 
284
                query.setParameter(1, "%" + search.toLowerCase() + "%");
 
285
            }
 
286
            query.setFirstResult((page - 1) * pageLength);
 
287
            query.setMaxResults(pageLength);
 
288
            return query.getResultList();
 
289
        }
 
290
 
 
291
        public String getSearchQuery(String searchFields) {
 
292
            List<String> fields = null;
 
293
            if (searchFields != null && !searchFields.equals("")) {
 
294
                fields = Arrays.asList(searchFields.split("[ ]"));
 
295
            }
 
296
            String q = "";
 
297
            for (ObjectField field : getFields()) {
 
298
                if (field.searchable && (fields == null ? true : fields.contains(field.name))) {
 
299
                    if (!q.equals("")) {
 
300
                        q += " or ";
 
301
                    }
 
302
                    q += "lower(" + field.name + ") like ?1";
 
303
                }
 
304
            }
 
305
            return q;
 
306
        }
 
307
 
 
308
        public JPASupport findById(Object id) {
 
309
            Query query = JPA.em().createQuery("from " + entityClass.getName() + " where id = ?");
 
310
            try {
 
311
                query.setParameter(1, play.data.binding.Binder.directBind(id + "", play.db.jpa.JPASupport.findKeyType(entityClass)));
 
312
            } catch (Exception e) {
 
313
                throw new RuntimeException("Something bad with id type ?", e);
 
314
            }
 
315
            return (JPASupport) query.getSingleResult();
 
316
        }
 
317
 
 
318
        public List<ObjectField> getFields() {
 
319
            List fields = new ArrayList();
 
320
            for (Field f : entityClass.getFields()) {
 
321
                if (Modifier.isTransient(f.getModifiers()) || Modifier.isFinal(f.getModifiers())) {
 
322
                    continue;
 
323
                }
 
324
                ObjectField of = new ObjectField(f);
 
325
                if (of.type != null) {
 
326
                    fields.add(of);
 
327
                }
 
328
            }
 
329
            return fields;
 
330
        }
 
331
 
 
332
        public ObjectField getField(String name) {
 
333
            for (ObjectField field : getFields()) {
 
334
                if (field.name.equals(name)) {
 
335
                    return field;
 
336
                }
 
337
            }
 
338
            return null;
 
339
        }
 
340
 
 
341
        public int compareTo(ObjectType other) {
 
342
            return modelName.compareTo(other.modelName);
 
343
        }
 
344
 
 
345
        public static class ObjectField {
 
346
 
 
347
            public String type = "unknown";
 
348
            public String name;
 
349
            public String relation;
 
350
            public boolean multiple;
 
351
            public boolean searchable;
 
352
            public Object[] choices;
 
353
            public boolean required;
 
354
            public String serializedValue;
 
355
 
 
356
            public ObjectField(Field field) {
 
357
                if (CharSequence.class.isAssignableFrom(field.getType())) {
 
358
                    type = "text";
 
359
                    searchable = true;
 
360
                    if (field.isAnnotationPresent(MaxSize.class)) {
 
361
                        int maxSize = field.getAnnotation(MaxSize.class).value();
 
362
                        if (maxSize > 100) {
 
363
                            type = "longtext";
 
364
                        }
 
365
                    }
 
366
                    if (field.isAnnotationPresent(Password.class)) {
 
367
                        type = "password";
 
368
                    }
 
369
                }
 
370
                if (Number.class.isAssignableFrom(field.getType()) || field.getType().equals(double.class) || field.getType().equals(int.class) || field.getType().equals(long.class)) {
 
371
                    type = "number";
 
372
                }
 
373
                if (Boolean.class.isAssignableFrom(field.getType()) || field.getType().equals(boolean.class)) {
 
374
                    type = "boolean";
 
375
                }
 
376
                if (Date.class.isAssignableFrom(field.getType())) {
 
377
                    type = "date";
 
378
                }
 
379
                if (byte[].class.isAssignableFrom(field.getType())) {
 
380
                    type = "byte";
 
381
                }
 
382
                if (FileAttachment.class.isAssignableFrom(field.getType())) {
 
383
                    type = "file";
 
384
                }
 
385
                if (JPASupport.class.isAssignableFrom(field.getType())) {
 
386
                    if (field.isAnnotationPresent(OneToOne.class)) {
 
387
                        if (field.getAnnotation(OneToOne.class).mappedBy().equals("")) {
 
388
                            type = "relation";
 
389
                            relation = field.getType().getName();
 
390
                        }
 
391
                    }
 
392
                    if (field.isAnnotationPresent(ManyToOne.class)) {
 
393
                        type = "relation";
 
394
                        relation = field.getType().getName();
 
395
                    }
 
396
                }
 
397
                if (Collection.class.isAssignableFrom(field.getType())) {
 
398
                    Class fieldType = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
 
399
                    if (field.isAnnotationPresent(OneToMany.class)) {
 
400
                        if (field.getAnnotation(OneToMany.class).mappedBy().equals("")) {
 
401
                            type = "relation";
 
402
                            relation = fieldType.getName();
 
403
                            multiple = true;
 
404
                        }
 
405
                    }
 
406
                    if (field.isAnnotationPresent(ManyToMany.class)) {
 
407
                        if (field.getAnnotation(ManyToMany.class).mappedBy().equals("")) {
 
408
                            type = "relation";
 
409
                            relation = fieldType.getName();
 
410
                            multiple = true;
 
411
                        }
 
412
                    }
 
413
                }
 
414
                if (Collection.class.isAssignableFrom(field.getType())) {
 
415
                    if (!(field.isAnnotationPresent(OneToMany.class) ||
 
416
                            (field.isAnnotationPresent(ManyToMany.class)))) {
 
417
                        type = "serializedText";
 
418
                    }
 
419
                }
 
420
                if (field.getType().isEnum()) {
 
421
                    type = "enum";
 
422
                    relation = field.getType().getSimpleName();
 
423
                    choices = field.getType().getEnumConstants();
 
424
                }
 
425
                if (field.isAnnotationPresent(Id.class)) {
 
426
                    type = null;
 
427
                }
 
428
                if (field.isAnnotationPresent(Transient.class)) {
 
429
                    type = null;
 
430
                }
 
431
                if (field.isAnnotationPresent(Required.class)) {
 
432
                    required = true;
 
433
                }
 
434
                name = field.getName();
 
435
            }
 
436
 
 
437
            public Object[] getChoices() {
 
438
                return choices;
 
439
            }
 
440
        }
 
441
    }
 
442
 
 
443
    public static String collectionSerializer(Collection<?> coll) {
 
444
        StringBuffer sb = new StringBuffer();
 
445
        for (Object obj : coll) {
 
446
            sb.append("\"" + obj.toString() + "\",");
 
447
        }
 
448
        if (sb.length() > 2) {
 
449
            return sb.substring(0, sb.length() - 1);
 
450
        }
 
451
        return null;
 
452
 
 
453
    }
 
454
 
 
455
    public static String arraySerializer(Object[] coll) {
 
456
       return collectionSerializer(Arrays.asList(coll));
 
457
    }
 
458
 
 
459
    public static Collection<?> collectionDeserializer(String target, Class<?> type) {
 
460
        String[] targets = target.trim().split(",");
 
461
        Collection results;
 
462
        Logger.info("type [" + type + "]");
 
463
        if (List.class.isAssignableFrom(type)) {
 
464
            results = new ArrayList();
 
465
        } else {
 
466
            results = new TreeSet();
 
467
        }
 
468
        for (String targ : targets) {
 
469
            if (targ.length() > 1) {
 
470
                targ = targ.substring(1, targ.length() - 1);
 
471
            }
 
472
            if (type.isEnum()) {
 
473
                Object[] constants = type.getEnumConstants();
 
474
                for (Object c : constants) {
 
475
                    if  (c.toString().equals(targ)) {
 
476
                        results.add(c);
 
477
                    }
 
478
                }
 
479
            } else if (CharSequence.class.isAssignableFrom(type)) {
 
480
                results.add(targ);
 
481
            } else if (Integer.class.isAssignableFrom(type)) {
 
482
                results.add(Integer.valueOf(targ));
 
483
            } else if (Float.class.isAssignableFrom(type)) {
 
484
                results.add(Float.valueOf(targ));
 
485
            } else if (Boolean.class.isAssignableFrom(type)) {
 
486
                 results.add(Boolean.valueOf(targ));
 
487
            } else if (Double.class.isAssignableFrom(type)) {
 
488
                 results.add(Double.valueOf(targ));
 
489
            } else if (Long.class.isAssignableFrom(type)) {
 
490
                results.add(Long.valueOf(targ));
 
491
            }  else if (Byte.class.isAssignableFrom(type)) {
 
492
                 results.add(Byte.valueOf(targ));
 
493
            }
 
494
        }
 
495
 
 
496
        return results;
 
497
 
 
498
    }
 
499
}
 
500