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

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

Added enhanced REST wrapper method for querying SAM.

File size: 9.2 KB
Line 
1package dbnp.rest.common
2
3import grails.converters.JSON
4import java.net.URLEncoder
5import org.codehaus.groovy.grails.web.json.*
6import dbnp.studycapturing.Study
7
8/**  CommunicationManager
9 *
10 *   @author Jahn
11 *
12 *   This class manages communication between dbNP modules such as GSCF and SAM.
13 *   By communication we mean two ways of exchanging information: (1) via Rest resources,
14 *   and (2) via Grails views that a module can make available to another module.
15 *
16 *   For Rest communication this class implements a Rest client that fetches data
17 *   from other modules' Rest resources. The Rest implementation transfers data in JSON.
18 *
19 *   Note: Do not use this class directly to fetch data. Instead use your module's
20 *   rest wrapper methods. Use this module, to create these rest wrapper methods.
21 *   For instance, use dbnp.rest.sam.registerRestWrapperMethodsGSCFtoSAM to register new methods
22 *   for accessing GSCF's Rest service in SAM; your new method shoud then use this class.
23 */
24
25
26class CommunicationManager {
27
28    def        static Encoding      = "UTF-8" 
29    def public static SAMServerURL  = "http://localhost:8182/sam"
30    def public static GSCFServerURL = "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        println "registered + ${restName}"
119        }
120
121
122
123
124
125    /**
126     * This method dynamically registers a static method to the CommunicationManager. The new method
127     * gives url for a Grails view on some server and takes as arguments the arguments required
128     * as params by the view.
129     * 
130     * @params String methodname        The name for method to be registered.
131     * @params String serverURL         The server's URL.
132     * @params String viewName          The view's name, e.g., '/Assay/show'
133     * @params Map params               The parameter list required by this view.
134     * @return String URL
135     * 
136     */ 
137    public static addViewWrapper( methodName, serverURL, viewName, params = [] ) {
138
139                CommunicationManager.metaClass.registerStaticMethod( methodName ) { Object [] strangeGroovyArgs ->
140                        def map = [:]
141                    def args = strangeGroovyArgs[0]        // groovy nests the parameters of the methods in some other array
142                        for( i in 0..(params.size-1) ) {
143                                def param = params[i]
144                            map[param] = args[i]
145                        }
146                        return getRestURL( serverURL, viewName, map )
147                }
148    }
149
150
151    /**
152     *  This creates on run time new methods for accessing Rest resources that GSCF provides for SAM.
153     *  This method should be called in grails-app/conf/BootStrap.groovy in the SAM module.
154     */ 
155    public static registerRestWrapperMethodsGSCFtoSAM() {
156        def url = GSCFServerURL
157                addRestWrapper( url , 'getStudies' )
158                addRestWrapper( url , 'getSubjects', ['externalStudyID'] )
159                addRestWrapper( url , 'getAssays',   ['externalStudyID'] )
160                addRestWrapper( url , 'getSamples',  ['externalAssayID'] )
161    }
162
163
164    /**
165     *  This method creates on run time new methods for accessing Grails views that SAM provides for GSCF.
166     *  This method should be called in grails-app/conf/BootStrap.groovy in the GSCF module.
167     */ 
168    public static registerRestWrapperMethodsSAMtoGSCF() {
169                def url = SAMServerURL
170
171                // register method that links to the SAM view for importing a SimpleAssay.
172        // parameters: externalAssayID, an externalAssayID
173                addViewWrapper( 'getAssayImportURL', url, 'importer/pages', ['externalAssayID', 'externalStudyID'] )
174
175                // register method that links to the SAM view for showing a SimpleAssay
176        // parameters: externalAssayID
177                addViewWrapper( 'getAssayShowURL', url, 'simpleAssay/show', ['externalAssayID'] )
178
179                // register method that links to the SAM view for editing a SimpleAssay
180        // parameters: externalAssayID
181                addViewWrapper( 'getAssayEditURL', url, 'simpleAssay/show', ['externalAssayID'] )
182
183                // register method that links to the SAM view for editing a SimpleAssay
184        // parameters: externalAssayID
185                addViewWrapper( 'getMeasurementTypesURL', url, 'simpleAssayMeasurementType/list', ['externalStudyID'] )
186
187                // register rest resource that returns the results of a full text query on SAM
188        // parameters:   query. A string for fulltext search on SAM
189        // return value: results map. It contains two keys 'studyIds', and 'assays'. 'studyIds'
190                //               key maps to a list of Study domain objects of GSCF. 'assays' map to a
191                //               list of pairs. Each pair consists of an Assay domain object of GSCF and
192                //               additional assay information from SAM provided as a map.
193                // Example of a returned map:
194                //               [studyIds:[PPSH],
195                //                               assays:[[isIntake:false, isDrug:false, correctionMethod:test Correction Method 1,
196                //                               detectableLimit:1, isNew:false, class:data.SimpleAssay, externalAssayID:1, id:1,
197                //                               measurements:null, unit:Insulin, inSerum:false, name:test Simple Assay 1,
198                //                               referenceValues:test Reference Values 1]]]
199                def closure = { map -> 
200                    def studies = []   
201                    def assays  = []   
202                        map['studyIds'].each { studies.add( dbnp.studycapturing.Study.find("from dbnp.studycapturing.Study as s where s.code=?",[it]) ) }
203                        map['assays'].each { samAssay ->
204                                def assayID = samAssay['externalAssayID']
205                                def assay = dbnp.studycapturing.Assay.find("from dbnp.studycapturing.Assay as a where a.externalAssayID='${assayID}'")
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 
217    /** Send a request for the REST resource to SAM and deliver the
218     *  results for the Query controller.
219     *
220     *  @param  compound        a SAM compound, e.g., "ldl" or "weight"
221     *  @param  value           a SAM value of a measurement, e.g. "20" (without unit, please)
222     *  @param  opperator       a SAM operator, i.e., "", "=", "<", or ">"
223     *  @return List of matching studies
224     */
225    public List<Study> getSAMStudies( String compound, String value, String opperator ) {
226         return []
227    }
228
229
230}
Note: See TracBrowser for help on using the repository browser.