/** * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * 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 Lesser General Public License for more details. * * Copyright 2005 - 2009 Pentaho Corporation. All rights reserved. * * * @created Jul 5, 2005 * @author William Seyler **/ package org.pentaho.platform.plugin.action.builtin; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import javax.print.PrintService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.Driver; import org.apache.fop.render.awt.AWTRenderer; import org.pentaho.actionsequence.dom.ActionInputConstant; import org.pentaho.actionsequence.dom.IActionOutput; import org.pentaho.actionsequence.dom.actions.PrinterAction; import org.pentaho.platform.api.engine.IActionSequenceResource; import org.pentaho.platform.api.repository.ISolutionRepository; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.services.solution.ComponentBase; import org.pentaho.platform.engine.services.solution.StandardSettings; import org.pentaho.platform.plugin.action.messages.Messages; import org.xml.sax.InputSource; /** * * Implements a PrintComponent class that will send a attached print file to a * specified printer. */ public class PrintComponent extends ComponentBase { /** * */ private static final long serialVersionUID = 7377566797214172734L; private static final String DEFAULT_PRINTER = "PENTAHO_DEFAULT_PRINTER"; // This should never be a real printer //$NON-NLS-1$ @Override public Log getLogger() { return LogFactory.getLog(PrintComponent.class); } @Override public boolean init() { // TODO Auto-generated method stub return true; } @Override protected boolean validateSystemSettings() { // This component does not have any system settings to validate return true; } @Override protected boolean validateAction() { PrinterAction printerAction = null; boolean actionValidated = true; if (getActionDefinition() instanceof PrinterAction) { printerAction = (PrinterAction) getActionDefinition(); if ((printerAction.getPrintfile() == ActionInputConstant.NULL_INPUT) && (printerAction.getResourcesPrintFile() == null) && (printerAction.getReportOutput() == ActionInputConstant.NULL_INPUT) && (printerAction.getOutputPrinterName() == null)) { actionValidated = false; error(Messages.getInstance().getErrorString("PrintComponent.ERROR_0001_NO_PRINT_FILE_DEFINED") + getActionName()); //$NON-NLS-1$ } } else { actionValidated = false; error(Messages.getInstance().getErrorString( "ComponentBase.ERROR_0001_UNKNOWN_ACTION_TYPE", getActionDefinition().getElement().asXML())); //$NON-NLS-1$ } return actionValidated; } @Override protected boolean executeAction() { String printFileName = null; IActionSequenceResource printFileResource = null; PrinterAction printAction = (PrinterAction) getActionDefinition(); if (printAction.getPrintfile() != ActionInputConstant.NULL_INPUT) { printFileName = printAction.getPrintfile().getStringValue(); } else if (printAction.getResourcesPrintFile() != null) { org.pentaho.actionsequence.dom.IActionResource tempResource = printAction.getResourcesPrintFile(); printFileResource = getResource(tempResource.getName()); } InputStream inStream = null; String printerName = printAction.getPrinterName().getStringValue(PrintComponent.DEFAULT_PRINTER); String lastPrinter = printAction.getDefaultPrinter().getStringValue(); if ((printAction.getOutputPrinterName() != null) && !printerName.equals("")) { //$NON-NLS-1$ IActionOutput output = printAction.getOutputPrinterName(); output.setValue(printerName); if (printAction.getOutputDefaultPrinter() != null) { IActionOutput defaultPrinterOutput = printAction.getOutputDefaultPrinter(); defaultPrinterOutput.setValue(printerName); } return true; } PrintService printer = getPrinterInternal(printerName, lastPrinter); if (printer == null) { if (!feedbackAllowed()) { error(Messages.getInstance().getErrorString("PrintComponent.ERROR_0002_NO_SUITABLE_PRINTER")); //$NON-NLS-1$ return false; } // we created the printer feedback entry already return true; } if (printAction.getOutputDefaultPrinter() != null) { IActionOutput defaultPrinterOutput = printAction.getOutputDefaultPrinter(); defaultPrinterOutput.setValue(printerName); } // Get the number of copies int copies = printAction.getCopies().getIntValue(1); // Check for a valid printFileName or printFile Resource if (printFileName != null) { ISolutionRepository repository = PentahoSystem.get(ISolutionRepository.class, getSession()); try { inStream = repository.getResourceInputStream(printFileName, true, ISolutionRepository.ACTION_EXECUTE); } catch (FileNotFoundException e) { return false; } } else if (printFileResource != null) { try { inStream = getResourceInputStream(printFileResource); } catch (FileNotFoundException e) { return false; } } else if (printAction.getReportOutput() != ActionInputConstant.NULL_INPUT) { inStream = getInputStream(PrinterAction.REPORT_OUTPUT); } else { // This should never happen if we validated ok. return false; } try { // Set the input source for sending to the driver. InputSource source = new InputSource(inStream); try { Driver driver = new Driver(source, null); PrinterJob pj = PrinterJob.getPrinterJob(); // Check to see if we're using the default printer or the user // requested a different printer. if (!(PrinterAction.DEFAULT_PRINTER.equals(printerName))) { pj.setPrintService(getPrinterInternal(printerName, lastPrinter)); } PrintRenderer renderer = new PrintRenderer(pj, copies); driver.setRenderer(renderer); driver.run(); } catch (Exception ex) { return false; } } finally { try { inStream.close(); } catch (IOException ex) { // TODO: Provide message here... ex.printStackTrace(); } } return true; } @Override public void done() { // TODO Auto-generated method stub } /** * Takes a printer name and find the associated PrintService. If no match * can be made it randomly picks the first printer listed from the call to * lookupPrintServices. * * @param printerName * @return PrintService referenced by the printerName */ public PrintService getPrinterInternal(final String printerName, final String lastPrinterName) { // The parameter value was not provided, and we are allowed to create // user interface forms PrintService[] services = PrinterJob.lookupPrintServices(); for (PrintService element : services) { if (element.getName().equals(printerName)) { return element; } } if (feedbackAllowed()) { // If it's not valid then lets find one and end this current run. ArrayList values = new ArrayList(); for (PrintService element : services) { String value = element.getName(); values.add(value); } createFeedbackParameter(StandardSettings.PRINTER_NAME, Messages.getInstance().getString("PrintComponent.USER_PRINTER_NAME"), "", lastPrinterName, values, null, "select"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ promptNeeded(); return null; } return services[0]; } /** * Takes a printer name and find the associated PrintService. If no match * can be made it randomly picks the first printer listed from the call to * lookupPrintServices. * * @param printerName * @return PrintService referenced by the printerName */ public static PrintService getPrinter(final String printerName) { // The parameter value was not provided, and we are allowed to create // user interface forms PrintService[] services = PrinterJob.lookupPrintServices(); for (PrintService element : services) { if (element.getName().equals(printerName)) { return element; } } return services[0]; } public static PrintService getDefaultPrinter() { // The parameter value was not provided, and we are allowed to create // user interface forms PrintService[] services = PrinterJob.lookupPrintServices(); if ((services == null) || (services.length == 0)) { return null; } return services[0]; } /** * * Extends AWTRenderer to create a class that will print to a specified * printerJob * */ class PrintRenderer extends AWTRenderer { private static final int EVEN_AND_ALL = 0; private static final int EVEN = 1; private static final int ODD = 2; private int startNumber; private int endNumber; private int mode = PrintRenderer.EVEN_AND_ALL; private int copies = 1; private PrinterJob printerJob; PrintRenderer(final PrinterJob printerJob, final int copies) { super(null); this.printerJob = printerJob; this.copies = copies; startNumber = 0; endNumber = -1; printerJob.setPageable(this); printerJob.setCopies(this.copies); mode = PrintRenderer.EVEN_AND_ALL; String str = null; if (str != null) { try { mode = Boolean.valueOf(str).booleanValue() ? PrintRenderer.EVEN : PrintRenderer.ODD; } catch (Exception e) { } } } @Override public void stopRenderer(final OutputStream outputStream) throws IOException { super.stopRenderer(outputStream); if (endNumber == -1) { endNumber = getPageCount(); } ArrayList numbers = getInvalidPageNumbers(); for (int i = numbers.size() - 1; i > -1; i--) { removePage(Integer.parseInt((String) numbers.get(i))); } try { printerJob.print(); } catch (PrinterException e) { e.printStackTrace(); throw new IOException(Messages.getInstance().getString( "PrintComponent.ERROR_0003_UNABLE_TO_PRINT", e.getClass().getName(), e.getMessage())); //$NON-NLS-1$ } } // public void renderPage(Page page) { // pageWidth = (int) (page.getWidth() / 1000f); // pageHeight = (int) (page.getHeight() / 1000f); // super.renderPage(page); // } private ArrayList getInvalidPageNumbers() { ArrayList vec = new ArrayList(); int max = getPageCount(); boolean isValid; for (int i = 0; i < max; i++) { isValid = true; if ((i < startNumber) || (i > endNumber)) { isValid = false; } else if (mode != PrintRenderer.EVEN_AND_ALL) { if ((mode == PrintRenderer.EVEN) && ((i + 1) % 2 != 0)) { isValid = false; } else if ((mode == PrintRenderer.ODD) && ((i + 1) % 2 != 1)) { isValid = false; } } if (!isValid) { vec.add(i + ""); //$NON-NLS-1$ } } return vec; } } // class PrintRenderer }