source: trunk/src/groovy/dbnp/rest/common/CommunicationManager.groovy @ 646

Last change on this file since 646 was 646, checked in by jahn, 10 years ago

Fixed rest url.

File size: 8.7 KB
Line 
1package dbnp.rest.common
2
3import grails.converters.JSON
4import java.net.URLEncoder
5import org.codehaus.groovy.grails.web.json.*
6
7/**  CommunicationManager
8 *
9 *   @author Jahn
10 *
11 *   This class manages communication between dbNP modules such as GSCF and SAM.
12 *   By communication we mean two ways of exchanging information: (1) via Rest resources,
13 *   and (2) via Grails views that a module can make available to another module.
14 *
15 *   For Rest communication this class implements a Rest client that fetches data
16 *   from other modules' Rest resources. The Rest implementation transfers data in JSON.
17 *
18 *   Note: Do not use this class directly to fetch data. Instead use your module's
19 *   rest wrapper methods. Use this module, to create these rest wrapper methods.
20 *   For instance, use dbnp.rest.sam.registerRestWrapperMethodsGSCFtoSAM to register new methods
21 *   for accessing GSCF's Rest service in SAM; your new method shoud then use this class.
22 */
23
24
25class CommunicationManager {
26
27    def        static Encoding      = "UTF-8" 
28    def public static SAMServerURL  = "http://localhost:8182/sam"
29    def public static GSCFServerURL = "http://localhost:8080/gscf"
30
31     
32
33    /**
34     * Get the results of provided by a rest Rest resource.
35     *
36     * @params String resource The name of the resource, e.g. importer/pages
37     * @params Map params      A Map of parmater names and values., e.g. ['externalAssayID':12]
38     * @return String url   
39     */
40    public static Object getRestResource( RestServerURL, resource, params ) {
41                def url = getRestURL( RestServerURL, resource, params )
42                return  JSON.parse( url.newReader() )
43    }
44
45
46    /**
47     * Convenience method for constructing URLs for SAM that need parameters.
48     * Note that parameters are first convereted to strings by calling their toString() method
49     * and then Encoded to protect special characters.
50     *
51     * @params String resource The name of the resource, e.g. importer/pages
52     * @params Map params      A Map of parmater names and values., e.g. ['externalAssayID':12]
53     * @return String url   
54     */
55    public static URL getRestURL( RestServerURL, resource, params ) {
56        def url = RestServerURL + '/' + resource
57                def first = true
58                println "url: " + url
59                params.each { name, value ->
60                        if(first) {
61                                first = false
62                                url += '/nil?' + name + "=" + URLEncoder.encode( value.toString(), Encoding )
63                        }
64                        else { 
65                                url += '&' + name + "=" + URLEncoder.encode( value.toString(), Encoding  )
66                        }
67                }
68                return new URL( url )
69    }
70
71
72
73    /**
74     * This method dynamically adds a static method to the CommunicationManager.
75     * 
76     * @params String serverURL         A rest server URL.
77     * @params String restName          The name of a rest resource on the server.     
78     * @params Map params               A list of parameter names to be passed to this resource.
79     * @return String url   
80     * 
81     * Given a rest resource at serverURL called resourceName, we register a static method
82     * for the CommunicationManager. The new method has the same name and arity as the resource.
83     * 
84     * Example: Suppopse http://localhost:8080/gscf/rest/getSamples is a Rest resource.
85     * 
86     * In our grails app, we would like to connect to this service. We want to have a
87     * method getSamples() that fetches the result from the service. We do this by calling
88     * 
89     *          CommunicationManager.addRestWrapper( 'http://localhost:8080/gscf/rest', 'getSamples', ['externalStudyID'] )
90     * 
91     * This registers a new method:
92     * 
93         *               public static Object CommunicationManager.getSamples( Object arg )
94     * 
95     * This method has arrity 1 and expects to be given a map. The map is the parameter map
96     * of the rest service getSamples. It maps parameter called "externalStudyID" to some object
97     * that is passed. So, it can be called like as follows:
98     * 
99     *      def sampleList = CommunicationManager.getSamples( [externalStudyID:4711] )
100     * 
101     *  The call will deliver the results of the parameterized rest resource given at:
102     * 
103     *          http://localhost:8080/gscf/rest/nil?externalStudyID=4711
104     *
105     */
106
107    public static addRestWrapper( serverURL, restName, params = [], closure = { return it } ) {
108                CommunicationManager.metaClass.registerStaticMethod( restName ) { Object [] strangeGroovyArgs ->
109                        def map = [:]
110                    def args = strangeGroovyArgs[0]        // groovy nests the parameters of the methods in some other array
111                        for( i in 0..(params.size-1) ) {
112                                def param = params[i]
113                            map[param] = args[i]
114                        }
115                        return closure( getRestResource( serverURL, restName, map ) )
116                }
117        }
118
119
120
121
122
123    /**
124     * This method dynamically registers a static method to the CommunicationManager. The new method
125     * gives url for a Grails view on some server and takes as arguments the arguments required
126     * as params by the view.
127     * 
128     * @params String methodname        The name for method to be registered.
129     * @params String serverURL         The server's URL.
130     * @params String viewName          The view's name, e.g., '/Assay/show'
131     * @params Map params               The parameter list required by this view.
132     * @return String URL
133     * 
134     */ 
135    public static addViewWrapper( methodName, serverURL, viewName, params = [] ) {
136
137                CommunicationManager.metaClass.registerStaticMethod( methodName ) { Object [] strangeGroovyArgs ->
138                        def map = [:]
139                    def args = strangeGroovyArgs[0]        // groovy nests the parameters of the methods in some other array
140                        for( i in 0..(params.size-1) ) {
141                                def param = params[i]
142                            map[param] = args[i]
143                        }
144                        return getRestURL( serverURL, viewName, map )
145                }
146    }
147
148
149    /**
150     *  This creates on run time new methods for accessing Rest resources that GSCF provides for SAM.
151     *  This method should be called in grails-app/conf/BootStrap.groovy in the SAM module.
152     */ 
153    public static registerRestWrapperMethodsGSCFtoSAM() {
154        def url = GSCFServerURL + '/rest'
155                addRestWrapper( url , 'getStudies' )
156                addRestWrapper( url , 'getSubjects', ['externalStudyID'] )
157                addRestWrapper( url , 'getAssays',   ['externalStudyID'] )
158                addRestWrapper( url , 'getSamples',  ['externalAssayID'] )
159    }
160
161
162    /**
163     *  This method creates on run time new methods for accessing Grails views that SAM provides for GSCF.
164     *  This method should be called in grails-app/conf/BootStrap.groovy in the GSCF module.
165     */ 
166    public static registerRestWrapperMethodsSAMtoGSCF() {
167                def url = SAMServerURL
168
169                // register method that links to the SAM view for importing a SimpleAssay.
170        // parameters: externalAssayID, an externalAssayID
171                addViewWrapper( 'getAssayImportURL', url, 'importer/pages', ['externalAssayID', 'externalStudyID'] )
172
173                // register method that links to the SAM view for showing a SimpleAssay
174        // parameters: externalAssayID
175                addViewWrapper( 'getAssayShowURL', url, 'simpleAssay/show', ['externalAssayID'] )
176
177                // register method that links to the SAM view for editing a SimpleAssay
178        // parameters: externalAssayID
179                addViewWrapper( 'getAssayEditURL', url, 'simpleAssay/show', ['externalAssayID'] )
180
181                // register method that links to the SAM view for editing a SimpleAssay
182        // parameters: externalAssayID
183                addViewWrapper( 'getMeasurementTypesURL', url, 'simpleAssayMeasurementType/list', ['externalStudyID'] )
184
185                // register rest resource that returns the results of a full text query on SAM
186        // parameters:   query. A string for fulltext search on SAM
187        // return value: results map. It contains two keys 'studyIds', and 'assays'. 'studyIds'
188                //               key maps to a list of Study domain objects of GSCF. 'assays' map to a
189                //               list of pairs. Each pair consists of an Assay domain object of GSCF and
190                //               additional assay information from SAM provided as a map.
191                // Example of a returned map:
192                //               [studyIds:[PPSH],
193                //                               assays:[[isIntake:false, isDrug:false, correctionMethod:test Correction Method 1,
194                //                               detectableLimit:1, isNew:false, class:data.SimpleAssay, externalAssayID:1, id:1,
195                //                               measurements:null, unit:Insulin, inSerum:false, name:test Simple Assay 1,
196                //                               referenceValues:test Reference Values 1]]]
197                def closure = { map -> 
198                    def studies = []   
199                    def assays  = []   
200                        def studiesHQ = "from dbnp.studycapturing.Study as s where s.code=?"
201                        map['studyIds'].each { studies.add( dbnp.studycapturing.Study.find(studiesHQ,[it]) ) }
202                        map['assays'].each { samAssay ->
203                                def assayID = samAssay['externalAssayID']
204                            def assayHQ = "from dbnp.studycapturing.Assay as a where a.externalAssayID='${assayID}'"
205                                def assay = dbnp.studycapturing.Assay.find(assayHQ)
206                                assays.add( [samAssay,assay] )
207                        } 
208                        return [studies:studies, assays:assays] 
209                }
210
211                addRestWrapper( url+'/rest', 'getQueryResult',  ['query'], closure )
212               
213    }
214
215
216}
Note: See TracBrowser for help on using the repository browser.