středa 13. února 2013

Jax-WS - SchemaValidation zkouší číst stream 2x

JAX-WS, Metro, hází "Stream already closed" Při použití streamovaného dataSource

@StreamingAttachment(parseEagerly = true, memoryThreshold = 4000000L)
@WebService(name = "SomeService", targetNamespace = "http://www.comnapy.com/Some/Namespace", serviceName = "SomeService")
@MTOM
@SchemaValidation
view raw gistfile1.java hosted with ❤ by GitHub
Stane se to, že když je zapnutá Schema Validation, tak při validaci se přečte celý stream (ten attachment). Takže validace ho celý přečte a když dojde na skutečné spracování requestu a chtějí se přečíst data, tak to hodí "Stream already closed". A je po srandě.

Neznám žádné rozumné řešení tohoto problému. U nás jsme to pořešili tím, že jsme udělali vlastní DataSource. Která obalí skutečný stream a při prvním zavolání metody getInputStream() - což je z validace nevrátí skutečný stream, ale jen "new ByteArrayInputStream(new byte[]{})"
A až při druhém zavolání metody getInputStream() vrátí skutečný stream.
Tím ho validace nezničí a vše funguje. Jak říkám, jestli ví někdo jak to řešit lépe - sem s tím.

Takový hrozný DataSource pak vypadá zhruba takhle:

import javax.activation.DataSource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Vzniklo to, protoze servisa, ktera ma zapnute @SchemaValidation
* Udela to, ze pri validaci zavola getInputStream a cely ho precte
* Potom se pri vyplnovani responsu znova zavola getInputStream a chce ho napsat do response, jenomze
* to umre, protoze ho uz precetla a zavrela validace.
*
* Reseni: na prvni volani to nevrati pravy inputStream
*/
public class InputStreamDataSourceWithHackForSchemaValidation implements DataSource {
private InputStream inputStream;
private int count = 0;
public InputStreamDataSourceWithHackForSchemaValidation(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public InputStream getInputStream() throws IOException {
if (count == 0) {
//First access to data stream is for @SchemaValidation (and we do not need read stream for validation)
count++;
return new ByteArrayInputStream(new byte[]{});
}
if (count != 1) {
throw new IllegalStateException("getInputStream was expected to be called exactly twice");
}
//second access is for writing data to response
count++;
return inputStream;
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException("Not implemented");
}
@Override
public String getContentType() {
return "*/*";
}
@Override
public String getName() {
return "InputStreamDataSource";
}
}
view raw gistfile1.java hosted with ❤ by GitHub

Žádné komentáře:

Okomentovat