root/trunk/grails-app/domain/dbnp/studycapturing/Template.groovy @ 1348

Revision 1348, 8.4 KB (checked in by work@…, 3 years ago)

- fix for Javassist issue #254, needs some thorough testing...

  • Property svn:keywords set to Author Date Rev
Line 
1package dbnp.studycapturing
2
3import dbnp.authentication.SecUser
4import dbnp.authentication.AuthenticationService
5
6/**
7 * The Template class describes a TemplateEntity template, which is basically an extension of the study capture entities
8 * in terms of extra fields (which are described by classes that extend the TemplateField class).
9 * Study, Subject, Sample and Event are all TemplateEntities.
10 *
11 * Within a Template, we have two different types of fields: 'domain fields' and 'template fields'.
12 * The domain fields are TemplateFields which are given by the TemplateEntity itself and therefore always present
13 * in any instance of that TemplateEntity. They are specified by implementing TemplateEntity.giveDomainFields()
14 * The template fields are TemplateFields which are added specifically by the Template. They are specified
15 * in the fields property of the Template object which is referenced by the TemplateEntity.template property.
16 *
17 * Revision information:
18 * $Rev$
19 * $Author$
20 * $Date$
21 */
22class Template implements Serializable {
23
24        /** The name of the template */
25        String name
26
27        /** A string describing the template to other users */
28        String description
29
30        /** The target TemplateEntity for this template */
31        Class entity
32
33        /** The owner of the template. If the owner is not defined, it is a shared/public template */
34        SecUser owner
35
36        /** The template fields which are the members of this template. This is a List to preserve the field order */
37        List fields
38
39        static hasMany = [fields: TemplateField]
40        static mapping = {
41        }
42
43        // constraints
44        static constraints = {
45                owner(nullable: true, blank: true)
46                description(nullable: true, blank: true)
47
48                fields(validator: { fields, obj, errors ->
49                        // 'obj' refers to the actual Template object
50
51                        // define a boolean
52                        def error = false
53
54                        // iterate through fields
55                        fields.each { field ->
56                                // check if the field entity is the same as the template entity
57                                if (!field.entity.equals(obj.entity)) {
58                                        error = true
59                                        errors.rejectValue(
60                                                'fields',
61                                                'templateEntity.entityMismatch',
62                                                [field.name, obj.entity, field.entity] as Object[],
63                                                'Template field {0} must be of entity {1} and is currently of entity {2}'
64                                                )
65                                }
66                        }
67
68                        // got an error, or not?
69                        return (!error)
70                })
71
72                // outcommented for now due to bug in Grails / Hibernate
73                // see http://jira.codehaus.org/browse/GRAILS-6020
74                // This is to verify that the template name is unique with respect to the parent entity.
75                // TODO: this probably has to change in the case of private templates of different users,
76                // which can co-exist with the same name. See also TemplateField
77                // name(unique:['entity'])
78
79        }
80
81        public Template() {
82                super()
83        }
84
85        /**
86         * Creates a clone of the given other template and also copies its owner
87         *
88         * @param       otherTemplate
89         */
90        public Template( Template otherTemplate) {
91                this( otherTemplate, otherTemplate.owner )
92        }
93
94        /**
95         * Creates a clone of the given other template. The currently logged in user
96         * is set as the owner
97         * @param       otherTemplate
98         */
99        public Template( Template otherTemplate, SecUser owner ) {
100                this()
101
102                //authenticationService = new AuthenticationService()
103
104                this.name = otherTemplate.name + " (Copy)"
105                this.description = otherTemplate.description
106                this.entity = otherTemplate.entity
107                this.owner = owner
108
109                // The fields are copied by reference
110                this.fields = []
111                otherTemplate.fields.each {
112                        this.fields.add( it )
113                }
114        }
115
116        /**
117         * overloaded toString method
118         * @return String
119         */
120        def String toString() {
121                return this.name;
122        }
123
124        /**
125         * Check whether the contents of the other template and the current template are equal.
126         * For this check the name, description and owner don't matter. Also, the order of
127         * template fields doesn't matter
128         *
129         * @return      true iff this template and the other template are used for the same entity and
130         *                      the template contain the same template fields
131         */
132        public boolean contentEquals( Template otherTemplate ) {
133                if( otherTemplate == this )
134                        return true
135
136                if( otherTemplate == null )
137                        return false
138
139                if( otherTemplate.entity != this.entity )
140                        return false
141
142                // Check all template fields
143                def size1 = otherTemplate.fields?.size() ?: 0
144                def size2 = otherTemplate.fields?.size() ?: 0
145                if( size1 != size2 ) {
146                        return false
147                }
148
149                if( otherTemplate.fields != null && this.fields != null ) {
150                        for( def field in this.fields ) {
151                                def fieldFound = false;
152                                for( def otherField in otherTemplate.fields ) {
153                                        if( otherField.contentEquals( field ) ) {
154                                                fieldFound = true;
155                                                break
156                                        }
157                                }
158
159                                if( !fieldFound ) {
160                                        return false
161                                }
162                        }
163                }
164
165                // If all tests pass, the objects are content-equal
166                return true
167        }
168
169        /**
170         * Look up the type of a certain template subject field
171         * @param String fieldName The name of the template field
172         * @return String       The type (static member of TemplateFieldType) of the field, or null of the field does not exist
173         */
174        def TemplateFieldType getFieldType(String fieldName) {
175                def field = fields.find {
176                        it.name == fieldName
177                }
178                field?.type
179        }
180
181        /**
182         * get all field of a particular type
183         * @param Class fieldType
184         * @return Set < TemplateField >
185         */
186        def getFieldsByType(TemplateFieldType fieldType) {
187                def result = fields.findAll {
188                        it.type == fieldType
189                }
190                return result;
191        }
192
193        /**
194         * get all required fields
195         * @param Class fieldType
196         * @return Set < TemplateField >
197         */
198        def getRequiredFields() {
199                def result = fields.findAll {
200                        it.required == true
201                }
202                return result;
203        }
204
205        /**
206         * get all required fields
207         * @param Class fieldType
208         * @return Set < TemplateField >
209         */
210        def getRequiredFieldsByType(TemplateFieldType fieldType) {
211                def result = fields.findAll {
212                        (it.required == true && it.type == fieldType)
213                }
214                return result;
215        }
216
217        /**
218         * Checks whether this template is used by any object
219         *
220         * @returns             true iff this template is used by any object, false otherwise
221         */
222        def inUse() {
223                return (numUses() > 0 );
224        }
225
226        /**
227         * The number of objects that use this template
228         *
229         * @returns             the number of objects that use this template.
230         */
231        def numUses() {
232                // This template can only be used in objects of the right entity. Find objects of that
233                // entity and see whether they use this method.
234                //
235                // Unfortunately, due to the grails way of creating classes, we can not use reflection for this
236                def elements;
237                switch( this.entity ) {
238                        case Event:
239                                elements = Event.findAllByTemplate( this ); break;
240                        case Sample:
241                                elements = Sample.findAllByTemplate( this ); break;
242                        case Study:
243                                elements = Study.findAllByTemplate( this ); break;
244                        case Subject:
245                                elements = Subject.findAllByTemplate( this ); break;
246                        default:
247                                return 0;
248                }
249
250                return elements.size();
251        }
252
253        /**
254         * overloading the findAllByEntity method to make it function as expected
255         * @param Class entity (for example: dbnp.studycapturing.Subject)
256         * @return ArrayList
257         */
258        public static findAllByEntity(java.lang.Class entity) {
259                def results = []
260                // 'this' should not work in static context, so taking Template instead of this
261                Template.findAll().each() {
262                        if (entity.equals(it.entity)) {
263                                results[results.size()] = it
264                        }
265                }
266
267                return results
268        }
269
270        /**
271         * Create a new template based on the parsed XML object.
272         *
273         * @see grails.converters.XML#parse(java.lang.String)
274         * @throws IllegalArgumentException
275         * @throws ClassNotFoundException
276         *
277         */
278        public static parse(Object xmlObject, SecUser loggedInUser) {
279                def t = new Template();
280                t.name = xmlObject?.name?.text()
281                t.description = xmlObject?.description?.text()
282
283                // Check whether a correct entity is given. The parseEntity method might
284                // throw a ClassNotFoundException, but that is OK, it should be thrown if the class
285                // doesn't exist.
286                def entity = TemplateEntity.parseEntity( xmlObject.entity?.text() );
287                if( !entity ) {
288                        throw new Exception( "Incorrect entity given" );
289                }
290
291                t.entity = entity
292
293                // Set the owner to the currently logged in user
294                t.owner = loggedInUser
295
296                // Set all template fields
297                xmlObject.templateFields.templateField.each {
298                        def field = TemplateField.parse( it, entity );
299
300                        // Check whether a similar field already exists. For that, we search in all
301                        // template fields with the same name, in order to have as little comparisons
302                        // as possible
303                        for( def otherField in TemplateField.findAllByName( field?.name ) ) {
304                                if( field.contentEquals( otherField ) ) {
305                                        field = otherField;
306                                        break;
307                                }
308                        }
309                       
310                        t.addToFields( field );
311                }
312
313                return t
314        }
315}
Note: See TracBrowser for help on using the browser.