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

Last change on this file since 1199 was 1199, checked in by j.saito@…, 10 years ago

Further streamlined CommunicationManager?. It now builds fetches its URL from config.modules and is further minimized.

File size: 6.8 KB
Line 
1package dbnp.rest.common
2
3import grails.converters.JSON
4import java.net.URLEncoder
5import org.codehaus.groovy.grails.web.json.*
6
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
29    def        static Encoding      = "UTF-8" 
30                                         // map that maps name strings of dbNP modules to urls
31        def public static URLMap = [:]   // e.g., 'gscf' -> 'http://sam.
32        def public static ModuleName = ''
33
34
35    /**
36     * Get the results provided by a rest Rest resource.
37     *
38     * @params String resource The name of the resource, e.g. importer/pages
39     * @params Map params      A Map of parmater names and values., e.g. ['externalAssayID':12]
40     * @return String url   
41     */
42    public static Object getRestResource( RestServerURL, resource, params ) {
43                def url = getRestURL( RestServerURL, resource, params )
44                return  JSON.parse( url.newReader() )
45    }
46
47        private static getURL( serverName ) {
48                return URLMap[serverName]?.url
49        }
50
51    /** Register this module once before run time.
52      * @params moduleName      the string name for this module, e.g., 'sam' or 'gscf'
53      * @params serverURL           the URL of this module, e.g., 'localhost:8080/sam'
54      * @params map             a map that maps module names to urls
55      */ 
56        public static registerModule( moduleName, serverURL, urlMap ) {
57                ModuleName = moduleName
58                URLMap = urlMap
59                URLMap[ModuleName] = ['url':serverURL] 
60        }
61
62
63
64    /**
65     * Convenience method for constructing URLs for SAM that need parameters.
66     * Note that parameters are first convereted to strings by calling their toString() method
67     * and then Encoded to protect special characters.
68     *
69     * @params String resource The name of the resource, e.g. importer/pages
70     * @params Map params      A Map of parmater names and values., e.g. ['externalAssayID':12]
71     * @return String url   
72     */
73    public static URL getRestURL( serverName, resource, params ) {
74        def url = getURL(serverName) + '/rest/' + resource
75                def first = true
76                params['consumer'] = getURL( ModuleName )
77                params.each { name, value ->
78                        if(first) {
79                                first = false
80                                url += '/nil?' + name + "=" + URLEncoder.encode( value.toString(), Encoding )
81                        }
82                        else { 
83                                url += '&' + name + "=" + URLEncoder.encode( value.toString(), Encoding  )
84                        }
85                }
86                return new URL( url )
87    }
88
89
90
91    /**
92     * This method dynamically adds a static method to the CommunicationManager.
93     * 
94     * @params String serverURL         A rest server URL.
95     * @params String restName          The name of a rest resource on the server.     
96     * @params Map params               A list of parameter names to be passed to this resource.
97     * @return String url   
98     * 
99     * Given a rest resource at serverURL called resourceName, we register a static method
100     * for the CommunicationManager. The new method has the same name and arity as the resource.
101     * 
102     * Example: Suppopse http://localhost:8080/gscf/rest/getSamples is a Rest resource.
103     * 
104     * In our grails app, we would like to connect to this service. We want to have a
105     * method getSamples() that fetches the result from the service. We do this by calling
106     * 
107     *          CommunicationManager.addRestWrapper( 'http://localhost:8080/gscf/rest', 'getSamples', ['externalStudyID'] )
108     * 
109     * This registers a new method:
110     * 
111         *               public static Object CommunicationManager.getSamples( Object arg )
112     * 
113     * This method has arrity 1 and expects to be given a map. The map is the parameter map
114     * of the rest service getSamples. It maps parameter called "externalStudyID" to some object
115     * that is passed. So, it can be called like as follows:
116     * 
117     *      def sampleList = CommunicationManager.getSamples( [externalStudyID:4711] )
118     * 
119     *  The call will deliver the results of the parameterized rest resource given at:
120     * 
121     *          http://localhost:8080/gscf/rest/nil?externalStudyID=4711
122     *
123     */
124
125    public static addRestWrapper( serverName, restName, params = [], closure = { return it } ) {
126                if(!serverName) { throw new Exception("addRestWrapper: REST serverURL is null") }
127                def result
128                try {
129                        CommunicationManager.metaClass.registerStaticMethod( restName ) { Object [] strangeGroovyArgs ->
130                                def map = [:]
131                            def args = strangeGroovyArgs[0]        // groovy nests the parameters of the methods in some other array
132                                if(params.size > 0 )
133                                {
134                                        for( i in 0..(params.size-1) ) {
135                                                def param = params[i]
136                                                map[param] = args[i]
137                                        }
138                                }
139                                result = closure( getRestResource( serverName, restName, map ) )
140                        } 
141                } catch ( Exception e ) { 
142                        throw new Exception("addRestWrapper: error. Could not retrieve data from RESTFful service. ") 
143                }
144
145                return result
146        }
147
148
149
150    /**
151     * Give list of missing parameters for a parameter call in a RestController.
152     * 
153     * @params params Map params        The parameter list required by this view.
154     * @params requiredParamers                 List of parameter names that must be provided
155     * @return true, if params has all required parameters, false otherwise
156     */ 
157        static String hasValidParams( params, Object [] requiredParams ) {
158                requiredParams.every { params[it] }
159        }
160
161
162
163    /**
164     *  This creates on run time new methods for accessing Rest resources that GSCF provides for SAM.
165     *  This method should be called in grails-app/conf/BootStrap.groovy in the SAM module.
166     */ 
167    public static registerRestWrapperMethodsFromGSCF() {
168                addRestWrapper( 'gscf', 'getStudies', ['token'] )
169                addRestWrapper( 'gscf', 'getSubjects', ['token','studyToken'] )
170                addRestWrapper( 'gscf', 'getAssays',   ['token','studyToken','url'] )
171                addRestWrapper( 'gscf', 'getSamples',  ['token','assayToken'] )
172    }
173
174    /**
175     *  This method creates on run time new methods for accessing Grails views that SAM provides for GSCF.
176     *  This method should be called in grails-app/conf/BootStrap.groovy in the GSCF module.
177     */         
178    public static registerRestWrapperMethodsFromSAM() {
179                addRestWrapper( 'gscf', 'getQueryResult',  ['query'] )
180    }
181
182}
Note: See TracBrowser for help on using the repository browser.