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

Last change on this file since 755 was 755, checked in by vinlud, 10 years ago

Sam module changes including rest interface, merging results, subquery workflow

File size: 9.3 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 'samples'. 'studyIds'
189                //               key maps to a list of Study domain objects of GSCF. 'samples' maps to a
190                //               list of pairs. Each pair consists of a Sample domain object of GSCF and
191                //               additional sample information from SAM provided as a map.
192                // Example of a returned map:
193                //                               ["studies":[NuGO PPS human study],
194                //               "samples":[[ [...], dbnp.studycapturing.Sample: 1]]]
195                def closure = { map ->
196                    def studies = []
197                    def samples = []
198                        def studiesHQ = "from dbnp.studycapturing.Study as s where s.code=?"
199                        map['studyIds'].each { studies.add( dbnp.studycapturing.Study.find(studiesHQ,[it]) ) }
200                        map['Samples'].each { samSample ->
201                                def sampleID = samSample['externalSampleID']
202                            def sampleHQ = "from dbnp.studycapturing.Sample as a where a.externalSampleID='${sampleID}'"
203                                def sample = dbnp.studycapturing.Sample.find(sampleHQ)
204                                samples.add( [samSample,sample] )
205                        }
206                        return [studies:studies, samples:samples]
207                }
208
209                addRestWrapper( url+'/rest', 'getQueryResult',  ['query'], closure )
210    }
211
212
213    /**
214     *  This method creates on run time new methods for accessing Grails views that SAM provides for GSCF.
215     *  This method should be called in grails-app/conf/BootStrap.groovy in the GSCF module.
216     */ 
217    public static registerRestWrapperMethodsGSCFtoDSP() {
218                def url = DSPServerURL
219                addRestWrapper( url, 'isUser',  ['username','password'] )
220                addRestWrapper( url, 'listStudies',  ['username','password'] )
221                addRestWrapper( url, 'listStudySamples',  ['username','password','study_token'] )
222                addRestWrapper( url, 'getStudy',  ['username','password','study_token'] )
223                addRestWrapper( url, 'getStudySample',  ['username','password','study_token','sample_token'] )
224                addRestWrapper( url, 'isUser',  ['username','password'] )
225    }
226
227
228
229}
Note: See TracBrowser for help on using the repository browser.