/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. 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., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
* For the text or an alternative of this public license, you may reach us *
*****************************************************************************/
package ar.com.ergio.report;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.PropertyResourceBundle;
import java.util.logging.Level;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.JobName;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRPrintServiceExporter;
import net.sf.jasperreports.engine.export.JRPrintServiceExporterParameter;
import net.sf.jasperreports.engine.export.JRTextExporter;
import net.sf.jasperreports.engine.export.JRTextExporterParameter;
import net.sf.jasperreports.engine.util.JRLoader;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.exceptions.DBException;
import org.compiere.apps.ADialog;
import org.compiere.db.CConnection;
import org.compiere.interfaces.MD5;
import org.compiere.model.MAttachment;
import org.compiere.model.MAttachmentEntry;
import org.compiere.model.MProcess;
import org.compiere.model.PrintInfo;
import org.compiere.model.X_AD_PInstance_Para;
import org.compiere.print.MPrintFormat;
import org.compiere.print.PrintUtil;
import org.compiere.print.ReportCtl;
import org.compiere.process.ClientProcess;
import org.compiere.process.ProcessCall;
import org.compiere.process.ProcessInfo;
import org.compiere.process.ProcessInfoParameter;
import org.compiere.report.JRViewerProvider;
import org.compiere.report.SwingJRViewerProvider;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Ini;
import org.compiere.util.Language;
import org.compiere.util.Trx;
import org.compiere.util.Util;
import org.compiere.utils.DigestOfFile;
/**
* @author rlemeill
* Originally coming from an application note from compiere.co.uk
* ---
* Modifications: Allow Jasper Reports to be able to be run on VPN profile (i.e: no direct connection to DB).
* Implemented ClientProcess for it to run on client.
* @author Ashley Ramdass
* @author victor.perez@e-evolution.com
* @see FR 1906632 http://sourceforge.net/tracker/?func=detail&atid=879335&aid=1906632&group_id=176962
* @author Teo Sarca, www.arhipac.ro
* <li>FR [ 2581145 ] Jasper: Provide parameters info
* @author Cristina Ghita, www.arhipac.ro
* <li>BF [ 2778472 ] Subreport bug
*/
public class ReportStarterWithTxtExporter implements ProcessCall, ClientProcess
{
/** Logger */
private static CLogger log = CLogger.getCLogger(ReportStarterWithTxtExporter.class);
private static File REPORT_HOME = null;
private static JRViewerProvider viewerProvider = new SwingJRViewerProvider();
private static JasperPrint jasperPrint;
static {
String reportPath = System.getProperty("org.compiere.report.path");
if (reportPath == null) {
REPORT_HOME = new File(Ini.getAdempiereHome() + File.separator + "reports");
} else {
REPORT_HOME = new File(reportPath);
}
}
private ProcessInfo processInfo;
private MAttachment attachment;
/**
* @param requestURL
* @return true if the report is on the same ip address than Application Server
*/
private boolean isRequestedonAS(URL requestURL)
{
boolean tBool = false;
try{
InetAddress[] request_iaddrs = InetAddress.getAllByName(requestURL.getHost());
InetAddress as_iaddr = InetAddress.getByName(CConnection.get().getAppsHost());
for(int i=0;i<request_iaddrs.length;i++)
{
log.info("Got "+request_iaddrs[i].toString()+" for "+requestURL+" as address #"+i);
if(request_iaddrs[i].equals(as_iaddr))
{
log.info("Requested report is on application server host");
tBool = true;
break;
}
}
}
catch (UnknownHostException e) {
log.severe("Unknown dns lookup error");
return false;
}
return tBool;
}
/**
* @return true if the class org.compiere.interfaces.MD5Home is present
*/
private boolean isMD5HomeInterfaceAvailable()
{
try
{
Class.forName("org.compiere.interfaces.MD5");
log.info("EJB client for MD5 remote hashing is present");
return true;
}
catch (ClassNotFoundException e)
{
log.warning("EJB Client for MD5 remote hashing absent\nyou need the class org.compiere.interfaces.MD5 - from webEJB-client.jar - in classpath");
return false;
}
}
/**
* @param requestedURLString
* @return md5 hash of remote file computed directly on application server
* null if problem or if report doesn't seem to be on AS (different IP or 404)
*/
private String ejbGetRemoteMD5(String requestedURLString)
{
InitialContext context = null;
String md5Hash = null;
try {
URL requestURL = new URL(requestedURLString);
//String requestURLHost = requestURL.getHost();
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.put(InitialContext.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
env.put(InitialContext.PROVIDER_URL, requestURL.getHost() + ":" + CConnection.get().getAppsPort());
context = new InitialContext(env);
if (isRequestedonAS(requestURL) && isMD5HomeInterfaceAvailable())
{
MD5 md5 = (MD5) context.lookup(MD5.JNDI_NAME);
md5Hash = md5.getFileMD5(requestedURLString);
log.info("MD5 for " + requestedURLString + " is " + md5Hash);
}
}
catch (MalformedURLException e) {
log.severe("URL is invalid: "+ e.getMessage());
return null;
}
catch (NamingException e){
log.warning("Unable to create jndi context did you deployed webApp.ear package?\nRemote hashing is impossible");
return null;
}
return md5Hash;
}
/**
* @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);
InputStream in = reportURL.openStream();
File downloadedFile = new File(localPath);
if (downloadedFile.exists())
{
downloadedFile.delete();
}
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);
in.close();
fout.flush();
fout.close();
return downloadedFile;
} catch (FileNotFoundException e) {
if(reportLocation.indexOf("Subreport") == -1) // Only show the warning if it is not a subreport
log.warning("404 not found: Report cannot be found on server "+ e.getMessage());
return null;
} catch (IOException e) {
log.severe("I/O error when trying to download (sub)report from server "+ e.getMessage());
return null;
}
}
/**
* Search for additional subreports deployed to a webcontext if
* the parent report is located there
* @author deathmeat
* @param reportName The original report name
* @param reportPath The full path to the parent report
* @param fileExtension The file extension of the parent report
* @return An Array of File objects referencing to the downloaded subreports
*/
private File[] getHttpSubreports(String reportName, String reportPath, String fileExtension)
{
ArrayList<File> subreports = new ArrayList<File>();
String remoteDir = reportPath.substring(0, reportPath.lastIndexOf("/"));
// Currently check hardcoded for max. 10 subreports
for(int i=1; i<10; i++)
{
// Check if subreport number i exists
File subreport = httpDownloadedReport(remoteDir + "/" + reportName + i + fileExtension);
if(subreport == null) // Subreport doesn't exist, abort further approaches
break;
subreports.add(subreport);
}
File[] subreportsTemp = new File[0];
subreportsTemp = subreports.toArray(subreportsTemp);
return subreportsTemp;
}
/**
* @author rlemeill
* @param reportLocation http string url ex: http://adempiereserver.domain.com/webApp/standalone.jrxml
* @return downloaded File (or already existing one)
*/
private File httpDownloadedReport(String reportLocation)
{
File reportFile = null;
File downloadedFile = null;
log.info(" report deployed to " + reportLocation);
try {
String[] tmps = reportLocation.split("/");
String cleanFile = tmps[tmps.length-1];
String localFile = System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + cleanFile;
String downloadedLocalFile = System.getProperty("java.io.tmpdir") + System.getProperty("file.separator")+"TMP" + cleanFile;
reportFile = new File(localFile);
if (reportFile.exists())
{
String localMD5hash = DigestOfFile.GetLocalMD5Hash(reportFile);
String remoteMD5Hash = ejbGetRemoteMD5(reportLocation);
log.info("MD5 for local file is "+localMD5hash );
if ( remoteMD5Hash != null)
{
if (localMD5hash.equals(remoteMD5Hash))
{
log.info(" no need to download: local report is up-to-date");
}
else
{
log.info(" report on server is different that local one, download and replace");
downloadedFile = getRemoteFile(reportLocation, downloadedLocalFile);
reportFile.delete();
downloadedFile.renameTo(reportFile);
}
}
else
{
log.warning("Remote hashing is not available did you deployed webApp.ear?");
downloadedFile = getRemoteFile(reportLocation, downloadedLocalFile);
// compare hash of existing and downloaded
if ( DigestOfFile.md5localHashCompare(reportFile,downloadedFile) )
{
//nothing file are identical
log.info(" no need to replace your existing report");
}
else
{
log.info(" report on server is different that local one, replacing");
reportFile.delete();
downloadedFile.renameTo(reportFile);
}
}
}
else
{
reportFile = getRemoteFile(reportLocation,localFile);
}
}
catch (Exception e) {
log.severe("Unknown exception: "+ e.getMessage());
return null;
}
return reportFile;
}
/**
* Returns the Server Connection if direct connection is not available
* (VPN, WAN, Terminal) and thus query has to be run on server only else return
* a direct connection to DB.
*
* Notes: Need to refactor and integrate in DB if confirmed to be working as
* expected.
*
* @author Ashley Ramdass
* @return Connection DB Connection
*/
protected Connection getConnection()
{
return DB.getConnectionRW();
}
/**
* Start the process.
* Called then pressing the Process button in R_Request.
* It should only return false, if the function could not be performed
* as this causes the process to abort.
* @author rlemeill
* @param ctx context
* @param pi standard process info
* @param trx
* @return true if success
*/
public boolean startProcess(Properties ctx, ProcessInfo pi, Trx trx)
{
processInfo = pi;
String Name=pi.getTitle();
int AD_PInstance_ID=pi.getAD_PInstance_ID();
int Record_ID=pi.getRecord_ID();
log.info( "Name="+Name+" AD_PInstance_ID="+AD_PInstance_ID+" Record_ID="+Record_ID);
String trxName = null;
if (trx != null) {
trxName = trx.getTrxName();
}
ReportData reportData = getReportData(pi, trxName);
if (reportData == null) {
reportResult(AD_PInstance_ID, "Can not find report data", trxName);
return false;
}
String reportPath = reportData.getReportFilePath();
if (Util.isEmpty(reportPath, true))
{
reportResult(AD_PInstance_ID, "Can not find report", trxName);
return false;
}
JasperData data = null;
File reportFile = null;
String fileExtension = "";
HashMap<String, Object> params = new HashMap<String, Object>();
addProcessParameters(AD_PInstance_ID, params, trxName);
addProcessInfoParameters(params, pi.getParameter());
reportFile = getReportFile(reportPath, (String)params.get("ReportType"));
if (reportFile == null || reportFile.exists() == false)
{
log.severe("No report file found for given type, falling back to " + reportPath);
reportFile = getReportFile(reportPath);
}
if (reportFile == null || reportFile.exists() == false)
{
String tmp = "Can not find report file at path - " + reportPath;
log.severe(tmp);
reportResult(AD_PInstance_ID, tmp, trxName);
}
if (reportFile != null)
{
data = processReport(reportFile);
fileExtension = reportFile.getName().substring(reportFile.getName().lastIndexOf("."),
reportFile.getName().length());
}
else
{
return false;
}
JasperReport jasperReport = data.getJasperReport();
String jasperName = data.getJasperName();
String name = jasperReport.getName();
File reportDir = data.getReportDir();
// Add reportDir to class path
ClassLoader scl = ClassLoader.getSystemClassLoader();
try {
java.net.URLClassLoader ucl = new java.net.URLClassLoader(new java.net.URL[]{reportDir.toURI().toURL()}, scl);
net.sf.jasperreports.engine.util.JRResourcesUtil.setThreadClassLoader(ucl);
} catch (MalformedURLException me) {
log.warning("Could not add report directory to classpath: "+ me.getMessage());
}
if (jasperReport != null) {
File[] subreports;
// Subreports
if(reportPath.startsWith("http://") || reportPath.startsWith("https://"))
{
// Locate and download subreports from remote webcontext
subreports = getHttpSubreports(jasperName + "Subreport", reportPath, fileExtension);
}
else if (reportPath.startsWith("attachment:"))
{
subreports = getAttachmentSubreports(reportPath);
}
else if (reportPath.startsWith("resource:"))
{
subreports = getResourceSubreports(name+ "Subreport", reportPath, fileExtension);
}
// TODO: Implement file:/ lookup for subreports
else
{
// Locate subreports from local/remote filesystem
subreports = reportDir.listFiles( new FileFilter( jasperName+"Subreport", reportDir, fileExtension));
}
for( int i=0; i<subreports.length; i++) {
// @Trifon - begin
if (subreports[i].getName().toLowerCase().endsWith(".jasper")
|| subreports[i].getName().toLowerCase().endsWith(".jrxml")
)
{
JasperData subData = processReport( subreports[i] );
if (subData.getJasperReport()!=null) {
params.put( subData.getJasperName(), subData.getJasperFile().getAbsolutePath());
}
} // @Trifon - end
}
if (Record_ID > 0)
params.put("RECORD_ID", new Integer( Record_ID));
// contribution from Ricardo (ralexsander)
// in iReports you can 'SELECT' AD_Client_ID, AD_Org_ID and AD_User_ID using only AD_PINSTANCE_ID
params.put("AD_PINSTANCE_ID", new Integer( AD_PInstance_ID));
// FR [3123850] - Add continuosly needed parameters to Jasper Starter - Carlos Ruiz - GlobalQSS
params.put("AD_CLIENT_ID", new Integer( Env.getAD_Client_ID(Env.getCtx())));
params.put("AD_ROLE_ID", new Integer( Env.getAD_Role_ID(Env.getCtx())));
params.put("AD_USER_ID", new Integer( Env.getAD_User_ID(Env.getCtx())));
Language currLang = Env.getLanguage(Env.getCtx());
String printerName = null;
MPrintFormat printFormat = null;
PrintInfo printInfo = null;
ProcessInfoParameter[] pip = pi.getParameter();
// Get print format and print info parameters
if (pip!=null) {
for (int i=0; i<pip.length; i++) {
if (ReportCtl.PARAM_PRINT_FORMAT.equalsIgnoreCase(pip[i].getParameterName())) {
printFormat = (MPrintFormat)pip[i].getParameter();
}
if (ReportCtl.PARAM_PRINT_INFO.equalsIgnoreCase(pip[i].getParameterName())) {
printInfo = (PrintInfo)pip[i].getParameter();
}
if (ReportCtl.PARAM_PRINTER_NAME.equalsIgnoreCase(pip[i].getParameterName())) {
printerName = (String)pip[i].getParameter();
}
}
}
if (printFormat!=null) {
if (printInfo!=null) {
// Set the language of the print format if we're printing a document
if (printInfo.isDocument()) {
currLang = printFormat.getLanguage();
}
}
// Set printer name unless already set.
if (printerName==null) {
printerName = printFormat.getPrinterName();
}
}
params.put("CURRENT_LANG", currLang.getAD_Language());
params.put(JRParameter.REPORT_LOCALE, currLang.getLocale());
// Resources
File resFile = null;
if (reportPath.startsWith("attachment:") && attachment != null) {
resFile = getAttachmentResourceFile(jasperName, currLang);
} else if (reportPath.startsWith("resource:")) {
resFile = getResourcesForResourceFile(jasperName, currLang);
// TODO: Implement file:/ for resources
} else {
resFile = new File(jasperName+"_"+currLang.getLocale().getLanguage()+".properties");
if (!resFile.exists()) {
resFile = null;
}
if (resFile == null) {
resFile = new File(jasperName+".properties");
if (!resFile.exists()) {
resFile = null;
}
}
}
if (resFile!=null) {
try {
PropertyResourceBundle res = new PropertyResourceBundle( new FileInputStream(resFile));
params.put("RESOURCE", res);
} catch (IOException e) {
;
}
}
Connection conn = null;
try {
conn = getConnection();
jasperPrint = JasperFillManager.fillReport( jasperReport, params, conn);
// @Marcos Custom - begin
log.info( "ReportStarterWithTxtExporter.startProcess print report -" + jasperPrint.getName());
String Param_Inicial;
String Param_Final;
if (params.containsKey("FECHA_INICIAL_Info1"))
Param_Inicial = params.get("FECHA_INICIAL_Info1").toString();
else
Param_Inicial = "";
if (params.containsKey("FECHA_FINAL_Info1"))
Param_Final = "_al_" + params.get("FECHA_FINAL_Info1").toString();
else
Param_Final = "";
String fileName = new String(jasperPrint.getName()
+ "_"
+ Param_Inicial.replace ("/", "-")
+ Param_Final.replace ("/", "-")
+ ".txt");
JRTextExporter jrtxt = new JRTextExporter();
File destFile = new File(fileName);
Integer PageWidth = jasperPrint.getPageWidth();
Integer CharWidth = 10;
Integer Par_PageWidth = PageWidth / CharWidth;
jrtxt.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
jrtxt.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, destFile.toString());
jrtxt.setParameter(JRTextExporterParameter.CHARACTER_WIDTH, new Float(10));
jrtxt.setParameter(JRTextExporterParameter.CHARACTER_HEIGHT, new Float(20));
jrtxt.setParameter(JRTextExporterParameter.PAGE_WIDTH, Par_PageWidth.floatValue());
try {
jrtxt.exportReport();
log.info("Archivo Exportado: ");
if (Env.getWindow(0)!=null)
ADialog.info(0, Env.getWindow(0), "Archivo Exportado:", fileName);
} catch (JRException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// @Marcos Custom - end
if (reportData.isDirectPrint())
{
log.info( "ReportStarterWithTxtExporter.startProcess print report -" + jasperPrint.getName());
//RF 1906632
if (!processInfo.isBatch()) {
// Get printer job
PrinterJob printerJob = org.compiere.print.CPrinter.getPrinterJob(printerName);
// Set print request attributes
// Paper Attributes:
PrintRequestAttributeSet prats = new HashPrintRequestAttributeSet();
// add: copies, job-name, priority
if (printInfo == null || printInfo.isDocumentCopy() || printInfo.getCopies() < 1) // @Trifon
prats.add (new Copies(1));
else
prats.add (new Copies(printInfo.getCopies()));
Locale locale = Language.getLoginLanguage().getLocale();
// @Trifon
String printFormat_name = printFormat == null ? "" : printFormat.getName();
int numCopies = printInfo == null ? 0 : printInfo.getCopies();
prats.add(new JobName(printFormat_name + "_" + pi.getRecord_ID(), locale));
prats.add(PrintUtil.getJobPriority(jasperPrint.getPages().size(), numCopies, true));
// Create print service exporter
JRPrintServiceExporter exporter = new JRPrintServiceExporter();;
// Set parameters
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRPrintServiceExporterParameter.PRINT_SERVICE, printerJob.getPrintService());
exporter.setParameter(JRPrintServiceExporterParameter.PRINT_SERVICE_ATTRIBUTE_SET, printerJob.getPrintService().getAttributes());
exporter.setParameter(JRPrintServiceExporterParameter.PRINT_REQUEST_ATTRIBUTE_SET, prats);
exporter.setParameter(JRPrintServiceExporterParameter.DISPLAY_PAGE_DIALOG, Boolean.FALSE);
exporter.setParameter(JRPrintServiceExporterParameter.DISPLAY_PRINT_DIALOG, Boolean.FALSE);
// Print report / document
exporter.exportReport();
}
else
{
// You can use JasperPrint to create PDF
// Used For the PH
try
{
File PDF = File.createTempFile("mail", ".pdf");
JasperExportManager.exportReportToPdfFile(jasperPrint, PDF.getAbsolutePath());
processInfo.setPDFReport(PDF);
}
catch (IOException e)
{
log.severe("ReportStarterWithTxtExporter.startProcess: Can not make PDF File - "+ e.getMessage());
}
}
// You can use JasperPrint to create PDF
// JasperExportManager.exportReportToPdfFile(jasperPrint, "BasicReport.pdf");
} else {
// @Marcos : ProcessCtl.java llama a ReportStarter y se vuelve a generar la visualizacion del reporte.
// log.info( "ReportStarterWithTxtExporter.startProcess run report -"+jasperPrint.getName());
// JRViewerProvider viewerLauncher = getReportViewerProvider();
// viewerLauncher.openViewer(jasperPrint, pi.getTitle()+" - " + reportPath);
}
} catch (JRException e) {
log.severe("ReportStarterWithTxtExporter.startProcess: Can not run report - "+ e.getMessage());
} finally {
if (conn != null)
try {
conn.close();
} catch (SQLException e) {
}
}
}
reportResult( AD_PInstance_ID, null, trxName);
return true;
}
public static JasperPrint getJasperPrint()
{
return jasperPrint;
}
/**
* Get .property resource file from process attachment
* @param jasperName
* @param currLang
* @return File
*/
private File getAttachmentResourceFile(String jasperName, Language currLang) {
File resFile = null;
MAttachmentEntry[] entries = attachment.getEntries();
// try baseName + "_" + language
for( int i=0; i<entries.length; i++) {
if ( entries[i].getName().equals( jasperName+currLang.getLocale().getLanguage()+".properties")) {
resFile = getAttachmentEntryFile(entries[i]);
break;
}
}
if (resFile==null) {
// try baseName only
for( int i=0; i<entries.length; i++) {
if ( entries[i].getName().equals( jasperName+".properties")) {
resFile = getAttachmentEntryFile(entries[i]);
break;
}
}
}
return resFile;
}
/**
* Get .property resource file from resources
* @param jasperName
* @param currLang
* @return File
*/
private File getResourcesForResourceFile(String jasperName, Language currLang) {
File resFile = null;
try {
resFile = getFileAsResource(jasperName+currLang.getLocale().getLanguage()+".properties");
} catch (Exception e) {
// ignore exception - file couldn't exist
}
return resFile;
}
/**
* Get subreports from attachment. Assume all other jasper attachment is subreport.
* @param reportPath
* @return File[]
*/
private File[] getAttachmentSubreports(String reportPath) {
String name = reportPath.substring("attachment:".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)
&& (entries[i].getName().toLowerCase().endsWith(".jrxml")
|| entries[i].getName().toLowerCase().endsWith(".jasper")
|| entries[i].getName().toLowerCase().endsWith(".jpg")
|| entries[i].getName().toLowerCase().endsWith(".png")
)
)
{
File reportFile = getAttachmentEntryFile(entries[i]);
if (reportFile != null)
subreports.add(reportFile);
}
}
File[] subreportsTemp = new File[0];
subreportsTemp = subreports.toArray(subreportsTemp);
return subreportsTemp;
}
/**
* Search for additional subreports deployed as resources
* @param reportName The original report name
* @param reportPath The full path to the parent report
* @param fileExtension The file extension of the parent report
* @return An Array of File objects referencing to the downloaded subreports
*/
private File[] getResourceSubreports(String reportName, String reportPath, String fileExtension)
{
ArrayList<File> subreports = new ArrayList<File>();
String remoteDir = reportPath.substring(0, reportPath.lastIndexOf("/"));
// Currently check hardcoded for max. 10 subreports
for(int i=1; i<10; i++)
{
// Check if subreport number i exists
File subreport = null;
try {
subreport = getFileAsResource(remoteDir + "/" + reportName + i + fileExtension);
} catch (Exception e) {
// just ignore it
}
if(subreport == null) // Subreport doesn't exist, abort further approaches
break;
subreports.add(subreport);
}
File[] subreportsTemp = new File[subreports.size()];
subreportsTemp = subreports.toArray(subreportsTemp);
return subreportsTemp;
}
/**
* @author alinv
* @param reportPath
* @param reportType
* @return the abstract file corresponding to typed report
*/
protected File getReportFile(String reportPath, String reportType) {
if (reportType != null)
{
int cpos = reportPath.lastIndexOf('.');
reportPath = reportPath.substring(0, cpos) + "_" + reportType + reportPath.substring(cpos, reportPath.length());
}
return getReportFile(reportPath);
}
/**
* @author alinv
* @param reportPath
* @return the abstract file corresponding to report
*/
protected File getReportFile(String reportPath)
{
File reportFile = null;
// Reports deployment on web server Thanks to Alin Vaida
if (reportPath.startsWith("http://") || reportPath.startsWith("https://")) {
reportFile = httpDownloadedReport(reportPath);
} else if (reportPath.startsWith("attachment:")) {
//report file from process attachment
reportFile = downloadAttachment(reportPath);
} else if (reportPath.startsWith("/")) {
reportFile = new File(reportPath);
} else if (reportPath.startsWith("file:/")) {
try {
reportFile = new File(new URI(reportPath));
} catch (URISyntaxException e) {
log.warning(e.getLocalizedMessage());
reportFile = null;
}
} else if (reportPath.startsWith("resource:")) {
try {
reportFile = getFileAsResource(reportPath);
} catch (Exception e) {
log.warning(e.getLocalizedMessage());
reportFile = null;
}
} else {
reportFile = new File(REPORT_HOME, reportPath);
}
// Set org.compiere.report.path because it is used in reports which refer to subreports
if (reportFile != null)
{
System.setProperty("org.compiere.report.path", reportFile.getParentFile().getAbsolutePath());
}
return reportFile;
}
/**
* @param reportPath
* @return
* @throws Exception
*/
private File getFileAsResource(String reportPath) throws Exception {
File reportFile;
String name = reportPath.substring("resource:".length()).trim();
String localName = name.replace('/', '_');
log.info("reportPath = " + reportPath);
log.info("getting resource from = " + getClass().getClassLoader().getResource(name));
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(name);
String localFile = System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + localName;
log.info("localFile = " + localFile);
reportFile = new File(localFile);
OutputStream out = null;
out = new FileOutputStream(reportFile);
if (out != null){
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0)
out.write(buf,0,len);
out.close();
inputStream.close();
}
return reportFile;
}
/**
* Download db attachment
* @param reportPath must of syntax attachment:filename
* @return File
*/
private File downloadAttachment(String reportPath) {
File reportFile = null;
String name = reportPath.substring("attachment:".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 = System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + entry.getName();
String downloadedLocalFile = System.getProperty("java.io.tmpdir") + System.getProperty("file.separator")+"TMP" + entry.getName();
File reportFile = new File(localFile);
if (reportFile.exists()) {
String localMD5hash = DigestOfFile.GetLocalMD5Hash(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 that local one, 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;
}
/**
* Update AD_PInstance result and error message
* @author rlemeill
* @param AD_PInstance_ID
* @param errMsg error message or null if there is no error
*/
protected void reportResult(int AD_PInstance_ID, String errMsg, String trxName)
{
int result = (errMsg == null ? 1 : 0);
String sql = "UPDATE AD_PInstance SET Result=?, ErrorMsg=?"
+" WHERE AD_PInstance_ID="+AD_PInstance_ID;
DB.executeUpdateEx(sql, new Object[]{result, errMsg}, trxName);
}
/**
* @author rlemeill
* @param reportFile
* @return
*/
protected JasperData processReport( File reportFile) {
log.info( "reportFile.getAbsolutePath() = "+reportFile.getAbsolutePath());
JasperReport jasperReport = null;
String jasperName = reportFile.getName();
int pos = jasperName.indexOf('.');
if (pos!=-1) jasperName = jasperName.substring(0, pos);
File reportDir = reportFile.getParentFile();
//test if the compiled report exists
File jasperFile = new File( reportDir.getAbsolutePath(), jasperName+".jasper");
if (jasperFile.exists()) { // test time
if (reportFile.lastModified() == jasperFile.lastModified()) {
log.info(" no need to compile use "+jasperFile.getAbsolutePath());
try {
jasperReport = (JasperReport)JRLoader.loadObject(jasperFile.getAbsolutePath());
} catch (JRException e) {
jasperReport = null;
log.severe("Can not load report - "+ e.getMessage());
}
} else {
jasperReport = compileReport( reportFile, jasperFile);
}
} else { // create new jasper file
jasperReport = compileReport( reportFile, jasperFile);
}
return new JasperData( jasperReport, reportDir, jasperName, jasperFile);
}
/**
* Load Process Parameters into given params map
* @param AD_PInstance_ID
* @param params
* @param trxName
*/
private static void addProcessParameters(int AD_PInstance_ID, Map<String, Object> params, String trxName)
{
final String sql = "SELECT "
+" "+X_AD_PInstance_Para.COLUMNNAME_ParameterName
+","+X_AD_PInstance_Para.COLUMNNAME_P_String
+","+X_AD_PInstance_Para.COLUMNNAME_P_String_To
+","+X_AD_PInstance_Para.COLUMNNAME_P_Number
+","+X_AD_PInstance_Para.COLUMNNAME_P_Number_To
+","+X_AD_PInstance_Para.COLUMNNAME_P_Date
+","+X_AD_PInstance_Para.COLUMNNAME_P_Date_To
+","+X_AD_PInstance_Para.COLUMNNAME_Info
+","+X_AD_PInstance_Para.COLUMNNAME_Info_To
+" FROM "+X_AD_PInstance_Para.Table_Name
+" WHERE "+X_AD_PInstance_Para.COLUMNNAME_AD_PInstance_ID+"=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, trxName);
pstmt.setInt(1, AD_PInstance_ID);
rs = pstmt.executeQuery();
while (rs.next())
{
String name = rs.getString(1);
String pStr = rs.getString(2);
String pStrTo = rs.getString(3);
BigDecimal pNum = rs.getBigDecimal(4);
BigDecimal pNumTo = rs.getBigDecimal(5);
Timestamp pDate = rs.getTimestamp(6);
Timestamp pDateTo = rs.getTimestamp(7);
if (pStr != null) {
if (pStrTo!=null) {
params.put( name+"1", pStr);
params.put( name+"2", pStrTo);
} else {
params.put( name, pStr);
}
} else if (pDate != null) {
if (pDateTo!=null) {
params.put( name+"1", pDate);
params.put( name+"2", pDateTo);
} else {
params.put( name, pDate);
}
} else if (pNum != null) {
if (pNumTo!=null) {
params.put( name+"1", pNum);
params.put( name+"2", pNumTo);
} else {
params.put( name, pNum);
}
}
//
// Add parameter info - teo_sarca FR [ 2581145 ]
String info = rs.getString(8);
String infoTo = rs.getString(9);
params.put(name+"_Info1", (info != null ? info : ""));
params.put(name+"_Info2", (infoTo != null ? infoTo : ""));
}
}
catch (SQLException e)
{
// log.severe("Execption; sql = "+sql+"; e.getMessage() = " +e.getMessage());
throw new DBException(e, sql);
}
finally
{
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
}
private void addProcessInfoParameters(Map<String, Object> params, ProcessInfoParameter[] para)
{
if (para != null) {
for (int i = 0; i < para.length; i++) {
if (para[i].getParameter_To() == null) {
params.put(para[i].getParameterName(), para[i].getParameter());
} else {
params.put( para[i].getParameterName()+"1", para[i].getParameter());
params.put( para[i].getParameterName()+"2", para[i].getParameter_To());
}
}
}
}
/**
* @author rlemeill
* Correct the class path if loaded from java web start
*/
private void JWScorrectClassPath()
{
URL jasperreportsAbsoluteURL = Thread.currentThread().getContextClassLoader().getResource("net/sf/jasperreports/engine");
String jasperreportsAbsolutePath = "";
if(jasperreportsAbsoluteURL.toString().startsWith("jar:http:") || jasperreportsAbsoluteURL.toString().startsWith("jar:https:"))
{
// Jasper classes are deployed to a webserver (Java Webstart)
jasperreportsAbsolutePath = jasperreportsAbsoluteURL.toString().split("!")[0].split("jar:")[1];
// Download the required jasper libraries if they are not already existing
File reqLib = new File(System.getProperty("java.io.tmpdir"), "CompiereJasperReqs.jar");
if(!reqLib.exists() && !(reqLib.length() > 0))
{
try{
URL reqLibURL = new URL(jasperreportsAbsolutePath);
InputStream in = reqLibURL.openStream();
FileOutputStream fout = new FileOutputStream(reqLib);
byte buf[] = new byte[1024];
int s = 0;
while((s = in.read(buf, 0, 1024)) > 0)
fout.write(buf, 0, s);
in.close();
fout.flush();
fout.close();
} catch (FileNotFoundException e) {
log.warning("Required library not found "+ e.getMessage());
reqLib.delete();
reqLib = null;
} catch (IOException e) {
log.severe("I/O error downloading required library from server "+ e.getMessage());
reqLib.delete();
reqLib = null;
}
}
jasperreportsAbsolutePath = reqLib.getAbsolutePath();
}
else
{
// Jasper classes are locally available (Local client)
jasperreportsAbsolutePath = jasperreportsAbsoluteURL.toString().split("!")[0].split("file:")[1];
}
if(jasperreportsAbsolutePath != null && !jasperreportsAbsolutePath.trim().equals(""))
{
// Check whether the current CLASSPATH already contains our
// jasper libraries and dependencies or not.
if(System.getProperty("java.class.path").indexOf(jasperreportsAbsolutePath) < 0)
{
System.setProperty("java.class.path",
System.getProperty("java.class.path") +
System.getProperty("path.separator") +
jasperreportsAbsolutePath);
log.info("Classpath has been corrected to " + System.getProperty("java.class.path"));
}
}
}
/**
* @author rlemeill
* @param reportFile
* @param jasperFile
* @return compiled JasperReport
*/
private JasperReport compileReport( File reportFile, File jasperFile)
{
JWScorrectClassPath();
JasperReport compiledJasperReport = null;
try {
JasperCompileManager.compileReportToFile ( reportFile.getAbsolutePath(), jasperFile.getAbsolutePath() );
jasperFile.setLastModified( reportFile.lastModified()); //Synchronize Dates
compiledJasperReport = (JasperReport)JRLoader.loadObject(jasperFile);
} catch (JRException e) {
log.log(Level.SEVERE, "Error", e);
}
return compiledJasperReport;
}
/**
* @author rlemeill
* @param ProcessInfo
* @return ReportData or null if no data found
*/
public ReportData getReportData (ProcessInfo pi, String trxName)
{
log.info("");
String sql = "SELECT pr.JasperReport, pr.IsDirectPrint "
+ "FROM AD_Process pr, AD_PInstance pi "
+ "WHERE pr.AD_Process_ID = pi.AD_Process_ID "
+ " AND pi.AD_PInstance_ID=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, trxName);
pstmt.setInt(1, pi.getAD_PInstance_ID());
rs = pstmt.executeQuery();
String path = null;
boolean directPrint = false;
boolean isPrintPreview = pi.isPrintPreview();
if (rs.next()) {
path = rs.getString(1);
if ("Y".equalsIgnoreCase(rs.getString(2)) && !Ini.isPropertyBool(Ini.P_PRINTPREVIEW)
&& !isPrintPreview )
directPrint = true;
} else {
log.severe("data not found; sql = "+sql);
return null;
}
return new ReportData( path, directPrint);
}
catch (SQLException e)
{
throw new DBException(e, sql);
// log.severe("sql = "+sql+"; e.getMessage() = "+ e.getMessage());
// return null;
}
finally
{
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
}
/**
* Set jasper report viewer provider.
* @param provider
*/
public static void setReportViewerProvider(JRViewerProvider provider) {
if (provider == null)
throw new IllegalArgumentException("Cannot set report viewer provider to null");
viewerProvider = provider;
}
/**
* Get the current jasper report viewer provider
* @return JRViewerProvider
*/
public static JRViewerProvider getReportViewerProvider() {
return viewerProvider;
}
class ReportData {
private String reportFilePath;
private boolean directPrint;
public ReportData(String reportFilePath, boolean directPrint) {
this.reportFilePath = reportFilePath;
this.directPrint = directPrint;
}
public String getReportFilePath() {
return reportFilePath;
}
public boolean isDirectPrint() {
return directPrint;
}
}
public static class JasperData
implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 4375195020654531202L;
private JasperReport jasperReport;
private File reportDir;
private String jasperName;
private File jasperFile;
public JasperData(JasperReport jasperReport, File reportDir, String jasperName, File jasperFile) {
this.jasperReport = jasperReport;
this.reportDir = reportDir;
this.jasperName = jasperName;
this.jasperFile = jasperFile;
}
public JasperReport getJasperReport() {
return jasperReport;
}
public File getReportDir() {
return reportDir;
}
public String getJasperName() {
return jasperName;
}
public File getJasperFile() {
return jasperFile;
}
}
class FileFilter implements FilenameFilter {
private String reportStart;
private File directory;
private String extension;
public FileFilter(String reportStart, File directory, String extension) {
this.reportStart = reportStart;
this.directory = directory;
this.extension = extension;
}
public boolean accept(File file, String name) {
if (file.equals( directory)) {
if (name.startsWith( reportStart)) {
int pos = name.lastIndexOf( extension);
if ( (pos!=-1) && (pos==(name.length()-extension.length()))) return true;
}
}
return false;
}
}
}