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

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

Added five controller actions (RestController?) and corresponding Rest Wrapper (CommunicationManager?) methods for Rest communication with DSP.
The contents of three actions still need to be completed.
Authentication is still in a dummy method. When Michael has figured out how to do the authentication, it will be added.

File size: 9.6 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    def public static DSPServerURL  = "http://localhost:8080/gscf"
31
32     
33
34    /**
35     * Get the results of provided by a rest Rest resource.
36     *
37     * @params String resource The name of the resource, e.g. importer/pages
38     * @params Map params      A Map of parmater names and values., e.g. ['externalAssayID':12]
39     * @return String url   
40     */
41    public static Object getRestResource( RestServerURL, resource, params ) {
42                def url = getRestURL( RestServerURL, resource, params )
43                return  JSON.parse( url.newReader() )
44    }
45
46
47    /**
48     * Convenience method for constructing URLs for SAM that need parameters.
49     * Note that parameters are first convereted to strings by calling their toString() method
50     * and then Encoded to protect special characters.
51     *
52     * @params String resource The name of the resource, e.g. importer/pages
53     * @params Map params      A Map of parmater names and values., e.g. ['externalAssayID':12]
54     * @return String url   
55     */
56    public static URL getRestURL( RestServerURL, resource, params ) {
57        def url = RestServerURL + '/' + resource
58                def first = true
59                println "url: " + url
60                params.each { name, value ->
61                        if(first) {
62                                first = false
63                                url += '/nil?' + name + "=" + URLEncoder.encode( value.toString(), Encoding )
64                        }
65                        else { 
66                                url += '&' + name + "=" + URLEncoder.encode( value.toString(), Encoding  )
67                        }
68                }
69                return new URL( url )
70    }
71
72
73
74    /**
75     * This method dynamically adds a static method to the CommunicationManager.
76     * 
77     * @params String serverURL         A rest server URL.
78     * @params String restName          The name of a rest resource on the server.     
79     * @params Map params               A list of parameter names to be passed to this resource.
80     * @return String url   
81     * 
82     * Given a rest resource at serverURL called resourceName, we register a static method
83     * for the CommunicationManager. The new method has the same name and arity as the resource.
84     * 
85     * Example: Suppopse http://localhost:8080/gscf/rest/getSamples is a Rest resource.
86     * 
87     * In our grails app, we would like to connect to this service. We want to have a
88     * method getSamples() that fetches the result from the service. We do this by calling
89     * 
90     *          CommunicationManager.addRestWrapper( 'http://localhost:8080/gscf/rest', 'getSamples', ['externalStudyID'] )
91     * 
92     * This registers a new method:
93     * 
94         *               public static Object CommunicationManager.getSamples( Object arg )
95     * 
96     * This method has arrity 1 and expects to be given a map. The map is the parameter map
97     * of the rest service getSamples. It maps parameter called "externalStudyID" to some object
98     * that is passed. So, it can be called like as follows:
99     * 
100     *      def sampleList = CommunicationManager.getSamples( [externalStudyID:4711] )
101     * 
102     *  The call will deliver the results of the parameterized rest resource given at:
103     * 
104     *          http://localhost:8080/gscf/rest/nil?externalStudyID=4711
105     *
106     */
107
108    public static addRestWrapper( serverURL, restName, params = [], closure = { return it } ) {
109                CommunicationManager.metaClass.registerStaticMethod( restName ) { Object [] strangeGroovyArgs ->
110                        def map = [:]
111                    def args = strangeGroovyArgs[0]        // groovy nests the parameters of the methods in some other array
112                        for( i in 0..(params.size-1) ) {
113                                def param = params[i]
114                            map[param] = args[i]
115                        }
116                        return closure( getRestResource( serverURL, restName, map ) )
117                }
118        }
119
120
121
122
123
124    /**
125     * This method dynamically registers a static method to the CommunicationManager. The new method
126     * gives url for a Grails view on some server and takes as arguments the arguments required
127     * as params by the view.
128     * 
129     * @params String methodname        The name for method to be registered.
130     * @params String serverURL         The server's URL.
131     * @params String viewName          The view's name, e.g., '/Assay/show'
132     * @params Map params               The parameter list required by this view.
133     * @return String URL
134     * 
135     */ 
136    public static addViewWrapper( methodName, serverURL, viewName, params = [] ) {
137
138                CommunicationManager.metaClass.registerStaticMethod( methodName ) { Object [] strangeGroovyArgs ->
139                        def map = [:]
140                    def args = strangeGroovyArgs[0]        // groovy nests the parameters of the methods in some other array
141                        for( i in 0..(params.size-1) ) {
142                                def param = params[i]
143                            map[param] = args[i]
144                        }
145                        return getRestURL( serverURL, viewName, map )
146                }
147    }
148
149
150    /**
151     *  This creates on run time new methods for accessing Rest resources that GSCF provides for SAM.
152     *  This method should be called in grails-app/conf/BootStrap.groovy in the SAM module.
153     */ 
154    public static registerRestWrapperMethodsGSCFtoSAM() {
155        def url = GSCFServerURL + '/rest'
156                addRestWrapper( url , 'getStudies' )
157                addRestWrapper( url , 'getSubjects', ['externalStudyID'] )
158                addRestWrapper( url , 'getAssays',   ['externalStudyID'] )
159                addRestWrapper( url , 'getSamples',  ['externalAssayID'] )
160    }
161
162
163    /**
164     *  This method creates on run time new methods for accessing Grails views that SAM provides for GSCF.
165     *  This method should be called in grails-app/conf/BootStrap.groovy in the GSCF module.
166     */ 
167    public static registerRestWrapperMethodsSAMtoGSCF() {
168                def url = SAMServerURL
169
170                // register method that links to the SAM view for importing a SimpleAssay.
171        // parameters: externalAssayID, an externalAssayID
172                addViewWrapper( 'getAssayImportURL', url, 'importer/pages', ['externalAssayID', 'externalStudyID'] )
173
174                // register method that links to the SAM view for showing a SimpleAssay
175        // parameters: externalAssayID
176                addViewWrapper( 'getAssayShowURL', url, 'simpleAssay/show', ['externalAssayID'] )
177
178                // register method that links to the SAM view for editing a SimpleAssay
179        // parameters: externalAssayID
180                addViewWrapper( 'getAssayEditURL', url, 'simpleAssay/show', ['externalAssayID'] )
181
182                // register method that links to the SAM view for editing a SimpleAssay
183        // parameters: externalAssayID
184                addViewWrapper( 'getMeasurementTypesURL', url, 'simpleAssayMeasurementType/list', ['externalStudyID'] )
185
186                // register rest resource that returns the results of a full text query on SAM
187        // parameters:   query. A string for fulltext search on SAM
188        // return value: results map. It contains two keys 'studyIds', and 'assays'. 'studyIds'
189                //               key maps to a list of Study domain objects of GSCF. 'assays' map to a
190                //               list of pairs. Each pair consists of an Assay domain object of GSCF and
191                //               additional assay information from SAM provided as a map.
192                // Example of a returned map:
193                //                               ["studies":[NuGO PPS human study],
194                //               "assays":[[["isIntake":false, "isDrug":false, "correctionMethod":"test Correction Method 1", "detectableLimit":1, "isNew":false,
195                //               "class":"data.SimpleAssay", "externalAssayID":"1", "id":1, "measurements":null, "unit":"Insulin", "inSerum":false,
196        //                               "name":"test Simple Assay 1", "referenceValues":"test Reference Values 1"], dbnp.studycapturing.Assay : 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     *  This method creates on run time new methods for accessing Grails views that SAM provides for GSCF.
217     *  This method should be called in grails-app/conf/BootStrap.groovy in the GSCF module.
218     */ 
219    public static registerRestWrapperMethodsGSCFtoDSP() {
220                def url = DSPServerURL
221                addRestWrapper( url, 'isUser',  ['username','password'] )
222                addRestWrapper( url, 'listStudies',  ['username','password'] )
223                addRestWrapper( url, 'listStudySamples',  ['username','password','study_token'] )
224                addRestWrapper( url, 'getStudy',  ['username','password','study_token'] )
225                addRestWrapper( url, 'getStudySample',  ['username','password','study_token','sample_token'] )
226                addRestWrapper( url, 'isUser',  ['username','password'] )
227    }
228
229
230
231}
Note: See TracBrowser for help on using the repository browser.