Я пишу приложение play 2 и борюсь с проблемой потоковой передачи файлов. Я получаю свои файлы с помощью стороннего API с помощью метода, имеющего следующую сигнатуру:
FileMetadata getFile(OutputStream destination, String fileId)
В традиционном приложении Servlet, если бы я хотел отправить содержимое своему клиенту, я бы сделал что-то вроде:
HttpServletResponse resp;
myService.getFile(resp.getOutpuStream, fileId);
Моя проблема в том, что в моем классе контроллера play 2 у меня нет доступа к базовому OuputStream, поэтому простейшей реализацией моего метода контроллера будет:
public static downloadFile(String id) {
ByteArrayOutputStream baos = new BAOS(...);
myApi.getFile(baos,id); //Load inside temp Array
ByteArrayInputStream bais = new BAIS(baos.toByteArray())
return Ok(bais);
}
Это будет работать, но для этого требуется загрузить весь контент в память перед его обслуживанием, поэтому это не вариант (файлы могут быть огромными ).
Я думал о решении, состоящем в:
Проблема в том, что я не знаю, возможно ли, что (вызов getFile блокируется, поэтому для этого потребуется несколько потоков с общим OutputStream ), и не будет ли это излишним.
Кто-нибудь когда-нибудь сталкивался с такой проблемой и нашел решение? Может ли предложенное мной решение решить мою проблему?
Любые идеи будут оценены.
Спасибо
РЕДАКТИРОВАТЬ 1 Основываясь на предложении kheraud, мне удалось получить рабочий, но все же не идеальный код решения (ниже ).
К сожалению, если во время вызова метода getFile возникает проблема, ошибка не отправляется обратно клиенту (, потому что я вернул Ok ), и браузер бесконечно ждет файл, который никогда не придет.
Есть ли способ справиться с этим случаем?
public static Result downloadFile(String fileId {
Thread readerThread = null;
try {
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);
//Reading must be done in another thread
readerThread = new DownloadFileWorker(fileId,pos);
readerThread.start();
return ok(pis);
} catch (Exception ex) {
ex.printStackTrace();
return internalServerError(ex.toString());
}
}
static class DownloadFileWorker extends Thread{
String fileId;
PipedOutputStream pos;
public DownloadFileWorker(String fileId, PipedOutputStream pos) {
super();
this.fileId = fileId
this.pos = pos;
}
public void run(){
try {
myApi.getFile(pos,fileId);
pos.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
РЕДАКТИРОВАТЬ 2
Я нашел способ избежать бесконечной загрузки страницы, просто добавив pos.close в часть catch ()рабочего потока. Клиент получает файл с нулевым КБ, но я думаю, что это лучше, чем бесконечное ожидание.