From 689573c90d33198e90c3d04259302ca1d5ff9d0c Mon Sep 17 00:00:00 2001 From: Diego Ruiz <12065321+d-ruiz@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:51:58 +0200 Subject: [PATCH] =?UTF-8?q?IDEMPIERE-6165=20-=20Custom=20name=20is=20not?= =?UTF-8?q?=20taken=20when=20running=20a=20core=20report=20=E2=80=A6=20(#2?= =?UTF-8?q?386)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * IDEMPIERE-6165 - Custom name is not taken when running a core report programatically * IDEMPIERE-6165 - Add unit test * IDEMPIERE-6165 - Peer review changes * IDEMPIERE-6165 - Modified condition to avoid potential NPE * IDEMPIERE-6165 - Changed Unit Test to be thread safe * IDEMPIERE-6165 - Create file in a thread-safe way respecting folder name if existing * IDEMPIERE-6165 - Updated Unit test * IDEMPIERE-6165 - Updated Unit test * IDEMPIERE-6165 - Code refactor to remove code duplication in different classes * IDEMPIERE-6165 - Improved Javadoc --- .../src/org/compiere/print/ReportEngine.java | 24 ++---- .../org/compiere/print/ServerReportCtl.java | 2 + .../src/org/compiere/tools/FileUtil.java | 70 +++++++++++++++-- .../report/jasper/ReportStarter.java | 25 ++---- .../org/idempiere/test/base/ReportTest.java | 76 +++++++++++++++++++ 5 files changed, 154 insertions(+), 43 deletions(-) create mode 100644 org.idempiere.test/src/org/idempiere/test/base/ReportTest.java diff --git a/org.adempiere.base/src/org/compiere/print/ReportEngine.java b/org.adempiere.base/src/org/compiere/print/ReportEngine.java index 3168acee80..232075d855 100644 --- a/org.adempiere.base/src/org/compiere/print/ReportEngine.java +++ b/org.adempiere.base/src/org/compiere/print/ReportEngine.java @@ -857,7 +857,8 @@ queued-job-count = 0 (class javax.print.attribute.standard.QueuedJobCount) try { if (file == null) - file = FileUtil.createTempFile (makePrefix(getName()), ".pdf"); + file = (m_pi != null && !Util.isEmpty(m_pi.getPDFFileName(),true)) ? FileUtil.createFile(m_pi.getPDFFileName()) : + FileUtil.createTempFile (FileUtil.makePrefix(getName()), ".pdf"); } catch (IOException e) { @@ -888,7 +889,7 @@ queued-job-count = 0 (class javax.print.attribute.standard.QueuedJobCount) try { if (file == null) - file = FileUtil.createTempFile (makePrefix(getName()), ".html"); + file = FileUtil.createTempFile (FileUtil.makePrefix(getName()), ".html"); } catch (IOException e) { @@ -919,7 +920,7 @@ queued-job-count = 0 (class javax.print.attribute.standard.QueuedJobCount) try { if (file == null) - file = FileUtil.createTempFile (makePrefix(getName()), ".csv"); + file = FileUtil.createTempFile (FileUtil.makePrefix(getName()), ".csv"); } catch (IOException e) { @@ -950,7 +951,7 @@ queued-job-count = 0 (class javax.print.attribute.standard.QueuedJobCount) try { if (file == null) - file = FileUtil.createTempFile (makePrefix(getName()), ".xls"); + file = FileUtil.createTempFile (FileUtil.makePrefix(getName()), ".xls"); } catch (IOException e) { @@ -988,7 +989,7 @@ queued-job-count = 0 (class javax.print.attribute.standard.QueuedJobCount) try { if (file == null) - file = FileUtil.createTempFile (makePrefix(getName()), ".xlsx"); + file = FileUtil.createTempFile (FileUtil.makePrefix(getName()), ".xlsx"); } catch (IOException e) { @@ -1064,19 +1065,6 @@ queued-job-count = 0 (class javax.print.attribute.standard.QueuedJobCount) return file2.exists(); } // createPDF - private String makePrefix(String name) { - StringBuilder prefix = new StringBuilder(); - char[] nameArray = name.toCharArray(); - for (char ch : nameArray) { - if (Character.isLetterOrDigit(ch)) { - prefix.append(ch); - } else { - prefix.append("_"); - } - } - return prefix.toString(); - } - /** * Create PDF as Data array * @return pdf data diff --git a/org.adempiere.base/src/org/compiere/print/ServerReportCtl.java b/org.adempiere.base/src/org/compiere/print/ServerReportCtl.java index 87a1f7ac03..1ade000110 100644 --- a/org.adempiere.base/src/org/compiere/print/ServerReportCtl.java +++ b/org.adempiere.base/src/org/compiere/print/ServerReportCtl.java @@ -94,6 +94,7 @@ public class ServerReportCtl { { if (pi != null && pi.isBatch() && pi.isPrintPreview()) { + re.setProcessInfo(pi); if ("HTML".equals(pi.getReportType())) { pi.setExport(true); @@ -163,6 +164,7 @@ public class ServerReportCtl { if (pi != null) { jasperProcessInfo.setPrintPreview(pi.isPrintPreview()); jasperProcessInfo.setIsBatch(pi.isBatch()); + jasperProcessInfo.setPDFFileName(pi.getPDFFileName()); } else { jasperProcessInfo.setPrintPreview( !IsDirectPrint ); } diff --git a/org.adempiere.base/src/org/compiere/tools/FileUtil.java b/org.adempiere.base/src/org/compiere/tools/FileUtil.java index f60aceeafd..17cd380c67 100644 --- a/org.adempiere.base/src/org/compiere/tools/FileUtil.java +++ b/org.adempiere.base/src/org/compiere/tools/FileUtil.java @@ -475,12 +475,7 @@ public class FileUtil if (suffix == null) suffix = ".tmp"; - Calendar cal = Calendar.getInstance(); - SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); - String dt = sdf.format(cal.getTime()); - String tmpdirname = (directory != null) ? directory.getCanonicalPath() : System.getProperty("java.io.tmpdir"); - tmpdirname += System.getProperty("file.separator") + "rpttmp_" + dt + "_" + Env.getContext(Env.getCtx(), Env.AD_SESSION_ID) + System.getProperty("file.separator"); - + String tmpdirname = getTempFolderName(directory); File tmpdir = new File(tmpdirname); tmpdir.mkdirs(); @@ -490,11 +485,74 @@ public class FileUtil return f; } + + /** + * Generates a unique temporary folder name based on the current timestamp and session ID.
+ * The folder name is either within the specified directory or the default temporary directory. + * + * @param directory the base directory where the temporary folder will be created; + * if null, the system's default temporary directory is used + * @return a string representing the path to the unique temporary folder + * @throws IOException + */ + public static String getTempFolderName(File directory) throws IOException { + Calendar cal = Calendar.getInstance(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); + String dt = sdf.format(cal.getTime()); + String tmpdirname = (directory != null) ? directory.getCanonicalPath() : System.getProperty("java.io.tmpdir"); + tmpdirname += System.getProperty("file.separator") + "rpttmp_" + dt + "_" + Env.getContext(Env.getCtx(), Env.AD_SESSION_ID) + System.getProperty("file.separator"); + + return tmpdirname; + } public static File createTempFile(String prefix, String suffix) throws IOException { return createTempFile(prefix, suffix, null); } + + /** + * Creates a file with the given filename.
+ * If the filename includes the path, the file is created as requested.
+ * If it only includes the name, the file is created in a thread-safe temporary folder. + * @param fileName + * @return file + * @throws IOException + */ + public static File createFile(String fileName) throws IOException { + if (Util.isEmpty(fileName)) + throw new IllegalArgumentException("Name is required"); + + File file = null; + if (fileName.contains(System.getProperty("file.separator"))) { + file = new File(fileName); + } else { + String tmpdirname = getTempFolderName(null); + File tmpdir = new File(tmpdirname); + tmpdir.mkdirs(); + + file = new File(tmpdirname, fileName); + } + + return file; + } + + /** + * Creates a valid file name prefix from "name" + * @param name + * @return file name prefix + */ + public static String makePrefix(String name) { + StringBuilder prefix = new StringBuilder(); + char[] nameArray = name.toCharArray(); + for (char ch : nameArray) { + if (Character.isLetterOrDigit(ch)) { + prefix.append(ch); + } else { + prefix.append("_"); + } + } + return prefix.toString(); + } /** * diff --git a/org.adempiere.report.jasper/src/org/adempiere/report/jasper/ReportStarter.java b/org.adempiere.report.jasper/src/org/adempiere/report/jasper/ReportStarter.java index 34f0644f51..94b40863aa 100644 --- a/org.adempiere.report.jasper/src/org/adempiere/report/jasper/ReportStarter.java +++ b/org.adempiere.report.jasper/src/org/adempiere/report/jasper/ReportStarter.java @@ -492,7 +492,7 @@ public class ReportStarter implements ProcessCall, ClientProcess processInfo.setPDFReport(batchPDFExportList.get(0)); } else { try { - File pdfFile = File.createTempFile(makePrefix(processInfo.getTitle()), ".pdf"); + File pdfFile = File.createTempFile(FileUtil.makePrefix(processInfo.getTitle()), ".pdf"); Util.mergePdf(batchPDFExportList, pdfFile); processInfo.setPDFReport(pdfFile); } catch (Exception e) { @@ -542,7 +542,7 @@ public class ReportStarter implements ProcessCall, ClientProcess } private File createMultiFileArchive(List exportFileList) throws Exception { - File archiveFile = File.createTempFile(makePrefix(processInfo.getTitle()), ".zip"); + File archiveFile = File.createTempFile(FileUtil.makePrefix(processInfo.getTitle()), ".zip"); try (FileOutputStream out = new FileOutputStream(archiveFile)) { try (ZipOutputStream zip = new ZipOutputStream(out);) { zip.setMethod(ZipOutputStream.DEFLATED); @@ -575,9 +575,9 @@ public class ReportStarter implements ProcessCall, ClientProcess { File pdfFile = null; if (processInfo.getPDFFileName() != null) { - pdfFile = new File(processInfo.getPDFFileName()); + pdfFile = FileUtil.createFile(processInfo.getPDFFileName()); } else { - pdfFile = File.createTempFile(makePrefix(jasperPrint.getName()), ".pdf"); + pdfFile = File.createTempFile(FileUtil.makePrefix(jasperPrint.getName()), ".pdf"); } JRPdfExporter exporter = new JRPdfExporter(jasperReportContext); @@ -637,7 +637,7 @@ public class ReportStarter implements ProcessCall, ClientProcess else newQueryText = originalQueryText + " WHERE " + query.toString(); - File jrxmlFile = File.createTempFile(makePrefix(jasperReport.getName()), ".jrxml"); + File jrxmlFile = File.createTempFile(FileUtil.makePrefix(jasperReport.getName()), ".jrxml"); JRXmlWriter.writeReport(jasperReport, new FileOutputStream(jrxmlFile), "UTF-8"); JasperDesign jasperDesign = JRXmlLoader.load(jrxmlFile); @@ -706,7 +706,7 @@ public class ReportStarter implements ProcessCall, ClientProcess if (ext == null) ext = "pdf"; try { - File exportFile = File.createTempFile(makePrefix(jasperPrint.getName()), "." + ext); + File exportFile = File.createTempFile(FileUtil.makePrefix(jasperPrint.getName()), "." + ext); try (FileOutputStream outputStream = new FileOutputStream(exportFile);) { @@ -826,19 +826,6 @@ public class ReportStarter implements ProcessCall, ClientProcess return viewerLauncher; } - private String makePrefix(String name) { - StringBuilder prefix = new StringBuilder(); - char[] nameArray = name.toCharArray(); - for (char ch : nameArray) { - if (Character.isLetterOrDigit(ch)) { - prefix.append(ch); - } else { - prefix.append("_"); - } - } - return prefix.toString(); - } - private WebResourceLoader getWebResourceLoader() { if (webResourceLoader == null) webResourceLoader = new WebResourceLoader(getLocalDownloadFolder()); diff --git a/org.idempiere.test/src/org/idempiere/test/base/ReportTest.java b/org.idempiere.test/src/org/idempiere/test/base/ReportTest.java new file mode 100644 index 0000000000..eab18899e8 --- /dev/null +++ b/org.idempiere.test/src/org/idempiere/test/base/ReportTest.java @@ -0,0 +1,76 @@ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - Carlos Ruiz - globalqss * + **********************************************************************/ +package org.idempiere.test.base; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.File; + +import org.compiere.model.MOrder; +import org.compiere.model.MPInstance; +import org.compiere.model.MProcess; +import org.compiere.process.ProcessInfo; +import org.compiere.process.ServerProcessCtl; +import org.compiere.util.Env; +import org.idempiere.test.AbstractTestCase; +import org.junit.jupiter.api.Test; + +/** + * @author Diego Ruiz - BX Service GmbH + */ +public class ReportTest extends AbstractTestCase { + + public ReportTest() { + } + + private static final int Order_Print_Process = 110; + + /** + * https://idempiere.atlassian.net/browse/IDEMPIERE-6165 + */ + @Test + public void testPDFFileName() { + MProcess orderReport = MProcess.get(Env.getCtx(), Order_Print_Process); + MOrder order = new MOrder(Env.getCtx(), 108, getTrxName()); // Garden Order 60000 + + String fileName = order.getDocumentNo() + ".pdf"; + + ProcessInfo pi = new ProcessInfo(orderReport.getName(), orderReport.getAD_Process_ID()); + pi.setRecord_ID(order.getC_Order_ID()); + pi.setAD_Client_ID(Env.getAD_Client_ID(Env.getCtx())); + pi.setTable_ID(order.get_Table_ID()); + pi.setPrintPreview(true); + pi.setIsBatch(true); + pi.setPDFFileName(fileName); + pi.setReportType("PDF"); + MPInstance instance = new MPInstance(orderReport, order.get_Table_ID(), order.getC_Order_ID(), order.getC_Order_UU()); + instance.saveEx(); + ServerProcessCtl.process(pi, null); + File file = pi.getPDFReport(); + + assertEquals(file.getName(), fileName); + + } +}