Pages

Monday, May 3, 2010

Write an installer with IzPack

Features and Drawbacks of Using IzPack

Because of the following reasons I chose IzPack to create the installer for my application, from all other free and open source installer software. The reasons which helped me to make my decision are as follows,
  • IzPack is Open Source
  • It has attractive GUI
  • Great Customizability
  • It is a Cross-Platform Installer
  • Automatic Uninstaller Creation
The drawback of using IzPack is, it doesn’t contain enough documentation or working examples for a beginner to use it and get the job done easily.
Because of this reason I thought of discussing and guiding you on how to use IzPack to create an Installer today in this blog.

How IzPack Installer Operates

All what we have to do to make the installer is write an xml file stating all the necessary configuration information and compile it using the compiler provided by the IzPack. Then according to our xml, an installer file named install.jar will be created by the IzPack. It will wrap all the files and folder structure from the end user. Then a separate application should be used to convert this jar file to a windows executable or a Mac application. For this example I’m using a software named Launch4j for this purpose.
Download and Install IzPack latest version from: http://izpack.org/
Download and Install Launch4j latest version from: http://launch4j.sourceforge.net/

Creating an install.xml file

This xml file has a root element as “installation” which has an attribute named “version”. i.e. all other tags of the xml file should be placed somewhere inside the main tag of <installation version=”1.0></installation>
The first configuration data to appear inside these installation tag is the data of information section.
<info>
        <appname>Jefe</appname>
        <appversion>1.0</appversion>
        <authors>
            <author name="Ms. K.M.L. Sureshika" email=""/>
            <author name="Ms. A.P. Pathirage" email=""/>
            <author name="Ms. S.P. Mendis" email=""/>
            <author name="Mr. S. Nirathan" email=""/>
        </authors>
        <javaversion>1.5</javaversion>
        <requiresjdk>no</requiresjdk>
        <url>
http://www.jefe-sdwms.com/</url>
        <uninstaller name="uninstall.jar" path="${INSTALL_PATH}/uninstaller" write="yes"/>
        <summarylogfilepath>$INSTALL_PATH/InstallationSummary.htm</summarylogfilepath>
        <writeinstallationinformation>no</writeinstallationinformation>
</info>

Information in the appname, appversion,authors and url tags will be used to display on the HelloPanel. javaversion will be used to specify the minimum java version required for your application to work. requirejdk has the values yes and no which will enforce the user to install a java jdk of minimum java version specified or above. uninstaller tag will allow you to specify the location where the uninstaller should be created and its name. summarylogfilepath will be used to store a html file of installation summary after successful installation. writeinstallainformation has values yes or no. If yes is given it gives the user the ability to generate an installation script for further installations.
The next section in my install.xml is “guiprefs”. It will allow me to change the appearance of the ultimate installer of my application.
<guiprefs width="600" height="480" resizable="no">
        <modifier key="layoutAnchor" value="CENTER"/>
        <modifier key="useHeadingPanel" value="yes"/>
        <modifier key="useHeadingForSummary" value="yes"/>
        <modifier key="headingImageOnLeft" value="yes"/>
        <modifier key="headingLineCount" value="2"/>
        <modifier key="headingFontSize" value="1.5"/>
        <modifier key="headingBackgroundColor" value="0x00ffffff"/>
        <modifier key="headingPanelCounter" value="text"/>
        <modifier key="headingPanelCounterPos" value="inHeading"/>
</guiprefs>

Here I’m specifying the width and the height of the gui and restricting it from resizing which will be problematic since I’m using two images in the installer. I’m also placing a layout anchor for the gui and instructing it that I’m using a header panel and heading image on the left.
According to the IzPack manual, you can specify various new variables other than the default variables as $INSTALL_PATH and $JAVA_HOME. In my code I have used the following variable to use in the shortcut panel.
<variables>
        <variable name="DesktopShortcutCheckboxEnabled" value="true"/>
</variables>

We can also specify many languages for the installer to operates. For my installer I only specified English. Because there aren’t any choice the initial panel for language selection is not appearing in my installer. All the language codes needed for configuring this option is given in the IzPack manual clearly
<locale>
    <langpack iso3="eng"/>
</locale>

Next comes an important section in the install.xml. Resources tag will contain information and location of all the additional files in the installation other than the install.xml itself.
<resources>
        <res id="shortcutSpec.xml" src="shortcutSpec.xml"/>
        <res id="HTMLInfoPanel.readme" src="Readme.html"/>
        <res id="HTMLLicencePanel.licence" src="Licence.html"/>
        <res id="Heading.image" src="images/heading-image.png"/>
       <res id="Installer.image" src="images/side-image.png"/>
</resources>

In here, shortcutSpec.xml file, Readme.html file and Licence.html file are located on the root of the installation folder. But header image and side image are located inside a folder named images which is located on the root. Likewise you can specify any resource used for the installation process, located anywhere with respect to the installation folder. For all the resources you also need to give a unique id which can be used later for identifying the resource. And remember to include all the files you have mentioned under resources with exact names and locations unless you need half a dozen compilation errors.
Panel section will be used to specify the different panels you need to show in your installation and their order of appearance. All different panels are given in the manual. These are what I’m using for my installation in the order they required to appear.
<panels>
        <panel classname="HelloPanel"/>
        <panel classname="HTMLInfoPanel" id="readme"/>
        <panel classname="HTMLLicencePanel" id="licence"/>
        <panel classname="TargetPanel"/>
        <panel classname="TreePacksPanel"/>
        <panel classname="SummaryPanel"/>
        <panel classname="InstallPanel"/>
        <panel classname="ShortcutPanel"/>
        <panel classname="FinishPanel"/>
</panels>

For your information I’ll include GUIs of the above panels in the above order.










Then next most important section of our install.xml is the packs section, which define what need to be installed, to where and how. This implements the core of the installation process. Since the code of the packs section of my installer is so lengthy I will include the code of one pack only.
<packs>
        <pack name="core" required="yes">
            <description>This will include the necessary processing of Liferay framework and other core files used in the jefe solution.</description>
            <file src="Readme.html" targetdir="$INSTALL_PATH"/>
            <file src="Licence.html" targetdir="$INSTALL_PATH"/>
            <fileset dir="images" targetdir="$INSTALL_PATH\images">
                <include name="**"/>
            </fileset>
            <file src="liferay-portal-tomcat-6.0-5.2.3.zip" targetdir="$INSTALL_PATH\core" unpack="true"/>
            <executable targetfile="$INSTALL_PATH/liferay-portal-5.2.3/tomcat-6.0.18/bin/startup.bat" stage="never" />
            <executable targetfile="$INSTALL_PATH/liferay-portal-5.2.3/tomcat-6.0.18/bin/shutdown.bat" stage="never" />   
    </pack>
    …
    …
</packs>

Installation process is divided into many parts according to packs. As you can see in the 5th image since pack give in the above code is set as “required=yes” user does not get the opportunity to select or deselect it according to his requirements. Hence this is a good option to include all the required and essential features of the application under this pack. So I have used this pack named core to copy the Readme file, Licence file and images folder to the root of the installation location and i have also unzipped the zip file named “liferay-portal-tomcat-6.0-5.2.3.zip” to the folder “core” in the root. After unzipping I’m specifying 2 runnable bat file locations in it which I need to run later. But here I’m asking the installer not to run these files by specifying the stage as never. The other alternatives to the stage are postinstall and uninstall which will be called soon after installation and at the time of uninstalling respectively. Description will appear when you click on a pack.
You can also list packs that appears inside some other packs as in image 5. For this, you can code your packs as follows.
<pack name="stack" required="no" preselect="yes">
            <description>This is custom portlet stack provided by the jefe solution.</description>
</pack>

            <pack name="Document Repository" required="no" parent="stack">
                  <description>This will include all the document repository plugins to the core.</description>
            </pack>

Parent pack needs not contain any special tags for this functionality to implement. But the child pack need to have an attribute named parent with the name of its parent pack as the value. When compared to previous pack code this code has some more changes. I have stated the attribute “required=no” giving the user the flexibility to choice and added a new attribute “preselect=yes” to persuade the user to install this pack too.
I  have also used an listener for windows users, to catch the summary log of the installer. The code for the following segment represent the inclusion of the above listener.
<listeners>
      <listener installer="SummaryLoggerInstallerListener">
          <os family="windows"/>
      </listener>
</listeners>

Native packs are also required to include in your installation xml file to implement the installer functionality. The code for the above native pack is included below.
<native type="izpack" name="ShellLink.dll"/>
<native type="izpack" name="ShellLink_x64.dll"/>
<native type="3rdparty" name="COIOSHelper.dll" stage="both">
    <os family="windows"/>
</native>

The code of the completed install.xml file is attached here: install.xml
The code of the completed shortcutSpec.xml file is attached here: shortcutSpec.xml
 

Creating an install.jar out of install.xml

install.xml file alone will not lead you to any where. So let’s make a cross-platform install.jar file that will build your actual installer. For this,

  1. Create a new folder and include all the resource files to it in the exact location mentioned in the resources tag.

  2. Now save the install.xml file the root of the same folder.

  3. Go to the IzPack installation folder and then to IzPack bin using command prompt with Administration privileges and type the following command
    E:\IzPack\bin>compile E:\jefeInst\install.xml -b E:\jefeInst
This will compile your install.xml file to a install.jar file. For this command after the key word “compile” you are required to give the path of the install.xml file then –b and then the path to which the install.jar file need to be saved.
After creating the install.jar file, you can once again navigate to the location where you saved it in the command prompt and execute the following command to launch your installer as how you launch any other .jar file.
E:\jefeInst>java -jar install.jar

Creating install.exe out of install.jar

Start the Launch4j and create an new project in it.
  1. In the Basic tab input the output file name and location where you need your executable file to be saved in “*Output file”.
  2. In the Basic tab again under “*Jar” browse and give the install.jar file you just created using IzPack.
  3. In the Basic tab you can also give a custom icon for the executable installer you are going to create.
  4. In the JRE tab under “Min JRE Version” include the minimum JRE version needed for your application to work.
  5. Now save the file and build the wrapper from the menu.
You are now having a complete single file windows executable for your application!

29 comments:

  1. You gave me a few ideas regarding my IzPack installation; thanks. Surprised you hadn't gotten any comments on this post as it's very well done.

    ReplyDelete
  2. Really nice article, I need ur suggestions on below-
    I need to create installer, which will install jdk,tomcat and mysql with my web application deployed there.
    On single click I need to carry out all the insatllations like wizards as you shown for Jefe screen shots

    ReplyDelete
  3. Thanks a lot for this wonderful post.

    ReplyDelete
  4. Very helpful. Thanks a lot.

    ReplyDelete
  5. Thanks for writing this. It was very helpful.

    The two links that point to your Google Docs are broken. Please fix them.

    ReplyDelete
  6. Thank you so much, It was a great thing to me and my team. We now can package our java application.

    Bless Ya'

    ReplyDelete
  7. This was very awesome and helpful.. thankyou for your tyme and effort!

    ReplyDelete
  8. Do you have any idea about installer taking long time on Finish Panel.. It says its writing uninstaller data in command prompt.. and varies with size of package..
    It took me 3 mins on last step last time..
    Do you know of any resolution to this

    ReplyDelete
  9. Hi,Thanks for the write-up. I am having tough time to call a executable from IzPack Installer. The compilation is successful and installer is hanging before finish. The Install.xml has below entries:-


    The base files









    If I remove the executable tag from install.xml everything looks Ok, but it is not serving my purpose.
    The files dbscript.bat and cr.sql resides in the $INSTALL_PATH directory and I could run dbscript manually.
    Do you see any thing suspicious over here which is preventing the installer to call the dbscript.bat ?

    ReplyDelete
  10. Very Nice and detailed. Thanks for this

    ReplyDelete
  11. hi, I am getting error while launching my install.jar using java -jar install.jar ....
    ClassNotFound Exception. Pls help me to recover this error and tel me wat mistake could i done.

    ReplyDelete
  12. Thanks for your tutorial. It helped a lot. I was using IzPack 4.3.5. and found that the compile.bat had to be changed as below to make it work:
    REM set LOCALCLASSPATH="%IZPACK_HOME%\Izpack.jar";%CLASSPATH%
    set LOCALCLASSPATH=%IZPACK_HOME%\Izpack.jar;\lib\compiler.jar;%CLASSPATH%

    ReplyDelete
  13. Great info! The only thing missing is info on what it takes to get the installer to show up in the add/remove programs control panel in Windows. Might be the same thing that allows the uninstaller to work, since I can't get that to do anything either.

    ReplyDelete
  14. Can you please keep your source code that you have written for izpack example.

    ReplyDelete
  15. This comment has been removed by the author.

    ReplyDelete
  16. Thanks for this very well written article. it helped me a lot.

    ReplyDelete
  17. I want to customize Installation Panel and shortcut Panel (In ShortcutPanel i want only create desktop shortcut option)....
    Please Help me....

    ReplyDelete
  18. Hi I want to unzip a file with installer please help

    ReplyDelete
  19. This comment has been removed by the author.

    ReplyDelete
  20. I am using Izpack 5. I have added myapplication.jar in the install.xml.
    After compiling the xml, it shows in the logs that the file has been extracted and added at the target location. But it does not appear physically at that location. Hence the actual application is not installed. Am I missing any configuration?

    ReplyDelete
  21. Thank you :)
    It is very well explained and very useful.

    ReplyDelete
  22. Thank you Sonali!! This post helped me a lot!

    ReplyDelete
  23. When i compile the install.xml i am getting exception as
    java.lang.NullPointerException
    at com.izforge.izpack.util.IoHelper.copyStreamToJar(IoHelper.java:465)

    ReplyDelete
  24. I am also getting the mentioned NullPointerException

    ReplyDelete
    Replies
    1. If you open the command prompt with Administration privileges and then run the compile command, it works perfectly fine.

      Delete