IDEMPIERE-4873 Jasper Report Starter Refactoring (#779)

This commit is contained in:
hengsin 2021-07-22 17:42:07 +08:00 committed by GitHub
parent 8d5cf4539d
commit 162c48ec4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1709 additions and 1019 deletions

View File

@ -16,16 +16,20 @@
*****************************************************************************/
package org.compiere.util;
import java.awt.Color;
import java.awt.font.TextAttribute;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
@ -37,6 +41,13 @@ import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
/**
* General Utilities
*
@ -654,26 +665,6 @@ public class Util
return str;
} // trimSize
/**************************************************************************
* Test
* @param args args
*/
public static void main (String[] args)
{
String str = "a<EFBFBD>b<EFBFBD>c?d?e?f?g?";
System.out.println(str + " = " + str.length() + " - " + size(str));
String str1 = trimLength(str, 10);
System.out.println(str1 + " = " + str1.length() + " - " + size(str1));
String str2 = trimSize(str, 10);
System.out.println(str2 + " = " + str2.length() + " - " + size(str2));
//
AttributedString aString = new AttributedString ("test test");
aString.addAttribute(TextAttribute.FOREGROUND, Color.blue);
aString.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, 2, 4);
getIterator (aString, new AttributedCharacterIterator.Attribute[] {TextAttribute.UNDERLINE});
} // main
/**
* String diacritics from given string
* @param s original string
@ -707,4 +698,54 @@ public class Util
cal.set(Calendar.MILLISECOND, 0);
return new Timestamp(cal.getTimeInMillis());
}
/**
*
* @param pdfList
* @param outFile
* @throws IOException
* @throws DocumentException
* @throws FileNotFoundException
*/
public static void mergePdf(List<File> pdfList, File outFile) throws IOException,
DocumentException, FileNotFoundException {
Document document = null;
PdfWriter copy = null;
List<PdfReader> pdfReaders = new ArrayList<PdfReader>();
try
{
for (File f : pdfList)
{
PdfReader reader = new PdfReader(f.getAbsolutePath());
pdfReaders.add(reader);
if (document == null)
{
document = new Document(reader.getPageSizeWithRotation(1));
copy = PdfWriter.getInstance(document, new FileOutputStream(outFile));
document.open();
}
int pages = reader.getNumberOfPages();
PdfContentByte cb = copy.getDirectContent();
for (int i = 1; i <= pages; i++) {
document.newPage();
copy.newPage();
PdfImportedPage page = copy.getImportedPage(reader, i);
cb.addTemplate(page, 0, 0);
copy.releaseTemplate(page);
}
}
document.close();
}
finally
{
for(PdfReader reader:pdfReaders)
{
reader.close();
}
}
}
} // Util

View File

@ -12,12 +12,15 @@ Import-Package: net.sourceforge.barbecue,
org.apache.commons.logging.impl;version="1.1.1",
org.jfree.chart,
org.jfree.chart.plot,
org.osgi.framework;version="1.10.0",
org.osgi.service.event
Require-Bundle: org.adempiere.base;bundle-version="0.0.0",
net.sf.jasperreports.engine;bundle-version="6.3.1"
net.sf.jasperreports.engine;bundle-version="6.3.1",
com.itextpdf;bundle-version="5.5.13"
Service-Component: OSGI-INF/*.xml
Export-Package: org.adempiere.report.jasper
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
Automatic-Module-Name: org.adempiere.report.jasper
Bundle-Vendor: iDempiere Community
Bundle-Activator: org.adempiere.report.jasper.Activator

View File

@ -0,0 +1,54 @@
/***********************************************************************
* 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: *
* - hengsin *
**********************************************************************/
package org.adempiere.report.jasper;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
/**
* @author hengsin
*
*/
public class Activator implements BundleActivator {
private static BundleContext bundleContext = null;
@Override
public void start(BundleContext context) throws Exception {
bundleContext = context;
}
@Override
public void stop(BundleContext context) throws Exception {
bundleContext = null;
}
/**
* @return bundle context
*/
public static BundleContext getBundleContext() {
return bundleContext;
}
}

View File

@ -0,0 +1,191 @@
/***********************************************************************
* 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: *
* - hengsin *
**********************************************************************/
package org.adempiere.report.jasper;
import java.io.File;
import java.util.ArrayList;
import org.adempiere.exceptions.AdempiereException;
import org.compiere.model.MAttachment;
import org.compiere.model.MAttachmentEntry;
import org.compiere.model.MProcess;
import org.compiere.process.ProcessInfo;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.compiere.util.Language;
import org.compiere.utils.DigestOfFile;
/**
* Load report resources from attachment to process
* @author hengsin
*
*/
public class AttachmentResourceLoader {
private final static CLogger log = CLogger.getCLogger(AttachmentResourceLoader.class);
private String destinationFolder;
private MAttachment attachment;
private static final String ATTACHMENT_PATH_PREFIX = "attachment:";
/**
*
* @param destinationFolder
*/
public AttachmentResourceLoader(String destinationFolder) {
this.destinationFolder = destinationFolder;
}
/**
* Get report file from process attachment
*
* @param reportPath must of syntax attachment:filename
* @return File
*/
public File getReportFile(ProcessInfo processInfo, String reportPath) {
File reportFile = null;
String name = reportPath.substring(ATTACHMENT_PATH_PREFIX.length()).trim();
MProcess process = new MProcess(Env.getCtx(), processInfo.getAD_Process_ID(), processInfo.getTransactionName());
attachment = process.getAttachment();
if (attachment != null) {
MAttachmentEntry[] entries = attachment.getEntries();
MAttachmentEntry entry = null;
for (int i = 0; i < entries.length; i++) {
if (entries[i].getName().equals(name)) {
entry = entries[i];
break;
}
}
if (entry != null) {
reportFile = getAttachmentEntryFile(entry);
}
}
return reportFile;
}
/**
* Download db attachment to local file
*
* @param entry
* @return File
*/
private File getAttachmentEntryFile(MAttachmentEntry entry) {
String localFile = destinationFolder + entry.getName();
String downloadedLocalFile = destinationFolder + "TMP_" + entry.getName();
File reportFile = new File(localFile);
if (reportFile.exists()) {
String localMD5hash = DigestOfFile.getMD5Hash(reportFile);
String entryMD5hash = DigestOfFile.getMD5Hash(entry.getData());
if (localMD5hash.equals(entryMD5hash)) {
log.info(" no need to download: local report is up-to-date");
} else {
log.info(" report on server is different from local copy, download and replace");
File downloadedFile = new File(downloadedLocalFile);
entry.getFile(downloadedFile);
if (!reportFile.delete()) {
throw new AdempiereException("Cannot delete temporary file " + reportFile.toString());
}
if (!downloadedFile.renameTo(reportFile)) {
throw new AdempiereException("Cannot rename temporary file " + downloadedFile.toString() + " to "
+ reportFile.toString());
}
}
} else {
entry.getFile(reportFile);
}
return reportFile;
}
private File getAttachmentEntryFile(String resname) {
File fileattach = null;
MAttachmentEntry[] entries = attachment.getEntries();
for (int i = 0; i < entries.length; i++) {
if (entries[i].getName().equals(resname)) {
fileattach = getAttachmentEntryFile(entries[i]);
break;
}
}
return fileattach;
}
/**
* Get property resource file from process attachment
*
* @param bundleName
* @param currLang
* @return File
*/
public File getResourceBundle(String bundleName, Language currLang) {
String resname = bundleName + "_" + currLang.getLocale().getLanguage() + "_" + currLang.getLocale().getCountry()
+ ".properties";
File resFile = getAttachmentEntryFile(resname);
if (resFile == null) {
resname = bundleName + "_" + currLang.getLocale().getLanguage() + ".properties";
resFile = getAttachmentEntryFile(resname);
if (resFile == null) {
resname = bundleName + ".properties";
resFile = getAttachmentEntryFile(resname);
}
}
return resFile;
}
/**
* Get subreports and other resources (for e.g images) from attachment. Assume all other jasper attachment is
* subreport.
*
* @param reportPath
* @return File[] of subreports
*/
public File[] getSubreports(String reportPath) {
String name = reportPath.substring(ATTACHMENT_PATH_PREFIX.length()).trim();
ArrayList<File> subreports = new ArrayList<File>();
MAttachmentEntry[] entries = attachment.getEntries();
for (int i = 0; i < entries.length; i++) {
// @Trifon
if (!entries[i].getName().equals(name)) {
File reportFile = getAttachmentEntryFile(entries[i]);
if (reportFile != null) {
if (entries[i].getName().toLowerCase().endsWith(".jrxml")
|| entries[i].getName().toLowerCase().endsWith(".jasper")) {
subreports.add(reportFile);
}
}
}
}
return subreports.toArray(new File[0]);
}
/**
*
* @param path
* @return true if path starts with "attachment:"
*/
public static boolean isAttachmentResourcePath(String path) {
return path != null && path.startsWith(AttachmentResourceLoader.ATTACHMENT_PATH_PREFIX);
}
}

View File

@ -0,0 +1,229 @@
/***********************************************************************
* 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: *
* - hengsin *
**********************************************************************/
package org.adempiere.report.jasper;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Enumeration;
import java.util.logging.Level;
import org.compiere.util.CLogger;
import org.compiere.util.Language;
import org.compiere.utils.DigestOfFile;
/**
*
* Get report resources from fragment bundle
* @author hengsin
*
*/
public class BundleResourceLoader {
private final static CLogger log = CLogger.getCLogger(BundleResourceLoader.class);
private String destinationFolder;
private String resourcePath;
private static final String BUNDLE_PATH_PREFIX = "bundle:";
/**
*
* @param destinationFolder
*/
public BundleResourceLoader(String destinationFolder) {
this.destinationFolder = destinationFolder;
}
/**
* @param path
* @return File or URL
*/
public Object getResource(String path) {
String resourceName = path.startsWith(BUNDLE_PATH_PREFIX) ? path.substring(BUNDLE_PATH_PREFIX.length()).trim() : path.trim();
File reportFile = null;
boolean empty = true;
String parentPath = "/";
String bundleFileName = resourceName;
if (resourceName.lastIndexOf("/") > 0) {
parentPath = "/"+resourceName.substring(0, resourceName.lastIndexOf("/"));
bundleFileName = resourceName.substring(resourceName.lastIndexOf("/")+1);
}
URL url = null;
Enumeration<URL> entries = Activator.getBundleContext().getBundle().findEntries(parentPath, bundleFileName, false);
if (entries != null && entries.hasMoreElements())
url = entries.nextElement();
if (url != null) {
if (resourceName.endsWith(".jrxml")) {
File tmpOutputFile = null;
try (InputStream inputStream = url.openStream()) {
if (inputStream != null) {
String localResourceName = toLocalName(resourceName);
String localAbsoluteFileName = destinationFolder + localResourceName;
String localAbsolutePathName = localAbsoluteFileName.substring(0, localAbsoluteFileName.lastIndexOf(System.getProperty("file.separator"))+1);
Path localPath = Path.of(localAbsolutePathName);
try {
if (!Files.exists(localPath))
Files.createDirectory(localPath);
} catch (IOException e) {
throw new RuntimeException(e);
}
String localFileName = localAbsoluteFileName.substring(localAbsoluteFileName.lastIndexOf(System.getProperty("file.separator"))+1);
String extension = localFileName.substring(localFileName.lastIndexOf("."));
reportFile = new File(localAbsoluteFileName);
if (!reportFile.exists()) {
reportFile.createNewFile();
tmpOutputFile = reportFile;
} else {
tmpOutputFile = File.createTempFile(localFileName.substring(0, localFileName.lastIndexOf(".")), extension, localPath.toFile());
}
try (OutputStream out = new FileOutputStream(tmpOutputFile);) {
if (out != null) {
byte buf[] = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0) {
empty = false;
out.write(buf, 0, len);
}
}
}
}
} catch (Exception e) {
log.log(Level.SEVERE, e.getMessage(), e);
empty = true;
}
if (!empty && tmpOutputFile != reportFile) {
if (!DigestOfFile.md5HashCompare(reportFile, tmpOutputFile)) {
Path to = reportFile.toPath();
Path from = tmpOutputFile.toPath();
try {
Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
log.log(Level.SEVERE, e.getMessage(), e);
return null;
}
}
try {
Files.delete(tmpOutputFile.toPath());
} catch (IOException e) {}
}
} else {
empty = false;
}
}
if (empty)
return null;
if (url != null) {
resourcePath = url.toString();
if (resourcePath != null && resourcePath.lastIndexOf("/") > 0)
resourcePath = resourcePath.substring(0, resourcePath.lastIndexOf("/")+1);
}
return reportFile != null ? reportFile : url;
}
private String toLocalName(String name) {
String localName = name;
if (localName.startsWith("/"))
localName = localName.substring(1);
if (localName.lastIndexOf("/") > 0) {
String path = localName.substring(0, localName.lastIndexOf("/"));
localName = localName.substring(localName.lastIndexOf("/")+1);
path = path.replace('/', '_');
localName = path + System.getProperty("file.separator") + localName;
}
return localName;
}
/**
* Get property resource file from resources
*
* @param bundleName
* @param currLang
* @return URL
*/
public URL getResourceBundle(String bundleName, Language currLang) {
String resname = bundleName + "_" + currLang.getLocale().getLanguage() + "_" + currLang.getLocale().getCountry()
+ ".properties";
URL resourceURL = null;
try {
resourceURL = (URL) getResource(resname);
} catch (Exception e) {
// ignore exception - file couldn't exist
}
if (resourceURL == null) {
resname = bundleName + "_" + currLang.getLocale().getLanguage() + ".properties";
try {
resourceURL = (URL) getResource(resname);
} catch (Exception e) {
// ignore exception - file couldn't exist
}
if (resourceURL == null) {
resname = bundleName + ".properties";
try {
resourceURL = (URL) getResource(resname);
} catch (Exception e) {
// ignore exception - file couldn't exist
}
}
}
return resourceURL;
}
/**
* @param path The full path to the parent report
* @return File[0];
*/
public File[] getSubreports(String path) {
return new File[0];
}
/**
*
* @return url path to load subreports, images and resource bundle
*/
public String getRelatedResourcesPath() {
return resourcePath;
}
/**
*
* @param path
* @return true if path is "bundle:*"
*/
public static boolean isBundleResourcePath(String path) {
return path != null && path.startsWith(BUNDLE_PATH_PREFIX);
}
}

View File

@ -0,0 +1,222 @@
/***********************************************************************
* 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: *
* - hengsin *
**********************************************************************/
package org.adempiere.report.jasper;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.logging.Level;
import org.compiere.util.CLogger;
import org.compiere.util.Language;
import org.compiere.utils.DigestOfFile;
/**
*
* Get report resources from class path
* @author hengsin
*
*/
public class ClassResourceLoader {
private final static CLogger log = CLogger.getCLogger(ClassResourceLoader.class);
private String destinationFolder;
private String resourcePath;
private static final String RESOURCE_PATH_PREFIX = "resource:";
/**
*
* @param destinationFolder
*/
public ClassResourceLoader(String destinationFolder) {
this.destinationFolder = destinationFolder;
}
/**
* @param path
* @return File or URL
*/
public Object getResource(String path) {
boolean empty = true;
URL url = null;
File reportFile = null;
String resourceName = path.startsWith(RESOURCE_PATH_PREFIX) ? path.substring(RESOURCE_PATH_PREFIX.length()).trim() : path.trim();
//only copy to tmp if reportPath is jrxml file (for compilation)
if (resourceName.endsWith(".jrxml")) {
String localResourceName = toLocalName(resourceName);
String localAbsolutePathName = destinationFolder + localResourceName;
reportFile = new File(localAbsolutePathName);
String localPathName = localAbsolutePathName.substring(0, localAbsolutePathName.lastIndexOf(System.getProperty("file.separator"))+1);
Path localAbsolutePath = Path.of(localPathName);
try {
if (!Files.exists(localAbsolutePath))
Files.createDirectory(localAbsolutePath);
} catch (IOException e) {
throw new RuntimeException(e);
}
String localFileName = localAbsolutePathName.substring(localAbsolutePathName.lastIndexOf(System.getProperty("file.separator"))+1);
String extension = localFileName.substring(localFileName.lastIndexOf("."));
File tmpOutputFile = null;
url = getClass().getClassLoader().getResource(resourceName);
if (url != null) {
try (InputStream inputStream = url.openStream()) {
if (inputStream != null) {
if (!reportFile.exists()) {
reportFile.createNewFile();
tmpOutputFile = reportFile;
} else {
tmpOutputFile = File.createTempFile(localFileName.substring(0, localFileName.lastIndexOf(".")), extension, localAbsolutePath.toFile());
}
try (OutputStream out = new FileOutputStream(tmpOutputFile);) {
if (out != null) {
byte buf[] = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0) {
empty = false;
out.write(buf, 0, len);
}
}
}
}
} catch (Exception e) {
log.log(Level.SEVERE, e.getMessage(), e);
empty = true;
}
if (!empty && tmpOutputFile != reportFile) {
if (!DigestOfFile.md5HashCompare(reportFile, tmpOutputFile)) {
Path to = reportFile.toPath();
Path from = tmpOutputFile.toPath();
try {
Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
log.log(Level.SEVERE, e.getMessage(), e);
return null;
}
}
try {
Files.delete(tmpOutputFile.toPath());
} catch (IOException e) {}
}
}
} else {
url = getClass().getClassLoader().getResource(resourceName);
empty = (url == null);
}
if (empty)
return null;
if (url != null) {
resourcePath = url.toString();
if (resourcePath != null && resourcePath.lastIndexOf("/") > 0)
resourcePath = resourcePath.substring(0, resourcePath.lastIndexOf("/")+1);
}
return reportFile != null ? reportFile : url;
}
private String toLocalName(String name) {
String localName = name;
if (localName.startsWith("/"))
localName = localName.substring(1);
if (localName.lastIndexOf("/") > 0) {
String path = localName.substring(0, localName.lastIndexOf("/"));
localName = localName.substring(localName.lastIndexOf("/")+1);
path = path.replace('/', '_');
localName = path + System.getProperty("file.separator") + localName;
}
return localName;
}
/**
* Get property resource file from resources
*
* @param bundleName
* @param currLang
* @return URL
*/
public URL getResourceBundle(String bundleName, Language currLang) {
String resourceName = bundleName + "_" + currLang.getLocale().getLanguage() + "_" + currLang.getLocale().getCountry()
+ ".properties";
URL resourceURL = null;
try {
resourceURL = (URL) getResource(resourceName);
} catch (Exception e) {
// ignore exception - file couldn't exist
}
if (resourceURL == null) {
resourceName = bundleName + "_" + currLang.getLocale().getLanguage() + ".properties";
try {
resourceURL = (URL) getResource(resourceName);
} catch (Exception e) {
// ignore exception - file couldn't exist
}
if (resourceURL == null) {
resourceName = bundleName + ".properties";
try {
resourceURL = (URL) getResource(resourceName);
} catch (Exception e) {
// ignore exception - file couldn't exist
}
}
}
return resourceURL;
}
/**
* @param path The full path to the parent report
* @return File[0]
*/
public File[] getSubreports(String path) {
return new File[0];
}
/**
*
* @return url path to load subreports, images and resource bundle
*/
public String getRelatedResourcesPath() {
return resourcePath;
}
/**
*
* @param path
* @return true if path is "resource:*"
*/
public static boolean isClassResourcePath(String path) {
return path != null && path.startsWith(RESOURCE_PATH_PREFIX);
}
}

View File

@ -0,0 +1,136 @@
/***********************************************************************
* 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: *
* - hengsin *
**********************************************************************/
package org.adempiere.report.jasper;
import java.io.File;
import java.io.FilenameFilter;
import java.net.URI;
import java.net.URISyntaxException;
import org.compiere.util.CLogger;
import org.compiere.util.Language;
/**
*
* @author hengsin
*
*/
public class FileResourceLoader {
private final static CLogger log = CLogger.getCLogger(FileResourceLoader.class);
private static final String FILE_PATH_PREFIX = "file:/";
public FileResourceLoader() {
}
/**
*
* @param reportPath
* @return File
*/
public File getReportFile(String reportPath) {
File reportFile = null;
try {
reportFile = new File(new URI(reportPath));
} catch (URISyntaxException e) {
log.warning(e.getLocalizedMessage());
reportFile = null;
}
return reportFile;
}
/**
* Get property resource file from file://
*
* @param resourcePath
* @param bundleName
* @param currLang
* @return File
*/
public File getResourceBundle(String resourcePath, String bundleName, Language currLang) {
String resname = bundleName + "_" + currLang.getLocale().getLanguage() + "_" + currLang.getLocale().getCountry()
+ ".properties";
File resFile = new File(resourcePath, resname);
if (!resFile.exists()) {
resname = bundleName + "_" + currLang.getLocale().getLanguage() + ".properties";
resFile = new File(resourcePath, resname);
if (!resFile.exists()) {
resname = bundleName + ".properties";
resFile = new File(resourcePath, resname);
if (!resFile.exists()) {
resFile = null;
}
}
}
return resFile;
}
/**
*
* @param reportFile
* @param reportDir
* @return File[]
*/
public File[] getSubreports(File reportFile, File reportDir) {
return reportDir.listFiles(new FileFilter(reportFile, reportDir));
}
/**
*
* @param path
* @return true if path is "file:*"
*/
public static boolean isFileResourcePath(String path) {
return path != null && path.startsWith(FILE_PATH_PREFIX);
}
private static class FileFilter implements FilenameFilter {
private File directory;
private File reportFile;
/**
*
* @param reportFile
* @param directory
*/
public FileFilter(File reportFile, File directory) {
this.reportFile = reportFile;
this.directory = directory;
}
@Override
public boolean accept(File file, String name) {
if (file.equals(directory)) {
if (!name.equals(reportFile.getName())) {
String lower = name.toLowerCase();
if (lower.endsWith(".jasper") || lower.endsWith(".jrxml"))
return true;
}
}
return false;
}
}
}

View File

@ -0,0 +1,241 @@
/***********************************************************************
* 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: *
* - hengsin *
**********************************************************************/
package org.adempiere.report.jasper;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.compiere.util.CLogger;
import org.compiere.util.Language;
import org.compiere.util.Util;
import org.compiere.utils.DigestOfFile;
/**
*
* Load report resources from http or https
* @author hengsin
*
*/
public class WebResourceLoader {
private final static CLogger log = CLogger.getCLogger(WebResourceLoader.class);
private String destinationFolder;
/**
*
* @param destinationFolder destination folder to download report file to
*/
public WebResourceLoader(String destinationFolder) {
this.destinationFolder = destinationFolder;
}
/**
* Download remote report file from web server
*
* @param reportFilePath full http path to report file
* @return downloaded File
*/
private File downloadFile(String reportFilePath) {
File reportFile = null;
File downloadedFile = null;
if (log.isLoggable(Level.INFO))
log.info(" report deployed to " + reportFilePath);
try {
String[] tmps = reportFilePath.split("/");
String fileName = tmps[tmps.length - 1];
String localFilePath = destinationFolder + fileName;
String tmpLocalFilePath = destinationFolder + "TMP_" + fileName;
reportFile = new File(localFilePath);
if (reportFile.exists()) {
String remoteMD5Hash = getRemoteMD5(reportFilePath);
if (!Util.isEmpty(remoteMD5Hash, true)) {
String localMD5hash = DigestOfFile.getMD5Hash(reportFile);
if (log.isLoggable(Level.INFO))
log.info("MD5 for local file is " + localMD5hash);
if (localMD5hash.equals(remoteMD5Hash.trim())) {
if (log.isLoggable(Level.INFO))
log.info("MD5 match: local report file is up-to-date");
return reportFile;
} else {
if (log.isLoggable(Level.INFO))
log.info("MD5 is different, download and replace");
downloadedFile = getRemoteFile(reportFilePath, tmpLocalFilePath);
if (downloadedFile != null) {
Path to = reportFile.toPath();
Path from = downloadedFile.toPath();
Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING);
Files.delete(from);
return to.toFile();
} else {
return null;
}
}
} else {
downloadedFile = getRemoteFile(reportFilePath, tmpLocalFilePath);
if (downloadedFile == null)
return null;
// compare hash of existing and downloaded
if (DigestOfFile.md5HashCompare(reportFile, downloadedFile)) {
// nothing file are identical
if (log.isLoggable(Level.INFO))
log.info("MD5 match: local report file is up-to-date");
return reportFile;
} else {
if (log.isLoggable(Level.INFO))
log.info("MD5 is different, replace with downloaded file");
Path to = reportFile.toPath();
Path from = downloadedFile.toPath();
Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING);
Files.delete(from);
return to.toFile();
}
}
} else {
reportFile = getRemoteFile(reportFilePath, localFilePath);
return reportFile;
}
} catch (Exception e) {
throw new AdempiereException("Unknown exception: " + e.getLocalizedMessage());
}
}
/**
*
* @param reportFilePath
* @return File
*/
public File getReportFile(String reportFilePath) {
return downloadFile(reportFilePath);
}
/**
* Get property resource file from http URL
*
* @param reportPath
* @param bundleName
* @param currLang
* @return File
*/
public File getResourceBundle(String reportPath, String bundleName, Language currLang) {
String remoteDir = reportPath.substring(0, reportPath.lastIndexOf("/"));
String resname = bundleName + "_" + currLang.getLocale().getLanguage() + "_" + currLang.getLocale().getCountry()
+ ".properties";
try {
File resFile = downloadFile(remoteDir + "/" + resname);
if (resFile == null) {
resname = bundleName + "_" + currLang.getLocale().getLanguage() + ".properties";
resFile = downloadFile(remoteDir + "/" + resname);
if (resFile == null) {
resname = bundleName + ".properties";
resFile = downloadFile(remoteDir + "/" + resname);
}
}
return resFile;
} catch (Exception e) {
if (log.isLoggable(Level.CONFIG))
log.log(Level.CONFIG, e.getMessage(), e);
return null;
}
}
private String getRemoteMD5(String reportLocation) {
try {
String md5url = reportLocation + ".md5";
URL reportURL = new URL(md5url);
try (InputStream in = reportURL.openStream()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buf[] = new byte[1024];
int s = 0;
while ((s = in.read(buf, 0, 1024)) > 0)
baos.write(buf, 0, s);
String hash = new String(baos.toByteArray());
int posSpace = hash.indexOf(" ");
if (posSpace > 0)
hash = hash.substring(0, posSpace);
return hash;
}
} catch (Exception e) {
if (log.isLoggable(Level.CONFIG))
log.log(Level.CONFIG, "MD5 not available for " + reportLocation, e);
return null;
}
}
/**
* @author rlemeill
* @param reportLocation http://applicationserver/webApp/standalone.jrxml for
* example
* @param localPath Where to put the http downloaded file
* @return abstract File which represent the downloaded file
*/
private File getRemoteFile(String reportLocation, String localPath) {
try {
URL reportURL = new URL(reportLocation);
try (InputStream in = reportURL.openStream();) {
File downloadedFile = new File(localPath);
if (downloadedFile.exists()) {
downloadedFile.delete();
}
try (FileOutputStream fout = new FileOutputStream(downloadedFile);) {
byte buf[] = new byte[1024];
int s = 0;
while ((s = in.read(buf, 0, 1024)) > 0)
fout.write(buf, 0, s);
fout.flush();
}
return downloadedFile;
}
} catch (Exception e) {
throw new AdempiereException(e.getMessage(), e);
}
}
/**
*
* @param path
* @return true if path is http or https
*/
public static boolean isWebResourcePath(String path) {
return path.startsWith("http://") || path.startsWith("https://");
}
}

View File

@ -19,12 +19,10 @@ package org.adempiere.webui.apps;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
@ -74,12 +72,7 @@ import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.Executions;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
/**
* ZK Application Environment and utilities
@ -615,44 +608,7 @@ public final class AEnv
*/
public static void mergePdf(List<File> pdfList, File outFile) throws IOException,
DocumentException, FileNotFoundException {
Document document = null;
PdfWriter copy = null;
List<PdfReader> pdfReaders = new ArrayList<PdfReader>();
try
{
for (File f : pdfList)
{
PdfReader reader = new PdfReader(f.getAbsolutePath());
pdfReaders.add(reader);
if (document == null)
{
document = new Document(reader.getPageSizeWithRotation(1));
copy = PdfWriter.getInstance(document, new FileOutputStream(outFile));
document.open();
}
int pages = reader.getNumberOfPages();
PdfContentByte cb = copy.getDirectContent();
for (int i = 1; i <= pages; i++) {
document.newPage();
copy.newPage();
PdfImportedPage page = copy.getImportedPage(reader, i);
cb.addTemplate(page, 0, 0);
copy.releaseTemplate(page);
}
}
document.close();
}
finally
{
for(PdfReader reader:pdfReaders)
{
reader.close();
}
}
Util.mergePdf(pdfList, outFile);
}
/**

View File

@ -15,6 +15,7 @@ import javax.activation.FileDataSource;
import org.adempiere.base.upload.IUploadService;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.report.jasper.ReportStarter;
import org.adempiere.webui.ClientInfo;
import org.adempiere.webui.Extensions;
import org.adempiere.webui.LayoutUtils;
@ -174,7 +175,7 @@ public class ZkJRViewer extends Window implements EventListener<Event>, ITabOnCl
private void init() {
final boolean isCanExport=MRole.getDefault().isCanExport();
defaultType = jasperPrint == null ? null : jasperPrint.getProperty("IDEMPIERE_REPORT_TYPE");
defaultType = jasperPrint == null ? null : jasperPrint.getProperty(ReportStarter.IDEMPIERE_REPORT_TYPE);
if (Util.isEmpty(defaultType)) {
defaultType = MSysConfig.getValue(MSysConfig.ZK_REPORT_JASPER_OUTPUT_TYPE, "PDF",
Env.getAD_Client_ID(Env.getCtx()), Env.getAD_Org_ID(Env.getCtx()));//It gets default Jasper output type