ReportServlet.java
/*
** Module : ReportServlet.java
** Abstract : ReportServlet provides report service for external clients.
**
** Copyright (c) 2017-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- ----------------Description----------------------
** 001 SBI 20170601 Created initial version.
** 002 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
** 003 GBB 20240430 Replace jPod lib used for merging split docs with pdfbox.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.admin.server;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.goldencode.p2j.admin.server.reports.ReportBuilder.*;
import com.goldencode.p2j.admin.server.reports.*;
import com.goldencode.p2j.admin.shared.*;
import com.goldencode.p2j.util.logging.*;
import org.apache.pdfbox.io.*;
import org.apache.pdfbox.multipdf.*;
/**
* Report servlet handles print requests. Accepted report parameters are listed by
* this enumeration ReportParameters.
*/
public class ReportServlet extends HttpServlet
{
/** The buffer size to hold responses */
private static final int BUFFER_SIZE = 102400;
/** Logger. */
private static final CentralLogger LOG = CentralLogger.get(ReportServlet.class);
/** Max memory in bytes for the buffer writing to the temp merged pdf file. */
private static final int MAX_BUFFER_MEMORY_BYTES = 1000 * 1000; // 1MB
/**
* Handles HTTP GET requests to build reports.
*
* @param req
* The http request
* @param resp
* The http response
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException
{
try
{
Enumeration<String> parameterNames = req.getParameterNames();
ReportRequest reportRequest = new ReportRequest();
LinkedHashMap<String, String> reportParameters = new LinkedHashMap<>();
LinkedHashSet<String> selectedRowsList = new LinkedHashSet<String>();
boolean printAction = false;
while(parameterNames.hasMoreElements())
{
String name = parameterNames.nextElement();
String value = req.getParameter(name);
if (ReportParameters.REPORT_ID.getParameter().equals(name))
{
reportRequest.setReportId(value);
}
else if (ReportParameters.FILTER.getParameter().equals(name))
{
reportRequest.setFilter(value);
}
else if (ReportParameters.PAPER_FORMAT.getParameter().equals(name) ||
ReportParameters.PAPER_ORIENT.getParameter().equals(name) ||
ReportParameters.DETAILS.getParameter().equals(name) ||
ReportParameters.REPORT_TYPE.getParameter().equals(name) ||
ReportParameters.ACTION.getParameter().equals(name)
&& (/*set print action */ printAction = true))
{
reportParameters.put(name, value);
}
else if (name.startsWith(ReportParameters.SELECTION.getParameter()))
{
if (!value.isEmpty())
{
selectedRowsList.add(value);
}
}
else if (name.startsWith(ReportParameters.EXTENSION.getParameter()))
{
reportParameters.put(name, value);
}
};
reportRequest.setReportParameters(reportParameters);
reportRequest.setSelectedRows(selectedRowsList.toArray(new String[0]));
try (Document doc = ReportsManager.buildReport(reportRequest))
{
int parts = doc.getSplittedContent().size();
if (parts > 1)
{
writeMergedDocuments(doc, resp, printAction);
}
else
{
writeOriginalDocument(doc, resp, printAction);
}
}
}
catch (Throwable t)
{
LOG.warning("", t);
throw t;
}
}
/**
* Writes the target document in the http output stream preserving its content type.
*
* @param doc
* The target document
* @param resp
* Provides output stream
* @param printAction
* The true value indicates a print request, otherwise a download file request.
*
* @throws IOException
* The exception if there is a failed output operation.
*/
private void writeOriginalDocument(Document doc,
HttpServletResponse resp,
boolean printAction)
throws IOException
{
byte[] binaryContent = doc.getBinaryContent();
writeDocument(new ByteArrayInputStream(binaryContent),
binaryContent.length,
doc.getDocumentType(),
doc.getDocumentFileName(),
resp,
printAction);
}
/**
* Writes split content of the target document in a one merged pdf file.
*
* @param doc
* The document with split content
* @param resp
* Provides output stream
* @param printAction
* The true value indicates a print request, otherwise a download file request.
*
* @throws IOException
* The exception if there is a failed output operation.
*/
private void writeMergedDocuments(Document doc, HttpServletResponse resp, boolean printAction)
throws IOException
{
String fileName = doc.getDocumentFileName();
DocumentType docType = doc.getDocumentType();
String ext = docType.getExtension();
int index = fileName.lastIndexOf("." + ext);
if (index != -1)
{
fileName = fileName.substring(0, index);
}
PDFMergerUtility pdfMerger = new PDFMergerUtility();
File tempFile = File.createTempFile(fileName, ext);
pdfMerger.setDestinationFileName(tempFile.getAbsolutePath());
tempFile.deleteOnExit();
for (byte[] content : doc.getSplittedContent())
{
pdfMerger.addSource(new ByteArrayInputStream(content));
}
pdfMerger.mergeDocuments(MemoryUsageSetting.setupMixed(MAX_BUFFER_MEMORY_BYTES));
long startDeliver = System.currentTimeMillis();
writeDocument(new FileInputStream(tempFile),
(int) tempFile.length(),
docType,
fileName,
resp,
printAction);
LOG.info(fileName + " was delivered within " + (System.currentTimeMillis() - startDeliver) + "ms");
tempFile.delete();
}
/**
* Writes the document in the http output stream preserving its content type.
*
* @param inputStream
* The input stream of the document.
* @param contentLength
* The length of the content in the input stream.
* @param docType
* The document type.
* @param fileName
* The name of the file to be written.
* @param resp
* The http response.
* @param printAction
* The true value indicates a print request, otherwise a download file request.
*
* @throws IOException
* The exception if there is a failed output operation.
*/
private void writeDocument(InputStream inputStream,
int contentLength,
DocumentType docType,
String fileName,
HttpServletResponse resp,
boolean printAction)
throws IOException
{
if (inputStream == null || docType == null || fileName == null)
{
return;
}
resp.setContentType(docType.getMimeType());
resp.setHeader( "Content-Disposition:", printAction ? "inline" : "attachment;filename=" + fileName);
resp.setContentLength(contentLength);
resp.setBufferSize(BUFFER_SIZE);
ServletOutputStream outputStream = resp.getOutputStream();
try
{
int data = 0;
while ((data = inputStream.read()) != -1)
{
outputStream.write(data);
}
}
finally
{
inputStream.close();
outputStream.flush();
}
}
}