source: trunk/grails-app/services/dbnp/studyexport/ExportService.groovy @ 1561

Last change on this file since 1561 was 1561, checked in by s.h.sikkema@…, 12 years ago

Removed some imports and a reference to dbnp.studycapturing.Book to fix things

File size: 8.2 KB
Line 
1/**
2 *  ExporterService
3 * 
4 *  @author Jahn
5 * 
6 *  This service for exporting a Study and all domain objects depending on it to XML.
7 */ 
8
9
10
11package dbnp.studyexport
12
13import dbnp.authentication.*
14import dbnp.studycapturing.*
15import grails.converters.XML
16import groovy.util.slurpersupport.*
17import org.dbnp.gdt.*
18
19class ExportService 
20{
21
22    static transactional = true
23    static scope = "session"
24
25
26    def grailsApplication
27    /**
28     *  List of classes that recursion does not go further into when building an XML 
29     *  document.
30         * 
31         *  @see #getRelatedObjects().
32     */ 
33        def static IgnoredClasses = [ String, long, Date, Boolean, SecUser, Publication, SecUser ]
34
35
36    /**
37     *  List of classes that recursion does not go further into when building an XML 
38     *  document; the elements are still included.
39         * 
40         *  (For importing Study objects)
41         * 
42         *  @see #getRelatedObjects().
43     */ 
44        def static TerminalClasses = [ AssayModule, Identity, Ontology, PersonAffiliation, 
45                        PersonRole, Template, TemplateField, 
46                        TemplateFieldListItem, TemplateFieldType, Term ] 
47
48
49    /**
50     *  List of domain classes related to Study.
51     */ 
52        def static DomainClasses = [ 'RegistrationCode':dbnp.authentication.RegistrationCode,
53                        'SecRole':dbnp.authentication.SecRole, 'SecUser':dbnp.authentication.SecUser,
54                        'SecUserSecRole':dbnp.authentication.SecUserSecRole,
55                        'SessionAuthenticatedUser':dbnp.authentication.SessionAuthenticatedUser,
56                        'Assay':dbnp.studycapturing.Assay,
57                        'Event':dbnp.studycapturing.Event, 'EventGroup':dbnp.studycapturing.EventGroup,
58                        'PersonAffiliation':dbnp.studycapturing.PersonAffiliation,
59                        'Person':dbnp.studycapturing.Person,
60                        'PersonRole':dbnp.studycapturing.PersonRole,
61                        'Publication':dbnp.studycapturing.Publication,
62                        'Sample':dbnp.studycapturing.Sample,
63                        'SamplingEvent':dbnp.studycapturing.SamplingEvent,
64                        'Study':dbnp.studycapturing.Study,
65                        'StudyPerson':dbnp.studycapturing.StudyPerson,
66                        'Subject':dbnp.studycapturing.Subject,
67                        'AssayModule':org.dbnp.gdt.AssayModule,
68                        'Identity':org.dbnp.gdt.Identity,
69                        'RelTime':org.dbnp.gdt.RelTime,
70                        'TemplateEntity':org.dbnp.gdt.TemplateEntity,
71                        'TemplateField':org.dbnp.gdt.TemplateField,
72                        'TemplateFieldListItem':org.dbnp.gdt.TemplateFieldListItem,
73                        'TemplateFieldType':org.dbnp.gdt.TemplateFieldType,
74                        'Template':org.dbnp.gdt.Template ]
75
76
77        /**
78         *  Returns a list of all Grails domain objects relevant for creating a full
79         *  XML representation of a Study.
80         * 
81         *  The actual XML is then created by the controller using Grails' XML converter.
82         * 
83         *  @param Study
84         *
85         *  @return List of all Grails domain objects
86         */ 
87
88        def getDependentObjects( Study study ) {
89                return getRelatedObjects( study )
90        }
91
92
93        /**
94         *  Returns a list of Grails domain objects. 
95         * 
96         *  Helper method for getDependentObjects().
97         * 
98         *  This method produces a list of all objects that need to be
99         *  written out in order to get an XML representation of a Study object.
100         * 
101         *  This is achieved by recursion. The recursion stops at objects whose
102         *  class is member of IgnoredClasses or TerminalClasses.
103         * 
104         *      Example call:
105         * 
106         *              def objects = getDependentObjects( Study.get(1) )
107         *              (objects*.class).unique().sort().each { println it }
108         * 
109         *  @param domainObject  A grails domain object.
110         * 
111         *  @return List of all Grails domain objects
112         */ 
113
114        def     getRelatedObjects( domainObject ) {
115
116                if(domainObject==null) {
117                        return []
118                }
119
120                def domainClass = domainObject.class
121                def objects = []
122
123                if( IgnoredClasses.contains(domainClass) )   {
124                        return objects
125                }
126
127                if( domainClass.toString()==~/class dbnp.authentication.SecUser.+/ || 
128                    domainClass.toString()==~/class dbnp.studycapturing.Publication.+/ ) {
129                        return objects
130                }
131
132
133
134                if( TerminalClasses.contains(domainClass) )  {
135                        return [domainObject]
136                }
137
138                objects = [domainObject]
139
140                                                                                                // enter recursion with regular domain fields
141                domainObject.properties.domainFields.each { field ->
142                        objects.addAll( getRelatedObjects(field) )
143                }
144
145                                                                                                // enter recursion with hasMany fields
146                domainObject.getProperties().hasMany.each { property, theClass ->
147
148                        boolean isTemplateField = ( domainObject instanceof TemplateEntity  && 
149                                property==~/template(.+)Fields/ ) 
150                        if( !isTemplateField ) {
151                                domainObject."$property".each { 
152                                                objects.addAll( getRelatedObjects(it) )
153                                }
154                        }
155
156                }
157                return objects.unique()
158        }
159
160
161
162
163        /**
164         *  Parse XML object to List of objects to be translated into
165         *  a Study by getStudy().
166         * 
167         *  @param Study
168         *
169         *  @return List of all Grails domain objects
170         *
171         *  @see getStudy()
172         */ 
173
174        def     parseXMLStudy() {
175                XML.parse(new FileInputStream('/tmp/test.xml'), "UTF-8")
176        }
177
178
179
180        def     parseXMLStudyList( GPathResult result ) {
181                def parseObjects = 
182                        result.childNodes().collect { 
183                                new ParseObject(it) 
184                        }               
185                def study = createStudy( parseObjects ) 
186                study.save()   
187        }
188
189
190
191
192        /**
193         *  Create Study from list of objects repesenting a Study.
194         * 
195         *  (For importing Study objects)
196         * 
197         *  @param  List of objects representing a Study.
198         *
199         *  @return void
200         */ 
201
202        def createStudy( List parseObjects ) {
203                parseObjects.each{ 
204                        populateFields( it.domainObject, it.node, parseObjects )
205                }
206                parseObjects.each{ 
207                        populateOneToManies( it.domainObject, it.node, parseObjects )
208                }
209                parseObjects.each{ 
210                        populateTemplateFields( it.domainObject, it.node, parseObjects )
211                }
212        }
213
214
215
216        /**
217         *  Populate fields of a domainObject to be created.
218         *  The fields of a new object are filled with simple Class objects.
219         * 
220         *  (For importing Study objects)
221         * 
222         *  @param domainObject   The Object to be fielled 
223         * 
224         *  @param  List of ParseObjects representing a Study.
225         *
226         *  @return the new domainObject
227         */ 
228
229        def populateFields( domainObject, node, List parseObjects ) {
230
231                def fields = 
232                        domainObject.getProperties().domainFields.collect { it.toString() }
233
234                def map = [:]
235                domainObject.metaClass.getProperties().each { property ->
236                        def name = property.name
237                        def field = fields.find{ it == name }
238
239                        if(field) { 
240                                def type = property.type
241                                def value = node.children().find{ it.name == field }.text()
242
243                                switch(type) {
244                                        case String: map[field]=value; break
245                                        case Date: map[field] = Date.parse( 'yyyy-MM-dd', value ); break
246                                }
247                        }
248                }
249
250                def newDomainObject = domainObject.class.newInstance(map)
251                newDomainObject.id = 0
252                domainObject = newDomainObject
253        }
254
255
256
257        /**
258         *  Populate one-to-many maps of a new domainObject 
259         *  from list of ParseObjects.
260         * 
261         *  (For importing Study objects)
262         * 
263         *  @param domainObject   domainObject to be fielled 
264         * 
265         *  @param  List of parseObjects representing a Study.
266         *
267         *  @return the new domainObject
268         */ 
269       
270        def populateOneToManies( domainObject, node, parseObjects ) {
271                if( !domainObject.class.metaClass.getProperties().find{ it.name=='hasMany' } ) {
272                        return
273                }
274
275                domainObject.class.hasMany.each{ name, theClass ->
276                        node.children().each { child -> 
277                                if(child.name==name) {
278                                        child.children().each { grandChild ->
279                                                def id = grandChild.attributes.id
280                                                if(id) {
281                                                        def ref = parseObjects.find{ it.theClass==theClass && it.id==id }
282                                                        if(ref) {
283                                                                def addTo = "addTo" + name.replaceFirst(name[0],name[0].toUpperCase()) 
284                                                                domainObject.invokeMethod(addTo,(Object) ref.domainObject )
285                                                        }
286                                                }
287                                        }
288                                }
289                        }
290                }
291        }
292
293
294        def populateTemplateFields( domainObject, Node node, List parseObjects ) {
295        }
296
297
298
299        /**
300         *  Populate one-to-many maps of a new domainObject 
301         *  from list of ParseObjects.
302         *
303         *  (For importing Study objects)
304         *
305         *  @param domainObject   domainObject to be fielled 
306         * 
307         *  @param  List of parseObjects representing a Study.
308         *
309         *  @return the new domainObject
310         */ 
311
312        private class ParseObject { 
313                String tag
314                String id
315                Class theClass
316                Object domainObject
317                groovy.util.slurpersupport.Node node
318       
319
320                public ParseObject( node ){
321                        tag = node.name()
322                        theClass = getClassForTag( tag ) 
323                        domainObject = theClass.newInstance() 
324                        id = null
325                        if(node.attributes && node.attributes.id) {
326                                id = node.attributes.id
327                        }
328                        this.node=node
329                }
330
331                private static getClassForTag( String tag ) {
332                        def shortName = tag.replaceFirst( tag[0], tag[0].toUpperCase() )
333                        return DomainClasses[ shortName ] 
334                }
335
336        }
337
338}
Note: See TracBrowser for help on using the repository browser.