GlassFish v3 で WebService NetBeans6.5 を使って簡単 Web サービスアプリケーションの作成 その3
今回は、前回の予告どおり、 Web サービスへ、クライアントのローカルファイルを送信するアプリケーションの作成について、執筆して行きたいと思います。
前回判ったことを、簡単におさらいすると、「転送するファイルは base64Binary でエンコードされて SOAP Message Body 部に埋め込まれる」、「 base64Binary に対応する Java の型は、サービス側は、 javax.activation.DataHandler 、クライアント側は byte[] にそれぞれ対応される」、と言うことが判りました。これに従いアプリケーションの作成を進めて行きたいと思います。
今回作成するリソースは、前回同様、ファイルのアップロードを行うための JSP ページ、 Multipart form data を受け取り、公開サービスへ、ファイル送信を行うクライアントとなる Servlet 、 クライアントからファイルを受け取るサービスオペレーションの追加、そして、クライアントへ処理結果を返却する為のメッセージフォームの4つを作成します。
では早速、いつもどおりサービス側のコードの実装作業から取り掛かります。まず最初に前回同様、今回も、サービスの要求元への返信用メッセージフォームの作成をします。メッセージフォームの内容は、以下のとおり :
import java.io.Serializable;実装するメンバーは "error" と "message" の二つ、 "error" については前回同様の使い方で、サービスプロセス中にエラーが発生した場合に、クライアントへエラーであることを伝えるためのフラグ、 "message" は、 "error end" 、 "normal end" 如何に関わらず、サービスプロセス側の処理結果となるメッセージを格納する領域として用意しました。
public class PutFileForm implements Serializable {
private static final long serialVersionUID = 2590453366314788615L;
private boolean error;
private String message;
public boolean isError() {
return error;
}
public void setError(boolean error) {
this.error = error;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
次にサービスオペレーションの追加、前回同様サービスアプリケーションのソースファイルを開き、エディター画面上の任意の最適位置にて右クリックし、 "Web サービス" → "オペレーションを追加"の順にクリックして、オペレーション追加画面を開きます。
"オペレーション名"には "putFile" 、"戻り値の型"については"参照"をクリックして、先ほど作成した form を選択します。そして今回は、前回と違い、ファイルを受け取ると言う処理があるので、パラメーターを指定する必要があります。指定するパラメーターついては、以下のスクリーンショットのとおり :
前回同様、ここまで出来たら配備し、以下の URL にアクセスして xsd を見てみましょう。
http://localhost:8080/sparrow-webservice-server/PortRoyal?xsd=1
今回新たに追加したオペレーション "putFile" が追加されたことが確認できます。オペレーション "putFile" のパラメーターに関する情報については、以下のとおり :
<xs:complexType name="putFile">上記に見られるとおり、サービスパラメーターの型が、 javax.activation.DataHandler に対して、前回同様 "base64Binary" と宣言されていますね。しかしこれは、前回と違い、 byte[] で受け取ったデータを逆に、 javax.activation.DataHandler に変換して、要求元からの転送ファイルを受け取ることを意味しています。
<xs:sequence>
<xs:element name="fileName" type="xs:string" minOccurs="0"/>
<xs:element name="file" type="xs:base64Binary" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
参考までに、サービスオペレーションメソッドの内部実装例を、以下に記載します。 :
@WebMethod(operationName = "putFile")これでサービスアプリケーション側の作業は完了です。次にこのサービスを利用する、クライアント側のアプリケーション作成の作業に取りかかります。前回同様、クライアント側で作成するリソースは、 JSP と Servlet です。まずは Web アプリケーションのクライアントブラウザからファイルを受け取る為の Servet を作成しますが、 http binary upload を行うと言うことは、 multipart request として要求が送信されてくるので、その機能を実装する必要があります。
public PutFileForm putFile(@WebParam(name = "fileName")
final String fileName, @WebParam(name = "file")
final DataHandler file) {
final PutFileForm putFileForm = new PutFileForm();
InputStream receiveFile = null;
OutputStream saveFile = null;
try {
final byte[] buffer = new byte[8192];
int size = 0;
receiveFile = file.getInputStream();
saveFile = new BufferedOutputStream(new FileOutputStream(new File("/Users/Shared/upload/" + fileName)));
while ((size = receiveFile.read(buffer, 0, buffer.length)) != -1) {
saveFile.write(buffer, 0, size);
}
putFileForm.setError(false);
putFileForm.setMessage("Send File Successful !");
} catch (IOException ex) {
putFileForm.setError(true);
putFileForm.setMessage(ex.getLocalizedMessage());
} finally {
try {
if (receiveFile != null) {
receiveFile.close();
}
if (saveFile != null) {
saveFile.flush();
saveFile.close();
}
} catch (IOException ex) {
if (!putFileForm.isError()) {
putFileForm.setError(true);
putFileForm.setMessage(ex.getLocalizedMessage());
}
}
}
return putFileForm;
}
multipart request を自力でハンドリングするのはしんどいですよね、てな訳で、今回 commons-fileupload に頼ることとしました。 commons-fileupload のダウンロードはこちらから取得できます。当ライブラリを利用するにあたり、合わせて、依存関係にある、 "commons-io" についても一緒にダウンロードしておく必要があります。ご注意ください。
commons-fileupload と commons-io の二つのバイナリーをダウンロードしたら、 zip ファイルを展開し、その中から該当の jar ファイルを $GLASSFISH_HOME/lib 配下に配備します。その後、 NetBeans 側にてプロジェクトビルド時のクラスパスに、この二つの jar ファイルを加えます。以上で作成の準備は完了となります。
次に、前回同様、 Web サービス関連のリソースを削除した後、 Web サービスクライアントの再生成を行います。再生成完了後、 Servlet アプリケーションへ、ファイルアップロード受信機能の実装と、 Web サービスクライアント機能の実装を進めていきます。前回も述べたとおり、 Web サービスアプリケーションの実装手順はまったく変わらないので、今回も省略いたします。
因みに Web サービスクライアントアプリケーションのサンプル実装コードについては、以下のとおり、
/** 上記のとおり、サービスオペレーション呼び出しメソッドの引数において、サービス側では javaxactivation.DataHandler に対応するパラメータが、 byte[] とされているのが判ります。 JAX-WS において、 SOAP メッセージ上でファイルの送受信を行う際、クライアント側は byte[] 、サービス側は javax.activation.DataHandler と言うのがお約束事のようですね。 NetBeans を使うと、この辺実装しながら知らず知らずのうちに学んで行けるので、素晴しいですね。
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
final ServletFileUpload sfu = new ServletFileUpload(new DiskFileItemFactory());
FileChannel sendFile = null;
try {
final List list = sfu.parseRequest(request);
final Iterator iterator = list.iterator();
while (iterator.hasNext()) {
final Object obj = iterator.next();
if (obj instanceof FileItem) {
sendFile = ((FileInputStream) ((FileItem) obj).getInputStream()).getChannel();
final int fileSize = new Long(((FileItem) obj).getSize()).intValue();
if (fileSize > Integer.MAX_VALUE) {
request.setAttribute("is.error", new Boolean("true"));
request.setAttribute("error.message", "送信ファイルのサイズは " + Integer.MAX_VALUE + "bytes 以下にして下さい。");
} else {
final ByteBuffer buffer = ByteBuffer.allocateDirect(fileSize);
sendFile.read(buffer);
byte[] sendData = new byte[new Long(((FileItem) obj).getSize()).intValue()];
buffer.flip();
buffer.get(sendData, 0, new Long(((FileItem) obj).getSize()).intValue());
// Call Web Service Operation
PortRoyalService service = new PortRoyalService();
PortRoyal port = service.getPortRoyalPort();
PutFileForm result = port.putFile(((FileItem) obj).getName(), sendData);
//Result message is contained to the context
request.setAttribute("is.error", new Boolean(result.isError()));
request.setAttribute("error.message", result.getMessage());
}
}
}
} catch (FileUploadException ex) {
ex.printStackTrace();
this.buildStackTraceMessage(request, ex);
} catch (Exception ex) {
ex.printStackTrace();
this.buildStackTraceMessage(request, ex);
} finally {
if (sendFile != null) {
sendFile.close();
}
this.getServletContext().getRequestDispatcher("/putfile.jsp").forward(request, response);
}
}
そして最後にファイルアップロード用の JSP ページを作成します。今回は本当に簡単なフォームをと言うことで、入力フォームには file のみを定義しました。サンプルコードは以下のとおり :
<%@page contentType="text/html" pageEncoding="UTF-8"%>これで動かす為のリソースは、全てそろいました。後は、サービス側のコードにも書いたとおりに送信ファイル保存用のディレクトリを作成した後、それぞれのアプリケーションを、 GlassFish v3-Prelude に配備し、実行してみます。
<%@page import="jp.glassfish.sparrow.webservice.server.PortRoyalService" %>
<%@page import="jp.glassfish.sparrow.webservice.server.PortRoyal" %>
<%@page import="jp.glassfish.sparrow.webservice.server.GetFileForm" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Put File</title>
</head>
<body>
<div align="center">
<h1>Web Service Sample</h1>
<form enctype="multipart/form-data" action="./PutFileClient" method="POST">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td align="center">
<br><input type="file" name="file" />
<br><input type="submit" value="Put File Now!" />
</td>
</tr>
<tr>
<td align="left"><br>
<%
try {
if (request.getAttribute("is.error") != null) {
if (((Boolean) request.getAttribute("is.error")).booleanValue()) {
out.println("<font color=\"#FF0000\">");
} else {
out.println("<font color=\"#000000\">");
}
out.println(request.getAttribute("error.message").toString());
}
} catch (Exception ex) {
out.println(ex);
}
%>
</td>
</tr>
</table>
</form>
<br>
</div>
</body>
</html>
まずはファイル送信用のページにアクセス・・・
送信ファイルを選択して、 "Put File Now!" をクリック・・・
以下のスクリーンショットの様に、 "Send File Successful ! " と言うメッセージが表示されればファイルの送信は成功です。
で、画面だけではまだ検証し切れたとは言えないので、ターミナルを使って確認してみました。送信元と送信先のディレクトリを参照し、ファイルサイズと diff コマンドで検証した結果は以下のとおり :
Macintosh:~ jack_spallaw$ cd Downloads/双方のファイルに相違が無い事が確認できました。如何でしたでしょうか? 基礎知識さえあれば、誰でも簡単に Web サービスアプリケーションの作成が出来ますね。但し、 Soap メッセージでファイル転送する際には、制限事項がいくつか存在するようです。私が確認できているものは、以下2つです。
Macintosh:Downloads jack_spallaw$ ls -l glassfish-v3-prelude-unix.sh
-rwxr-xr-x@ 1 jack_spallaw jack_spallaw 27627031 1 11 20:21 glassfish-v3-prelude-unix.sh
Macintosh:Downloads jack_spallaw$ ls -l /Users/Shared/upload/glassfish-v3-prelude-unix.sh
-rw-r--r-- 1 jack_spallaw wheel 27627031 1 12 02:05 /Users/Shared/upload/glassfish-v3-prelude-unix.sh
Macintosh:Downloads jack_spallaw$ diff ./glassfish-v3-prelude-unix.sh /Users/Shared/upload/glassfish-v3-prelude-unix.sh
Macintosh:Downloads jack_spallaw$
・ファイルがサイズが、 java.lang.Integer.MAX_VALUE を超えているものは扱えない。
・ファイルの形式によっては "Unsupported Content-Type" の例外が発生する。
以上になります。この他ご存知の方、いらっしゃれば、是非コメント頂きたいです。
今回使用したサンプルアプリケーションはこちらから取得できます。是非ご活用ください。
さて次回の Web サービストピックは、第4弾として、 SOAPMessageHandler についてのトピックを執筆して生きたいと思います。是非又ご購読のほど、宜しくお願いします。 (*`д´)b goo♪
Comments
Pingback from jacksparrow » GlassFish v3 で WebService NetBeans6.5 を使って簡単 Web サービスアプリケーションの作成 その4
Date: 2009 年 6 月 12 日, 12:52 AM
[...] 前回の投稿からかなりの期間が過ぎてしまい、まことに申し訳ありませんが、今回は予告したとおり、 javax.jws.soap.SOAPMessageHandler の実装方法について執筆して行きたいと思います。今回 [...]



Write a comment