В процессе работы над портлетом столкнулся с небольшой проблемой, решение которой в итоге потребовало определённого количества шаманства. Мой портлет, в ответ на заполнение пользователем текстового поля, должен был возвращать ему некоторый динамически сгенерированный файл. Для того, чтобы это сделать, портлетный ActionResponse не подходит, нужно использовать HttpServletResponse. В итоге код, который возвращает пользователю файл, должен выглядеть примерно так:
HttpServletResponse servletResponse = PortalUtil.getHttpServletResponse(response);
servletResponse.setContentType("text/plain");
servletResponse.setHeader("Content-disposition", "attachment; filename=Lab2.java");
PrintWriter out = servletResponse.getWriter();
generateFile(out); // Пишем файл в поток вывода
out.flush();
out.close();
После того, как портлет с такой реализацией генерации файла был развёрнут на сервере, выяснилась одна странность - в возвращаемом файле были аккуратно "вырезаны" все переносы строк (остальной контент остался в целости и сохранности):
Стандартные операции с установкой кодировки ответа, добавлением "\n\r" в конец каждой строки файла и т.д. ни к чему не привели - переносы строк в возвращаемом файле так и не появились. При этом, если таким же PrintWriter'ом попытаться записать данные в файл, то переносы строк волшебным образом возвращаются на свои места:
Гугление никаких конкретных результатов не дало, но, неожиданно, положительный результат был получен при простой замене вызова метода getWriter() респонса на getOutputStream():
HttpServletResponse servletResponse = PortalUtil.getHttpServletResponse(response);
servletResponse.flushBuffer(); // Предотвращаем IllegalStateException
servletResponse.setContentType("text/plain");
servletResponse.setHeader("Content-disposition", "attachment; filename=Lab2.java");
PrintWriter out = new PrintWriter(servletResponse.getOutputStream());
generateFile(out);
out.flush();
out.close();
Обратите внимание на строку 2 листинга - если заранее не выгрузить буфер, то при обращении к потоку портлет упадёт на IllegalStateException (проблема описана здесь).
В итоге от замены кода на, казалось бы, эквивалентный, переносы строк в файл мистическим образом вернулись:
Причины этой мистики сокрыты в глубинах исходников Liferay и мне пока что непонятны.