Permalink
Browse files

Grails REST client applicatio

  • Loading branch information...
1 parent cfc8169 commit 3cc8bdad0687b4be7ba263626957c141febef812 @janm janm committed Aug 11, 2012
Showing with 3,167 additions and 0 deletions.
  1. +6 −0 webapp/application.properties
  2. +5 −0 webapp/grails-app/conf/ApplicationResources.groovy
  3. +7 −0 webapp/grails-app/conf/BootStrap.groovy
  4. +56 −0 webapp/grails-app/conf/BuildConfig.groovy
  5. +91 −0 webapp/grails-app/conf/Config.groovy
  6. +43 −0 webapp/grails-app/conf/DataSource.groovy
  7. +15 −0 webapp/grails-app/conf/UrlMappings.groovy
  8. +3 −0 webapp/grails-app/conf/spring/resources.groovy
  9. +31 −0 webapp/grails-app/controllers/webapp/CustomerController.groovy
  10. +7 −0 webapp/grails-app/controllers/webapp/CustomerForm.groovy
  11. +115 −0 webapp/grails-app/controllers/webapp/RestClient.groovy
  12. +34 −0 webapp/grails-app/controllers/webapp/RestResponse.groovy
  13. +55 −0 webapp/grails-app/i18n/messages.properties
  14. +55 −0 webapp/grails-app/i18n/messages_cs_CZ.properties
  15. +56 −0 webapp/grails-app/i18n/messages_da.properties
  16. +55 −0 webapp/grails-app/i18n/messages_de.properties
  17. +55 −0 webapp/grails-app/i18n/messages_es.properties
  18. +19 −0 webapp/grails-app/i18n/messages_fr.properties
  19. +55 −0 webapp/grails-app/i18n/messages_it.properties
  20. +55 −0 webapp/grails-app/i18n/messages_ja.properties
  21. +55 −0 webapp/grails-app/i18n/messages_nl.properties
  22. +59 −0 webapp/grails-app/i18n/messages_pl.properties
  23. +59 −0 webapp/grails-app/i18n/messages_pt_BR.properties
  24. +34 −0 webapp/grails-app/i18n/messages_pt_PT.properties
  25. +31 −0 webapp/grails-app/i18n/messages_ru.properties
  26. +55 −0 webapp/grails-app/i18n/messages_sv.properties
  27. +55 −0 webapp/grails-app/i18n/messages_th.properties
  28. +18 −0 webapp/grails-app/i18n/messages_zh_CN.properties
  29. +55 −0 webapp/grails-app/views/customer/add.gsp
  30. +30 −0 webapp/grails-app/views/customer/list.gsp
  31. +16 −0 webapp/grails-app/views/customer/show.gsp
  32. +11 −0 webapp/grails-app/views/error.gsp
  33. +122 −0 webapp/grails-app/views/index.gsp
  34. +28 −0 webapp/grails-app/views/layouts/main.gsp
  35. +17 −0 webapp/test/unit/webapp/CustomerControllerTests.groovy
  36. +33 −0 webapp/web-app/WEB-INF/applicationContext.xml
  37. +14 −0 webapp/web-app/WEB-INF/sitemesh.xml
  38. +550 −0 webapp/web-app/WEB-INF/tld/grails.tld
  39. +311 −0 webapp/web-app/WEB-INF/tld/spring.tld
  40. +109 −0 webapp/web-app/css/errors.css
  41. +596 −0 webapp/web-app/css/main.css
  42. +82 −0 webapp/web-app/css/mobile.css
  43. BIN webapp/web-app/images/apple-touch-icon-retina.png
  44. BIN webapp/web-app/images/apple-touch-icon.png
  45. BIN webapp/web-app/images/favicon.ico
  46. BIN webapp/web-app/images/grails_logo.jpg
  47. BIN webapp/web-app/images/grails_logo.png
  48. BIN webapp/web-app/images/leftnav_btm.png
  49. BIN webapp/web-app/images/leftnav_midstretch.png
  50. BIN webapp/web-app/images/leftnav_top.png
  51. BIN webapp/web-app/images/skin/database_add.png
  52. BIN webapp/web-app/images/skin/database_delete.png
  53. BIN webapp/web-app/images/skin/database_edit.png
  54. BIN webapp/web-app/images/skin/database_save.png
  55. BIN webapp/web-app/images/skin/database_table.png
  56. BIN webapp/web-app/images/skin/exclamation.png
  57. BIN webapp/web-app/images/skin/house.png
  58. BIN webapp/web-app/images/skin/information.png
  59. BIN webapp/web-app/images/skin/shadow.jpg
  60. BIN webapp/web-app/images/skin/sorted_asc.gif
  61. BIN webapp/web-app/images/skin/sorted_desc.gif
  62. BIN webapp/web-app/images/spinner.gif
  63. BIN webapp/web-app/images/springsource.png
  64. +9 −0 webapp/web-app/js/application.js
@@ -0,0 +1,6 @@
+#Grails Metadata file
+#Sat Aug 11 10:14:32 BST 2012
+app.grails.version=2.1.0
+app.name=webapp
+app.version=0.1
+plugins.rest-client-builder=1.0.2
@@ -0,0 +1,5 @@
+modules = {
+ application {
+ resource url:'js/application.js'
+ }
+}
@@ -0,0 +1,7 @@
+class BootStrap {
+
+ def init = { servletContext ->
+ }
+ def destroy = {
+ }
+}
@@ -0,0 +1,56 @@
+grails.servlet.version = "2.5" // Change depending on target container compliance (2.5 or 3.0)
+grails.project.class.dir = "target/classes"
+grails.project.test.class.dir = "target/test-classes"
+grails.project.test.reports.dir = "target/test-reports"
+grails.project.target.level = 1.6
+grails.project.source.level = 1.6
+//grails.project.war.file = "target/${appName}-${appVersion}.war"
+
+grails.project.dependency.resolution = {
+ // inherit Grails' default dependencies
+ inherits("global") {
+ // specify dependency exclusions here; for example, uncomment this to disable ehcache:
+ // excludes 'ehcache'
+ }
+ log "error" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose'
+ checksums true // Whether to verify checksums on resolve
+
+ repositories {
+ inherits true // Whether to inherit repository definitions from plugins
+
+ grailsPlugins()
+ grailsHome()
+ grailsCentral()
+
+ mavenLocal()
+ mavenCentral()
+
+ // uncomment these (or add new ones) to enable remote dependency resolution from public Maven repositories
+ //mavenRepo "http://snapshots.repository.codehaus.org"
+ //mavenRepo "http://repository.codehaus.org"
+ //mavenRepo "http://download.java.net/maven/2/"
+ //mavenRepo "http://repository.jboss.com/maven2/"
+ }
+ dependencies {
+ // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg.
+
+ // runtime 'mysql:mysql-connector-java:5.1.20'
+ }
+
+ plugins {
+ runtime ":hibernate:$grailsVersion"
+ runtime ":jquery:1.7.2"
+ runtime ":resources:1.1.6"
+
+ // Uncomment these (or add new ones) to enable additional resources capabilities
+ //runtime ":zipped-resources:1.0"
+ //runtime ":cached-resources:1.0"
+ //runtime ":yui-minify-resources:0.1.4"
+
+ build ":tomcat:$grailsVersion"
+
+ runtime ":database-migration:1.1"
+
+ compile ':cache:1.0.0'
+ }
+}
@@ -0,0 +1,91 @@
+// locations to search for config files that get merged into the main config;
+// config files can be ConfigSlurper scripts, Java properties files, or classes
+// in the classpath in ConfigSlurper format
+
+// grails.config.locations = [ "classpath:${appName}-config.properties",
+// "classpath:${appName}-config.groovy",
+// "file:${userHome}/.grails/${appName}-config.properties",
+// "file:${userHome}/.grails/${appName}-config.groovy"]
+
+// if (System.properties["${appName}.config.location"]) {
+// grails.config.locations << "file:" + System.properties["${appName}.config.location"]
+// }
+
+grails.project.groupId = appName // change this to alter the default package name and Maven publishing destination
+grails.mime.file.extensions = true // enables the parsing of file extensions from URLs into the request format
+grails.mime.use.accept.header = false
+grails.mime.types = [
+ all: '*/*',
+ atom: 'application/atom+xml',
+ css: 'text/css',
+ csv: 'text/csv',
+ form: 'application/x-www-form-urlencoded',
+ html: ['text/html','application/xhtml+xml'],
+ js: 'text/javascript',
+ json: ['application/json', 'text/json'],
+ multipartForm: 'multipart/form-data',
+ rss: 'application/rss+xml',
+ text: 'text/plain',
+ xml: ['text/xml', 'application/xml']
+]
+
+// URL Mapping Cache Max Size, defaults to 5000
+//grails.urlmapping.cache.maxsize = 1000
+
+// What URL patterns should be processed by the resources plugin
+grails.resources.adhoc.patterns = ['/images/*', '/css/*', '/js/*', '/plugins/*']
+
+// The default codec used to encode data with ${}
+grails.views.default.codec = "none" // none, html, base64
+grails.views.gsp.encoding = "UTF-8"
+grails.converters.encoding = "UTF-8"
+// enable Sitemesh preprocessing of GSP pages
+grails.views.gsp.sitemesh.preprocess = true
+// scaffolding templates configuration
+grails.scaffolding.templates.domainSuffix = 'Instance'
+
+// Set to false to use the new Grails 1.2 JSONBuilder in the render method
+grails.json.legacy.builder = false
+// enabled native2ascii conversion of i18n properties files
+grails.enable.native2ascii = true
+// packages to include in Spring bean scanning
+grails.spring.bean.packages = []
+// whether to disable processing of multi part requests
+grails.web.disable.multipart=false
+
+// request parameters to mask when logging exceptions
+grails.exceptionresolver.params.exclude = ['password']
+
+// configure auto-caching of queries by default (if false you can cache individual queries with 'cache: true')
+grails.hibernate.cache.queries = false
+
+environments {
+ development {
+ grails.logging.jul.usebridge = true
+ }
+ production {
+ grails.logging.jul.usebridge = false
+ // TODO: grails.serverURL = "http://www.changeme.com"
+ }
+}
+
+// log4j configuration
+log4j = {
+ // Example of changing the log pattern for the default console appender:
+ //
+ //appenders {
+ // console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n')
+ //}
+
+ error 'org.codehaus.groovy.grails.web.servlet', // controllers
+ 'org.codehaus.groovy.grails.web.pages', // GSP
+ 'org.codehaus.groovy.grails.web.sitemesh', // layouts
+ 'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
+ 'org.codehaus.groovy.grails.web.mapping', // URL mapping
+ 'org.codehaus.groovy.grails.commons', // core / classloading
+ 'org.codehaus.groovy.grails.plugins', // plugins
+ 'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
+ 'org.springframework',
+ 'org.hibernate',
+ 'net.sf.ehcache.hibernate'
+}
@@ -0,0 +1,43 @@
+dataSource {
+ pooled = true
+ driverClassName = "org.h2.Driver"
+ username = "sa"
+ password = ""
+}
+hibernate {
+ cache.use_second_level_cache = true
+ cache.use_query_cache = false
+ cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
+}
+// environment specific settings
+environments {
+ development {
+ dataSource {
+ dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
+ url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
+ }
+ }
+ test {
+ dataSource {
+ dbCreate = "update"
+ url = "jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
+ }
+ }
+ production {
+ dataSource {
+ dbCreate = "update"
+ url = "jdbc:h2:prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
+ pooled = true
+ properties {
+ maxActive = -1
+ minEvictableIdleTimeMillis=1800000
+ timeBetweenEvictionRunsMillis=1800000
+ numTestsPerEvictionRun=3
+ testOnBorrow=true
+ testWhileIdle=true
+ testOnReturn=true
+ validationQuery="SELECT 1"
+ }
+ }
+ }
+}
@@ -0,0 +1,15 @@
+class UrlMappings {
+
+ static mappings = {
+ "/customers"(controller: "customer", action: [GET: "list", POST: "doAdd", PUT: "doSave"])
+ "/customers/add"(controller: "customer", action: [GET: "add"])
+ "/customers/$customerId"(controller: "customer", action: [GET: "show", DELETE: "doDelete"]) {
+ constraints {
+ customerId(minSize: 36, maxSize: 36)
+ }
+ }
+
+ "/"(view:"/index")
+ "500"(view:'/error')
+ }
+}
@@ -0,0 +1,3 @@
+// Place your Spring DSL code here
+beans = {
+}
@@ -0,0 +1,31 @@
+package webapp
+
+class CustomerController extends RestClient {
+
+ // GET /
+ def list = {
+ [customers: doGet("/customers").ok()]
+ }
+
+ // GET /UUID
+ def show = {
+ [customers: doGet("/customers/{customerId}", params).ok()]
+ }
+
+ // GET /add
+ def add = {
+ [customer: new CustomerForm()]
+ }
+
+ // DELETE /UUID
+ def delete = {
+ doDelete("/customers/{customerId}", params)
+ redirect(url: "/customers")
+ }
+
+ // POST /customers
+ def doSave(CustomerForm form) {
+
+ redirect(url: "/customers")
+ }
+}
@@ -0,0 +1,7 @@
+package webapp
+
+/**
+ * @author janmachacek
+ */
+class CustomerForm {
+}
@@ -0,0 +1,115 @@
+package webapp
+
+import org.springframework.util.FileCopyUtils
+import groovy.json.JsonSlurper
+
+class RestClient {
+ def url = "http://localhost:9000/"
+ def pathVariablePattern = ~/\{([^\}]*)\}/
+
+ enum Method {
+ Get, Post, Put, Delete
+ }
+
+ private def RestResponse doRest(Method method, String path, params = [:], body = null) {
+ def matcher = pathVariablePattern.matcher(path)
+ matcher.each {
+ def param = it[1]
+ def value = params[param]
+ if (value == null) throw new Exception("Missing param " + param)
+ path = path.replace(it[0], value)
+ }
+
+ def result = withRest(uri: url) {
+ if (token != null) headers = ["x-token": session["token"]]
+
+ // the server failures still reply with JSON object
+ handler.failure = { response, responseBody ->
+ def content = FileCopyUtils.copyToString(responseBody)
+ def jsonResponseBody = null
+ try {
+ jsonResponseBody = new JsonSlurper().parse(new StringReader(content))
+ } catch (ignored) {
+ // this could be OK--the response is not even JSON
+ }
+
+ def result = new RestResponse(
+ status: response.statusLine.statusCode,
+ json: jsonResponseBody,
+ text: content
+ )
+ result
+ }
+ handler.success = { resp, data ->
+ new RestResponse(
+ status: 200,
+ json: data,
+ text: null
+ )
+ }
+
+ switch (method) {
+ case Method.Get:
+ get(path: path, body: body, requestContentType: "application/json")
+ break
+ case Method.Post:
+ post(path: path, body: body, requestContentType: "application/json")
+ break
+ case Method.Put:
+ put(path: path, body: body, requestContentType: "application/json")
+ break
+ case Method.Delete:
+ delete(path: path, body: body, requestContentType: "application/json")
+ break
+ }
+
+ }
+
+ result
+ }
+
+ def RestResponse doGet(String path, params = [:], body = null) {
+ doRest(Method.Get, path, params, body)
+ }
+
+ def RestResponse doPost(String path, params = [:], body = null) {
+ doRest(Method.Post, path, params, body)
+ }
+
+ def RestResponse doPut(String path, params = [:], body = null) {
+ doRest(Method.Put, path, params, body)
+ }
+
+ def RestResponse doDelete(String path, params = [:], body = null) {
+ doRest(Method.Delete, path, params, body)
+ }
+
+ private def nullRemover(Map body) {
+ def newBody = [:]
+ body.each { k, v ->
+ if (v == null) return;
+ if (v == "null") return;
+ if (v instanceof UUID) v = v.toString()
+ if (v instanceof Map) v = nullRemover(v)
+ newBody[k] = v
+ }
+
+ newBody
+ }
+
+ def doPutOrPost(String path, body) {
+ if (body instanceof Map) body = nullRemover(body)
+
+ def json
+
+ if (body.id == null) {
+ body.id = UUID.randomUUID().toString()
+ json = body.encodeAsJSON()
+ doPost(path, [:], json)
+ } else {
+ json = body.encodeAsJSON()
+ doPut(path, [:], json)
+ }
+
+ }
+}
Oops, something went wrong.

0 comments on commit 3cc8bda

Please sign in to comment.