Question

J'ai un service Web Java dans JAX-WS qui retourne un OutputStream d'une autre méthode. Je ne peux pas sembler comprendre comment diffuser le OutputStream dans le retour DataHandler tout autre moyen que de créer un fichier temporaire, écrire, puis ouvrez-le revenir à nouveau comme un InputStream. Voici un exemple:

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

Le principal problème est que la méthode writeToOut () peut renvoyer des données qui sont beaucoup plus grandes que la mémoire de l'ordinateur. Voilà pourquoi la méthode utilise MMD en premier lieu - pour diffuser les données. Je ne peux pas sembler envelopper la tête autour de la façon de diffuser les données directement à partir du OutputStream que je dois fournir au retour DataHandler (et en fin de compte du client, qui reçoit le StreamingDataHandler).

J'ai essayé de jouer avec PipedInputStream et PipedOutputStream, mais ceux-ci ne semble pas être tout à fait ce que je dois, parce que le DataHandler devra être retourné après la PipedOutputStream est écrit.

Toutes les idées?

Était-ce utile?

La solution

Je me suis dit la réponse, le long des lignes que Christian parlait (création d'un nouveau thread pour exécuter 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;
    }
}

Il est un peu plus complexe en raison de variables final, mais pour autant que je peux dire cela est correct. Lorsque le fil est commencé, il bloque quand il essaie d'abord d'appeler out.write(); en même temps, le flux d'entrée est retourné au client, qui débloque l'écriture par la lecture des données. (Le problème avec mes précédentes implémentations de cette solution est que je ne fermait pas correctement le flux, et en cours d'exécution ainsi en erreur.)

Autres conseils

Désolé, je ne l'ai fait pour C # et non java, mais je pense que votre méthode devrait lancer un thread à exécuter « writeToOut (out); » en paralléle. Vous devez créer un flux spécial et de le transmettre au nouveau fil qui donne ce courant à writeToOut. Après avoir démarré le fil que vous revenez ce flux-objet à votre correspondant.

Si vous avez seulement une méthode qui écrit dans un flux et retourne ensuite et une autre méthode qui consomme un courant et retourne plus tard, il n'y a pas d'autre moyen.

De la coure partie la plus délicate est de mettre la main sur un tel flux -multithreading sauf-:. Elle bloque chaque côté si un tampon interne est trop plein

Je ne sais pas si un Java-pipe-stream fonctionne pour cela.

modèle Wrapper? : -).

mise en œuvre personnalisée javax.activation.DataSource (seulement 4 méthodes) pour pouvoir le faire?

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

Je n'ai pas l'IDE disponible pour tester ce que je fais donc qu'une suggestion. Je voudrais également besoin de l':-) mise en page générale writeToOut.

Dans ma demande, j'utilise la mise en œuvre InputStreamDataSource qui prennent InputStream comme argument du constructeur au lieu de fichier dans FileDataSource. Il fonctionne jusqu'à présent.

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

}

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top