X-APIのデータ通信を行います。
nexacroまたはPlatformDataを利用する全てのクライアントとデータ送受信を行います。データ通信のほとんどはHTTP上で行われ、XML形式に変換された後送受信されます。主なクラスはHttpPlatformRequest、HttpPlatformResponseなどがあります。
はじめに
次はX-APIを用いて、データを送受信する簡単なJSPの例題です。
$r_title(X-APIを用いるJSPの例題)
<%@ page import="com.nexacro.java.xapi.data.*" %>
<%@ page import="com.nexacro.java.xapi.tx.*" %>
<%@ page contentType="text/xml; charset=UTF-8" %>
<%
// バッファ(buffer)初期化
out.clearBuffer();
// HttpServletRequestによるHttpPlatformRequest生成
HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream());
// データ受信
req.receiveData();
// 受信したデータ取得
PlatformData reqData = req.getData();
VariableList reqVarList = reqData.getVariableList();
// 部署名取得
String name = reqVarList.getString("name");
// 送信データ生成
PlatformData resData = new PlatformData();
VariableList resVarList = resData.getVariableList();
// 部署ごとの社員を格納するDataSetオブジェクト生成
DataSet employees = new DataSet("employees");
// DataSetに列(column)追加
employees.addColumn(new ColumnHeader("name", DataTypes.STRING, 8));
employees.addColumn(new ColumnHeader("jobTitle", DataTypes.STRING));
employees.addColumn(new ColumnHeader("number", DataTypes.INT));
employees.addColumn(new ColumnHeader("manager", DataTypes.BOOLEAN));
// 部署ごとの社員データ追加
if ("R&D Center".equals(name)) {
// 行(row)追加
int row = employees.newRow();
// 追加された行(row)のデータ設定
employees.set(row, "name", "John Jones");
employees.set(row, "jobTitle", "developer");
employees.set(row, "number", 1234);
employees.set(row, "manager", false);
// ...
// 正常系
resData.addDataSet(employees);
resVarList.add("ERROR_CODE", 200);
} else if ("Quality Assurance".equals(name)) {
// 行(row)追加
int row = employees.newRow();
// 追加された行(row)のデータ設定
employees.set(row, "name", "Tom Glover");
employees.set(row, "jobTitle", "manager");
employees.set(row, "number", 9876);
employees.set(row, "manager", true);
// ...
// 正常系
resData.addDataSet(employees);
resVarList.add("ERROR_CODE", 200);
} else {
// 異常系
resVarList.add("ERROR_CODE", 500);
}
// HttpServletResponseによるHttpPlatformResponse生成
HttpPlatformResponse res = new HttpPlatformResponse(response);
res.setData(resData);
// データ送信
res.sendData();
%>データ送受信
nexacroとのデータ通信はほとんどの場合にHTTP上で行われ、特定の形式に変換された後に送受信されます。
送受信形式(contentType)はデータが送受信されるためにオブジェクトで特定の形式のデータ(stream)に変換されることを意味し、プロトコル形式(protocolType)はデータの圧縮や暗号化などを行うことを意味します。
送受信形式(contentType)とプロトコル形式(protocolType)などのデータ変換に対する主なインタフェースは下記の通りです。
インタフェース名 | 説明 |
|---|---|
DataSerializer | PlatformDataを特定の形式のデータ(stream)に変換 |
DataDeserializer | 特定の形式のデータ(stream)をPlatformDataに変換 |
ProtocolEncoder | データ(stream)の圧縮や暗号化など |
ProtocolDecoder | 圧縮や暗号化などが適用されたデータ(stream)に対して、圧縮解凍や復号化 |
データ送受信の内部フロー
データ送信フロー
サーバーからデータをPlatformDataに格納して送信
DataSerializerによりPlatformDataが特定の形式のデータ(stream)に変換される
ProtocolEncoderにより圧縮や暗号化などが適用される
HTTP上でデータ(stream)が送信される
データ受信フロー
HTTP上で圧縮や暗号化などが適用されたデータ(stream)を受信
ProtocolDecoderにより圧縮解凍や復号化などが行われる
DataDeserializerにより特定の形式のデータ(stream)がPlatformDataに変換される
Client側がデータの格納されているPlatformDataを受信
下記はPlatformDataをBinary送受信形式で暗号化や圧縮を行う場合の内部フローの例です。
サーバー上のHTTPデータ通信
nexacroとHTTP上でデータ通信を行うためには、HttpPlatformRequestと HttpPlatformResponseを用いてJSPもしくはServletを実装します。
HttpPlatformRequestとHttpPlatformResponseは Jakarta.servlet.http.HttpServletRequestと Jakarta.servlet.http.HttpServletResponse(またはjavax.servlet.http.HttpServletRequestと javax.servlet.http.HttpServletResponse)を用いてHTTP通信を行います。HttpPlatformRequestはnexacroからデータ(stream)を受信した後にPlatformDataに変換し、HttpPlatformResponseはPlatformDataをデータ(stream)に変換した後にnexacroへ送信します。
$r_title(HttpServletRequestによるデータ受信) // HttpServletRequestによりHttpPlatformRequest生成 HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream()); // データ受信 req.receiveData(); PlatformData data = req.getData();
$r_title(HttpServletResponseによるデータ送信) PlatformData data = ...; // HttpServletResponseによりHttpPlatformResponse生成 HttpPlatformResponse res = new HttpPlatformResponse(response); res.setData(data); // データ送信 res.sendData();
$r_title(echo.jspの例題) <%@ page import="com.nexacro.java.xapi.tx.*" %> <%@ page import="com.nexacro.java.xapi.data.*" %> <%@ page contentType="text/xml; charset=UTF-8" %> <% out.clearBuffer(); HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream()); req.receiveData(); PlatformData data = req.getData(); HttpPlatformResponse res = new HttpPlatformResponse(response); res.setData(data); res.sendData(); %>
クライアント上のHTTPデータ通信
PlatformHttpClientはX-APIを用いて実装されたJSPなどのサービスと通信を行い、通信する過程は下記の通りです。
PlatformHttpClient生成
データ送信:sendData
データ受信:receiveData
終了:close
$r_title(PlatformHttpClientによるサーバーとの通信) PlatformData reqData = ...; // Client生成 String url = "http://host/context/service.jsp"; PlatformHttpClient client = new PlatformHttpClient(url); // データ送信 client.sendData(reqData); // データ受信 PlatformData resData = client.receiveData(); // 終了 client.close();
データの送受信形式
送受信形式はデータ送受信の説明通りに、データの送受信のためにオブジェクトで特定の形式のデータ(stream)に変換される形式を意味します。既に用意されている形式は下記の通りです。
定数値 | 説明 |
|---|---|
PlatformType.CONTENT_TYPE_XML | Platformに定義されたXML形式 |
PlatformType.CONTENT_TYPE_BINARY | Platformに定義されたバイナリー形式 |
PlatformType.CONTENT_TYPE_SSV | Platformに定義されたSSV形式 |
PlatformType.CONTENT_TYPE_JSON | Platformに提起されたJSON形式 |
$r_title(XML形式でデータを受信し、Binary形式でデータを送信する例題) <%@ page import="com.nexacro.java.xapi.data.*" %> <%@ page import="com.nexacro.java.xapi.tx.*" %> <% // XML形式でデータ受信 HttpPlatformRequest req = new HttpPlatformRequest(request, PlatformType.CONTENT_TYPE_XML); req.receiveData(); PlatformData data = req.getData(); // Binary形式でデータ送信 HttpPlatformResponse res = new HttpPlatformResponse(response, PlatformType.CONTENT_TYPE_BINARY); res.setData(data); res.sendData(); %>
ユーザ定義の送受信形式ではなく、既に用意されている送受信形式の場合、下記のように HttpPlatformRequestに送受信形式を別途指定しなくても、内部で自動的に送受信形式を判断して処理します。
$r_title(送受信形式を自動判断するHttpPlatformRequest) <%@ page import="com.nexacro.java.xapi.data.*" %> <%@ page import="com.nexacro.java.xapi.tx.*" %> <%@ page contentType="text/xml; charset=UTF-8" %> <% out.clearBuffer(); // 送受信形式を自動で判断してデータ受信 HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream()); req.receiveData(); PlatformData data = req.getData(); // HttpPlatformRequestにより判断された送受信形式でデータ送信 HttpPlatformResponse res = new HttpPlatformResponse(response.getOutputStream(), req); res.setData(data); res.sendData(); %>
データのプロトコル形式
プロトコル形式はデータ送受信の説明通りに、データの圧縮や暗号化などを行うことを意味します。既に用意されている形式は下記の通りです。
定数値 | 説明 |
|---|---|
PlatformType.PROTOCOL_TYPE_ZLIB | ZLIB方式で圧縮 |
$r_title(ZLIB方式で圧縮してデータ送信) <%@ page import="com.nexacro.java.xapi.data.*" %> <%@ page import="com.nexacro.java.xapi.tx.*" %> <% // データ受信 HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream()); req.receiveData(); PlatformData data = req.getData(); // ZLIB方式で圧縮してデータ送信 HttpPlatformResponse res = new HttpPlatformResponse(response, PlatformType.CONTENT_TYPE_BINARY); res.addProtocolType(PlatformType.PROTOCOL_TYPE_ZLIB); res.setData(data); res.sendData(); %>
データの分割送信
一般的にデータはDataSetに格納し、HttpPlatformResponseを用いてnexacroへデータを送信します。しかし、件数が多い大容量データの場合、全てのデータをDataSetに格納すると、メモリ使用量が増えてシステムに負荷がかかることがあります。
このような問題を回避するために、データを複数回分けて送信する機能をサポートします。データは分けて送信しますが、複数のコネクション(connection)は生成せず、1つのコネクション(connection)ですべてのデータを送信します。
データの分割送信は下記の手順で行う必要があります。
オブジェクトの初期化 - HttpPartPlatformResponse生成
送信開始 - HttpPartPlatformResponse.start()の呼び出し(任意)
Variableの送信 - HttpPartPlatformResponse.sendVariable(Variable)の呼び出し
Variableの繰り返し送信
DataSetの送信 - HttpPartPlatformResponse.sendDataSet(DataSet)の呼び出し
DataSetの繰り返し送信
送信終了 - HttpPartPlatformResponse.end()の呼び出し(必須)
Variableの送信とDataSetの送信はそれぞれ省略可能であり、DataSetの送信後にVariableを送信する場合には例外が発生します。
$r_title(データの分割送信)
// HttpPartPlatformResponse生成
HttpPartPlatformResponse res = new HttpPartPlatformResponse(response);
// "company" Variable送信
Variable companyVar = Variable.createVariable("company", "Amazon.com, Inc.");
res.sendVariable(companyVar);
// "url" Variable送信
Variable urlVar = Variable.createVariable("url", "http://www.amazon.com/");
res.sendVariable(urlVar);
// "2011BestBooks" DataSet生成
DataSet bestBooksDs = new DataSet("2011BestBooks");
bestBooksDs.addColumn("title", DataTypes.STRING, 64);
bestBooksDs.addColumn("author", DataTypes.STRING, 64);
bestBooksDs.addColumn("publisher", DataTypes.STRING, 64);
bestBooksDs.addColumn("price", DataTypes.INT, 16);
// "2011BestBooks" DataSetのデータ追加
String[][] bestBooks = {
{ "Lost in Shangri-La", "Mitchell Zuckoff", "Harper", "27" }
// ...
};
for (int i = 0; i < bestBooks.length; i++) {
int row = bestBooksDs.newRow();
bestBooksDs.set(row, "title", bestBooks[i][0]);
bestBooksDs.set(row, "author", bestBooks[i][1]);
bestBooksDs.set(row, "publisher", bestBooks[i][2]);
bestBooksDs.set(row, "price", Float.parseFloat(bestBooks[i][3]));
}
// "2011BestBooks" DataSet送信
// 送信後のDataSetのデータは自動的に削除される
res.sendDataSet(bestBooksDs);
// "fictionBooks" DataSet生成
DataSet fictionBooksDs = new DataSet("fictionBooks");
fictionBooksDs.addColumn("title", DataTypes.STRING, 64);
fictionBooksDs.addColumn("author", DataTypes.STRING, 64);
fictionBooksDs.addColumn("publisher", DataTypes.STRING, 64);
fictionBooksDs.addColumn("price", DataTypes.INT, 16);
// "fictionBooks" DataSetの"comic"データ追加
String[][] comicBooks = {
{ "The Slackers Guide to U.S. History", "John Pfeiffer", "Adams Media", "13" }
// ...
};
for (int i = 0; i < comicBooks.length; i++) {
// ...
}
// "fictionBooks" DataSetの"comic"データ送信
res.sendDataSet(fictionBooksDs);
// "fictionBooks" DataSetの"drama"データ追加
String[][] dramaBooks = {
{ "Megan's Way", "Melissa Foster", "Outskirts Press, Inc.", "15" }
// ...
};
for (int i = 0; i < dramaBooks.length; i++) {
// ...
}
// "fictionBooks" DataSetの"drama"データ送信
res.sendDataSet(fictionBooksDs);
// "fictionBooks" DataSetの"essays"データ追加
String[][] essaysBooks = {
{ "Dracula", "Bram Stoker", "Bedrick. Blackie", "8" }
// ...
};
for (int i = 0; i < essaysBooks.length; i++) {
// ...
}
// "fictionBooks" DataSetの"essays"データ送信
res.sendDataSet(fictionBooksDs);
// HttpPartPlatformResponse終了
res.end();HTTP GET方式のデータ
簡単なデータをHTTP GET方式に送受信する用途として、HttpPlatformRequestでは下記の属性をサポートします。
属性名 | データ形式 | 有効な値 | デフォルト値 | 説明 |
|---|---|---|---|---|
http.getparameter.register | String | trueもしくはfalse | false | データ受信時のHTTP GETデータの登録有無 |
http.getparameter.asvariable | String | trueもしくはfalse | false | HTTP GETデータ登録時Variable形式への変換有無。falseに指定した場合、HTTP GETデータはDataSet形式に変換される。 |
$r_title(HTTP GET方式のデータ受信)
// HttpPlatformRequest生成
HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream());
// HTTP GETデータの登録設定
req.setProperty("http.getparameter.register", "true");
// Variable形式への変換設定
req.setProperty("http.getparameter.asvariable", "true");
// データ受信
req.receiveData();
PlatformData data = req.getData();
// HttpPlatformResponse生成
HttpPlatformResponse res = new HttpPlatformResponse(response);
res.setData(data);
// データ送信
res.sendData();ファイルアップロード
ファイルアップロードはクライアントからサーバー(X-API)へファイルを送信することを意味します。X-APIはファイル送受信のためのAPIでないため、できれば他製品や他パッケージを用いてファイルを送受信することを推奨します。特に、X-APIからXML形式でファイルを送受信する場合にはメモリ使用量が増え、パフォーマンスに影響を与えることがあるため、ご注意ください。
送信データもしくは受信データのデータ形式(dataType)を変更したい場合にはDataTypeChangeにより変更することができます。DataTypeChangerにより、受信したbyte配列もしくはStringデータをファイルとして保存することができます。
ファイルアップロード
クライアントでファイルデータをbyte配列形式としてDataSetに保存
クライアントからサーバーへデータ送信
サーバーでbyte配列形式で送信されたデータのデータ型(dataType)をDataTypes.FILEデータ形式(dataType)に変換するDataTypeChangerを登録
サーバーでクライアントからデータ受信
サーバーでデータを受信する過程で、DataTypes.FILEデータ形式(dataType)に変換されるデータは自動的にテンポラリファイルとして保存
サーバーで保存されたテンポラリファイルを操作
$r_title(ファイルアップロードのjsp例題)
<%@ page import="java.io.*" %>
<%@ page import="com.nexacro.java.xapi.tx.*" %>
<%@ page import="com.nexacro.java.xapi.data.*" %>
<%@ page contentType="text/xml; charset=UTF-8" %>
<%
// バッファ(buffer)初期化
out.clearBuffer();
// HttpPlatformRequest生成
HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream());
// byte配列データをファイルとして保存するためのDataTypeChanger設定
req.setDataTypeChanger(new UploadDataTypeChanger());
// データ受信
req.receiveData();
// 受信されたデータの参照
PlatformData reqData = req.getData();
// テンポラリファイルをアップロードする場所に移動
copyFiles(reqData);
// 送信データの生成
PlatformData resData = new PlatformData();
VariableList resVl = resData.getVariableList();
// エラーコード設定
resVl.add("ERROR_CODE", "200");
// HttpPlatformResponse生成
HttpPlatformResponse res = new HttpPlatformResponse(response.getOutputStream(), req);
// 送信データ設定
res.setData(resData);
// データ送信
res.sendData();
%>
<%!
// テンポラリファイルをアップロードする場所に移動
void copyFiles(PlatformData data) {
// ファイルのアップロード先
String dir = "C:\\upload";
// ファイルデータが保存されたDataSet参照
DataSet ds = data.getDataSet("resources");
// DataSetの行(row)の個数参照
int count = (ds == null) ? 0 : ds.getRowCount();
// DataSetの行(row)の数(=アップロードされたファイル数)分繰り返す
for (int i = 0; i < count; i++) {
// ファイル名参照
String name = ds.getString(i, "name");
// ファイルサイズ参照
int size = ds.getInt(i, "size");
// ファイルの更新時刻参照
long lastWriteTime = ds.getLong(i, "lastWriteTime");
// テンポラリファイルのパス参照
String filename = ds.getString(i, "content");
// テンポラリファイル
File file = new File(filename);
// アップロード先に移動するファイル
File dest = new File(dir, name);
// ファイル移動
file.renameTo(dest);
}
}
// 受信したDataSetの列(column)のデータ形式(dataType)を変更するDataTypeChanger
class UploadDataTypeChanger implements DataTypeChanger {
// byte配列のデータが保存されたDataSetの列(column)データ形式(dataType)をDataTypes.FILEデータ形式(dataType)に変更
// 受信したデータのデータ形式(dataType)をDataTypes.FILEデータ形式(dataType)に変更する場合
// データは自動的にテンポラリファイルとして保存され、DataSetにテンポラリファイルのパスが保存される
public int getDataType(String dsName, String columnName, int dataType) {
// "resources" DataSetの"content"列(columnの場合、DataTypes.FILEデータ形式(dataType)を返す
if ("resources".equals(dsName) && "content".equals(columnName)) {
return DataTypes.FILE;
}
// 上記以外には元のデータ形式(dataType)を返す
return dataType;
}
}
%>ファイルダウンロード
ファイルダウンロードはサーバー(X-API)からクライアントへファイルを送信することを意味します。X-APIはファイル送受信のためのAPIでないため、できれば他製品や他パッケージを用いてファイルを送受信することを推奨します。特に、X-APIからXML形式でファイルを送受信する場合にはメモリ使用量が増え、パフォーマンスに影響を与えることがあるため、ご注意ください。
ファイルデータをクライアントへ送信したい場合には下記の2つの方法があります。
DataSetの列(column)をDataTypes.BLOB形式として追加し、byte配列形式として読み込んだファイルデータをDataSetに設定する。
DataSetの列(column)をDataTypes.FILE形式として追加し、ダウンロードするファイルをパスをDataSetに設定する。データ送信時にDataTypes.FILE形式はDataTypes.BLOB形式に自動変換され、 ファイルパスに位置しているファイルデータが送信される。
下記はDataTypes.FILEのデータ形式(dataType)を利用したファイルダウンロードの例題です。
$r_title(ファイルダウンロードのjsp例題)
<%@ page import="java.io.*" %>
<%@ page import="com.nexacro.java.xapi.tx.*" %>
<%@ page import="com.nexacro.java.xapi.data.*" %>
<%@ page contentType="text/xml; charset=UTF-8" %>
<%
// バッファ(buffer)初期化
out.clearBuffer();
// HttpPlatformRequest生成
HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream());
// データ受信
req.receiveData();
// 受信データ参照
PlatformData reqData = req.getData();
// ファイルデータが含まれている送信データ生成
PlatformData resData = createData();
// HttpPlatformResponse生成
HttpPlatformResponse res = new HttpPlatformResponse(response.getOutputStream(), req);
// 送信データ設定
res.setData(resData);
// データ送信
res.sendData();
%>
<%!
// ファイルデータが含まれている送信データ生成
PlatformData createData() {
// PlatformData生成
PlatformData data = new PlatformData();
// ファイルデータを格納するDataSet生成
DataSet ds = new DataSet("resources");
// ファイル名の列(column)追加
ds.addColumn("name", DataTypes.STRING, 128);
// ファイルサイズの列(column)追加
ds.addColumn("size", DataTypes.INT);
// ファイルの更新時刻の列(column)追加
ds.addColumn("lastWriteTime", DataTypes.LONG);
// ファイルデータの列(column)追加
// データ形式(dataType)をDataTypes.FILEのデータ形式(dataType)として追加する場合
// データ送信時にデータ形式(dataType)はDataTypes.BLOBのデータ形式(dataType)に自動変換され、
// データは設定されているファイルパスのファイルデータを送信する
ds.addColumn("content", DataTypes.FILE);
// DataSetの行(row)にデータ追加
addRow(ds, "C:\\download\\data_structure.gif");
addRow(ds, "C:\\download\\serialize_flow.gif");
// PlatformDataのDataSet追加
data.addDataSet(ds);
// 生成されたPlatformDataを返す
return data;
}
// DataSetの行(row)にデータ追加
void addRow(DataSet ds, String filename) {
// DataSetの行(row)追加
int row = ds.newRow();
// ダウンロードされるFile生成
File file = new File(filename);
// ファイル名設定
ds.set(row, "name", file.getName());
// ファイルサイズ設定
ds.set(row, "size", file.length());
// ファイルの更新時刻設定
ds.set(row, "lastWriteTime", file.lastModified());
// ファイルのパス設定
ds.set(row, "content", file.getPath());
}
%>Streamを用いたデータ通信
SocketやFileなどのようにInputStreamとOutputStreamを用いてデータ通信を行う必要がある場合には、PlatformRequestとPlatformResponseによりデータのやりとりが可能です。もちろん、片方向通信のみ行うことも可能です。
$r_title(PlatformRequestとPlatformResponseによるデータ通信) InputStream in = ...; // PlatformRequest生成 PlatformRequest req = new PlatformRequest(in); // データ受信 req.receiveData(); PlatformData reqData = req.getData(); OutputStream out = ...; // PlatformResponse生成 PlatformData resData = ...; PlatformResponse res = new PlatformResponse(out); res.setData(resData); // データ送信 res.sendData();
ちなみに、下記のようにPlatformRequestとPlatformResponseによりPlatformHttpClientと同様の機能を行うことができます。
$r_title(PlatformRequestとPlatformResponseによるサーバー通信)
// コネクション生成
String loc = "http://host/context/service.jsp";
URL url = new URL(loc);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
// データ送信
PlatformData sendingData = ...;
OutputStream out = conn.getOutputStream();
PlatformResponse res = new PlatformResponse(out, PlatformType.CONTENT_TYPE_XML, "UTF-8");
res.setData(sendingData);
res.sendData();
out.close();
// データ受信
InputStream in = conn.getInputStream();
PlatformRequest req = new PlatformRequest(in);
req.receiveData();
PlatformData receivedData = req.getData();
in.close();
// コネクション終了
conn.disconnect();ファイルからのデータ蓄積と保存
ファイルデータの読み込みや書き出しを行うには下記のような方法があります。
PlatformRequestとPlatformResponseにより直接データの読み込みや書き出しを行う方法
PlatformFileClientによりデータの読み込みや書き出しを行う方法
$r_title(ファイルデータの読み込みや書き出し) // データが保存されているファイル String sourceFilename = ...; InputStream source = new FileInputStream(sourceFilename); // ファイルからデータを読み込む PlatformRequest req = new PlatformRequest(source, PlatformType.CONTENT_TYPE_XML); req.receiveData(); source.close(); PlatformData data = req.getData(); // データを保存するファイル String targetFilename = ...; OutputStream target = new FileOutputStream(targetFilename); // データをファイルに書く出す PlatformResponse res = new PlatformResponse(target, PlatformType.CONTENT_TYPE_BINARY); res.setData(data); res.sendData(); target.close();
$r_title(PlatformFileClientによるデータの読み込みと書き出し) // データ保存されているファイル String sourceFilename = ...; // データを保存するファイル String targetFilename = ...; // PlatformFileClient生成 PlatformFileClient client = new PlatformFileClient(sourceFilename, targetFilename); // 保存されているデータの形式 client.setSourceContentType(PlatformType.CONTENT_TYPE_XML); // データを保存する形式 client.setTargetContentType(PlatformType.CONTENT_TYPE_BINARY); // ファイルからデータを読み込む PlatformData data = client.receiveData(); // データをファイルに書き出す client.sendData(data); // 終了 client.close();
PlatformDataをXML文字列に変換
PlatformDataをXML文字列に変換するにはPlatformResponseを利用します。XML文字列を保存するバッファを生成し、PlatformResponseに渡します。PlatformResponseではXML方式でPlatformDataを出力します。
$r_title(PlatformDataをXML文字列に変換) PlatformData data = ...; // XML文字列を保存するバッファ Writer out = new CharArrayWriter(); // CONTENT_TYPE_XML形式でPlatformResponse生成 PlatformResponse res = new PlatformResponse(out, PlatformType.CONTENT_TYPE_XML); res.setData(data); // XML文字列保存 res.sendData(); out.close(); // 保存されたXML文字列 String xml = out.toString();
追加・変更・削除済データの送信
DataSetはデータ追加、変更、削除された場合に、更新状態および変更前の元のデータを保存します。詳細については、DataSetの元データと変更後のデータをご参照ください。
PlatformResponseもしくはHttpPlatformResponseは上記のようなデータを保存方式(saveType)により区分して送信します。
定数値 | 説明 |
|---|---|
DataSet.SAVE_TYPE_NONE | 未設定 |
DataSet.SAVE_TYPE_ALL | 現在のデータおよび追加・変更・削除済のすべてのデータを保存または送信 |
DataSet.SAVE_TYPE_NORMAL | 現在のデータのみ保存または送信 |
DataSet.SAVE_TYPE_UPDATED | 追加・変更されたデータのみ保存または送信 |
DataSet.SAVE_TYPE_DELETED | 削除済データのみ保存または送信 |
DataSet.SAVE_TYPE_CHANGED | 追加・変更・削除済データのみ保存または送信 |
保存方式(saveType)に関する情報はPlatformDataとDataSetが持っていて、DataSetの保存方式の方が優先的に適用されます。DataSetの保存方式が「DataSet.SAVE_TYPE_NONE」である場合には PlatformDataの保存方式が適用されます。
その際にPlatformDataの保存方式も「DataSet.SAVE_TYPE_NONE」である場合には、デフォルト値の「DataSet.SAVE_TYPE_NORMAL」が適用されます。
StreamLogによる送受信データ(stream)保存
PlatformRequestのStreamLogを用いて、クライアントから受信したデータ(stream)を任意の場所に保存することができます。
この機能は、サーバーからデータ受信中にエラーが発生したり、受信データが不正である可能性があった場合にファイルとして保存することで、あとから確認することができるようにするためです。
注意点としては、StreamLogを有効にしている場合にメモリ使用量が増大することがあるため、必要な場合にのみ有効にしてください。
$r_title(受信データ(stream)保存)
// HttpServletRequestによりHttpPlatformRequest生成
HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream());
// 受信データ(stream)ログの有効化
req.setStreamLogEnabled(true);
// 受信データ(stream)の保存場所
req.setStreamLogDir("/home/log");
// データ受信
// 例外発生時に、自動的に指定したログ保存場所に受信データ(stream)が保存される
req.receiveData();
// 例外が発生しない場合でも必要に応じて強制的にログを保存
req.storeStreamLog();
PlatformData data = req.getData();localhostでのテスト
X-APIの機能は本来サーバーライセンスがない場合には正常に動作しませんが、評価目的での利用はlocalhost(「localhost」もしくは「127.0.0.1」で始まるURLでリクエストする場合)で利用する場合に限定して許諾されます。
localhostでの利用でライセンスエラーを回避するためには下記の通りにソースコードを作成する必要があります。
HttpServletRequestによりHttpPlatformRequestを生成する。
HttpServletResponseと以前の過程で生成されたHttpPlatformRequestにより HttpPlatformResponseを生成する。
ローカルPC上で「localhost」もしくは「127.0.0.1」で始まるURLでリクエストする。
$r_title(localhostでのテストサンプル) <%@ page import="com.nexacro.java.xapi.tx.*" %> <%@ page import="com.nexacro.java.xapi.data.*" %> <%@ page contentType="text/xml; charset=UTF-8" %> <% out.clearBuffer(); HttpPlatformRequest req = new HttpPlatformRequest(request.getInputStream()); req.receiveData(); PlatformData data = req.getData(); HttpPlatformResponse res = new HttpPlatformResponse(response.getOutputStream(), req); res.setData(data); res.sendData(); %>
X-APIの内部ログの出力
X-APIの内部ロギング(logging)はApacheのCommons Loggingを用いて出力します。Apache Commons Loggingの詳細については、下記のページをご参照ください。Apache Commons Loggingのポリシーによってロギング設定をしてログを出力し、開発や運用時に参照する情報として出力されたログを分析します。
http://commons.apache.org/logging/
http://logging.apache.org/log4j/
下記はApache Log4jを用いてX-APIの内部ログをファイルとして出力する例題です。
クラスパスにX-APIのようにApache Log4jのjarファイル(log4j-x.x.x.jar)をコピーする。
log4j.propertiesを作成し、クラスパスにコピーする。
WAS(Web Application Server)を再起動する。
X-APIを利用しているサービスを呼び出す。
Apache Log4jに指定している場所にログファイルが出力される。
$r_title(log4j.properties例外) log4j.logger.com.nexacro.java.xapi.data=DEBUG, file log4j.logger.com.nexacro.java.xapi.tx=DEBUG, file log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.File=xapi.log log4j.appender.file.Append=false log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
Apache Tomcat環境では下記のように設定することができます。
Apache Commons Loggingの jar(commons-logging-x.x.x.jar)を $CATALINA_HOME/common/libにコピーする。
Apache Log4jのjar(log4j-x.x.x.jar)を$CATALINA_HOME/common/libにコピーする。
log4j.propertiesを作成し、$CATALINA_HOME/common/classesにコピーする。
Apache Tomcatを再起動する。
X-APIを利用しているサービスを呼び出す。
Apache Log4jに指定している場所にログファイルが出力される。
$r_title(Apache Tomcatのlog4j.properties例題)
log4j.rootLogger=INFO, tomcat
log4j.logger.com.nexacro.java.xapi.tx=DEBUG, xapi
log4j.logger.com.nexacro.java.xapi.data=DEBUG, xapi
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
log4j.appender.tomcat=org.apache.log4j.FileAppender
log4j.appender.tomcat.File=${catalina.home}/logs/tomcat.log
log4j.appender.tomcat.Append=false
log4j.appender.tomcat.layout=org.apache.log4j.PatternLayout
log4j.appender.tomcat.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
log4j.appender.xapi=org.apache.log4j.FileAppender
log4j.appender.xapi.File=${catalina.home}/logs/xapi.log
log4j.appender.xapi.Append=false
log4j.appender.xapi.layout=org.apache.log4j.PatternLayout
log4j.appender.xapi.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%nデータに含まれているnull文字(0x00)エラー
nexacroのNREとデータ通信を行場合、nexacroのNREとX-APIのnull文字(0x00)の処理方式の違いによって誤動作が発生することがあります。nexacroのNREではnull文字を文字列の終了として認識しますが、X-APIではnull文字を含むことができます。したがって、X-APIでnull文字が含まれていたデータをnexacroのNREに送信した場合、nexacroのNREではnull文字まで表現し、残りのデータは無視されます。
JSPでデータ送信時のjava.lang.IllegalStateException
JSPではHttpPlatformResponseによるデータ送信時に動作は成功しますが、ava.lang.IllegalStateExceptionの例外が発生することがあります。この事象はWeb Application Server環境に依存して発生します。
この例外が発生する原因は、HttpPlatformResponseでJakarta.servlet.http.HttpServletResponse(またはjavax.servlet.http.HttpServletResponse)のOutputStreamを利用するためです。つまり、HttpPlatformResponseで既に HttpServletResponse.getOutputStream()が呼び出された状態で、JSPからもそれを参照するため、Web Application Serverでこの例外を発生させると考えられます。
Web Application Server | 例外発生有無 | 例外メッセージ(バージョンによる) |
|---|---|---|
IBM WebSphere | 発生 | java.lang.IllegalStateException: OutputStream already obtained |
Oracle WebLogic | 無視 | |
Tmax JEUS | 無視 | |
Apache Tomcat | 発生 | java.lang.IllegalStateException: getOutputStream() has already been called for this response |
XMLまたはCSV形式でデータを送信する場合にはJakarta.servlet.http.HttpServletResponse(またはjavax.servlet.http.HttpServletResponse)のWriterを利用するため、上記のような例外は発生しません。SSVまたはBinary形式でデータを送信する場合にのみ例外が発生します。
この例外を回避する方法は下記の通りです。
JSP実行には支障がないため、無視する。(テストデバイスでは可能な方法)
SSVまたはBinary形式で送信する場合にのみ例外が発生するため、XML形式で送信する。
JSPで予めout.clear()とout = pageContext.pushBody()を呼び出して例外発生を防止する。
根本的な原因はJSPからBinary形式で送信することにあるため、JSPの代わりにServletにする。
$r_title(java.lang.IllegalStateExceptionの例外処理) <%@ page import="com.nexacro.java.xapi.tx.*" %> <%@ page import="com.nexacro.java.xapi.data.*" %> <% out.clear(); out = pageContext.pushBody(); // ... HttpPlatformResponse res = new HttpPlatformResponse(response, PlatformType.CONTENT_TYPE_BINARY); res.setData(data); res.sendData(); %>