From 3d982813b34f6f230baf4a467cdc37ec92a77595 Mon Sep 17 00:00:00 2001 From: netconomy Date: Fri, 17 Aug 2007 06:10:56 +0000 Subject: Performance git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@167 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../at/gv/egiz/pdfas/web/helper/SessionHelper.java | 48 ++++ .../egiz/pdfas/web/helper/SignServletHelper.java | 229 +++++++++++++++++++ .../at/gv/egiz/pdfas/web/helper/TempDirHelper.java | 242 +++++++++++++++++++++ 3 files changed, 519 insertions(+) create mode 100644 src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java create mode 100644 src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java create mode 100644 src/main/java/at/gv/egiz/pdfas/web/helper/TempDirHelper.java (limited to 'src/main/java/at/gv/egiz/pdfas/web/helper') diff --git a/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java b/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java new file mode 100644 index 0000000..5752838 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java @@ -0,0 +1,48 @@ +/** + * + */ +package at.gv.egiz.pdfas.web.helper; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.web.SessionExpiredException; +import at.knowcenter.wag.egov.egiz.web.SessionAttributes; + +/** + * @author wprinz + * + */ +public class SessionHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(SessionHelper.class); + + public static Object getSession(HttpServletRequest request) throws SessionExpiredException + { + + HttpSession session = request.getSession(false); + if (session == null) + { + String msg = "There is no session associated with this request."; //$NON-NLS-1$ + log.error(msg); + throw new SessionExpiredException(msg); + } + + Object sessionObject = session.getAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION); + if (sessionObject == null) + { + String msg = "The session is not found or no longer valid."; //$NON-NLS-1$ + log.error(msg); + throw new SessionExpiredException(msg); + } + + return sessionObject; + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java b/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java new file mode 100644 index 0000000..55e0051 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java @@ -0,0 +1,229 @@ +/** + * + */ +package at.gv.egiz.pdfas.web.helper; + +import java.io.IOException; +import java.net.URL; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.framework.SignatorFactory; +import at.gv.egiz.pdfas.framework.signator.Signator; +import at.gv.egiz.pdfas.web.SignSessionInformation; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.signators.DetachedSignator_1_0_0; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorChooser; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.web.FormFields; +import at.knowcenter.wag.egov.egiz.web.LocalRequestHelper; + +/** + * @author wprinz + * + */ +public class SignServletHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(SignServletHelper.class); + + protected static void dispatch(HttpServletRequest request, HttpServletResponse response, String resource, ServletContext context) throws ServletException, IOException + { + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + + RequestDispatcher disp = context.getRequestDispatcher(resource); + disp.forward(request, response); + } + + + /** + * Prepares the sign. + * + *

+ * This prepares the data for both being signed or being previewed. + *

+ * + * @param si + * The SessionInformation to be prepared. + * @throws PresentableException + * f.e. + */ + public static void prepareSign(SignSessionInformation si) throws PresentableException + { + log.debug("prepareSign:"); //$NON-NLS-1$ + + PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode); + Signator signator = SignatorFactory.createSignator(algorithm); + + // tzefferer: modified + // si.iui = signator.prepareSign(si.pdf, si.type, null, + // ConnectorFactory.needsSIG_ID(si.connector)); + si.si = signator.prepareSign(si.pdfDataSource, si.type, si.pos, ConnectorFactory.needsSIG_ID(si.connector)); + // end modify + log.debug("prepareSign finished."); //$NON-NLS-1$ + } + + /** + * Finishes the sign. + * + *

+ * For non local connectors this concludes the sign process, signs the + * document and returns the result. For local connectors this initializes the + * local sign process and redirects to following servlets. + *

+ * + * @param si + * The SessionInformation. + * @param request + * The servlet request for dispatching. + * @param response + * The servlet response for dispatching. + * @param context + * The servlet context for dispatching. + * @throws PresentableException + * f.e. + * @throws IOException + * f. e. + * @throws ServletException + * f. e. + */ + public static void finishSign(SignSessionInformation si, HttpServletRequest request, HttpServletResponse response, ServletContext context) throws PresentableException, IOException, ServletException + { + log.debug("finishSign:"); //$NON-NLS-1$ + + log.debug("connector = " + si.connector); //$NON-NLS-1$ + if (ConnectorFactory.isConnectorLocal(si.connector)) + { + log.debug("Connector is local -> dispatching to local processing."); //$NON-NLS-1$ + + String dispatch_to = LocalRequestHelper.processLocalSign(si, request, response); + dispatch(request, response, dispatch_to, context); + return; + } + log.debug("Connector is not local -> finishing the sign."); //$NON-NLS-1$ + + PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode); + Signator signator = SignatorFactory.createSignator(algorithm); + + log.debug("RequestURL = " + request.getRequestURL()); + log.debug("ContextPath = " + request.getContextPath()); + String host = request.getServerName(); + URL signature_data_URL = new URL(request.getScheme(), host, request.getServerPort(), request.getContextPath() + "/RetrieveSignatureData"); + String signature_data_url = response.encodeURL(signature_data_URL.toString()); + + Connector c = ConnectorChooser.chooseWebConnectorForSign(si.connector, si.type, signature_data_url); + SignSignatureObject signSignatureObject = c.doSign(si.si.getSignatureData()); + + si.si.setSignSignatureObject(signSignatureObject); + + si.output = TempDirHelper.createTempDataSink(si.filename + "_signed.pdf"); + signator.finishSign(si.si, si.output); + + returnSignResponse(si, response); + + log.debug("finishSign finished."); //$NON-NLS-1$ + } + + /** + * Returns the data in the SignResult with proper content disposition. + * + * @param si + * SessionInformation. + * @param response + * The servlet response. + * @throws IOException + * The IO Exception. + */ + public static void returnSignResponse(SignSessionInformation si, HttpServletResponse response) throws IOException + { +// SignResult sign_result = si.sign_result; + + String file_name = formatFileNameForSignResult(si.filename, si.output.getMimeType()); + + // tzefferer: added condition + if (si.exappinf == null) + { + + // The name parameter is actually deprecated in favour of + // Content-Disposition filename + // Unfortunately Acrobat reader does recognize neither of these parameters + // with its inline save-as. It always takes the page name. + response.setContentType(si.output.getMimeType() + "; name=\"" + file_name + "\""); + if (si.download_inline) + { + response.addHeader("Content-Disposition", "inline; filename=\"" + file_name + "\""); + } + else + { + response.addHeader("Content-Disposition", "attachment; filename=\"" + file_name + "\""); + } + + TempDirHelper.writeDataSinkToHttpResponse(si.output, response); + //response.getOutputStream().write(sign_result.getData()); + + // tzefferer: added else-block + } + else + { + // TODO @tzefferer: what is this code? + throw new RuntimeException("This has to be refactored."); +// SignResult sr = si.sign_result; +// byte[] signed_pdf = sr.getData(); +// PDFContainer entry = new PDFContainer(signed_pdf, si.exappinf.pdf_id); +// ProvidePDFServlet.signedDocuments.add(entry); +// +// // notify webapp... +// String invoke_url = si.exappinf.invoke_url; +// +// String providePDFServlet = "ProvidePDF"; +// String pdf_id = String.valueOf(si.exappinf.pdf_id); +// String session_id = si.exappinf.session_id; +// +// // build URL +// int ind = invoke_url.indexOf("?"); +// String query = invoke_url.substring(0, ind) + ";jsessionid=" + session_id + invoke_url.substring(ind) + "&" + FormFields.FIELD_PDF_URL + "=" + providePDFServlet + "&" + FormFields.FIELD_PDF_ID +// + "=" + pdf_id + "&" + FormFields.FIELD_FILE_LENGTH + "=" + signed_pdf.length; +// +// response.sendRedirect(query); + + } + + } + + /** + * Formats the file name according to the SignResult. + * + * @param file_name + * The file name. + * @param sign_result + * The sign result. + * @return Returns the formatted file name. + */ + public static String formatFileNameForSignResult(String file_name, String mimeType) + { + String output = file_name + "_signed"; + if (mimeType.equals(DetachedSignator_1_0_0.MIME_TYPE)) + { + output += ".xml"; + } + else + { + output += ".pdf"; + } + + return output; + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/web/helper/TempDirHelper.java b/src/main/java/at/gv/egiz/pdfas/web/helper/TempDirHelper.java new file mode 100644 index 0000000..9f2b6fb --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/web/helper/TempDirHelper.java @@ -0,0 +1,242 @@ +/** + * + */ +package at.gv.egiz.pdfas.web.helper; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.TextDataSource; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.impl.input.FileBased; +import at.gv.egiz.pdfas.impl.input.FileBasedPdfDataSourceImpl; +import at.gv.egiz.pdfas.impl.input.FileBasedTextDataSourceImpl; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; +import at.gv.egiz.pdfas.impl.output.FileBasedDataSink; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; + +/** + * @author wprinz + * + */ +public class TempDirHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(TempDirHelper.class); + + protected static long runningIndex = 0; + + public static void storeTextSignatureHoldersIfApplicable(List shs, String fileNameSuffix) throws IOException + { + Iterator it = shs.iterator(); + while (it.hasNext()) + { + SignatureHolder sh = (SignatureHolder) it.next(); + if (sh instanceof TextualSignatureHolder) + { + TextualSignatureHolder tsh = (TextualSignatureHolder) sh; + if (!(tsh.getDataSource() instanceof FileBased)) + { + TextDataSource tds = (TextDataSource) tsh.getDataSource(); + if (isReasonableToStore(tds.getText().length())) + { + TextDataSource fbtds = placeTextIntoTempDir(tds.getText(), fileNameSuffix); + tsh.exchangeDataSource(fbtds); + } + } + } + } + } + + /** + * Places the text into the temp dir if reasonable. + * + *

+ * Reasonable means that the text is longer than a certain threshold. + * Otherwise a short text is simply held in memory. + *

+ * + * @param text + * The text to be stored. + * @param fileNameSuffix + * A file name suffix so that the temp file gets a more "readable" + * name. + * @return Returns the TextDataSource. + * @throws IOException + * F.e. + */ + public static TextDataSource placeTextIntoTempDir(String text, String fileNameSuffix) throws IOException + { + if (isReasonableToStore(text.length())) + { + String fileName = formatFileName(fileNameSuffix); + + File tmpFile = createTempFileInDir(fileName); + + FileOutputStream fos = new FileOutputStream(tmpFile); + OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); + osw.write(text); + osw.close(); + + FileBasedTextDataSourceImpl textDataSource = new FileBasedTextDataSourceImpl(tmpFile, "UTF-8"); + return textDataSource; + } + else + { + return new TextDataSourceImpl(text); + } + } + + /** + * Tells, if it is reasonable to store the text of the given length onto the + * disk. + * + * @param textLength + * The length of the text under question. + * @return Returns true if the text should be stored on the disk. + */ + public static boolean isReasonableToStore(int textLength) + { + return textLength >= 10000; + } + + public static FileBasedPdfDataSourceImpl placePdfIntoTempDir(InputStream pdfInput, String fileNameSuffix) throws IOException + { + File pdfFile = placeInputIntoTempDirFile(pdfInput, fileNameSuffix); + + FileBasedPdfDataSourceImpl pdfDataSource = new FileBasedPdfDataSourceImpl(pdfFile, (int) pdfFile.length()); + return pdfDataSource; + } + + protected static File placeInputIntoTempDirFile(InputStream input, String fileNameSuffix) throws IOException + { + String fileName = formatFileName(fileNameSuffix); + + File tmpFile = createTempFileInDir(fileName); + + FileOutputStream fos = new FileOutputStream(tmpFile); + + byte[] buffer = new byte[2048]; + int read = -1; + while ((read = input.read(buffer)) > 0) + { + fos.write(buffer, 0, read); + } + fos.close(); + input.close(); + + return tmpFile; + } + + protected static String formatFileName(String fileNameSuffix) + { + String fileName = "tmp" + formatIndex(runningIndex) + "_" + fileNameSuffix; + runningIndex++; + + return fileName; + } + + protected static String formatIndex(long index) + { + NumberFormat nf = new DecimalFormat("00000000"); + + return nf.format(index); + } + + protected static File createTempFileInDir(String fileName) throws IOException + { + File tempDir = new File(new File(SettingsReader.RESOURCES_PATH), "pdfastmp"); + + File tmpFile = new File(tempDir, fileName); + + tmpFile.createNewFile(); + + tmpFile.deleteOnExit(); + + return tmpFile; + } + + public static FileBasedDataSink createTempDataSink(String fileNameSuffix) throws IOException + { + String fileName = formatFileName(fileNameSuffix); + + File tmpFile = createTempFileInDir(fileName); + + FileBasedDataSink fbds = new FileBasedDataSink(tmpFile); + + return fbds; + } + + public static void writeDataSinkToHttpResponse(FileBasedDataSink fbds, HttpServletResponse response) throws IOException + { + + response.setContentType(fbds.getMimeType()); + response.setCharacterEncoding(fbds.getCharacterEncoding()); + + OutputStream os = response.getOutputStream(); + + byte[] buffer = new byte[2048]; + FileInputStream fis = new FileInputStream(fbds.getFile()); + int n = -1; + while ((n = fis.read(buffer)) > 0) + { + os.write(buffer, 0, n); + } + fis.close(); + os.close(); + } + + /** + * Deletes the underlying file of the FileBased DataSource. + * + *

+ * If the DataSource is not FileBased, nothing is done. + *

+ *

+ * This is usually used by the application to delete temporary files. + *

+ * + * @param dataSource + */ + public static void deleteDataSourceIfFileBased(DataSource dataSource) + { + if (dataSource instanceof FileBased) + { + FileBased fb = (FileBased) dataSource; + log.debug("Deleting temp file " + fb.getFile()); + boolean deleted = fb.getFile().delete(); + log.debug("deleted = " + deleted); + } + } + + public static void deleteDataSinkIfFileBased(DataSink dataSink) + { + if (dataSink instanceof FileBased) + { + FileBased fb = (FileBased) dataSink; + log.debug("Deleting temp file " + fb.getFile()); + boolean deleted = fb.getFile().delete(); + log.debug("deleted = " + deleted); + } + } + +} -- cgit v1.2.3