From d918968d205f5d5f7bcacd72eab572b643ec11f7 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 23 Mar 2017 01:44:57 +0000 Subject: [PATCH 1/8] update config to use any available port in test environment. Does not fail tests if 8080 is already taken --- jaxrs-example/grails-app/conf/application.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jaxrs-example/grails-app/conf/application.yml b/jaxrs-example/grails-app/conf/application.yml index b5b3378..0e9ea41 100644 --- a/jaxrs-example/grails-app/conf/application.yml +++ b/jaxrs-example/grails-app/conf/application.yml @@ -12,13 +12,15 @@ dataSource: driverClassName: org.h2.Driver username: sa password: - + environments: development: dataSource: dbCreate: create-drop url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE test: + server: + port: 0 dataSource: dbCreate: update url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE From 54e193ca1e27df692bebf47e40c95c96bbffe483 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 23 Mar 2017 01:45:25 +0000 Subject: [PATCH 2/8] Add sample PDF --- .../groovy/com/budjb/resources/pdf-sample.pdf | Bin 0 -> 7945 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 jaxrs-example/src/integration-test/groovy/com/budjb/resources/pdf-sample.pdf diff --git a/jaxrs-example/src/integration-test/groovy/com/budjb/resources/pdf-sample.pdf b/jaxrs-example/src/integration-test/groovy/com/budjb/resources/pdf-sample.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f698ff53d41575b222e6778f87f9e9fd8da4f2b1 GIT binary patch literal 7945 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 Date: Thu, 23 Mar 2017 01:45:49 +0000 Subject: [PATCH 3/8] Add dependencies for jersey-multipart and apache mime --- jaxrs-example/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jaxrs-example/build.gradle b/jaxrs-example/build.gradle index 87adf59..e44d769 100644 --- a/jaxrs-example/build.gradle +++ b/jaxrs-example/build.gradle @@ -26,6 +26,7 @@ apply plugin:"asset-pipeline" ext { grailsVersion = project.grailsVersion gradleWrapperVersion = project.gradleWrapperVersion + jerseyVersion = '1.19' } repositories { @@ -64,6 +65,9 @@ dependencies { compile project(':jaxrs-jersey1') compile project(':jaxrs-swagger-ui') testCompile project(':jaxrs-integration-test') + + compile "com.sun.jersey.contribs:jersey-multipart:$jerseyVersion" + testCompile 'org.apache.httpcomponents:httpmime:4.4' } task wrapper(type: Wrapper) { From 1e87c8dd4034b0012ab1eced715fdfdc2962cda1 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 23 Mar 2017 01:46:30 +0000 Subject: [PATCH 4/8] TDD resource for sending multipart form data --- .../com/budjb/TestMultipartResource.groovy | 34 ++++++++++++++ .../budjb/TestMultipartResourceSpec.groovy | 47 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 jaxrs-example/grails-app/resources/com/budjb/TestMultipartResource.groovy create mode 100644 jaxrs-example/src/integration-test/groovy/com/budjb/TestMultipartResourceSpec.groovy diff --git a/jaxrs-example/grails-app/resources/com/budjb/TestMultipartResource.groovy b/jaxrs-example/grails-app/resources/com/budjb/TestMultipartResource.groovy new file mode 100644 index 0000000..0cf3dd4 --- /dev/null +++ b/jaxrs-example/grails-app/resources/com/budjb/TestMultipartResource.groovy @@ -0,0 +1,34 @@ +package com.budjb +import io.swagger.annotations.Api + +import javax.ws.rs.POST +import javax.ws.rs.Path +import javax.ws.rs.Consumes +import javax.ws.rs.Produces +import javax.ws.rs.core.Response +import javax.ws.rs.core.MediaType + +import com.sun.jersey.multipart.FormDataParam +import com.sun.jersey.multipart.FormDataBodyPart + +import grails.converters.JSON +@Path('/api/testMultipart') +@Api('test') +class TestMultipartResource { + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA ) + @Produces(MediaType.APPLICATION_JSON ) + @Path('/upload') + Response getTestMultipartRepresentation( + @FormDataParam('file') File file, + @FormDataParam('file') FormDataBodyPart fileBodyPart) { + // try with + // curl -v -X POST -H "Content-Type: multipart/form-data" -F "file=@src/integration-test/groovy/com/budjb/resources/pdf-sample.pdf" http://localhost:8060/api/testMultipart/upload + JSON ret = [ + name: fileBodyPart.getContentDisposition().getFileName(), + size: file.size(), + mimeType: fileBodyPart.getMediaType().toString() + ] as JSON + return Response.status(200).entity(ret).build() + } +} \ No newline at end of file diff --git a/jaxrs-example/src/integration-test/groovy/com/budjb/TestMultipartResourceSpec.groovy b/jaxrs-example/src/integration-test/groovy/com/budjb/TestMultipartResourceSpec.groovy new file mode 100644 index 0000000..c90146b --- /dev/null +++ b/jaxrs-example/src/integration-test/groovy/com/budjb/TestMultipartResourceSpec.groovy @@ -0,0 +1,47 @@ +package com.budjb + +import org.apache.http.entity.mime.MultipartEntityBuilder +import org.apache.http.entity.ContentType +import grails.test.mixin.integration.Integration +import org.grails.plugins.jaxrs.test.JaxrsIntegrationSpec +import org.grails.plugins.jaxrs.test.JaxrsRequestProperties + +@Integration +class TestMultipartResourceSpec extends JaxrsIntegrationSpec { + def 'Ensure can send a multipart file to the resource'() { + given: "A file to send" + File file = new File('src/integration-test/groovy/com/budjb/resources/pdf-sample.pdf') + + when: "Sending a file to the web service" + def response = makeRequest(new JaxrsRequestProperties(method: 'POST', + uri: '/api/testMultipart/upload', + headers: ['Content-Type' : ['multipart/form-data; boundary=fnord']], + body: getMultipartBody(file))) + def result = new groovy.json.JsonSlurper().parseText(response.bodyAsString) + + then: "The response is correct" + 200 == response.status + 'pdf-sample.pdf' == result.name + result.size > 0 + 'application/pdf' == result.mimeType + } + /** + * Return the list of additional resources to build the JAX-RS servlet with. + * + * @return + */ + @Override + List getResources() { + return [] + } + + + private byte[] getMultipartBody(File file) { + MultipartEntityBuilder e = new MultipartEntityBuilder() + e.setBoundary("fnord") + e.addBinaryBody("file", file, ContentType.create("application/pdf"), file.name) + ByteArrayOutputStream baos = new ByteArrayOutputStream() + e.build().writeTo(baos) + return baos.toByteArray() + } +} From a202ad1e9a5e887f843c6edaf54ca3fbbbaab60b Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 28 Apr 2017 00:43:13 +0100 Subject: [PATCH 5/8] Add ReusableServletInputStream class Wraps a ServletInputStream in a BufferedInputStream to allow reuse --- .../servlet/ReusableServletInputStream.groovy | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/servlet/ReusableServletInputStream.groovy diff --git a/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/servlet/ReusableServletInputStream.groovy b/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/servlet/ReusableServletInputStream.groovy new file mode 100644 index 0000000..e4fa565 --- /dev/null +++ b/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/servlet/ReusableServletInputStream.groovy @@ -0,0 +1,68 @@ +/* + * Copyright 2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.grails.plugins.jaxrs.servlet + +import groovy.transform.CompileStatic +import javax.servlet.ServletInputStream +import javax.servlet.ReadListener + + +/** + * + * @author Alex Stoia + */ +@CompileStatic +class ReusableServletInputStream extends ServletInputStream { + private BufferedInputStream wrappedStream + private ServletInputStream originalStream + + ReusableServletInputStream(ServletInputStream originalStream) { + super() + this.originalStream = originalStream + this.wrappedStream = new BufferedInputStream(originalStream) + } + + + @Override + boolean isReady() { + return originalStream.isReady() + } + @Override + boolean isFinished() { + return originalStream.isFinished() + } + @Override + void setReadListener(ReadListener readListener) { + originalStream.setReadListener(readListener) + } + + @Override + public int read() throws IOException { + return wrappedStream.read() + } + @Override + boolean markSupported() { + return wrappedStream.markSupported() + } + @Override + void mark(int readlimit) { + wrappedStream.mark(readlimit) + } + @Override + void reset() { + wrappedStream.reset() + } +} From 1be6f640b06df66f3b5be17c6e28b558327c92df Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 28 Apr 2017 00:43:59 +0100 Subject: [PATCH 6/8] Add ReusableHttpServletRequestWrapper Allows the Servlet stream to be reset and reused --- ...ableStreamHttpServletRequestWrapper.groovy | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/servlet/http/ReusableStreamHttpServletRequestWrapper.groovy diff --git a/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/servlet/http/ReusableStreamHttpServletRequestWrapper.groovy b/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/servlet/http/ReusableStreamHttpServletRequestWrapper.groovy new file mode 100644 index 0000000..5cb3901 --- /dev/null +++ b/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/servlet/http/ReusableStreamHttpServletRequestWrapper.groovy @@ -0,0 +1,51 @@ +/* + * Copyright 2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.grails.plugins.jaxrs.servlet.http + +import groovy.transform.CompileStatic +import javax.servlet.ServletInputStream +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletRequestWrapper +import org.apache.commons.io.IOUtils +import org.grails.plugins.jaxrs.servlet.ReusableServletInputStream + +/** + * + * @author Alex Stoia + */ +@CompileStatic +class ReusableStreamHttpServletRequestWrapper extends HttpServletRequestWrapper { + private BufferedInputStream wrappedStream + private ServletInputStream usedStream + + ReusableStreamHttpServletRequestWrapper(HttpServletRequest request) { + super(request) + ServletInputStream originalStream = request.getInputStream() + usedStream = new ReusableServletInputStream(originalStream) + usedStream.mark(Integer.MAX_VALUE) + // read the stream contents, otherwise this will not be available in + // the getInputStream method. Also tried reading one byte, works on + // first request, fails on all subsequent ones. Got no idea why at + // the moment + IOUtils.toString(usedStream, 'UTF-8') + } + + @Override + public ServletInputStream getInputStream() { + usedStream.reset() + return usedStream + } +} From 29ec6f633531128095f8c8b48fbf0b88faabc97e Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 28 Apr 2017 00:44:38 +0100 Subject: [PATCH 7/8] Add filter to wrap the request into one with a reusable stream. Need to load the plugin before core so the stream is not already read --- .../jaxrs/JaxrsCoreGrailsPlugin.groovy | 7 ++++ .../ReusableHttpRequestStreamFilter.groovy | 42 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/filters/ReusableHttpRequestStreamFilter.groovy diff --git a/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/JaxrsCoreGrailsPlugin.groovy b/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/JaxrsCoreGrailsPlugin.groovy index 0858ac5..30a81dd 100644 --- a/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/JaxrsCoreGrailsPlugin.groovy +++ b/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/JaxrsCoreGrailsPlugin.groovy @@ -8,6 +8,7 @@ import org.grails.plugins.jaxrs.core.JaxrsContext import org.grails.plugins.jaxrs.core.JaxrsFilter import org.grails.plugins.jaxrs.core.JaxrsListener import org.grails.plugins.jaxrs.core.JaxrsUtil +import org.grails.plugins.jaxrs.filters.ReusableHttpRequestStreamFilter import org.grails.plugins.jaxrs.provider.* import org.springframework.boot.context.embedded.FilterRegistrationBean import org.springframework.boot.context.embedded.ServletListenerRegistrationBean @@ -23,6 +24,7 @@ class JaxrsCoreGrailsPlugin extends Plugin { /** * Load order. */ + def loadBefore = ['core'] def loadAfter = ['hibernate3', 'hibernate4', 'hibernate5', 'controllers', 'services', 'spring-security-core'] /** @@ -138,6 +140,11 @@ mechanism for implementing RESTful web services. bean.autowire = true } } + reusableHttpRequestStreamFilter(FilterRegistrationBean) { + filter = bean(ReusableHttpRequestStreamFilter) + urlPatterns = ['/*'] + order = Ordered.HIGHEST_PRECEDENCE + } } } diff --git a/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/filters/ReusableHttpRequestStreamFilter.groovy b/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/filters/ReusableHttpRequestStreamFilter.groovy new file mode 100644 index 0000000..d481092 --- /dev/null +++ b/jaxrs-core/src/main/groovy/org/grails/plugins/jaxrs/filters/ReusableHttpRequestStreamFilter.groovy @@ -0,0 +1,42 @@ +/* + * Copyright 2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.grails.plugins.jaxrs.filters + +import groovy.transform.CompileStatic +import javax.servlet.FilterChain +import javax.servlet.ServletException +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import org.springframework.web.filter.OncePerRequestFilter +import org.grails.plugins.jaxrs.servlet.http.ReusableStreamHttpServletRequestWrapper + +/** + * + * @author Alex Stoia + */ +@CompileStatic +class ReusableHttpRequestStreamFilter extends OncePerRequestFilter { + + /** + * + */ + @Override + protected void doFilterInternal(HttpServletRequest request, + HttpServletResponse response, FilterChain chain) throws ServletException, + IOException { + chain.doFilter(new ReusableStreamHttpServletRequestWrapper(request), response) + } +} From e5579a4f8fb409d74f55c557db2d70d0009d26ff Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 28 Apr 2017 00:44:49 +0100 Subject: [PATCH 8/8] Add commons-io dependency --- jaxrs-core/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jaxrs-core/build.gradle b/jaxrs-core/build.gradle index 781fec8..8fda812 100644 --- a/jaxrs-core/build.gradle +++ b/jaxrs-core/build.gradle @@ -66,6 +66,8 @@ dependencies { compile('javax.ws.rs:jsr311-api:1.1.1') { exclude module: 'junit' } + compile group: 'commons-io', name: 'commons-io', version: '2.4' + }