Frage

Ich habe ein Java-Web-Service in JAX-WS bekam, die ein Output von einer anderen Methode zurückgibt. Ich kann nicht scheinen, um herauszufinden, wie die Outputstream in den zurückDataHandler als jede andere Art und Weise zu streamen, eine temporäre Datei zu erstellen, schreiben Sie es, es dann als Input wieder öffnen zurück. Hier ein Beispiel:

@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;
    }
}

Das Hauptproblem ist, dass der writeToOut () -Methode Daten zurückgeben kann, die weit größer ist als Speicher des Computers sind. Aus diesem Grunde ist das Verfahren MTOM in erster Linie mit - um die Daten zu streamen. Ich kann nicht meinen Kopf herum zu wickeln scheinen, wie die Daten aus dem Output direkt zu streamen, die ich zu dem zurückgegebenen Datahandler zur Verfügung stellen muß (und letztlich die Kunden, der die StreamingDataHandler erhält).

Ich habe versucht das Spiel mit PipedInputStream und PipedOutputStream, aber die scheinen nicht ganz zu sein, was ich brauche, weil die Datahandler zurückgegeben werden müssten, nachdem die PipedOutputStream zu geschrieben wird.

Irgendwelche Ideen?

War es hilfreich?

Lösung

dachte ich die Antwort aus, entlang der Linien, die Christian spricht über (einen neuen Thread zu schaffen writeToOut () auszuführen):

@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;
    }
}

Es ist ein bisschen komplizierter aufgrund Variablen final, aber soweit ich das richtig das ist sagen kann. Wenn der Thread gestartet wird, blockiert es, wenn es versucht ersten out.write() zu nennen; zur gleichen Zeit wird der Eingangsstrom an den Client zurückgegeben, der durch das Lesen der Daten, die die Schreib deblockiert. (Das Problem mit meinen früheren Implementierungen dieser Lösung war, dass ich nicht richtig, den Strom geschlossen wurde und damit in Fehler ausgeführt wird.)

Andere Tipps

Sorry, ich habe nur diese für C # und Java nicht, aber ich denke, Ihre Methode einen Thread starten sollte laufen „writeToOut (out);“ in parralel. Sie benötigen einen speziellen Strom zu erzeugen und an den neuen Thread übergeben, die diesen Strom zu writeToOut gibt. Nach dem Faden Start zurückkehren Sie dieses Strom-Objekt zu Ihrem Anrufer.

Wenn Sie nur eine Methode, die in einen Stream schreibt und kehrt danach und eine andere Methode, die einen Strom verbraucht und gibt danach, gibt es keinen anderen Weg.

Von coure der schwierige Teil ist halten eine solche -multithreading Safe- Strom zu erhalten. Es wird jede Seite sperren, wenn ein interner Puffer zu voll ist

Sie nicht wissen, ob ein Java-Rohr-Stream für das funktioniert.

Wrapper-Muster? : -).

Benutzerdefinierte javax.activation.DataSource Implementierung (nur 4 Methoden) in der Lage sein, dies zu tun?

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

Ich habe die IDE nicht zur Verfügung, dies zu testen, so bin ich nur einen Vorschlag machen. Ich müsste auch die writeToOut allgemeine Layout :-).

In meiner Anwendung verwende ich InputStreamDataSource Implementierung, die Input als Konstruktor Argument statt Datei in FileDataSource. Es funktioniert so weit.

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");
}

}

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top