Sending / Transfering / Pushing Files in MultiParts / Chunks from Server to Client with RESTful Web Services in Java
Table Of Content
- Introduction
- System Requirements
- Article Prerequisites
- Writing and Deploying the Web Service
- Testing the Web Service with Test Client
- Resources
- Feedback
Introduction
The sample application we are going to develop through this tutorial includes writing a Jersey/JAX-RS and Tomcat based RESTful Web service, which will respond to the requests by a Jersey Client. The sample application also includes writing a Jersey/JAX-RS Web service client, which can receive the attachments in response.
The tip uses a sample application to demonstrate some of the JAX-RS MutiPart API concepts and techniques.
System Requirements
- Java SE Development Kit (JDK) 6
- Apache Ant 1.7.1
- Jersey 1.1.1-ea implements JAX-RS 1.1
- Eclipse IDE for Java EE Developers
- Apache Tomcat 6.x
Article Prerequisites
- You must have setup all required tools and application as mentioned in article “Introduction, developing, implementing RESTful Web Services in Java”.
- Solid experience in Java Programming, including object-oriented Java and the Java streams model, is essential.
- Some experience with Java EE development, will be very helpful, but is not strictly required.
- Some experience with Eclipse and Tomcat.
- Experience or knowledge on RESTful Web Services. You can learn RESTful Web Service using article “Introduction, developing, implementing RESTful Web Services in Java”.
Writing and Deploying the Web Service
To get started we will create a simple Web Service Project by selecting Dynamic Web Project from the new toolbar menu
Alternatively, invoke the wizard using File > New > Dynamic Web Project.
Name the project DownloadFileDemo and select Target Runtime as Apache Tomcat v6.0.
NOTE: It is not required to set Target Runtime.
Click Next > on New Dynamic Web Project Dialog Box. Click Finish
Right click DownloadFileDemo project and select Properties. Select Java Build Path > Libraries > Add Library…. Select User Library from the Add Library dialog box. Click Next >. Select/Check jersey-1.1.1-ea and press Finish.
In Properties dialog box, Click Java Build Path > Order and Export and check jersey-1.1.1-ea checkbox. If asked click Apply
In Properties dialog box, click on Java EE Module Dependencies and under JAR/Module, check jersey-1.1.1-ea checkbox. Click OK.
Click and open DownloadFileDemo > WebContent > WEB-INF > web.xml. Edit your web.xml and add following code snippet under the root web-app.
<servlet> <display-name>JAX-RS REST Servlet</display-name> <servlet-name>JAX-RS REST Servlet</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>JAX-RS REST Servlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>
Now, create the DownloadFileResource class, the core of our web service. Use the File > New > Class wizard, put DownloadFileResource in the Name field, edu.bhavesh.restws.downloadfiledemo in the Package field and Finish the wizard. Replace the contents of the generated class with the following code:
package edu.bhavesh.restws.downloadfiledemo; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.sun.jersey.multipart.MultiPart; /** * @author Bhavesh.Thaker * */ @Path("downloadfile") @Produces("multipart/mixed") public class DownloadFileResource { /** * @return Response as 200. Response will also contain Multi Part object * which will be streamed to client in chunks. */ public Response getFile() { /* * Now create an object of very large file, which you want to * push/transfer/send to client. */ java.io.File objFile = new java.io.File("C:/files/filetosend.zip"); /* * Now create an object of MultiPart class. This class is responsible * for sending data in chunks. Set the MIME type for MultiPart object as * multipart/mixed */ MultiPart objMultiPart = new MultiPart(); objMultiPart.type(new MediaType("multipart", "mixed")); /* * Now set Body of MultiPart object. Here we are setting Filename, File * Length and File Object to Body of MultiPart Object. */ objMultiPart .bodyPart(objFile.getName(), new MediaType("text", "plain")); objMultiPart.bodyPart(objFile.length(), new MediaType("text", "plain")); objMultiPart.bodyPart(objFile, new MediaType("multipart", "mixed")); /* * Now return response 200 [ok] along with MultiPart object. */ return Response.ok(objMultiPart).build(); } }
Deploying the Web Service
- Use DownloadFileDemo project > Export > WAR file to generate .war for our project.
- In WAR Export dialog box, provide Web Project name [in this case, DownloadFileDemo] and Destination [where .war file will be copied]. Click Finish.
- Copy DownloadFileDemo.war to Tomcat > webapps directory. Start your Tomcat Server.
Testing the Web Service with Test Client
Now, create the DownloadFileClient class, the client of our web service. Use the File > New > Class wizard, put DownloadFileClient in the Name field, edu.bhavesh.restws.downloadfiledemo.client in the Package field and Finish the wizard. Replace the contents of the generated class with the following code:
package edu.bhavesh.restws.downloadfiledemo.client; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response.Status; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientHandlerException; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.multipart.BodyPart; import com.sun.jersey.multipart.MultiPart; /** * @author Bhavesh.Thaker * */ public class DownloadFileClient { private static final String BASE_URI = "http://localhost:8181/DownloadFileDemo/services/downloadfile"; /** * */ public DownloadFileClient() { try { /* * Create a client */ Client client = Client.create(); WebResource objWebResource = client.resource(BASE_URI); ClientResponse response = objWebResource.path("/").type( MediaType.TEXT_HTML).get(ClientResponse.class); System.out.println("response : " + response); /* * Check if response has data which web service sent. */ if (response.getStatus() == Status.OK.getStatusCode() && response.hasEntity()) { /* * Retrieve MultiPart object from response. */ MultiPart objMultiPart = response.getEntity(MultiPart.class); java.util.List<BodyPart> listBodyPart = objMultiPart .getBodyParts(); BodyPart filenameBodyPart = listBodyPart.get(0); BodyPart fileLengthBodyPart = listBodyPart.get(1); BodyPart fileBodyPart = listBodyPart.get(2); /* * Retrieve actual content from BodyParts */ String filename = filenameBodyPart.getEntityAs(String.class); String fileLength = fileLengthBodyPart .getEntityAs(String.class); File streamedFile = fileBodyPart.getEntityAs(File.class); /* * Get the streaming bytes using Input Stream */ BufferedInputStream objBufferedInputStream = new BufferedInputStream( new FileInputStream(streamedFile)); byte[] bytes = new byte[objBufferedInputStream.available()]; objBufferedInputStream.read(bytes); String outFileName = "D:\\" + filename; /* * Write bytes/file to physical system from stream. */ FileOutputStream objFileOutputStream = new FileOutputStream( outFileName); objFileOutputStream.write(bytes); /* * Closing Streams. */ objFileOutputStream.close(); objBufferedInputStream.close(); /* * Lets check, file we received is perfect or not. */ File receivedFile = new File(outFileName); System.out.print("Is the file size is same? :\t"); System.out.println(Long.parseLong(fileLength) == receivedFile .length()); } } catch (UniformInterfaceException e) { e.printStackTrace(); } catch (ClientHandlerException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * @param args */ public static void main(String[] args) { new DownloadFileClient(); } }
Note: If you deployed DownloadFileDemo to an application server other than Tomcat:8181, you may need to correct the port in the above links depending on your application server.
Now, to execute DownloadFileClient, right click on DownloadFileClient and goto Run As > Java Application.
Check your output file and console results.
Downloads
Resources
- DownloadFileDemo.zip contains the DownloadFileDemo project we created in this tutorial.
- JSR 311- JAX-RS: Java API for RESTful Web Services.
- Project Jersey is the JAX-RS reference implementation.
- Jersey Client API
- RESTful Web Services Developer’s Guide
- Architectural Styles and the Design of Network-based Software Architectures, by Roy Thomas Fielding
- Consuming RESTful Web Services With the Jersey Client API
- Configuring JSON for RESTful Web Services in Jersey 1.0
- Get more information about RFC 2616: Hypertext Transfer Protocol — HTTP/1.1
- Read the book RESTful Web Services.
Feedback
I would like to hear from you! If you liked this tutorial, have some suggestions or even some corrections for me, please let me know. I track all user feedback in comments sections.
Hi,
I am trying to send a file from Server to Client.
I get Response status 200 but I got error while reading MediaType.
12:57:33.900 [main] ERROR PathwayGuide::main@55 – org.jvnet.mimepull.MIMEParsingException: Reached EOF, but there is no closing MIME boundary.
javax.ws.rs.WebApplicationException: org.jvnet.mimepull.MIMEParsingException: Reached EOF, but there is no closing MIME boundary.
at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:146) ~[jersey-multipart-1.17.1.jar:1.17.1]
at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:82) ~[jersey-multipart-1.17.1.jar:1.17.1]
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:565) ~[jersey-bundle-1.16.jar:1.16]
Any thoughts on this…
Thanks
while invike service i am getting the below error
response : GET http://localhost:8082/DownloadFileDemo/services/downloadfile/downloadJar/ returned a response status of 405 Method Not Allowed
Client code
============
public DownloadFileClient() {
try {
/*
* Create a client
*/
Client client = Client.create();
WebResource objWebResource = client.resource(“http://localhost:8082/DownloadFileDemo/services/downloadfile/downloadJar”);
ClientResponse response = objWebResource.path(“/”).type(
MediaType.TEXT_HTML).get(ClientResponse.class);
System.out.println(“response : ” + response);
/*
* Check if response has data which web service sent.
*/
if (response.getStatus() == Status.OK.getStatusCode()
&& response.hasEntity()) {
/*
* Retrieve MultiPart object from response.
*/
MultiPart objMultiPart = response.getEntity(MultiPart.class);
java.util.List listBodyPart = objMultiPart
.getBodyParts();
BodyPart filenameBodyPart = listBodyPart.get(0);
BodyPart fileLengthBodyPart = listBodyPart.get(1);
BodyPart fileBodyPart = listBodyPart.get(2);
/*
* Retrieve actual content from BodyParts
*/
String filename = filenameBodyPart.getEntityAs(String.class);
String fileLength = fileLengthBodyPart
.getEntityAs(String.class);
File streamedFile = fileBodyPart.getEntityAs(File.class);
/*
* Get the streaming bytes using Input Stream
*/
BufferedInputStream objBufferedInputStream = new BufferedInputStream(
new FileInputStream(streamedFile));
byte[] bytes = new byte[objBufferedInputStream.available()];
objBufferedInputStream.read(bytes);
String outFileName = “D:\\” + filename;
/*
* Write bytes/file to physical system from stream.
*/
FileOutputStream objFileOutputStream = new FileOutputStream(
outFileName);
objFileOutputStream.write(bytes);
/*
* Closing Streams.
*/
objFileOutputStream.close();
objBufferedInputStream.close();
/*
* Lets check, file we received is perfect or not.
*/
File receivedFile = new File(outFileName);
System.out.print(“Is the file size is same? :\t”);
System.out.println(Long.parseLong(fileLength) == receivedFile
.length());
}
} catch (UniformInterfaceException e) {
e.printStackTrace();
} catch (ClientHandlerException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Server Code
=============
@Path(“downloadfile”)
@Produces(“multipart/mixed”)
//@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_HTML})
public class DownloadFileResource {
@POST
@Produces(“multipart/mixed”)
@Consumes(MediaType.APPLICATION_JSON)
@Path(“/downloadJar”)
public Response getFile() {
/*
* Now create an object of very large file, which you want to
* push/transfer/send to client.
*/
java.io.File objFile = new java.io.File(“C:/Users/mansund/CodeBase-15.3.2/CHOB/fwork-release/lib/CashSweep_Migration.csv”);
/*
* Now create an object of MultiPart class. This class is responsible
* for sending data in chunks. Set the MIME type for MultiPart object as
* multipart/mixed
*/
MultiPart objMultiPart = new MultiPart();
objMultiPart.type(new MediaType(“multipart”, “mixed”));
/*
* Now set Body of MultiPart object. Here we are setting Filename, File
* Length and File Object to Body of MultiPart Object.
*/
objMultiPart
.bodyPart(objFile.getName(), new MediaType(“text”, “plain”));
objMultiPart.bodyPart(objFile.length(), new MediaType(“text”, “plain”));
objMultiPart.bodyPart(objFile, new MediaType(“multipart”, “mixed”));
/*
* Now return response 200 [ok] along with MultiPart object.
*/
return Response.ok(objMultiPart).build();
}
}
It seems that your server code method is @POST while in your client code you are using GET call. That is why it gives 405 – Method not allowed.
Thanks for sharing this solution. It is very useful. I tried to create a upload project using the following code but I keep on getting the error:
com.sun.jersey.api.client.ClientHandlerException: com.sun.jersey.api.client.ClientHandlerException: A message body writer for Java type, class com.sun.jersey.multipart.MultiPart, and MIME media type, multipart/mixed, was not found
Here are the list of jar I have in the library. I have put them all under WEB-INF/lib folder:
aopalliance-repackaged-2.5.0-b05.jar
asm-debug-all-5.0.4.jar
grizzly-servlet-webserver-1.9.42.jar
hk2-api-2.5.0-b05.jar
hk2-locator-2.5.0-b05.jar
hk2-utils-2.5.0-b05.jar
javassist-3.20.0-GA.jar
javax.annotation-api-1.2.jar
javax.inject-2.5.0-b05.jar
javax.servlet-api-3.0.1.jar
javax.ws.rs-api-2.0.1.jar
jaxb-api-2.2.7.jar
jersey-bundle-1.19.1.jar
jersey-client-1.7.jar
jersey-client.jar
jersey-common.jar
jersey-container-servlet-core.jar
jersey-container-servlet.jar
jersey-core-1.1.1-ea.jar
jersey-guava-2.23.2.jar
jersey-media-jaxb.jar
jersey-multipart-1.12.jar
jersey-server-1.9.1.jar
jersey-server.jar
org.osgi.core-4.2.0.jar
osgi-resource-locator-1.0.1.jar
persistence-api-1.0.jar
validation-api-1.1.0.Final.jar
Here is the server code:
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.multipart.BodyPart;
import com.sun.jersey.multipart.MultiPart;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;
@Path(“jerseyattachment”)
public class JerseyAttachmentResource {
@GET
public Response get() {
return Response.ok().build();
}
@POST
@Consumes(“multipart/mixed”)
public Response post(MultiPart multiPart) {
try {
List listBodyPart = multiPart.getBodyParts();
BodyPart fileNameBodyPart = listBodyPart.get(0);
BodyPart fileLengthBodyPart = listBodyPart.get(1);
BodyPart fileBodyPart = listBodyPart.get(2);
String filename = fileNameBodyPart.getEntityAs(String.class);
String fileLength = fileLengthBodyPart.getEntityAs(String.class);
File streamedFile = fileBodyPart.getEntityAs(File.class);
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(streamedFile));
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
//String outFileName = “C:\\temp\\output\\” + filename;
String outFileName = “/tmp/” + filename;
FileOutputStream fileOutputStream = new FileOutputStream(outFileName);
fileOutputStream.write(bytes);
fileOutputStream.close();
inputStream.close();
File receivedFile = new File(outFileName);
System.out.println(“Check if the file size is the same?”);
System.out.println(Long.parseLong(fileLength)==receivedFile.length());
return Response.ok().build();
} catch(UniformInterfaceException e) {
e.printStackTrace();
return Response.status(502).build();
} catch(ClientHandlerException e) {
e.printStackTrace();
return Response.status(504).build();
} catch(FileNotFoundException e) {
e.printStackTrace();
return Response.status(504).build();
} catch(IOException e) {
e.printStackTrace();
return Response.status(506).build();
}
}
}
Here is the client code:
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.multipart.FormDataMultiPart;
import com.sun.jersey.multipart.MultiPart;
import com.sun.jersey.multipart.file.FileDataBodyPart;
import java.io.File;
import java.io.FileInputStream;
import org.junit.After;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import java.util.Properties;
import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.core.MediaType;
public class JerseyAttachmentResourceTest {
private String baseURI;
private String inputFileName;
private String shortFileName;
public JerseyAttachmentResourceTest() {
}
@Before
public void setUp() throws Exception {
String configFileName = “/scratch/ppang/temp/config.properties”;
readFromPropertyFile(configFileName);
}
private void readFromPropertyFile (String propFileName) {
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream(propFileName);
prop.load(input);
baseURI = prop.getProperty(“BaseURL”, “http://localhost:8080/DownloadFile/services/”);
inputFileName = prop.getProperty(“InputFileName”, “/scratch/ppang/temp/LargeFiles/PO_3Meg.xml”);
shortFileName = prop.getProperty(“ShortFileName”, “PO_3Meg.xml”);
} catch(IOException ioe) {
ioe.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
@After
public void tearDown() throws Exception {
}
/**
* @see JerseyAttachmentResource#post(com.sun.jersey.multipart.MultiPart)
*/
@Test
public void testPost() {
ClientResponse response = null;
try {
File file = null;
Client client = Client.create();
WebResource webResource = client.resource(baseURI);
client.setChunkedEncodingSize(1024);
file = new File(inputFileName);
MultiPart objMultiPart = new MultiPart();
objMultiPart.type(new MediaType(“multipart”, “mixed”));
objMultiPart.bodyPart(file.getName(), new MediaType(“text”, “plain”));
objMultiPart.bodyPart(file.length(), new MediaType(“text”, “plain”));
objMultiPart.bodyPart(file, new MediaType(“multipart”, “mixed”));
//FileDataBodyPart filePart = new FileDataBodyPart(“file”, file);
//MultiPart entity = new FormDataMultiPart().bodyPart(filePart);
//webResource.path(“/uploadfile”);
response = webResource.type(new MediaType(“multipart”, “mixed”)).post(ClientResponse.class, objMultiPart);
System.out.println(“Response Status: ” + response.getStatus());
assertEquals(“Response Status”, response.getStatus(), 200);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (response!=null) {
response.close();
}
}
//fail(“Unimplemented”);
}
}