StreamingDatahandler에 출력 스트림을 어떻게 파이프 할 수 있습니까?

StackOverflow https://stackoverflow.com/questions/866051

  •  21-08-2019
  •  | 
  •  

문제

JAX-WS에는 다른 방법에서 출력 스트림을 반환하는 Java 웹 서비스가 있습니다. OutputStream을 반환 된 Datahandler로 스트리밍하는 방법을 알아내는 방법을 알 수없는 것 같습니다. 임시 파일을 작성하고 작성한 다음 다시 입력 스트림으로 다시 열어줍니다. 예는 다음과 같습니다.

@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을 사용하여 데이터를 스트리밍하는 이유입니다. 반환 된 Datahandler (및 궁극적으로 StreamingDatahandler를받는 클라이언트)에게 제공 해야하는 출력 스트림에서 데이터를 직접 스트리밍하는 방법을 고려할 수없는 것 같습니다.

나는 PipedInputStream과 PipedOutputStream과 함께 놀아 보았지만 PipedOutputStream이 작성된 후 Datahandler를 반환해야하기 때문에 필요한 것 같지는 않습니다.

어떤 아이디어?

도움이 되었습니까?

해결책

나는 Christian이 말한 선을 따라 답을 알아 냈습니다 (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(); 동시에, 입력 스트림은 클라이언트로 되돌아 가서 데이터를 읽음으로써 쓰기를 차단 해제합니다. (이 솔루션의 이전 구현의 문제는 스트림을 제대로 닫지 않고 오류가 발생한다는 것입니다.)

다른 팁

죄송합니다. Java가 아닌 C#에 대해서만이 작업을 수행했지만 "writeToout (out)"를 실행하기위한 스레드를 시작해야한다고 생각합니다. Parralel에서. 특수 스트림을 만들어 새 스레드로 전달하여 해당 스트림을 WriteToout에 제공합니다. 스레드를 시작한 후 해당 스트림 객체를 발신자에게 반환합니다.

스트림에 쓰고 나중에 반환하는 메소드와 스트림을 소비하고 나중에 반환하는 다른 방법 만 있으면 다른 방법이 없습니다.

까다로운 부분은 그러한 무형의 금고를 잡는 것입니다. 내부 버퍼가 너무 가득 차면 각 측면을 차단해야합니다.

Java-Pipe-stream이 효과가 있는지 모르겠습니다.

래퍼 패턴? :-).

custom javax.activation.datasource 구현 (4 가지 방법 만)이 작업을 수행 할 수 있습니까?

return new DataHandler(new DataSource() { 
  // implement getOutputStream to return the stream used inside writeToOut() 
  ... 
});   

이것을 테스트 할 수있는 IDE가 없으므로 제안 만 수행합니다. 또한 writeToout 일반 레이아웃이 필요합니다 :-).

내 애플리케이션에서는 FiledAtasource의 파일 대신 생성자 인수로 입력을 취하는 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");
}

}

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top