どのようにパイプはStreamingDataHandlerへのOutputStreamできますか?
質問
私は別の方法からOutputStreamを返すJAX-WSのJava Webサービスを持っています。私は、InputStreamとしてバックアップし、再びそれを開く、それへの書き込み、返されたデータハンドラに一時ファイルを作成するよりも、他の方法をOutputStreamをストリーミングする方法を見つけ出すように見えることはできません。ここでは例があります:
@MTOM
@WebService
class Example {
@WebMethod
public @XmlMimeType("application/octet-stream") DataHandler service() {
// Create a temporary file to write to
File fTemp = File.createTempFile("my", "tmp");
OutputStream out = new FileOutputStream(fTemp);
// Method takes an output stream and writes to it
writeToOut(out);
out.close();
// Create a data source and data handler based on that temporary file
DataSource ds = new FileDataSource(fTemp);
DataHandler dh = new DataHandler(ds);
return dh;
}
}
主な問題は、writeToOut()メソッドは、コンピュータのメモリよりもはるかに大きいデータを返すことができるということです。データをストリーミングする - メソッドが最初の場所でMTOMを使用している理由です。私は(StreamingDataHandlerを受け、最終的にクライアント、)返されたデータハンドラに提供する必要があるのOutputStreamから直接データをストリーミングする方法のまわりで私の頭を包むように見えることはできません。
私が持つPipedInputStreamとPipedOutputStreamので遊んで試してみたが、それらはデータハンドラが持つPipedOutputStreamが書き込まれた後に返却する必要があるため、私は必要なかなり何もしていないようです。
任意のアイデア?
解決
私はクリスチャンが話していた線に沿って、答えを考え出した(writeToOutを実行するために、新しいスレッドを作成する()):
@MTOM
@WebService
class Example {
@WebMethod
public @XmlMimeType("application/octet-stream") DataHandler service() {
// Create piped output stream, wrap it in a final array so that the
// OutputStream doesn't need to be finalized before sending to new Thread.
PipedOutputStream out = new PipedOutputStream();
InputStream in = new PipedInputStream(out);
final Object[] args = { out };
// Create a new thread which writes to out.
new Thread(
new Runnable(){
public void run() {
writeToOut(args);
((OutputStream)args[0]).close();
}
}
).start();
// Return the InputStream to the client.
DataSource ds = new ByteArrayDataSource(in, "application/octet-stream");
DataHandler dh = new DataHandler(ds);
return dh;
}
}
これは少しより複雑な変数をfinal
する予定ですが、私の知る限り、これは正しいです。スレッドは、そのブロックを開始すると、それは最初out.write()
呼び出そうとした場合。同時に、入力ストリームは、データを読み出すことにより、書き込みのブロックを解除し、クライアントに返されます。 (このソリューションの私の以前の実装との問題は、私は適切にストリームを閉じ、これによりエラーに実行していなかったということでした。)
他のヒント
申し訳ありませんが、私はC#とJavaのではないためにこれをやったが、私はあなたの方法を実行するスレッドを起動するべきだと思いますparralelインチあなたは特別なストリームを作成し、writeToOutにそのストリームを与える新しいスレッドにそれを渡す必要があります。スレッドを起動した後、あなたの呼び出し元に、そのストリーム・オブジェクトを返します。
あなただけの流れと戻り、その後、その後、ストリームとリターンを消費し、別の方法で、他の方法がないへの書き込み方法を持っている場合。
coureのトリッキーな部分は、-multithreading safe-ストリームのホールドを得ることです:内部バッファがいっぱいである場合、それはそれぞれの側を遮断しなければならない
。Javaのパイプストリームが、そのために動作するかどうか分からないのです。
ラッパーパターン? : - 。)
カスタムjavax.activation.DataSource実装(のみ4メソッド)これを行うことができるようにする?
return new DataHandler(new DataSource() {
// implement getOutputStream to return the stream used inside writeToOut()
...
});
私はので、私は唯一の提案をやってこれをテストするために利用できるIDEを持っていません。私はまた、writeToOut一般的なレイアウト:-)が必要になります。
私のアプリケーションでは、私は、コンストラクタの引数の代わりに、FileDataSourceにファイルとしてInputStreamを取るInputStreamDataSource実装を使用しています。これは、これまでに動作します。
public class InputStreamDataSource implements DataSource {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
private final String name;
public InputStreamDataSource(InputStream inputStream, String name) {
this.name = name;
try {
int nRead;
byte[] data = new byte[16384];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getContentType() {
return new MimetypesFileTypeMap().getContentType(name);
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(buffer.toByteArray());
}
@Override
public String getName() {
return name;
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new IOException("Read-only data");
}
}