Sending / Transfering / Pushing Files in MultiParts / Chunks from Server to Client with RESTful Web Services in Java

Table Of Content

  1. Introduction
  2. System Requirements
  3. Article Prerequisites
  4. Writing and Deploying the Web Service
  5. Testing the Web Service with Test Client
  6. Resources
  7. 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

Article Prerequisites

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

Downloads

DownloadFileDemo.zip contains the DownloadFileDemo project we created in this tutorial.

Resources

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.

4 Comments

  1. Muhammad Javed says:

    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

  2. mani says:

    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();

    }

    }

    • MyBhavesh says:

      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.

  3. Patrick Pang says:

    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”);
    }
    }

Leave a Reply

Your email address will not be published. Required fields are marked *