/*!
* 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 (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.designer.core.util;
import edu.stanford.ejalbert.BrowserLauncher;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.designer.core.settings.ExternalToolSettings;
import org.pentaho.reporting.designer.core.settings.SettingsUtil;
import org.pentaho.reporting.designer.core.util.exceptions.UncaughtExceptionsModel;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
/**
* User: Martin Date: 01.03.2006 Time: 17:55:15
*/
public class ExternalToolLauncher {
private static final Log logger = LogFactory.getLog( ExternalToolLauncher.class );
private static final long timeout = 10000;
private ExternalToolLauncher() {
}
public static void openURL( final String url ) throws IOException {
//noinspection ConstantConditions
if ( url == null ) {
throw new IllegalArgumentException( "url must not be null" );
}
final ExternalToolSettings instance = ExternalToolSettings.getInstance();
if ( instance.isUseDefaultBrowser() ) {
try {
new BrowserLauncher().openURLinBrowser( url );
} catch ( Exception e ) {
UncaughtExceptionsModel.getInstance().addException( e );
}
} else {
if ( execute( instance.getCustomBrowserExecutable(),
instance.getCustomBrowserParameters(), url ) == false ) {
throw new IOException( UtilMessages.getInstance()
.getString( "ExternalToolLauncher.errorMessage", instance.getCustomBrowserExecutable() ) );
}
}
}
public static void openPDF( final File file ) throws IOException {
//noinspection ConstantConditions
if ( file == null ) {
throw new IllegalArgumentException( "file must not be null" );
}
final ExternalToolSettings toolSettings = ExternalToolSettings.getInstance();
if ( toolSettings.isUseDefaultPDFViewer() ) {
openDefaultViewer( file );
} else {
if ( execute
( toolSettings.getCustomPDFViewerExecutable(),
toolSettings.getCustomPDFViewerParameters(),
file.getCanonicalPath() ) == false ) {
throw new IOException( UtilMessages.getInstance()
.getString( "ExternalToolLauncher.errorMessage", toolSettings.getCustomPDFViewerExecutable() ) );
}
}
}
public static void openXLS( final File file ) throws IOException {
//noinspection ConstantConditions
if ( file == null ) {
throw new IllegalArgumentException( "file must not be null" );
}
final ExternalToolSettings toolSettings = ExternalToolSettings.getInstance();
if ( toolSettings.isUseDefaultXLSViewer() ) {
try {
openDefaultViewer( file );
} catch ( Exception e ) {
UncaughtExceptionsModel.getInstance().addException( e );
}
} else {
if ( execute(
toolSettings.getCustomXLSViewerExecutable(),
toolSettings.getCustomXLSViewerParameters(),
file.getCanonicalPath() ) == false ) {
throw new IOException( UtilMessages.getInstance()
.getString( "ExternalToolLauncher.errorMessage", toolSettings.getCustomXLSViewerExecutable() ) );
}
}
}
public static void openRTF( final File file ) throws IOException {
//noinspection ConstantConditions
if ( file == null ) {
throw new IllegalArgumentException( "file must not be null" );
}
final ExternalToolSettings toolSettings = ExternalToolSettings.getInstance();
if ( toolSettings.isUseDefaultRTFViewer() ) {
openDefaultViewer( file );
} else {
if ( execute(
toolSettings.getCustomRTFViewerExecutable(),
toolSettings.getCustomRTFViewerParameters(),
file.getCanonicalPath() ) == false ) {
throw new IOException( UtilMessages.getInstance()
.getString( "ExternalToolLauncher.errorMessage", toolSettings.getCustomRTFViewerExecutable() ) );
}
}
}
public static void openCSV( final File file ) throws IOException {
//noinspection ConstantConditions
if ( file == null ) {
throw new IllegalArgumentException( "file must not be null" );
}
final ExternalToolSettings toolSettings = ExternalToolSettings.getInstance();
if ( toolSettings.isUseDefaultCSVViewer() ) {
openDefaultViewer( file );
} else {
if ( execute( toolSettings.getCustomCSVViewerExecutable(),
toolSettings.getCustomCSVViewerParameters(),
file.getCanonicalPath() ) == false ) {
throw new IOException( UtilMessages.getInstance()
.getString( "ExternalToolLauncher.errorMessage", toolSettings.getCustomCSVViewerExecutable() ) );
}
}
}
public static boolean execute( final String executable, final String parameters, final String file )
throws IOException {
// todo: Use a stream tokenizer (well, a custom one, as the builtin one messes up escaped quotes)
// so that we can handle quoting gracefully ..
boolean exitValue = false;
final ArrayList<String> command = new ArrayList<String>();
command.add( executable );
for ( StringTokenizer tokenizer = new StringTokenizer( parameters ); tokenizer.hasMoreTokens(); ) {
String s = tokenizer.nextToken();
s = s.replace( "{0}", file );
command.add( s );
}
final String osname = safeSystemGetProperty( "os.name", "<protected by system security>" ); // NON-NLS
if ( StringUtils.startsWithIgnoreCase( osname, "Mac OS X" ) ) // NON-NLS
{
logger.debug( "Assuming Mac-OS X." ); // NON-NLS
if ( executable.endsWith( ".app" ) || executable.endsWith( ".app/" ) ) // NON-NLS
{
command.add( 0, "-a" ); // NON-NLS
command.add( 0, "/usr/bin/open" ); // NON-NLS
}
}
final ProcessBuilder processBuilder = new ProcessBuilder( command.toArray( new String[ command.size() ] ) );
Process process = null;
ProcessWrapper processWrapper = null;
try {
process = processBuilder.start();
processWrapper = new ProcessWrapper( process );
processWrapper.start();
processWrapper.join( timeout );
if ( processWrapper.getfExitCode() != null ) {
exitValue = processWrapper.getfExitCode() == 0;
} else {
// Set our exit code to 1
exitValue = false;
process.destroy();
}
//final Process p = process.start();
//p.waitFor();
//exitValue = p.exitValue() == 0;
// 0 == normal; 2 == permissions issue, 3 == no rules found in mimeType
logger.debug( "ProcessWrapper exitCode = " + processWrapper.getfExitCode() );
} catch ( InterruptedException ie ) {
processWrapper.interrupt();
Thread.currentThread().interrupt();
process.destroy();
exitValue = false;
} catch ( Exception e ) {
logger.error( "Error in execute shell command " + command + " error: " + e.getMessage() );
// process fails so redirect to openURL command to locate viewer
exitValue = false;
}
return exitValue;
}
protected static String safeSystemGetProperty( final String name,
final String defaultValue ) {
try {
return System.getProperty( name, defaultValue );
} catch ( final SecurityException se ) {
// ignore exception
return defaultValue;
}
}
public static void openDefaultViewer( final File file ) throws IOException {
final String osname = safeSystemGetProperty( "os.name", "<protected by system security>" ); // NON-NLS
final String jrepath = safeSystemGetProperty( "java.home", "." ); // NON-NLS
final String fs = safeSystemGetProperty( "file.separator", File.separator ); // NON-NLS
logger.debug( "Running on operating system: " + osname ); // NON-NLS
if ( StringUtils.startsWithIgnoreCase( osname, "windows" ) ) // NON-NLS
{
logger.debug( "Detected Windows." ); // NON-NLS
if ( execute( "rundll32.exe", "SHELL32.DLL,ShellExec_RunDLL {0}", file.getAbsolutePath() ) == false ) // NON-NLS
{
openURL( file.toURI().toURL().toString() );
}
} else if ( StringUtils.startsWithIgnoreCase( osname, "Mac OS X" ) ) // NON-NLS
{
logger.debug( "Assuming Mac-OS X." ); // NON-NLS
if ( execute( "/usr/bin/open", "{0}", file.getCanonicalPath() ) == false ) // NON-NLS
{
openURL( file.toURI().toURL().toString() );
}
} else if ( StringUtils.startsWithIgnoreCase( osname, "Linux" ) || // NON-NLS
StringUtils.startsWithIgnoreCase( osname, "Solaris" ) || // NON-NLS
StringUtils.startsWithIgnoreCase( osname, "HP-UX" ) || // NON-NLS
StringUtils.startsWithIgnoreCase( osname, "AIX" ) || // NON-NLS
StringUtils.startsWithIgnoreCase( osname, "SunOS" ) ) // NON-NLS
{
logger.debug( "Assuming unix." ); // NON-NLS
final File mailcapExe = new File( "/usr/bin/run-mailcap" ); // NON-NLS
if ( mailcapExe.exists() ) {
logger.debug( "found /usr/bin/run=mailcap" );
if ( execute( "/usr/bin/run-mailcap", "{0}", file.getCanonicalPath() ) == false ) // NON-NLS
{
openURL( file.toURI().toURL().toString() );
}
} else {
// use our private version instead ...
final File installDir = SettingsUtil.computeInstallationDirectory();
if ( installDir == null ) {
logger.debug( "Cannot determine installation directory; using browser as generic launcher." ); // NON-NLS
openURL( file.toURI().toURL().toString() );
return;
}
final File privateMailCapExe = new File( installDir, "resources/run-mailcap" ); // NON-NLS
if ( privateMailCapExe.exists() ) {
if ( execute( privateMailCapExe.getPath(), "{0}", file.getCanonicalPath() ) == false ) {
openURL( file.toURI().toURL().toString() );
}
} else {
logger.debug( "private copy of run-mailcap not found; using browser as generic launcher." ); // NON-NLS
openURL( file.toURI().toURL().toString() );
return;
}
}
} else {
logger.debug( "Not a known OS-Type; using browser as generic launcher." ); // NON-NLS
openURL( file.toURI().toURL().toString() );
}
}
static class ProcessWrapper extends Thread {
private final Process fProcess;
private Integer fExitCode;
public Integer getfExitCode() {
return fExitCode;
}
public ProcessWrapper( Process fProcess ) {
this.fProcess = fProcess;
}
public void run() {
try {
fExitCode = fProcess.waitFor();
} catch ( InterruptedException e ) {
fExitCode = 0;
} catch ( Exception ex ) {
fExitCode = -1;
}
}
}
}