RestEasyを使ってjson経由でバイナリファイルをやり取りする

RestEasyの返すjsonBase64エンコーディングした文字列でバイナリを埋め込む。
それをクライアントが受信してデコードしてファイルに戻すサンプル。

xml経由にしたければ @Produces("application/xml") にする。

pom.xml

<?xml version="1.0" encoding="UTF-16"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>sample</groupId>
  <artifactId>sample</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <!-- TODO project name  -->
  <name>quickstart</name>
  <description/>
  <dependencies>
   <dependency>
      <groupId>commons-httpclient</groupId>
      <artifactId>commons-httpclient</artifactId>
      <version>3.1</version>
  </dependency>
    <dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-jaxrs</artifactId>
      <version>2.0.1.GA</version>
      <!-- filter out unwanted jars -->
      <exclusions>
        <exclusion>
          <groupId>javax.servlet</groupId>
          <artifactId>servlet-api</artifactId>
        </exclusion>
        <exclusion>
          <groupId>javax.xml.bind</groupId>
          <artifactId>jaxb-api</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.sun.xml.bind</groupId>
          <artifactId>jaxb-impl</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-jettison-provider</artifactId>
      <version>2.0.1.GA</version>
      <exclusions>
        <exclusion>
          <groupId>javax.xml.bind</groupId>
          <artifactId>jaxb-api</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.sun.xml.bind</groupId>
          <artifactId>jaxb-impl</artifactId>
        </exclusion>
        <exclusion>
          <groupId>javax.xml.stream</groupId>
          <artifactId>stax-api</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <id>jboss</id>
      <name>jboss repo</name>
      <url>http://repository.jboss.org/nexus/content/groups/public/</url>
    </repository>
  </repositories>
  <build>
    <resources>
      <resource>
        <filtering>false</filtering>
        <directory>src/main/resources</directory>
      </resource>
      <resource>
        <filtering>false</filtering>
        <directory>src/main/java</directory>
        <includes>
          <include>**</include>
        </includes>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <filtering>false</filtering>
        <directory>src/test/java</directory>
        <includes>
          <include>**</include>
        </includes>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </testResource>
    </testResources>
    <plugins>
      <plugin>
        <inherited>true</inherited>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
          <optimize>true</optimize>
          <debug>true</debug>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-eclipse-plugin</artifactId>
        <configuration>
          <downloadSources>true</downloadSources>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
  <display-name>sample</display-name>
  <context-param>
    <param-name>resteasy.scan</param-name>
    <param-value>true</param-value>
  </context-param>
  <listener>
    <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
  </listener>
  <servlet>
    <servlet-name>Resteasy</servlet-name>
    <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    <load-on-startup>2</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Resteasy</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

サーバ側

package sample.sample.resources;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

import org.apache.commons.codec.binary.Base64;

import sample.sample.bean.ResponseBean;

/**
 * ローカルのファイルをJSONで処理する
 * 
 * @author bose999
 * 
 */
@Path("/sampleBinrary")
public class SampleBinaryResource {

	/**
	 * コンストラクタ
	 */
	public SampleBinaryResource() {
	}

	/**
	 * GETメソッドのQueryParamのfileNameをローカルのファイルシステムから取得し
	 * Base64エンコード文字列としてjsonで返す
	 * 
	 * @param fileName
	 * @return Response
	 */
	@GET
	@Produces("application/json")
	public Response getSample(@QueryParam("fileName") String fileName) {

		String fileBinaryString = "";
		try {
			// fileをbyte[]で取得する
			byte[] fileBinary = readBinaryFile("/data/sampleBinary/" + fileName);

			// byte[]をBase64エンコーディングしてUTF-8文字列にする
			byte[] encoded = Base64.encodeBase64(fileBinary);
			fileBinaryString = new String(encoded, "UTF-8");
		} catch (IOException e) {
			return makeResponse(404, null);
		}
		// RestEasyにステータスコード200でResponseBeanの内容でXMLを生成して処理を返してもらう
		return makeResponse(200, fileBinaryString);
	}

	/**
	 * statusCodeとreturnStringの内容でレスポンスのXMLを生成する
	 * 
	 * @param statusCode
	 *            int
	 * @param returnString
	 *            String
	 * @return Response
	 */
	private Response makeResponse(int statusCode, String returnString) {

		ResponseBean responseBean = new ResponseBean();
		responseBean.returnString = returnString;

		ResponseBuilder responseBuilder = Response.status(statusCode);

		if (returnString == null) {
			// 返す文字列がnullなので空文字をセット
			responseBuilder = responseBuilder.entity("");
		} else {
			// jsonを返す為にResponseBeanを渡す
			responseBuilder = responseBuilder.entity(responseBean);
		}

		// Responseを生成する
		Response response = responseBuilder.build();

		return response;
	}

	/**
	 * フルパスのファイル名のファイルをbyte[]に変換する
	 * 
	 * @param fileName
	 *            String
	 * @return byte[]
	 * @throws IOException
	 */
	private static byte[] readBinaryFile(String fileName) throws IOException {
		File file = new File(fileName);
		int fileLength = (int) file.length();
		byte[] bytes = new byte[fileLength];
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(file);
			inputStream.read(bytes);
		} finally {
			if (inputStream != null) {
				inputStream.close();
			}
		}
		return bytes;
	}
}

サーバ側Bean

package sample.sample.bean;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="response")
public class ResponseBean {
	
	@XmlElement(name="file")
	public String returnString;
	
}

クライアント

package sample.sample.bean.client;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import javax.ws.rs.core.UriBuilder;

import org.apache.commons.codec.binary.Base64;
import org.jboss.resteasy.client.ClientRequest;
import org.jboss.resteasy.client.ClientResponse;
import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
import org.jboss.resteasy.spi.ResteasyProviderFactory;

import sample.sample.bean.ResponseBean;

/**
 * http://localhost:8080/sample/sampleBinary/xxxに
 * アクセスしてファイルを保存する
 * 
 * @author bose999
 * 
 */
public class SampleBinaryClient {

	/**
	 * EasyRestのURLにアクセスして アクセスしてファイルを保存する
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		// RESTEasy初期化
		RegisterBuiltin.register(ResteasyProviderFactory.getInstance());

		// アクセスするURIをパラメータを含めて生成しリクエスト
		String fileName = "xxx.png";
		
		// http://localhost:8080/sample/sampleBinrary?fileName=xxx.png というURIを生成
		String uri = UriBuilder
				.fromUri("http://localhost:8080/sample/sampleBinrary")
				.queryParam("fileName", fileName).build().toString();
		ClientRequest request = new ClientRequest(uri);

		OutputStream outputStream = null;
		try {
			// レスポンスからファイルの文字列を取得
			ClientResponse<?> response = request.get(ResponseBean.class);
			if (response.getStatus() == 200) {
				ResponseBean responseBean = (ResponseBean) response.getEntity();
				String fileBinaryString = responseBean.returnString;

				// UTF-8のBase64文字列からbyte[]を復元
				byte[] decode = Base64.decodeBase64(fileBinaryString
						.getBytes("UTF-8"));

				// ファイルを生成する
				File outFile = new File("/data/sampleBinary/" + "return-"
						+ fileName);
				outputStream = new FileOutputStream(outFile);
				outputStream.write(decode);
			} else {
				System.out.println("ステータスコード:" + response.getStatus());
			}

		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}