/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ro.nextreports.designer.action.report.layout.export;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import ro.nextreports.designer.BandUtil;
import ro.nextreports.designer.Globals;
import ro.nextreports.designer.LayoutHelper;
import ro.nextreports.designer.datasource.DataSource;
import ro.nextreports.designer.querybuilder.ExportPropertiesDialog;
import ro.nextreports.designer.querybuilder.ExportPropertiesPanel;
import ro.nextreports.designer.querybuilder.ParameterManager;
import ro.nextreports.designer.util.FileUtil;
import ro.nextreports.designer.util.I18NSupport;
import ro.nextreports.designer.util.ImageUtil;
import ro.nextreports.designer.util.MessageUtil;
import ro.nextreports.designer.util.Show;
import ro.nextreports.designer.util.UIActivator;
import ro.nextreports.engine.EngineProperties;
import ro.nextreports.engine.Report;
import ro.nextreports.engine.ReportLayout;
import ro.nextreports.engine.exporter.ExporterBean;
import ro.nextreports.engine.exporter.ResultExporter;
import ro.nextreports.engine.exporter.event.ExporterEvent;
import ro.nextreports.engine.exporter.event.ExporterEventListener;
import ro.nextreports.engine.exporter.exception.NoDataFoundException;
import ro.nextreports.engine.exporter.util.ParametersBean;
import ro.nextreports.engine.i18n.I18nLanguage;
import ro.nextreports.engine.i18n.I18nUtil;
import ro.nextreports.engine.queryexec.QueryParameter;
import ro.nextreports.engine.queryexec.QueryResult;
import ro.nextreports.engine.util.DialectUtil;
import ro.nextreports.engine.util.QueryUtil;
import ro.nextreports.engine.util.ReportUtil;
/**
* @author mihai.panaitescu
*/
public abstract class ExportAction extends AbstractAction {
private static final Log LOG = LogFactory.getLog(ExportAction.class);
protected Report report;
protected String exportType;
public static final String REPORTS_DIR = Globals.USER_DATA_DIR + "/reports";
public boolean layoutSelection = false;
private Thread executorThread;
private List<QueryParameter> oldParameters;
// threshold after which we do something for the notified event
protected int eventThreshold = 1;
protected int eventCounter = 0;
// if we have more than RECORDS, we notify after RECORDS_INCREMENT,
// otherwise at every record
private int RECORDS = 10000;
private int RECORDS_INCREMENT = 50;
private boolean stop = false;
public ExportAction(Report report) {
this(report, false);
}
public ExportAction(Report report, boolean layoutSelection) {
super();
this.oldParameters = null;
this.report = report;
if (report != null) {
// a report is opened, we run a report from tree,
// after running we must set the parameters of the opened report!
oldParameters = ParameterManager.getInstance().getParameters();
}
this.layoutSelection = layoutSelection;
}
public void actionPerformed(ActionEvent event) {
executorThread = new Thread(new Runnable() {
public void run() {
if (MessageUtil.showReconnect()) {
return;
}
DataSource runDS = Globals.getReportLayoutPanel().getRunDataSource();
if (report != null) {
ParameterManager.getInstance().setParameters(report.getParameters());
}
UIActivator activator = null;
UIActivator activatorParam = null;
UIActivator exporterActivator = null;
QueryResult qr = null;
activatorParam = new UIActivator(Globals.getMainFrame(), I18NSupport.getString("generate.report.prepare"));
activatorParam.start();
try {
FileUtil.copyImagesToClasspath(report);
} catch (IOException e) {
e.printStackTrace();
}
try {
FileUtil.copyTemplateToClasspath(report);
} catch (IOException e) {
e.printStackTrace();
}
Connection con = null;
try {
Set<String> columns = BandUtil.getNotFoundColumns(report, runDS);
if (columns.size() > 0) {
StringBuilder message = new StringBuilder();
message.append(I18NSupport.getString("band.column.notfound"));
message.append("\r\n");
for (String col : columns) {
message.append(col).append("\r\n");
}
if (activatorParam != null) {
activatorParam.stop();
}
Show.error(message.toString());
return;
}
Set<String> groupColumns = BandUtil.getNotFoundColumnsUsedByGroups(report, runDS);
if (groupColumns.size() > 0) {
StringBuilder message = new StringBuilder();
message.append(I18NSupport.getString("band.column.group.notfound"));
message.append("\r\n");
for (String col : groupColumns) {
message.append(col).append("\r\n");
}
if (activatorParam != null) {
activatorParam.stop();
}
Show.error(message.toString());
return;
}
//NextReportsUtil.reloadReportIfNecessary();
if (activatorParam != null) {
activatorParam.stop();
activatorParam = null;
}
// name when run from explorer tree (without open)
String notLoadedName = null;
if (report != null) {
notLoadedName = getNameWithoutExtension(report.getName());
}
ExportPropertiesPanel propsPanel = new ExportPropertiesPanel(notLoadedName, exportType, layoutSelection);
ExportPropertiesDialog dialog = new ExportPropertiesDialog(propsPanel);
// we are interested only in layout property (generated report name is automatically set)
// otherwise we do not show the dialog
if (layoutSelection) {
Show.centrateComponent(Globals.getMainFrame(), dialog);
dialog.setVisible(true);
}
String name = dialog.getReportName();
if (name == null) {
return;
}
if (layoutSelection && !dialog.okPressed() && (report == null)) {
return;
}
name = name.trim();
if (name.length() == 0) {
name = "Report";
}
ParametersBean pBean = Globals.getMainFrame().getQueryBuilderPanel().selectParameters(report, runDS);
if (pBean == null) {
return;
}
if (QueryUtil.restrictQueryExecution(pBean.getQuery().getText())) {
Show.info(I18NSupport.getString("export.action.execute"));
return;
}
con = Globals.createTempConnection(runDS);
boolean isProcedure = QueryUtil.isProcedureCall(pBean.getQuery().getText());
if (isProcedure) {
if (!QueryUtil.isValidProcedureCall(pBean.getQuery().getText(), DialectUtil.getDialect(con))) {
Show.info(I18NSupport.getString("export.action.execute.procedure"));
return;
}
}
activator = new UIActivator(Globals.getMainFrame(),
I18NSupport.getString("generate.report"));
activator.start(new ExportStopAction());
qr = Globals.getMainFrame().getQueryBuilderPanel().runQuery(con, pBean, false);
if (activator != null) {
activator.stop();
activator = null;
}
if (qr == null) {
return;
}
final int records = qr.getRowCount();
if (records > RECORDS) {
eventThreshold = RECORDS_INCREMENT;
}
exporterActivator = new UIActivator(Globals.getMainFrame(),
I18NSupport.getString("generate.report.export"), records);
exporterActivator.start(new ExportStopAction());
//
boolean ok = startExporter(name, qr, pBean, exporterActivator, isProcedure);
if (!ok) {
Show.dispose(); // close a possible previous dialog message
Show.info(I18NSupport.getString("report.cancelled"));
}
//
} catch (NoDataFoundException e) {
Show.info(e.getMessage());
} catch (InterruptedException e) {
Show.dispose(); // close a possible previous dialog message
Show.info(I18NSupport.getString("report.cancelled"));
} catch (Exception e) {
Show.error(e);
} finally {
stop = false;
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (qr != null) {
qr.close();
}
Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
Globals.getMainFrame().setCursor(normalCursor);
if (activatorParam != null) {
activatorParam.stop();
}
if (activator != null) {
activator.stop();
}
if (exporterActivator != null) {
exporterActivator.stop();
}
if (oldParameters != null) {
ParameterManager.getInstance().setParameters(oldParameters);
}
}
}
}, "NEXT : " + getClass().getSimpleName());
executorThread.setPriority(EngineProperties.getRunPriority());
executorThread.start();
}
private boolean startExporter(String reportName, QueryResult qr, ParametersBean pBean,
final UIActivator activator, boolean isProcedure) throws Exception {
System.gc();
String fileName = REPORTS_DIR + File.separator + reportName + "." + getFileExtension();
OutputStream fos = new FileOutputStream(fileName);
ReportLayout layout = LayoutHelper.getReportLayout();
if (report != null) {
layout = report.getLayout();
}
Connection con = Globals.createTempConnection(Globals.getReportLayoutPanel().getRunDataSource());
ReportLayout convertedLayout = ReportUtil.getDynamicReportLayout(con, layout, pBean);
ExporterBean eb = new ExporterBean(con, Globals.getQueryTimeout(), qr, fos, convertedLayout, pBean, getReportName(), false, isProcedure);
I18nLanguage language = I18nUtil.getDefaultLanguage(layout);
if (language != null) {
eb.setLanguage(language.getName());
}
ResultExporter exporter = getResultExporter(eb);
exporter.setDocumentTitle(getReportName());
exporter.addExporterEventListener(new ExporterEventListener() {
public void notify(final ExporterEvent event) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
eventCounter++;
if ((eventCounter % eventThreshold == 0) ||
(eventCounter == event.getExporterObject().getRecordCount()) ){
activator.updateProgress(event.getExporterObject().getRecord(),
event.getExporterObject().getRecord() + "/" +
event.getExporterObject().getRecordCount());
}
}
});
}
});
boolean ok = true;
try {
ok = exporter.export();
} catch (NoDataFoundException e) {
fos.close();
//
// Delete bad file?
if (fos instanceof FileOutputStream) {
(new File(fileName)).delete();
}
throw new NoDataFoundException(I18NSupport.getString("run.nodata"));
}
con.close();
fos.close();
System.gc();
afterExport(fileName, getReportName());
FileUtil.openFile(fileName, ExportAction.class);
return ok;
}
protected abstract String getFileExtension();
protected abstract ResultExporter getResultExporter(ExporterBean bean);
protected boolean hasMacro() {
return false;
}
protected void afterExport(String filePath, String reportName) {
}
private class ExportStopAction extends AbstractAction {
public ExportStopAction() {
super();
putValue(Action.NAME, I18NSupport.getString("stop.export.action.name"));
putValue(Action.SMALL_ICON, ImageUtil.getImageIcon("stop_execution"));
putValue(Action.SHORT_DESCRIPTION, I18NSupport.getString("stop.export.action.desc"));
putValue(Action.LONG_DESCRIPTION, I18NSupport.getString("stop.export.action.desc"));
putValue(Action.MNEMONIC_KEY, new Integer('S'));
putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK));
}
public void actionPerformed(ActionEvent e) {
if (stop) {
Show.disposableInfo(I18NSupport.getString("stop.wait.second"));
return;
} else {
Show.disposableInfo(I18NSupport.getString("stop.wait"));
}
if (executorThread != null) {
stop = true;
executorThread.interrupt();
}
}
}
protected String getReportName() {
String name = Globals.getCurrentReportName();
if (name == null) {
name = "";
}
return name;
}
private String getNameWithoutExtension(String name) {
int index = name.lastIndexOf(".");
if (index == -1) {
return name;
}
return name.substring(0, index);
}
}