[izpack-user] How do I give the user an option to start application after installation,and actually start it ?

1,294 views
Skip to first unread message

Paul Taylor

unread,
Dec 10, 2013, 8:29:24 AM12/10/13
to us...@izpack.codehaus.org
How do I give the user an option to start application after
installation,and actually start it. This is when using Izpack on Windows
to install a desktop application

thanks Paul

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


Paul Bors

unread,
Dec 10, 2013, 2:45:32 PM12/10/13
to us...@izpack.codehaus.org
You would create a windows service and call it to start at the end of the installation on the FinishPanel.

There are a bunch of ways to do this, I for one use the postinstall.xml. In my install.xml I have something like:
<resources>
  ...
  <res src="postinstall.xml" id="ProcessPanel.Spec.xml" />
  ...
</resources>

Then you need to include the ProcessPanel right after the InstallPanel like so:
<panels>
  ...
  <panel classname="InstallPanel" id="installPanel" />
  <panel classname="ProcessPanel" id="processPanel" />
  ...
</panels>

Now izPack would use the ProcessPanel and read your postinstall.xml and start executing those jobs in different processes.
Read more about it at:


Now, the contents of my postinstall.xml are similar to:
<processing>
    <logfiledir>$INSTALL_PATH</logfiledir>
    ...
    <job name="Create Windows Service">
        <os family="windows" />
        <executeclass name="com.mycomp.installer.util.GlassfishPostInstall">
            <arg>GLASSFISH_JOB=createService</arg>
            <arg>GLASSFISH_HOME="$INSTALL_PATH\glassfish"</arg>
            <arg>adminPassFile="$INSTALL_PATH\glassfish\passfile"</arg>
            <arg>adminCfgFile="$INSTALL_PATH\glassfish\glassfish\config\asenv.bat"</arg>
            <arg>domain.name=domainName</arg>
            <arg>admin.user=${console.gfAdminName}</arg>
            <arg>admin.password=${console.gfAdminPassword}</arg>
            <arg>admin.port=${console.gfAdminPort}</arg>
            <arg>serviceName="${console.serviceName}"</arg>
        </executeclass>
    </job>
    ...
</processing>

Then in my com.mycomp.installer.util.GlassfishPostInstall I have:
    /**
     * Executing a Java Class with ProcessPanel</a> of the izPack documentation, the external Java class
     * must have a run() method with some parameters.<br>
     * <br>
     * <b>Note:</b> This is not (NOT!) the run() method from the java.lang.Runnable interface. Nor is this
     * codified as an interface in the IzPack javadoc. 
     * 
     * @param handler   {@link AbstractUIProcessHandler} used to emit errors.
     * @param args      String array with all of the specific arguments.
     */
public void run(AbstractUIProcessHandler handler, String[] args) {
    Map<String,String> jobArgs = new HashMap<String,String>();
    for(String arg:args) {
        String[] keyProp = arg.split("=");
        jobArgs.put(keyProp[0], keyProp[1]);
    }
    String glassfishJob = jobArgs.get("GLASSFISH_JOB");
    if(glassfishJob.equalsIgnoreCase("createDomain")) {
        createDomain(handler, jobArgs);
    }
    if(glassfishJob.equalsIgnoreCase("startDomain")) {
        gfUtil.startDomain(jobArgs.get("domain.name"));
    }
    if(glassfishJob.equalsIgnoreCase("createService")) {
       createService(handler, jobArgs);
    }
    ...
}
private void createService(AbstractUIProcessHandler handler, Map<String,String> serviceProps) {
        // Create Windows Service for the domain
        if(gfDebug) {
            StringBuilder cmd = new StringBuilder(serviceProps.get("GLASSFISH_HOME")).append("\\bin\\asadmin");
            cmd.append("\n").append("create-service");
            cmd.append("\n").append("--name ").append(serviceProps.get("serviceName"));
            cmd.append("\n").append("--force=true");
            handler.logOutput("\nCreating windows service...\n", false);
            handler.logOutput(cmd.toString(), false);
        }
        
        ArrayList<String> cmdArgs = new ArrayList<String>();
        cmdArgs = new ArrayList<String>();
        cmdArgs.add("create-service");
        cmdArgs.add("--name"); cmdArgs.add(serviceProps.get("serviceName"));
        cmdArgs.add("--force=true");
        gfUtil.asadmin(cmdArgs.toArray(new String[cmdArgs.size()]));
    }

Above only solves the job of creating the windows service and if you don't use GlassFish you can always escpace to dos and run something like "sc.exe create ...". 

To start the service at the end of the installer, I created my own panel that configures GlassFish by creating/updating my domain and deploys my webapp. At the very end it issues this:
    public void startService(String name) {
        List<String> params = new ArrayList<String>(Arrays.asList("cmd.exe", "/c", "sc.exe", "start", name));
        String output = util.runCommand(gfBinDir, true, params.toArray(new String[params.size()]));
        if(debug) {
            System.out.println(output);
        }
    }

And immediately following my custom panel is the FinishPanel.

Hope this helps!

Paul Taylor

unread,
Dec 10, 2013, 2:50:09 PM12/10/13
to us...@izpack.codehaus.org
On 10/12/2013 19:45, Paul Bors wrote:
> You would create a windows service and call it to start at the end of
> the installation on the FinishPanel.
To reiterate this is just a desktop application, in fact it is launched
using winrun4j, so actually the question is just

1. How ask the user whether they want to start the application
2. How to make it run .exe file

Paul Bors

unread,
Dec 10, 2013, 4:38:16 PM12/10/13
to us...@izpack.codehaus.org
You create a custom panel or extend the one you want from izpack, show a pop-up and invoke cmd.exe via java.

Paul Taylor

unread,
Dec 10, 2013, 6:23:31 PM12/10/13
to us...@izpack.codehaus.org
On 10/12/2013 21:38, Paul Bors wrote:
> You create a custom panel or extend the one you want from izpack, show
> a pop-up and invoke cmd.exe via java.
>
But where do i invoke cmd.exe from, the Process Panel ?

Sorry to be dense, but there quite alot of documentation in Izpack but
seems to be lacking examples of what seem to be to be very common
requirements.

Paul Bors

unread,
Dec 10, 2013, 6:49:10 PM12/10/13
to us...@izpack.codehaus.org
yes we do, and you can also do so from anywhere you would like given the Java API right?

 public String runCommand(File dir, boolean ignoreExitState, String... script) {
        Process process = null;
        StringBuilder out = new StringBuilder();
        StringBuilder err = new StringBuilder();
        try {
            ProcessBuilder builder = new ProcessBuilder(script);
            builder.redirectErrorStream(true);
            builder.directory(dir);
            if(debug) {
                System.out.println(builder.directory());
                System.out.println(builder.command());
            }
            process = builder.start();
            int result = doWaitFor(process, out, err);
            if(result != 0) {
            if (ignoreExitState) {
            if(debug) {
            System.out.println(builder.command() + " produced an abnormal exit state (" + result + ") that has been ignored.");
            }
            } else {
            throw new RuntimeException("exit state = " + result + "\nout = " + out + "\nerr = " + err.toString());
            }
            }
            return out.toString().trim();
        } catch(IOException e) {
            throw new RuntimeException(e.getMessage() + "\n" + err, e);
        } finally {
            if(process != null) {
                process.destroy();
            }
        }
    }

Paul Taylor

unread,
Jan 15, 2014, 6:11:36 AM1/15/14
to us...@izpack.codehaus.org
On 10/12/2013 23:49, Paul Bors wrote:

Right I attempted to do this but still doesnt make much sense to me. It appears ProcessPanel is for logging output of some 3rd party java class I dont want to do this I just want izpack to run a command on exit. And the command is an exe command since there is an exe wrapper around the application so essentially I just want to run a windows dos command to run my exe - where can I put this ?

Paul

 

Paul Bors

unread,
Jan 15, 2014, 12:03:48 PM1/15/14
to us...@izpack.codehaus.org
I also have my own custom finish panel that starts a windows service via the cmd.exe at the end of the installation.
That's the closest example I have to your use-case.
 
My method looks like:
public void startService(String name) {
        List<String> params = new ArrayList<String>(Arrays.asList("cmd.exe", "/c", "sc.exe", "start", name));
        String output = util.runCommand(gfBinDir, true, params.toArray(new String[params.size()]));
        if(debug) {
            System.out.println(output);
        }
    }
 
String name is the service name I crate earlier.
 
This method is invoked from my panel's runConsole(InstallData installData) { } which returns true at the end if no throwable is caught.
in turn that runConsole(installData) is called from the automated and gui panels such as:
 
/**
     * This method is called when the panel becomes active. Default is to do nothing : feel free to
     * implement what you need in your subclasses. A panel becomes active when the user reaches it
     * during the installation process.
     */
    @Override
    public void panelActivate() {
        super.panelActivate();
        if(configured) {
            parent.skipPanel();
        } else {
            Dimension dim = parent.getPanelsContainerSize();
            dim.width -= dim.width / 4;
            dim.height = 150;
            setMinimumSize(dim);
            setMaximumSize(dim);
            setPreferredSize(dim);
           
            parent.lockPrevButton();
            parent.lockNextButton();
            new Thread(new Runnable() {
                public void run() {
                    try {
                        GlassfishConfigPanelConsoleHelper panelHelper = new GlassfishConfigPanelConsoleHelper();
                        panelHelper.runConsole(installData);
                        SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                stopAction(false);
                            }
                        });
                    } catch(Exception e) {
                        if(Debug.isSTACKTRACE()) {
                            e.printStackTrace();
                        }
                        logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
                        SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                stopAction(true);
                            }
                        });
                    }
                }
            }).start();
        }
    }
 
private void stopAction(final boolean failure) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
            ... handle the clean-up
            }
 
This panel is the second to last, right before izPack's FinishPanel.
Thus, my service is started and even if it fails it will cleanup and allow the uninstaller to be written via the FinishPanel.

Paul Bors

unread,
Jan 15, 2014, 12:04:41 PM1/15/14
to us...@izpack.codehaus.org
You can do this in your own custom finish panel if you wish.
I choose to do it in the panel right before it.

Scott McDermott

unread,
Jan 15, 2014, 12:17:18 PM1/15/14
to us...@izpack.codehaus.org

Hello izpack community ---

First and foremost my _sincere_ apologies if this is the wrong place to post this request. I have searched Google, and the mailing list archives, and other places that came to mind, for the right place for this topic; and then I waited on this list to see what the norms were. My conclusion was that this was not the right place to ask for this kind of commercial help: but it was the best place to ask where the right place is!

My company needs someone who can put together installer(s), for Linux/Mac/Windows, for a Java console application that has native-library dependencies. Specifically, the application is for configuring our hardware products, and it uses RXTX to talk to those products --- RXTX in turn, has .so files, 32-bit .dlls, and 64-bit .dlls, to make it run on the various platforms.

Our internal team is excellent at embedded programming, okay at *nix platforms, but simply cannot keep up with how Windows desktop apps are supposed to be installed. We would like to contract out for this expertise, and we're hoping someone on this list can point us in the right direction. We hand over the .jar, support files (images etc.), and a handful of platform-dependent RXTX libraries, and we get back installer(s) that make life easy and bulletproof for our end users.

Definite bonus points if the installer can also take care of JRE installation itself.

Again apologies if this is a pollution of this list, but any pointers in the right direction are well appreciated.

With regards ---
Scott McDermott
Proto-Logic Consulting LLC

Paul Bors

unread,
Jan 15, 2014, 12:30:25 PM1/15/14
to us...@izpack.codehaus.org
That's fine, is okay to post open job positons on the user's mailing list.
 
This should be encouraged as it raises interest in a project.
Is always nice to see that IzPack is gaining more popularity.

Paul Taylor

unread,
Jan 16, 2014, 8:02:31 AM1/16/14
to us...@izpack.codehaus.org
On 15/01/2014 17:04, Paul Bors wrote:
> You can do this in your own custom finish panel if you wish.
> I choose to do it in the panel right before it.
>
Okay so I took your advice, and simply tried to start an already
installed instance of the application rather than the version I was
installing by modifiying my Finish class and adding code to run command
in a new thread, assuming it would either start application or not, but
instead just causes my installer to hang !

please see below

package net.jthink.izpack.panels;

import com.izforge.izpack.api.data.Panel;
import com.izforge.izpack.api.resource.Resources;
import com.izforge.izpack.gui.log.Log;
import com.izforge.izpack.installer.data.GUIInstallData;
import com.izforge.izpack.installer.data.UninstallDataWriter;
import com.izforge.izpack.installer.gui.InstallerFrame;
import com.izforge.izpack.panels.simplefinish.SimpleFinishPanel;
import com.izforge.izpack.util.Debug;

import java.io.*;
import java.util.*;
import java.util.Locale;

public class JthinkFinishPanel extends SimpleFinishPanel
{
private GUIInstallData installData;

public JthinkFinishPanel(Panel panel, InstallerFrame parent,
GUIInstallData installData, Resources resources,
UninstallDataWriter uninstallDataWriter,
Log log)
{
super(panel, parent, installData, resources,
uninstallDataWriter, log);
this.installData = installData;
}

@Override
public void panelActivate()
{
super.panelActivate();

Locale userLang = installData.getLocale();
String installDir = installData.getVariable("INSTALL_PATH");
try
{
OutputStreamWriter writer = new OutputStreamWriter(new
FileOutputStream(new File(installDir, "installer.properties")), "UTF-8");
writer.write("userLang=" + userLang.getLanguage() + "\n");
writer.close();
}
catch (Exception e)
{
if (Debug.isSTACKTRACE())
{
e.printStackTrace();
}
super.emitError(getInstallerFrame().getMessages().get("installer.error"), e.getLocalizedMessage());
}

new Thread(new Runnable()
{
public void run()
{
try
{
List<String> params = new ArrayList();
params.add("C:/Apps/jthink/songkong/SongKong_1.15.0/SongKong.exe");
Process p =
Runtime.getRuntime().exec(params.toArray(new String[1]));
}
catch (Exception e)
{
if (Debug.isSTACKTRACE())
{
e.printStackTrace();
}
//logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
}).start();

Earl Hood

unread,
Jan 16, 2014, 10:11:00 AM1/16/14
to us...@izpack.codehaus.org
On Thu, Jan 16, 2014 at 7:02 AM, Paul Taylor wrote:

>> You can do this in your own custom finish panel if you wish.
>> I choose to do it in the panel right before it.
>>
> Okay so I took your advice, and simply tried to start an already installed
> instance of the application rather than the version I was installing by
> modifiying my Finish class and adding code to run command
> in a new thread, assuming it would either start application or not, but
> instead just causes my installer to hang !

Properly executing a sub-process, especially one that should out-live
the parent process is a general Java programming issue and not specific
to izpack.

You should make the thread that invokes your program a daemon thread.
Also, you may need to slurp up the standard streams. If you google
around, you should find some solutions on how to execute your program so
the calling process does not hang.

--ewh

Paul Bors

unread,
Jan 16, 2014, 10:39:38 PM1/16/14
to us...@izpack.codehaus.org
Right, in windows land that would be a service that you can see inside the control panel’s service controller.
In linux and unix, those are deemons something like this:

Thread t = new Thread(new Evil());
 t.setDaemon(true);//success is here now
 t.start();
 Thread.sleep(1000);

Paul Taylor

unread,
Jan 23, 2014, 7:18:40 AM1/23/14
to us...@izpack.codehaus.org
On 17/01/2014 03:39, Paul Bors wrote:
Right, in windows land that would be a service that you can see inside the control panel’s service controller.
In linux and unix, those are deemons something like this:

Thread t = new Thread(new Evil());
 t.setDaemon(true);//success is here now
 t.start();
 Thread.sleep(1000);

Hi, note I'm only trying to solve the issue for Windows,
I know what a daemon is and I know what a Windows service is but I just want to start my gui application at the end of installation like can be done with InstallAnywhere, I dont want it to run a service.
I tried the change you recommended and now the installer does not hang but the application doesn't start I assume because it requires a windowing environment and set the thread to daemon prevents this. As I'm trying to start an exe what Im trying to achieve is just start a Windows application, the fact that the exe is a wrapper around a Java application is irrelevant.

Paul

Paul Bors

unread,
Jan 23, 2014, 1:06:27 PM1/23/14
to us...@izpack.codehaus.org
How would you do this from a dos shell when cmd.exe is one process and you want to start another (your GUI) unattended?
This is all build into the OS, you just need to make the right calls and start the right processes.

Paul Bors

unread,
Jan 23, 2014, 1:07:21 PM1/23/14
to us...@izpack.codehaus.org
hint: c:\>cmd /C java -jar myGui.jar

Paul Bors

unread,
Jan 23, 2014, 1:08:20 PM1/23/14
to us...@izpack.codehaus.org

Paul Taylor

unread,
Jan 23, 2014, 4:41:25 PM1/23/14
to us...@izpack.codehaus.org
On 23/01/2014 18:08, Paul Bors wrote:
> another hint:
> http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html#start()
> <http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html#start%28%29>
>
I tried this

Thread t = new Thread(new Runnable()
{
public void run()
{
try
{
List<String> params = new ArrayList();
params.add("cmd");
params.add("/c");
params.add("C:/Apps/jthink/songkong/SongKong_1.15.0/SongKong.exe");
Process p =
Runtime.getRuntime().exec(params.toArray(new String[1]));
}
catch (Exception e)
{
if (Debug.isSTACKTRACE())
{
e.printStackTrace();
}
//logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
});

t.setDaemon(true);//success is here now
t.start();
Thread.sleep(1000);

and then again with the t.setDaemon() commented out.

In both cases Izpack didn't hung but the application didn't start, I do
understand Java, what I dont understand is Izpack

Paul

Paul Bors

unread,
Jan 23, 2014, 10:40:36 PM1/23/14
to us...@izpack.codehaus.org
izPack is nothing but a Swing app in Java.

You almost got it, but instead of a thread you should have use the swing’s way:

public class MyPanel extends IzPanel {
    /**
     * This method is called when the panel becomes active. Default is to do nothing : feel free to
     * implement what you need in your subclasses. A panel becomes active when the user reaches it
     * during the installation process.
     */
    @Override
    public void panelActivate() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                List<String> params = new ArrayList();
                params.add(“cmd”).add(“/c”).add(“…SongKong.exe”);
		Runtime.getRuntime().exec(params.toArray(new String[]{}));
            }
        });
}
}

Let me know how that works out for you.

Paul Taylor

unread,
Jan 24, 2014, 7:32:58 AM1/24/14
to us...@izpack.codehaus.org
On 24/01/2014 03:40, Paul Bors wrote:
izPack is nothing but a Swing app in Java.

You almost got it, but instead of a thread you should have use the swing’s way:
Still no luck, nothing happens, but I notice if that if run the installer using java -jar rather than wrapped in Winrun4j I get this error on the last panel

24-Jan-2014 12:27:23 SEVERE: NativeLibException.functionFailed.RegOpenKeyEx
NativeLibException.libInternal.OsErrNumPraefix5
NativeLibException.libInternal.OsErrStringPraefixAccess is denied.

Paul

Paul Bors

unread,
Jan 27, 2014, 2:31:27 PM1/27/14
to us...@izpack.codehaus.org
Your native lib exceptions must be because you forgot to add the <natives> section to your install.xml:
 
Now, it is expected for the process you start to exit when the installer terminates because your new thread/process is a child of it.
Technically, you would have to do this from the main() method and to do that you'd have more customazation on top for the framework.
 
It is simpler to just create yourself a shell script (batch file for Windows) and have that start the new process or simply fall back to cmd.exe and issue the start command yourself.
 
Attached is a working example of an izPack installer that will start Notepad.exe and leave it running when you click on the Finish button.
Just rename the file from *.txt to *.zip since my e-mail client is acting up when it comes to attaching zips.
 
Have fun!
Example.zip.txt
Reply all
Reply to author
Forward
0 new messages