<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>ej-technologies blog</title>
    <link>https://www.ej-technologies.com/blog/</link>
    <description>Blog posts from ej-technologies</description>
    <language>en</language>
    <managingEditor>info@ej-technologies.com (ej-technologies)</managingEditor>
    <webMaster>webmaster@ej-technologies.com (ej-technologies)</webMaster>
    <ttl>360</ttl>
    <dc:language>en</dc:language>
    <image>
      <title>ej-technologies blog</title>
      <url>https://www.ej-technologies.com/images/logo2_rss.png</url>
      <link>https://www.ej-technologies.com/blog/</link>
      <width>144</width>
      <height>20</height>
    </image>
    <item>
      <title>Welcome!</title>
      <link>https://www.ej-technologies.com/blog/2009/04/welcome/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;/p&gt;

  In this blog we'll show you tips and tricks around JProfiler and install4j. Comments and questions are always welcome. 
  Enjoy!</description>
      <category>General</category>
      <pubDate>Tue, 21 Apr 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/04/welcome/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-04-21T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Object counts in dynamic memory views and the heap walker</title>
      <link>https://www.ej-technologies.com/blog/2009/04/object-counts-in-dynamic-memory-views-and-the-heap-walker/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  Often the question comes up why there are larger object counts in the dynamic memory views than in the heap walker. The 
  simple explanation is that the dynamic memory views show all objects on the heap - even those that are unreferenced, 
  while the heap walker only shows objects that are strongly referenced.
  
  &lt;br&gt;&lt;br&gt;
  
  Here, for example, in the &amp;quot;All objects&amp;quot; view, a particular class has an object count of 6741:
  &lt;br&gt;&lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/dynamic-heapwalker-all-objects-822db8aaec41d1553495b6e9eb8c66.png" class="img-fluid" loading="lazy" width="526" height="349"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  In the heap walker, the object count is only 6282:
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/dynamic-heapwalker-heapwalker-f818ba703a1feeda809d6982f6fb117b.png" class="img-fluid" loading="lazy" width="526" height="187"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  The difference comes from objects that are not referenced anymore, but that are still on the heap because the garbage 
  collector has not collected them yet. Clicking on the &amp;quot;Run GC&amp;quot; button in JProfiler might collect some, but not all of 
  them, since the garbage collector does not do full collections in modern JVMs. However, when you take a heap snapshot, a
  full collection is done internally, so you only look at objects that you can actually do something about.
  &lt;br&gt;&lt;br&gt;
  
  Ideally, we would exclude unreferenced objects from the dynamic memory views too, but this information requires an 
  expensive calculation that can only be performed when taking a heap snapshot.</description>
      <category>JProfiler</category>
      <pubDate>Wed, 22 Apr 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/04/object-counts-in-dynamic-memory-views-and-the-heap-walker/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-04-22T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Signing launchers and installers</title>
      <link>https://www.ej-technologies.com/blog/2009/04/signing-launchers-and-installers/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2009/04/signing-2-7d9ea1d2ebdb9b7b771fb35f68dcf5dd.png" class="img-fluid" loading="lazy" width="601" height="328"&gt;&lt;/div&gt;

  
  Since the release of Vista, code signing has been of growing interest for our users, mainly because a signed installer 
  or launcher produces nicer and less UAC dialogs when it wants to elevate its privileges.
  &lt;br&gt;&lt;br&gt;
  
  install4j provides a signing hook for all generated windows executables. On step 5 of the Windows Media Wizard, you can 
  specify any external tool with the executable files as parameter. The signing tool will be called with the working 
  directory set to the project file parent directory so you can specify keys and certificates relatively. You can use the &lt;code&gt;$EXECTUABLE&lt;/code&gt; 
  variable to refer to the launcher or installer and an &lt;code&gt;$OUTFILE &lt;/code&gt;
  variable if the tool you use requires different in and out files.
  
  &lt;br&gt;&lt;br&gt;
  
  I will explain below what tools you can use to sign your executables, but first, you would need a Microsoft Authenticode
  Certificate from a certificate authority like Thawte:
  &lt;br&gt;&lt;br&gt;&lt;a href="https://www.thawte.com/code-signing/index.html"&gt;https://www.thawte.com/code-signing/index.html&lt;/a&gt;&lt;br&gt;&lt;br&gt;
  
  In their order process, they will generate a private key (PVK) file and a certificate request. After Thawte verified 
  your identify, they will provide you a SPC file that contains your certificate. There are a bunch of other certificate 
  authorities, most notably verisign where the process is quite similar.
  &lt;br&gt;&lt;br&gt;&lt;b&gt;Code signing on Windows&lt;/b&gt;&lt;br&gt;&lt;br&gt;
  
  On Windows, you can quite easily use Microsoft's tools like signcode or signtool which are contained in the freely 
  available Platform and .Net SDKs. You can find the documentation in the MSDN:
  &lt;br&gt;&lt;br&gt;&lt;a href="https://msdn.microsoft.com/de-de/library/9sh96ycy%28VS.80%29.aspx"&gt;http://msdn.microsoft.com/de-de/library/9sh96ycy%28VS.80%29.aspx&lt;/a&gt;&lt;br&gt;&lt;br&gt;
  
  Below is a good summary of how to use signtool:
  &lt;br&gt;&lt;br&gt;&lt;a href="https://www.curlybrace.com/words/2008/09/12/using-certificates-and-signtool/"&gt;http://www.curlybrace.com/words/2008/09/12/using-certificates-and-signtool/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
  
  It also explains how to convert different file formats that other certificate authorities might issue.
  &lt;br&gt;&lt;br&gt;&lt;b&gt;Code signing on other platforms with Mono's signcode&lt;b&gt;&lt;br&gt;&lt;/b&gt;&lt;/b&gt;&lt;br&gt;
  
  It is also possible to sign executables on other platforms. The&lt;code&gt; $INSTALL4J_HOME/resource/signcode.exe&lt;/code&gt; 
  executable is a &lt;a href="https://www.mono-project.com/"&gt;mono&lt;/a&gt; 
  executable modified by ej-technologies to support signing of 64-bit executables. This executable can only be executed if
  mono is installed. Mono is available for a number of platforms and can be &lt;a href="https://www.mono-project.com/Downloads"&gt;downloaded free of charge&lt;/a&gt;.
  The tool has the same syntax as the one from Microsoft. A typical entry would be
  &lt;br&gt;&lt;br&gt;&lt;code&gt;mono /opt/install4j/resource/signcode.exe -spc mycert.spc -v mykey.pvk -vp password -t http://timestamp.verisign.com/scripts/timstamp.dll $EXECUTABLE&lt;/code&gt;&lt;br&gt;&lt;br&gt;
  
  Some SPC files cannot be read directly by this tool. If this is the case for your certificate, you can export all CER 
  files from the SPC file and generate a new SPC file with the &lt;code&gt;cert2spc&lt;/code&gt; 
  tool included with mono. You have to add the CER files in the order of the certificate chain (your own certificate is 
  the last one on the command line).
  &lt;br&gt;&lt;br&gt;&lt;b&gt;Code signing on other platforms with openssl and osslsigncode&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;a href="https://download.ej-technologies.com/resources/osslsigncode-1.3-patched.tgz"&gt;Here&lt;/a&gt; 
  is a download with a patch for signing PE32+ (Windows x64) executables. A short &lt;code&gt;./configure &amp;amp;&amp;amp; make&lt;/code&gt; 
  should be sufficient when you have curl and openssl installed. This tool requires the private key in a different form, 
  though. First, you would have to convert your PVK file to a PEM file with &lt;a href="https://support.globalsign.net/en/objectsign/PVK.zip"&gt;this tool&lt;/a&gt; 
  on Windows. A typical command line would be simply
  &lt;br&gt;&lt;br&gt;&lt;code&gt;pvk -in mykey.pvk -out mykey.pem&lt;/code&gt;.

  &lt;br&gt;&lt;br&gt;
  
  The upcoming openssl 1.0 will also be able to do this conversion. The PEM file is still encrypted, but osslsigncode 
  needs an unencrypted DER file. You might want to generate this DER file directly before your build process and delete it
  afterwards to avoid having your private key hanging around unencrypted longer than necessary. The conversion to a DER 
  file is done with
  &lt;br&gt;&lt;br&gt;&lt;code&gt;openssl rsa -passin pass:XXXXX -outform der -in mykey.pem -out mykey.der&lt;/code&gt;.

  &lt;br&gt;&lt;br&gt;
  
  A typcial command line in install4j would then be
  &lt;br&gt;&lt;br&gt;&lt;code&gt;osslsigncode -spc mycert.spc -key mykey.der -t http://timestamp.verisign.com/scripts/timstamp.dll -in $EXECUTABLE -out $OUTFILE&lt;/code&gt;.

  &lt;br&gt;&lt;br&gt;
  
  Remember that the spc and key files can be specified relatively to your install4j project file.
  &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
  &lt;hr&gt;
&lt;br&gt;&lt;br&gt;&lt;b&gt;Update: &lt;/b&gt;
  As of install4j 5.1, code signing is implemented directly and the above mentioned tools are no longer required.</description>
      <category>install4j</category>
      <pubDate>Wed, 22 Apr 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/04/signing-launchers-and-installers/</guid>
      <dc:creator>Hannes Kegel</dc:creator>
      <dc:date>2009-04-22T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Finding a memory leak with JProfiler (old)</title>
      <link>https://www.ej-technologies.com/blog/2009/04/finding-a-memory-leak-with-jprofiler-old/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=memory+leak"&gt;Memory Leak&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;&lt;b&gt;This screencast is outdated, please watch the &lt;a href="https://www.ej-technologies.com/blog/2017/03/finding-a-memory-leak-with-jprofiler/"&gt;more recent version&lt;/a&gt; instead.&lt;/b&gt;&lt;/p&gt;

  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/FSJMSe8TvpI" title="Play video 'Finding a memory leak with JProfiler (old)'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/FSJMSe8TvpI-7627a537b98f29882eff9b58f5971129.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <category>Memory Leak</category>
      <pubDate>Thu, 23 Apr 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/04/finding-a-memory-leak-with-jprofiler-old/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-04-23T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Evaluation of cross-platform installer builders</title>
      <link>https://www.ej-technologies.com/blog/2009/04/evaluation-of-cross-platform-installer-builders/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  On &lt;a href="https://stackoverflow.com/"&gt;stackoverflow&lt;/a&gt;,
  there's a question regarding the comparison of cross-platform installer builders. &lt;a href="https://stackoverflow.com/questions/759855/what-are-good-installanywhere-replacements-for-installing-a-java-ee-application/786307#786307"&gt;This answer&lt;/a&gt; 
  is apparently the result of a very thorough evaluation and paints a very favorable picture of install4j.</description>
      <category>install4j</category>
      <pubDate>Fri, 24 Apr 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/04/evaluation-of-cross-platform-installer-builders/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-04-24T07:00:57Z</dc:date>
    </item>
    <item>
      <title>The different references views in the heap walker</title>
      <link>https://www.ej-technologies.com/blog/2009/05/the-different-references-views-in-the-heap-walker/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=memory+leak"&gt;Memory Leak&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;&lt;b&gt;This screencast is outdated, please watch the &lt;a href="https://www.ej-technologies.com/blog/2022/08/working-with-merged-reference-trees-in-jprofiler/"&gt;more recent version&lt;/a&gt; instead.&lt;/b&gt;&lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I explain the different reference views in the heap walker.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/VpyUiLdar2Q" title="Play video 'The different references views in the heap walker'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/VpyUiLdar2Q-ef1ec72b859fd4ad3e2b615012dd957e.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <category>Memory Leak</category>
      <pubDate>Wed, 13 May 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/05/the-different-references-views-in-the-heap-walker/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-05-13T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Changing the visibility of form components at runtime</title>
      <link>https://www.ej-technologies.com/blog/2009/05/changing-the-visibility-of-form-components-at-runtime/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  One of the strong points of form screens is that they are displayed by console installers without any further 
  configuration. You don't have to program the user interface twice, once for the GUI and once for the console.
  
  
  &lt;p&gt;
  However, it is often necessary to hide certain form components at runtime. For example, a certain form component might 
  only make sense on a specific platform. Until now, you could use the initialization script of the form component to 
  change the visibility like this:
  &lt;/p&gt;

  
  &lt;pre&gt;
boolean visible = Util.isWindows();
component.setVisible(visible);&lt;/pre&gt;

  
  &lt;p&gt;
  This hides the form component unless the operating system is Windows.
  &lt;/p&gt;

  
  &lt;p&gt;
  However, the drawback of this method is that the console installer does not execute the initialization script of a form 
  component - there is no GUI widget created and so the configurationObject parameter would be null. In the upcoming 
  install4j 4.2.3, we have added a visibility script property that works for both the GUI and the console installer:
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/visibilty-script-cec39dfa2ad934d38877d3e62658983.png" class="img-fluid" loading="lazy" width="549" height="478"&gt;&lt;/div&gt;

  
  &lt;p&gt;
  Even simpler than the previous initialization script, a simple visibility expression of
  &lt;/p&gt;

  
  &lt;pre&gt;
Util.isWindows()&lt;/pre&gt;
 
  (no semicolon at the end to make it an expression rather than a script) hides the form component on non-Windows 
  platforms.</description>
      <category>install4j</category>
      <pubDate>Wed, 27 May 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/05/changing-the-visibility-of-form-components-at-runtime/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-05-27T07:00:57Z</dc:date>
    </item>
    <item>
      <title>install4j and Java for Mac OS X v10.5 Update 4</title>
      <link>https://www.ej-technologies.com/blog/2009/06/install4j-and-java-for-mac-os-x-v10-5-update-4/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Unfortunately the &lt;a href="https://support.apple.com/kb/HT3581"&gt;latest release of Java 6 on Mac OS X&lt;/a&gt;
    a few days ago broke all installers on Mac OS X that require Java 6 as a minimum Java version.
  &lt;/p&gt;

  
  &lt;p&gt;
    This is why we have sped up our release schedule for 4.2.3 and we pushed out the release today.
  &lt;/p&gt;

  
  &lt;p&gt;
    The error message you get with installers that are generated by older versions of install4j is:
  &lt;/p&gt;

  
  &lt;pre&gt;
Java application launched from PPC or bad stub. Relaunching in 32-bit, and tagging sub-processes to prefer 32-bit with $JAVA_ARCH=i386.
[JavaAppLauncher Error] This process is [i386] and was re-exec'd from [i386], but for some reason we are trying re-exec to [].&lt;/pre&gt;

  
  &lt;p&gt;
    How could this happen? The explanation goes like this: Installers on Mac OS X ship their own binary Java application
    stub. Prior to Java 6 this application stub only contained 32-bit executables for PPC and Intel architectures. So far,
    Java 6 is only available on 64-bit Intel machines. From the beginning, the 32-bit stub continued to work with Java 6.
    This behavior was changed in Java for Mac OS X v10.5 Update 4, so we had to add a 64-bit executable to the Java
    application stub.
  &lt;/p&gt;

  
  &lt;p&gt;
    If you're on an older version of install4j and cannot update to the latest version for whatever reason, you can copy the
    file &lt;code&gt;$INSTALL4J_HOME/resource/macos/JavaApplicationStub&lt;/code&gt;
    from a 4.2.3 installation to your older installation.
  &lt;/p&gt;</description>
      <category>install4j</category>
      <pubDate>Thu, 18 Jun 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/06/install4j-and-java-for-mac-os-x-v10-5-update-4/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-06-18T07:00:57Z</dc:date>
    </item>
    <item>
      <title>JProfiler's IDE integrations</title>
      <link>https://www.ej-technologies.com/blog/2009/06/jprofilers-ide-integrations/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    For The IntelliJ IDEA integration, this screen cast is outdated, please watch the &lt;a href="https://www.ej-technologies.com/blog/2017/03/jprofilers-integration-into-intellij-idea/"&gt;more recent version&lt;/a&gt;
    instead.
  &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I explain the benefits and the usage of JProfiler's IDE integrations.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/Xqkyl1Vi0lY" title="Play video 'JProfiler's IDE integrations'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/Xqkyl1Vi0lY-cbe9e2a397647b2d1ce0d8538b2a235c.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 30 Jun 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/06/jprofilers-ide-integrations/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-06-30T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Appending to redirection files</title>
      <link>https://www.ej-technologies.com/blog/2009/07/appending-to-redirection-files/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  install4j has always offered the possibility to redirect stderr and stdout to files. The main purpose of this feature is
  to analyze uncaught exceptions and to get debug information when something goes wrong in a customer's installation.
  
  &lt;br&gt;&lt;br&gt;
  
  The redirection files are created lazily, meaning that as long as there is no output, the file will not be created or 
  replaced. However, once output is detected, the redirection file is created or overwritten. This has been the only 
  option so far and while it is often sufficient to retain the error or debug output of the last run, in some cases you 
  might want to keep the entire output over multiple invocations of the launcher.
  &lt;br&gt;&lt;br&gt;
  
  In the upcoming install4j 4.2.4, we have added this feature and in the redirection step of the launcher wizard, you can 
  change the classic &amp;quot;Overwrite&amp;quot; behavior to &amp;quot;Append&amp;quot;.
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/redirection-append-5368fde534f34b30d5cb1eb15359cb9.png" class="img-fluid" loading="lazy" width="592" height="391"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  The redirection file will still be created lazily, but it will be appended to if it already exists.</description>
      <category>install4j</category>
      <pubDate>Thu, 09 Jul 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/07/appending-to-redirection-files/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-07-09T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Thread states in the CPU profiling views</title>
      <link>https://www.ej-technologies.com/blog/2009/07/thread-states-in-the-cpu-profiling-views/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I explain the thread status selector and the different threads states in the CPU profiling 
    views.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/T4ycsz1a5gU" title="Play video 'Thread states in the CPU profiling views'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/T4ycsz1a5gU-92d03e19f77c4b7fd88c832a8ea514.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 10 Jul 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/07/thread-states-in-the-cpu-profiling-views/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-07-10T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Fine-tuning console installers</title>
      <link>https://www.ej-technologies.com/blog/2009/08/fine-tuning-console-installers/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the upcoming install4j 4.2.4 release, we'll expand on the improvements that were introduced with the &lt;a href="https://blog.ej-technologies.com/2009/05/changing-visibilty-for-form-components.html"&gt;visibility script in install4j 4.2.3&lt;/a&gt;.
  &lt;/p&gt;

  
  &lt;p&gt;
    The GUI installer operates in a &amp;quot;one screen at a time&amp;quot; mode while the console installer does &amp;quot;one question at a time&amp;quot;.
    Due to this difference, the automatic translation of form screens from GUI to console mode will not always be optimal.
  &lt;/p&gt;

  
  &lt;p&gt;
    In 4.2.4 we will introduce a &amp;quot;Console handler&amp;quot; form component that allows you to fine-tune the console mode of your
    installers. The form component is invisible and has no effect in GUI mode. Its action is defined in the &amp;quot;Console script&amp;quot;
    property:
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/console-handler-config-eab1578e4dc19ab6b89a285387c07b.png" class="img-fluid" loading="lazy" width="582" height="501"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    Besides the usual parameters for form components, the script is passed a &amp;quot;console&amp;quot; parameter, which is of type &lt;code&gt;com.install4j.api.screens.Console&lt;/code&gt;
    and offers a number of methods for interacting with the user on the console. This has previously only been offered in
    the API for the development of custom screens and custom form components.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/console-handler-script-825e3345858a86969538b4dec1697d.png" class="img-fluid" loading="lazy" width="583" height="507"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    In the console script shown above, an error condition is handled in the middle of the form component sequence. In GUI
    mode, such error conditions are usually handled in the validation script of the screen, but due to the lack of &amp;quot;screens&amp;quot;
    in console mode, the validation might be more appropriate at an earlier time.
  &lt;/p&gt;

  
  &lt;p&gt;
    Another scenario for the use of console handler form components are form screens that do no require user input. In such
    a case, you could add a console handler form component and set its console script to
  &lt;/p&gt;

  
  &lt;pre&gt;
console.print(&amp;quot;Please read the information above&amp;quot;);
console.waitForEnter();
return true;&lt;/pre&gt;</description>
      <category>install4j</category>
      <pubDate>Thu, 06 Aug 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/08/fine-tuning-console-installers/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-08-06T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Allocation recording explained</title>
      <link>https://www.ej-technologies.com/blog/2009/08/allocation-recording-explained/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I explain allocation recording in the dynamic memory views in JProfiler.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/6sj0dxHFr2E" title="Play video 'Allocation recording explained'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/6sj0dxHFr2E-2afd787a598058d366fb36e5666dcd3.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 14 Aug 2009 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/08/allocation-recording-explained/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-08-14T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Locking graphs in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2009/11/locking-graphs-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I present some of the features in the locking graphs that have been introduced in JProfiler 6.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/6w-utHPJVog" title="Play video 'Locking graphs in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/6w-utHPJVog-706a36f69359926bb030616ec3617f.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    The test class that is profiled in this screen cast is given below:
  &lt;/p&gt;

  
  &lt;pre&gt;
public class MonitorTest {
    
    // The only monitor that all threads are blocking or waiting on 
    private static final MonitorTest monitor = new MonitorTest();
  
    public static void main(String[] args) throws InterruptedException {
  
        // All threads execute this runnable, each thread acquires the 
        // monitor, works for 3 seconds and then waits on the monitor 
        Runnable runnable = new Runnable() {
            public void run() {
                synchronized (monitor) {
                    try {
                        // Instead of doing any real work, the thread just
                        // sleeps for 3 second
                        Thread.sleep(3000);
                        monitor.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
  
            }
        };
  
        // 3 threads are started with an offset of 500 ms
        new Thread(runnable, &amp;quot;Test Thread 1&amp;quot;).start();
        Thread.sleep(500);
        new Thread(runnable, &amp;quot;Test Thread 2&amp;quot;).start();
        Thread.sleep(500);
        new Thread(runnable, &amp;quot;Test Thread 3&amp;quot;).start();
  
        // After 20 seconds, all threads are woken up and the test class
        // terminates
        Thread.sleep(20000);
        synchronized (monitor) {
            monitor.notifyAll();
        }
    }
}&lt;/pre&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 27 Nov 2009 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2009/11/locking-graphs-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2009-11-27T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Monitor events versus locking situations</title>
      <link>https://www.ej-technologies.com/blog/2010/01/monitor-events-versus-locking-situations/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I discuss cross-links between the various monitor views. The profiled test program is the same 
    as in the screencast on &lt;a href="https://blog.ej-technologies.com/2009/11/locking-graphs-in-jprofiler.html"&gt;Locking graphs in JProfiler&lt;/a&gt;.

  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/ChlPb-3E5Ko" title="Play video 'Monitor events versus locking situations'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/ChlPb-3E5Ko-1ac8b859935462da97a8eacfff637be0.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Thu, 21 Jan 2010 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2010/01/monitor-events-versus-locking-situations/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2010-01-21T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Cumulating and filtering monitor events</title>
      <link>https://www.ej-technologies.com/blog/2010/02/cumulating-and-filtering-monitor-events/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I explain how monitor events in the locking history graph can be cumulated and how you can 
    select monitors and threads of interest.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/mmzK5_Zjkx8" title="Play video 'Cumulating and filtering monitor events'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/mmzK5_Zjkx8-df2bfdecaa19883f61a3129f135e8fe.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 05 Feb 2010 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2010/02/cumulating-and-filtering-monitor-events/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2010-02-05T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Offline profiling and triggers</title>
      <link>https://www.ej-technologies.com/blog/2010/03/offline-profiling-and-triggers/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I explain how to automate profiling with offline profiling and triggers, so that you do not 
    have to use the JProfiler GUI for profiling and can analyze profiling results later on.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/YpYyoT47B-o" title="Play video 'Offline profiling and triggers'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/YpYyoT47B-o-2bcfe63192659182645d6dc2fb84f4.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Mon, 29 Mar 2010 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2010/03/offline-profiling-and-triggers/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2010-03-29T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Migrating to install4j 5</title>
      <link>https://www.ej-technologies.com/blog/2010/06/migrating-to-install4j-5/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=migration"&gt;Migration&lt;/a&gt; &lt;/p&gt;

  Those who made the move from install4j 3 to install4j 4 will remember that it was a lot of work to migrate custom code,
  because most core concepts had been changed.
  &lt;br&gt;&lt;b&gt;Not so with install4j 5&lt;/b&gt;
  : Your old project file will be transformed to the new format and most projects will work right away, without the need
  for any manual work. If you are interested in the changes in the project file structure, please see the file &lt;code&gt;config/transforms/transform_3.xsl &lt;/code&gt;
  in your install4j installation directory.
  
  &lt;br&gt;&lt;br&gt;

  However, there are a number of cases where old functionality has been replaced, behavior has been changed or the API has
  been fixed. In those cases backwards incompatibilities can arise. This post intends to present an exhaustive list of
  them:
  &lt;br&gt;
  &lt;ul&gt;
    &lt;li&gt;
      We have removed support for Java 1.3. This allows us to use the standard XML beans decoder and XML parser in the JRE.
      Java 1.4 is still supported.
    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;Require admin user&amp;quot; action and the &amp;quot;Request admin privileges on Windows Vista&amp;quot; option on the &amp;quot;Installer options&amp;quot;
      step of the Windows media wizard have been removed. They have been replaced with a much more capable &amp;quot;Request
      privileges&amp;quot; action. The &amp;quot;Request privileges&amp;quot; action is now added to all projects by default and will be inserted into
      the &amp;quot;Startup&amp;quot; sequence of old projects as well. If you had a &amp;quot;Require admin user&amp;quot; action in your project, the &amp;quot;failure&amp;quot;
      properties will all be selected (they are otherwise not selected by default). If you had a condition expression on the
      &amp;quot;Require admin user&amp;quot; action, it will be lost. Especially platform-dependent configuration is now possible directly in
      the &amp;quot;Request privileges&amp;quot; action.
    &lt;/li&gt;
    &lt;li&gt;
      On the Installer-&amp;gt;Custom Code tab, the old &amp;quot;Use installed JAR files if possible&amp;quot; option has been removed. Previously,
      the installer performed a two-phase initialization of screens and actions, before and after the &amp;quot;Install Files&amp;quot; action,
      so you could use custom code from installed JAR files. The main reason for that option was to prevent double packaging
      of JAR files, once for the installer and once for the launcher. In install4j 5, if entries in the custom code are also
      present in the distribution tree, they will be moved to the final destination by the &amp;quot;Install Files&amp;quot; action, and the
      custom code will automatically include the installed files in custom installer applications and the uninstaller. This
      change significantly improves custom code handling, because double packaging is always prevented and you can use such
      custom code before the &amp;quot;Install Files&amp;quot; action is executed.  &lt;br&gt;
      However, if your code depends on the location of the JAR file, this can be a breaking change and you have to change your
      custom code. In that case, the new &lt;code&gt;Screen#isCreatedLazily()&lt;/code&gt;
      method and the optional &lt;code&gt;Context#initializeLazilyCreatedScreens()&lt;/code&gt;
      method will help you to move the initialization of the custom screen after the &amp;quot;Install Files&amp;quot; action while the &lt;code&gt;Context#addToClassPath(File)&lt;/code&gt;
      method allows you to add installed JAR files to the custom code for dependencies that only work in the installed
      location.
    &lt;/li&gt;
    &lt;li&gt;
      The compiler variable &amp;quot;sys.platform&amp;quot; now resolves to &amp;quot;windows-x64&amp;quot; for 64 bit media files. Previously, it always
      resolved to &amp;quot;windows&amp;quot;. This variable is used in the standard media file name pattern on the General Settings-&amp;gt;Media File
      Options tab, so your 64-bit Windows media files will now be named differently if you have not changed or overridden the
      media file name.
    &lt;/li&gt;
    &lt;li&gt;
      There was a typo in the system message key name &amp;quot;LocateBrowerExecutable&amp;quot;. In the unlikely event that you used that key
      explicitly in your project before, it will lead to a runtime exception.
    &lt;/li&gt;
    &lt;li&gt;
      A few installer variable names have changed to make naming more consistent. The old names will be replaced automatically
      with the new names when you open your old project file for the first time. However, if you use them outside the
      install4j IDE, for example, in custom code, you will have to change them. The replacements are:
    
      &lt;ul&gt;
        &lt;li&gt;sys.mediaDirectory -&amp;gt; sys.mediaDir&lt;/li&gt;
        &lt;li&gt;sys.installerDirectory -&amp;gt; sys.installerDir&lt;/li&gt;
        &lt;li&gt;sys.programGroup.name -&amp;gt; sys.programGroupName&lt;/li&gt;
        &lt;li&gt;sys.programGroup.linkDir -&amp;gt; sys.symlinkDir&lt;/li&gt;
        &lt;li&gt;sys.programGroup.allUsers -&amp;gt; sys.programGroupAllUsers&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;
      (Updated on 2010-07-15) The &amp;quot;Services&amp;quot; screen has been removed. The reason is that since the service actions now support
      arbitrary service executables (not only those generated by install4j), it would be difficult for us to present a list
      like in 4.x. Also, we feel that this is really a technical question that users should not have to answer. If needed, you
      can create a question with a configurable form. The &amp;quot;Hello world&amp;quot; project has such a screen.
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;br&gt;

  Other breaking changes only concern the API:
  &lt;br&gt;&lt;br&gt;
  &lt;ul&gt;
    &lt;li&gt;
      The method ApplicationRegistry.ApplicationInfo#getProgramGroup() has been removed from the API. It has been obsolete
      since 4.2, when the &amp;quot;Load reponse file&amp;quot; action was added. In the GUI, the &amp;quot;Suggest previous program group&amp;quot; option on the
      Installer-&amp;gt;Update Options tab has been removed as well.
    &lt;/li&gt;
    &lt;li&gt;
      Several typos in method names have been fixed. Fortunately, typos were only discovered for the rarely used methods &lt;code&gt;Context#isErrorOccurred()&lt;/code&gt;,
 &lt;code&gt;Context#setErrorOccurred(boolean)&lt;/code&gt;
      and &lt;br&gt;&lt;code&gt;FormComponent#initialize()&lt;/code&gt;.
      If you are affected by the first two changes, the build will fail. If you derive a form component from &lt;code&gt;AbstractFormComponent&lt;/code&gt;,
      the third change concerns a method that is overridden and would not cause a compilation error, so we have added a method
      for backward compatibility in that case.
    &lt;/li&gt;
    &lt;li&gt;
      Several methods in the &lt;code&gt;Install4jBeanInfo &lt;/code&gt;
      and &lt;code&gt;Install4JPropertyDescriptor &lt;/code&gt;
      classes had their return values changed from void to the class itself in order to facilitate usages in builder patterns.
      You just have to recompile your code against the new runtime library, no source code changes are required.
    &lt;/li&gt;
    &lt;li&gt;
      The &lt;code&gt;Context#getWizardContext()&lt;/code&gt;
      does not return &lt;code&gt;null &lt;/code&gt;
      in unattended or console mode anymore. Instead, a dummy wizard context is returned that does nothing when its methods
      are invoked. If you use&lt;code&gt; Context#getWizardContext() &lt;/code&gt;
      to check for those installer modes, you have to change your code and use &lt;code&gt;Context#isUnattended()&lt;/code&gt;
      and &lt;code&gt;Context#isConsole()&lt;/code&gt;
      instead.
    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;installerAndUninstaller&amp;quot; argument from &lt;code&gt;ActionBeanInfo#setAssociatedStartupAction(String)&lt;/code&gt;
      was removed because the new &lt;code&gt;ActionBeanInfo#setComplementaryStartupLink(boolean)&lt;/code&gt;
      makes more sense.
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;br&gt;

  That's it! Most of these changes are only breaking changes for corner cases and even then it should be easy to fix them.
  If you notice any other breaking changes, please let us know, so we can add them to this list.</description>
      <category>install4j</category>
      <category>Migration</category>
      <pubDate>Thu, 17 Jun 2010 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2010/06/migrating-to-install4j-5/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2010-06-17T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Market study  for multicore software development tools featuring JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2010/10/market-study-for-multicore-software-development-tools-featuring-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  The &lt;a href="https://fraunhofer.com/"&gt;Fraunhofer&lt;/a&gt;&lt;a href="https://www.iao.fraunhofer.de/index.php"&gt;IAO&lt;/a&gt; 
  has &lt;a href="https://www.mware.fraunhofer.de/EN/solutions/study.jsp"&gt;published a study&lt;/a&gt; 
  on multi-core software development tools that features JProfiler.
  &lt;br&gt;&lt;br&gt;
  
  The study can be viewed free of charge, but requires a registration for download. The abstract of the study is as 
  follows:
  &lt;br&gt;  
  
  
  &lt;blockquote class="blockquote my-4 ps-4 border-start border-3"&gt;
    &lt;i&gt;To unlock the performance potentials of current processors, software has to be adapted for execution on multiple cores; it has to be parallelized. This requires the identification of parts that can run concurrently, adaptation of these parts, testing of the changes for correctness and the coordination of the concurrently running parts with regard to performance and scalability.&lt;/i&gt;
    &lt;br&gt;
    &lt;br&gt;
    In this study Fraunhofer IAO characterizes the challenges of software development for multicore processors and presents tools that assist in the process. Profilers reveal parallelizable parts, programming languages and libraries help with the correct introduction of parallelism, debuggers show errors during parallel execution and tuners help achieving maximum parallel performance.
  &lt;/blockquote&gt;
  
  
  &lt;br&gt;
  
  JProfiler's extensive support for locking analysis &lt;a href="https://www.ej-technologies.com/products/jprofiler/whatsnew6.html"&gt;introduced in 6.0&lt;/a&gt; 
  is an important tool for this kinds of analysis.</description>
      <category>JProfiler</category>
      <pubDate>Wed, 27 Oct 2010 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2010/10/market-study-for-multicore-software-development-tools-featuring-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2010-10-27T07:00:57Z</dc:date>
    </item>
    <item>
      <title>My first try with install4j</title>
      <link>https://www.ej-technologies.com/blog/2010/12/my-first-try-with-install4j/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=tutorial"&gt;Tutorial&lt;/a&gt; &lt;/p&gt;

  A tutorial for beginners
  &lt;br&gt;&lt;br&gt;
  
  This tutorial shows the various features offered by &lt;a href="https://www.ej-technologies.com/products/install4j/overview.html"&gt;install4j&lt;/a&gt; 
  5.0 through the step by step configuration of an installer for &lt;a href="https://www.sweethome3d.com/"&gt;Sweet Home 3D&lt;/a&gt;,
  a free open source Java program (so you can reproduce these steps if you want to).
  &lt;br&gt;&lt;br&gt;
  
  
  In its current version 3.0, Sweet Home 3D may be &lt;a href="https://www.sweethome3d.com/download.jsp"&gt;installed&lt;/a&gt; 
  with Java Web Start or its own installer (built with &lt;a href="https://www.jrsoftware.org/isinfo.php"&gt;Inno Setup&lt;/a&gt; 
  and &lt;a href="https://launch4j.sourceforge.net/"&gt;launch4j&lt;/a&gt; 
  tools under Windows). But install4j is able to build much more powerful installers and Java launchers than these free 
  products.
  &lt;br&gt;&lt;br&gt;&lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Downloading and installing install4j&lt;/h4&gt;

  
  install4j can be downloaded from this &lt;a href="https://www.ej-technologies.com/download/install4j/files.html"&gt;page&lt;/a&gt;.
  If you want to test it before buying a license you'll have to fill &lt;a href="https://www.ej-technologies.com/download/install4j/trial"&gt;this form&lt;/a&gt; 
  to receive an evaluation key.
  &lt;br&gt;&lt;br&gt;
  
  install4j is available for various operating systems and is available in two versions for each operating system, 
  depending on whether you have already installed a JRE 6 on your computer.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/Downloads-356a2be78a441b6a1f172a9d15dcaec.png" class="img-fluid" loading="lazy" width="594" height="487"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  From the previous matrix, I download the &lt;i&gt;Setup Executable (21 MB)&lt;/i&gt; 
  for &lt;i&gt;64-bit Windows&lt;/i&gt; 
  and double-click on the installer icon once the file was downloaded.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/InstallerIcon-cd98faf4772667c104a7530b00e05.png" class="img-fluid" loading="lazy" width="92" height="83"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Installing install4j already gives an idea of its abilities because the installer was of course built with install4j 
  itself. Once the installer launched, I'm surprised to get a screen telling that no JRE is installed on my computer:
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/NoJRE-c43d422026696b38eec335aa4b95280.png" class="img-fluid" loading="lazy" width="356" height="148"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  But in fact the installer was right, I didn't have a 64-bit JRE but only a 32-bit JRE! Therefore I click on Download to 
  get a 64-bit JRE.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/DownloadingJRE-3f6b28a58cf48e137a5226024bb9d5c.png" class="img-fluid" loading="lazy" width="356" height="148"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  From the license agreement, installation directory selection to license key entry and auto-update configuration, the 10 
  steps that following look familiar compared to other installers.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/InstallerSteps-6fb1a17ffa24233569eef92ccce3cb.png" class="img-fluid" loading="lazy" width="594" height="1238"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Launching install4j&lt;/h4&gt;

  
  At first launch, Windows Firewall asks me to let install4j use the network to check its license key. I accept to ensure 
  all features of install4j will work.
  &lt;br&gt;&lt;br&gt;
  
  Then the main screen of install4j appears and shows the various features offered to create an installer.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/MainScreen-26ab1d9048eaefd6abdb7c0bda3f294.jpg" class="img-fluid" loading="lazy" width="600" height="488"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Now I'll try to create a first version of an installer and launcher for Sweet Home 3D.
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;&lt;/h4&gt;
  
  
  
  &lt;h4 class="mt-5"&gt;General settings&lt;/h4&gt;

  
  First, I fill the &lt;i&gt;Application Info&lt;/i&gt; 
  tab with the software's name and version.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/GeneralSettingsApplicationInfo-e1cfc6b7ac972065531ca4a80fdd86f.png" class="img-fluid" loading="lazy" width="490" height="192"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Then, in the &lt;i&gt;Java Version&lt;/i&gt; 
  tab, I require a minimum Java version 1.5.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/GeneralSettingsJavaVersion-e92a85125a7a2a2bc283597bd910f719.png" class="img-fluid" loading="lazy" width="491" height="541"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  In the &lt;i&gt;Languages&lt;/i&gt; 
  tab, I keep &lt;i&gt;English&lt;/i&gt; 
  as the principal language and add all the languages supported by Sweet Home 3D found in the list (just missing Bulgarian
  and Vietnamese).
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/GeneralSettingsLanguages-5c79f31cab8f2d7af8fce3136d58bb64.png" class="img-fluid" loading="lazy" width="491" height="541"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  In the &lt;i&gt;Media Files Options&lt;/i&gt;,
  I choose an &lt;i&gt;Installer&lt;/i&gt; 
  directory on my desktop as output directory, change the name pattern to &amp;quot;&lt;code&gt;${compiler:sys.shortName}-${compiler:sys.version}-${compiler:sys.platform}&lt;/code&gt;
  &amp;quot; in respect to the format previously used for older versions of Sweet Home 3D, and uncheck &lt;i&gt;Convert dots to underscores&lt;/i&gt; 
  option.
  &lt;br&gt;&lt;br&gt;
  
  Note that this name pattern uses some variables between &lt;code&gt;${&lt;/code&gt; 
  and &lt;code&gt;}&lt;/code&gt; 
  symbols. There are all kind of variables available in install4j (you can even create your own if needed) and you can 
  select them in many text fields by clicking on the Insert variable button &lt;img alt="Blog image" src="/assets/blog/MyFirstTryWithInstall4j/InsertVariableButton-18c6b293d2f0215bc5f25bc5fa2bc19.png" class="" loading="lazy" width="18" height="18"&gt; 
  (the arrow button) that appears behind them.
  &lt;br&gt;
  
  The &amp;quot;&lt;code&gt;${compiler:sys.shortName}-${compiler:sys.version}-${compiler:sys.platform}&lt;/code&gt;
  &amp;quot; pattern will resolve to &lt;code&gt;SweetHome3D-3.0-windows&lt;/code&gt; 
  for a Windows installer.
  &lt;br&gt;&lt;br&gt;
  
  As Sweet Home 3D's current distribution is around 30 MB, I prefer the smallest distribution possible and I also increase &lt;i&gt;Compression level&lt;/i&gt; 
  to 9 and check all the compression options
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/GeneralSettingsMediaFileOptions-c57ee79d4931f866d1cad57e57d577.png" class="img-fluid" loading="lazy" width="491" height="554"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once &lt;i&gt;General Settings&lt;/i&gt; 
  are done I save my Installer project in the &lt;i&gt;Installer&lt;/i&gt; 
  directory of my desktop.
  &lt;br&gt;&lt;br&gt;&lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Files&lt;/h4&gt;

  
  Now I choose files that should be included in the distribution by clicking on the &lt;i&gt;Files&lt;/i&gt; 
  icon below the &lt;i&gt;General Setting&lt;/i&gt; 
  one. These files could be assembled by invoking the appropriate Ant target in the build.xml file of Sweet Home 3D 
  project, but as this tutorial isn't about Ant, I prefer to use the files installed by the existing setup program 
  available &lt;a href="https://prdownloads.sourceforge.net/sweethome3d/SweetHome3D-3.0-windows.exe"&gt;here&lt;/a&gt;.
  I launch this program and install the files in &lt;i&gt;C:Program Files (x86)Sweet Home 3D 3.0&lt;/i&gt; 
  directory.
  &lt;br&gt;&lt;br&gt;
  
  Once the existing installer finished, I have to include the jar and license files in the distribution tree of install4j.
  These files are indicated in blue in the following list:
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DFiles-df49e39a7f87ea6edfe2691ac8a74a5.png" class="img-fluid" loading="lazy" width="358" height="701"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Clicking on the &lt;i&gt;Insert&lt;/i&gt; 
  button (the green plus button), I choose the &lt;i&gt;Add Files and Directories&lt;/i&gt; 
  option,
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/FilesDefineDistributionTree-fe9da2f9f65e5148380a6af444ea019.png" class="img-fluid" loading="lazy" width="600" height="533"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  and choose the &lt;i&gt;Directory&lt;/i&gt; 
  entry type for the &lt;i&gt;C:Program file (x86)Sweet Home 3D 3.0lib&lt;/i&gt; 
  directory with the option &lt;i&gt;Add to subdirectory&lt;/i&gt; 
  selected, then &lt;i&gt;Single files&lt;/i&gt; 
  type for the licenses files.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/AddFilesAndDirectoriesSelectType-c36ac1e4f56db41f0525e986242d7d7.png" class="img-fluid" loading="lazy" width="595" height="316"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/AddFilesAndDirectoriesSelectDirectory-b0dc87561fe967f751154cadb65a67.png" class="img-fluid" loading="lazy" width="595" height="316"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/AddFilesAndDirectoriesSelectFiles-ebffcfdfcf9a5c7f23f3d21c385cdc.png" class="img-fluid" loading="lazy" width="595" height="364"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I also have to include the &lt;i&gt;javaws.jar&lt;/i&gt; 
  file found in the &lt;i&gt;jre6lib&lt;/i&gt; 
  subdirectory and required by Sweet Home 3D to run. I insert this file as as a &lt;i&gt;Single file&lt;/i&gt; 
  type and to make it appear in the lib subdirectory among other jar files, I insert a new folder named &lt;i&gt;lib&lt;/i&gt; 
  where I drag and drop the &lt;i&gt;javaws.jar&lt;/i&gt; 
  line.
  &lt;br&gt;&lt;br&gt;
  
  All these files and directory finally appear in the list of the &lt;i&gt;Define Distribution Tree&lt;/i&gt; 
  tab.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/FilesDefineDistributionTreeCompleted-922f5f582dbcc4499edb1404fa57743.png" class="img-fluid" loading="lazy" width="596" height="350"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Launcher&lt;/h4&gt;

  
  As I don't need to set any &lt;i&gt;File&lt;/i&gt; 
  options or don't want to propose optional files at this moment, I now click on the &lt;i&gt;Launchers&lt;/i&gt; 
  icon below the &lt;i&gt;Files&lt;/i&gt; 
  one, and double click on the &lt;i&gt;New launcher&lt;/i&gt; 
  icon.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/NewLauncherIcon-9c79b4a33160d086c4b3b1e81591ef98.png" class="img-fluid" loading="lazy" width="89" height="61"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  This will launch a wizard used to create a launcher. As I want to generate a new launcher to test install4j features, I 
  keep the &lt;i&gt;Generate launcher&lt;/i&gt; 
  option selected.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/LauncherSelectType-fae31b63067bd615ad141d22ce1.jpg" class="img-fluid" loading="lazy" width="600" height="364"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Then I give application name and the directory where it should appear. The &lt;i&gt;Executable info&lt;/i&gt; 
  second step offers also an interesting option that allows only a single running instance, that I would check if I didn't
  program already such a feature in Sweet Home 3D.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/LauncherConfigureExecutable-249261849cc5857343407f8c9dd4cc81.jpg" class="img-fluid" loading="lazy" width="600" height="364"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  In the &lt;i&gt;Advanced Options&lt;/i&gt; 
  list, I choose &lt;i&gt;Windows version info&lt;/i&gt; 
  and check the &lt;i&gt;Generate version info resource&lt;/i&gt; 
  to get correct values in the file properties dialog box of the future launcher. I let install4j replace &lt;i&gt;Product name&lt;/i&gt; 
  and &lt;i&gt;File version&lt;/i&gt; 
  fields and enter values in &lt;i&gt;Internal name&lt;/i&gt;,
 &lt;i&gt;File description&lt;/i&gt; 
  and &lt;i&gt;Legal copyright&lt;/i&gt; 
  text fields, using some existing variables.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/LauncherConfigureExecutableVersionInfo-5dc163fde26b6540225fa33b585c9e6.jpg" class="img-fluid" loading="lazy" width="600" height="365"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  The &lt;i&gt;Icon&lt;/i&gt; 
  third step proposes to choose an icon for the program. I select &lt;i&gt;Add icon to launcher&lt;/i&gt; 
  option, and configure the program &lt;a href="https://www.sweethome3d.com/support/forum/viewthread_thread,1060"&gt;icons&lt;/a&gt; 
  at 3 different sizes and add them to the &lt;i&gt;Cross-Platform Image File&lt;/i&gt; 
  list.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/LauncherIcon-66372c9b7ab199f883ef82a3a5d67ed.jpg" class="img-fluid" loading="lazy" width="600" height="394"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  The &lt;i&gt;Java invocation&lt;/i&gt; 
  steps shows information required to run a Java application. In VM Parameters, I increase the maximum memory to 512 MB 
  and specify where Java 3D DLLs are available with the parameters &lt;i&gt;-Xmx512m -Djava.library.path=lib&lt;/i&gt; 
  (DLLs directory can be set with &lt;i&gt;Advanced Options &amp;gt; Native libraries&lt;/i&gt; 
  too). I enter program main class &lt;i&gt;com.eteks.sweethome3d.SweetHome3D&lt;/i&gt; 
  and enter &lt;i&gt;-open&lt;/i&gt; 
  in &lt;i&gt;Arguments&lt;/i&gt; 
  text field because Sweet Home 3D expects this selector before any file passed as an argument.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/LauncherConfigureJavaInvocation-43e4ffac447fcbfce56b2d64eeb3158.jpg" class="img-fluid" loading="lazy" width="600" height="394"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Now I need to complete the &lt;i&gt;Class path&lt;/i&gt; 
  list, which accepts individual jar files, directories containing jar files, directories containing &lt;i&gt;.class&lt;/i&gt; 
  files or resources, and information from environment variables. As I keep all the jar files in the &lt;i&gt;lib&lt;/i&gt; 
  subdirectory, I click on the &lt;i&gt;Insert&lt;/i&gt; 
  button, select the &lt;i&gt;Scan directory&lt;/i&gt; 
  option and enter &lt;i&gt;lib&lt;/i&gt; 
  directory.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/LauncherClasspathEntry-d76685a160277cdb734a397ccc308b3d.png" class="img-fluid" loading="lazy" width="393" height="288"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  The &lt;i&gt;VM options file&lt;/i&gt; 
  step offers an interesting option to the end users who can change default VM parameters in case they need it. As Sweet 
  Home 3D uses a few System properties and may require more memory to run, I keep the default &lt;i&gt;Copy template file with explanations for user&lt;/i&gt; 
  selected.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/LauncherVMOptionsFile-236554eb341baefabbd17f6e9dffd6e.jpg" class="img-fluid" loading="lazy" width="600" height="354"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Finally, in the &lt;i&gt;Splash screen&lt;/i&gt; 
  step, I can choose the splash screen image that should be displayed during program launch. As Sweet Home 3D handles this
  feature itself, I don't change default settings but note that you can use install4j splash screen or Java 6 one if 
  needed.
  &lt;br&gt;&lt;br&gt;
  
  The &lt;i&gt;Advanced options&lt;/i&gt; 
  let you even write some texts over the image. Nice!
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/LauncherSplashScreen-32c8b3a765751f05e57c8e560a2cc93.jpg" class="img-fluid" loading="lazy" width="600" height="320"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once the &lt;i&gt;Launcher&lt;/i&gt; 
  wizard is finished, a new launcher icon is added to &lt;i&gt;Launchers&lt;/i&gt; 
  screen to let you change launcher settings later.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/ApplicationLauncherIcon-a6706ae8425e25e5e4a0c7c140499cf2.png" class="img-fluid" loading="lazy" width="456" height="202"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Installer&lt;/h4&gt;

  
  The &lt;i&gt;Installer&lt;/i&gt; 
  screen describes the various screens that will be displayed to the end user during program installation and 
  uninstallation. It's a highly configurable tool with many options that you can even extend if needed. The screens in the
  default template will show six screens from &lt;i&gt;Welcome&lt;/i&gt; 
  screen to &lt;i&gt;Finish&lt;/i&gt; 
  screen.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/InstallerConfigure-717cc979231ce6296d95a8e6bf1ab5b.jpg" class="img-fluid" loading="lazy" width="600" height="593"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;
  &lt;div&gt;
    In the &lt;i&gt;Screens &amp;amp; Actions&lt;/i&gt;
    tab, these screens are represented with an icon showing a gear in a window &lt;img alt="Blog image" src="/assets/blog/MyFirstTryWithInstall4j/ScreenIcon-f5b86f2541ff8b344d3a1fa896cfedf5.png" class="" loading="lazy" width="26" height="26"&gt;
    and sometimes by custom icons like the one used for the &lt;i&gt;Installation&lt;/i&gt;
    screen &lt;img alt="Blog image" src="/assets/blog/MyFirstTryWithInstall4j/InstallationScreenIcon-9ab1f95433032dfe974e243af26978.png" class="" loading="lazy" width="26" height="26"&gt;.
    The tree shown on the left contains also some actions represented with a gear icon window &lt;img alt="Blog image" src="/assets/blog/MyFirstTryWithInstall4j/ActionIcon-21a6f1846724ef3543cd03153c7ca.png" class="" loading="lazy" width="26" height="26"&gt;
    and by custom icons like the one for the &lt;i&gt;Startup&lt;/i&gt;
    action &lt;img alt="Blog image" src="/assets/blog/MyFirstTryWithInstall4j/StartupActionIcon-d4a61e3e2b7e23e13481069a0dcf240.png" class="" loading="lazy" width="26" height="26"&gt;.
    An action is simply one or more statements (either preprogrammed ones or custom ones programmed in Java) that the 
    installer should run during the installation.
  
  &lt;/div&gt;
&lt;br&gt;&lt;br&gt;
  &lt;div&gt;
    To ensure the installer created with install4j behaves as the existing one, I'll add two screens:
  
  &lt;/div&gt;
&lt;br&gt;&lt;br&gt;
  &lt;ul&gt;
    &lt;li&gt;
      one displaying the GNU GPL license of the software,
    &lt;/li&gt;
    &lt;li&gt;
      one that will let the user accept file associations,
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;br&gt;&lt;br&gt;
  &lt;div&gt;
    and I'll add also two types of actions:
  
  &lt;/div&gt;
&lt;br&gt;&lt;br&gt;
  &lt;ul&gt;
    &lt;li&gt;
      some registering file extension associations,
    &lt;/li&gt;
    &lt;li&gt;
      one that will let the user launch Sweet Home 3D once the installation is finished.
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;br&gt;
  
  To add the new screens, I click on the &lt;i&gt;Insert&lt;/i&gt; 
  button and choose &lt;i&gt;Add Screen&lt;/i&gt; 
  in the popup menu.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/AddScreenMenuItem-992d6d7452b472fde236391987a4fc.png" class="img-fluid" loading="lazy" width="139" height="175"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  In the displayed &lt;i&gt;Select an Installation Screen&lt;/i&gt; 
  dialog box, I filter the shown list by entering the first letters of &amp;quot;&lt;code&gt;license&lt;/code&gt;
  &amp;quot;. Once I select &lt;i&gt;Display license agreement&lt;/i&gt; 
  item, I definitively know that screen has some good chances to be the one I look for from its &lt;i&gt;Description&lt;/i&gt; 
  displayed below.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SelectDisplayLicenseAgreementInstallationScreen-9d507792907c6263687b359cb334874.png" class="img-fluid" loading="lazy" width="304" height="384"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I click on OK and the new screen is automatically inserted after the &lt;i&gt;Welcome&lt;/i&gt; 
  screen, just at the right place I wanted it to appear!
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/DisplayLicenseAgreementScreenProperties-5471ba1b5a1fbb0f86945309fc0a232.png" class="img-fluid" loading="lazy" width="573" height="461"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I now enter missing values in the screen properties list displayed at the right. I edit the &lt;i&gt;License file&lt;/i&gt; 
  property and install4j lets me choose it either as a file packaged with the installer or coming from installed files.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/ChooseFileMode-20b3d03a8e139b5ba7f7444c499b7a6f.png" class="img-fluid" loading="lazy" width="442" height="261"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I choose the first option and select the &lt;i&gt;COPYING.TXT&lt;/i&gt; 
  file that contains the GNU GPL license text. As the license wasn't translated to other languages, I leave the file empty
  for the other languages, so the default text in English will be displayed.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/ChooseLicenseFile-e25a97f7ef596efb2d588ade59f4cfa.png" class="img-fluid" loading="lazy" width="442" height="274"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Then I select the &lt;i&gt;User must scroll to bottom&lt;/i&gt; 
  option in the hope it will get more users to read the GNU GPL license.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/DisplayLicenseAgreementScreenPropertiesCompleted-7dc9bf2e38b9614ff23c643545490d1.png" class="img-fluid" loading="lazy" width="573" height="461"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I click again on the &lt;i&gt;Insert&lt;/i&gt; 
  button to add a &lt;i&gt;File associations&lt;/i&gt; 
  screen and select &lt;i&gt;File associations&lt;/i&gt; 
  item in the &lt;i&gt;Select an Installation Screen&lt;/i&gt; 
  dialog box.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SelectFileAssociationsInstallationScreen-67f3713ea95120f1f0b27521d751b.png" class="img-fluid" loading="lazy" width="299" height="326"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once I click on OK, install4j warns me that the &lt;i&gt;File associations&lt;/i&gt; 
  screen requires one or more &lt;i&gt;File association&lt;/i&gt; 
  actions to work.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/AddFileAssociationAction-5be5a5705ea512eb88e7c51269e5c9c.png" class="img-fluid" loading="lazy" width="314" height="164"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I close the warning message. The &lt;i&gt;File associations&lt;/i&gt; 
  screen is added between &lt;i&gt;Create program group&lt;/i&gt; 
  and &lt;i&gt;Installation&lt;/i&gt; 
  screens, and I check &lt;i&gt;Show selection&lt;/i&gt; 
  buttons property to speed up user choice. As Sweet Home 3D has 5 file associations, these buttons will let him or her to
  select or deselect them with one click.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/FileAssociationsScreenProperties-ca683c3ddd8a26f5ba2b212a46b223.png" class="img-fluid" loading="lazy" width="596" height="461"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  As file associations should be made only after the executable that handles them is installed, I select the &lt;i&gt;Installation&lt;/i&gt; 
  screen in the tree, then I click on the &lt;i&gt;Insert&lt;/i&gt; 
  button to add the desired action. In the displayed &lt;i&gt;Select an Installation Action&lt;/i&gt; 
  dialog box, I filter the shown list by entering the first letters of &amp;quot;&lt;code&gt;association&lt;/code&gt;
  &amp;quot; to quickly find the &lt;i&gt;Create a file association&lt;/i&gt; 
  action among the 60+ preprogrammed actions.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/CreateFileAssociationAction-30c852a26506efe442ecd240e75c91.png" class="img-fluid" loading="lazy" width="389" height="398"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once I click on OK, install4j appends the new action to the &lt;i&gt;Installation&lt;/i&gt; 
  screen, and in the properties list associated to the action, I enter &amp;quot;&lt;code&gt;sh3d&lt;/code&gt;
  &amp;quot; &lt;i&gt;File extension&lt;/i&gt;,
  describe it as &amp;quot;&lt;code&gt;Sweet Home 3D document&lt;/code&gt;
  &amp;quot; and select the &lt;i&gt;SweetHome3D&lt;/i&gt; 
  launcher.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/FileAssociationActionProperties-1441c159e552f76667d29112813b4ac1.png" class="img-fluid" loading="lazy" width="596" height="462"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Then I add the file associations for sh3f, sh3t, sh3p and sh3l extensions in the same way.
  &lt;br&gt;&lt;br&gt;
  
  For the action that should launch Sweet Home 3D at the end of the installation process, I select the &lt;i&gt;Finish&lt;/i&gt; 
  screen, click on the &lt;i&gt;Insert&lt;/i&gt; 
  button and select &lt;i&gt;Add action&lt;/i&gt;.
  In the displayed &lt;i&gt;Select an Installation Action&lt;/i&gt; 
  dialog box, I filter the actions list with the first letters of &amp;quot;&lt;code&gt;launcher&lt;/code&gt;
  &amp;quot; and select &lt;i&gt;Execute launcher&lt;/i&gt; 
  action.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/ExecuteLauncherAction-5c6c55d26b13f0ab6fd80ed793da54d.png" class="img-fluid" loading="lazy" width="389" height="419"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once I click on OK, install4j asks me whether I want to add a check box to the &lt;i&gt;Finish&lt;/i&gt; 
  screen that will will let the user choose to launch the program or not.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/ConfirmCheckBox-d6cd82aa339b888a7fd4f81acf196f2.png" class="img-fluid" loading="lazy" width="415" height="118"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I accept and in the properties list of the &lt;i&gt;Execute launcher&lt;/i&gt; 
  action, I finally choose SweetHome3D as the launcher to run.
  &lt;br&gt;&lt;br&gt;
  
  At the end, I get the following list of screens and actions for Sweet Home 3D installer.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/ScreensAndActions-f6f06e925d1b9d5e88d5afba3df33d95.png" class="img-fluid" loading="lazy" width="596" height="621"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Media&lt;/h4&gt;

  
  As I don't need &lt;i&gt;Custom&lt;/i&gt; 
  code or &lt;i&gt;Update features&lt;/i&gt; 
  at this time, I jump to the last part of the installer preparation by clicking on &lt;i&gt;Media&lt;/i&gt; 
  icon, then double-clicking on &lt;i&gt;New media file&lt;/i&gt; 
  icon.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/NewMediaFileIcon-6f3d88c5f68dd8abb6c7fc95bacaa8.png" class="img-fluid" loading="lazy" width="90" height="58"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  This will launch a wizard to configure a &lt;i&gt;Media&lt;/i&gt; 
  file. As I prefer an executable installer, I choose &lt;i&gt;Windows&lt;/i&gt; 
  in the Installer type combo box.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/MediaChooseType-55cc8ade972f6ddd9cecce2f67447.jpg" class="img-fluid" loading="lazy" width="600" height="363"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  In the &lt;i&gt;Configure installer options&lt;/i&gt; 
  step, I change installation directory to &amp;quot;&lt;code&gt;Sweet Home 3D&lt;/code&gt;
  &amp;quot;.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/MediaOptions-f87c03649f5c91af37a5d61aed68cf6.jpg" class="img-fluid" loading="lazy" width="600" height="363"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  The &lt;i&gt;Installer data files&lt;/i&gt; 
  step doesn't need any change since I want to create one installer file that will contain everything required.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/MediaDataFiles-78827c7f2e95dd67afdfbf7601d406c.jpg" class="img-fluid" loading="lazy" width="600" height="363"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I don't check the &lt;i&gt;64-bit executable&lt;/i&gt; 
  option in the &lt;i&gt;Select the architecture of the generated executables&lt;/i&gt; 
  step since the Java 3D DLLs delivered with Sweet Home 3D are 32-bit only.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/MediaArchitecture-c1f859d5a666f9fb498b4dd5aea38f62.jpg" class="img-fluid" loading="lazy" width="600" height="213"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  As I don't have any code certificate I must pass the &lt;i&gt;Configure code signing for launchers and installer&lt;/i&gt; 
  step too.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/MediaCodeSigning-68c8af15cdf0e31bb5f3c7739323c7f.jpg" class="img-fluid" loading="lazy" width="600" height="288"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  The &lt;i&gt;Bundle a JRE with your application&lt;/i&gt; 
  step is more interesting for my use case.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/MediaBundleJRE-af19e18a119184a8c99fe6a9613ca64.jpg" class="img-fluid" loading="lazy" width="600" height="448"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  As I want to bundle a JRE with Sweet Home 3D to spare users the installation of a JRE, I select the &lt;i&gt;Bundle the following JRE&lt;/i&gt; 
  option and chose the most recent one after clicking on &lt;i&gt;Download JREs.&lt;/i&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/DownloadJREs-59d47e7135efe6646af9aed67aa3f71f.png" class="img-fluid" loading="lazy" width="530" height="255"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once the JRE is downloaded, I select it in the &lt;i&gt;Bundle the following JRE&lt;/i&gt; 
  combo box.
  &lt;br&gt;&lt;br&gt;
  
  I'm not interested by any of the &lt;i&gt;Customize project default settings&lt;/i&gt; 
  last step, and I can finish the &lt;i&gt;Media Wizard&lt;/i&gt; 
  execution that will add an icon for the newly created media.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/ApplicationMediaFile-14dec9484fd395ee8d575e194698e66.png" class="img-fluid" loading="lazy" width="480" height="189"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Build&lt;/h4&gt;

  
  The installer is now ready to be built. I click on &lt;i&gt;Build&lt;/i&gt; 
  icon and then on &lt;i&gt;Start Build&lt;/i&gt; 
  button.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/Build-729fe2db43a347f3f85f327e5fc929bb.jpg" class="img-fluid" loading="lazy" width="600" height="468"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  After 60 seconds, the installer is generated, and my first surprise is than the generated &lt;i&gt;SweetHome3D-3.0-windows.exe&lt;/i&gt; 
  file is more than 4 MB smaller than the one generated by Inno Setup (26 MB instead of 30.6 MB)! This is probably due to 
  Pack200 compression algorithm.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerIcon-f42cae23d78022a1be06f47fce8b46.png" class="img-fluid" loading="lazy" width="105" height="131"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Test&lt;/h4&gt;

  
  I double-click on the new installer icon to launch it and get the expected installation screens sequence.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerLaunch-e7bb5b396f6fc549b8ee9baf46e88c48.png" class="img-fluid" loading="lazy" width="356" height="148"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerSelectLanguage-c5787cde75a65eadba0ee1d60939740.png" class="img-fluid" loading="lazy" width="350" height="143"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerStep1-5f6caf9516c1cece4dfe8e632773f3b.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerStep2-77ad1a4bf63d38b48ae19fb4a9a4493.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerStep3-efc3c77f97ce2f3d7753f54c818cc5d.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerStep4-38eeb4322375a1159cdc25e27125ff.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerStep5-56444183f6d743df16b7e9861fbea2.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerStep6-fde9cb825cde28c52f21e340d415beeb.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/SweetHome3DInstallerStep7-f652b3a7435358f2a6fb8de7645d19c2.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once Sweet Home 3D is installed and launched, I check how it's listed in the &lt;i&gt;Processes&lt;/i&gt; 
  tab of the &lt;i&gt;Windows Task Manager&lt;/i&gt;
  : it appears as &lt;i&gt;SweetHome3D.exe&lt;/i&gt; 
  which is much nicer than &lt;i&gt;javaw.exe&lt;/i&gt;.

  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/WindowsTaskManager-acf8bd35e445cd79528c8deebf7dbd1b.png" class="img-fluid" loading="lazy" width="511" height="459"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Conclusion&lt;/h4&gt;

  
  With install4j you can easily create an installer and launcher for your Java application. Even if there are many steps 
  in this installer wizard, you really feel install4j takes you by the hand to the right target. But in fact, install4j 
  offers much more features that I'll test in a second article.
  &lt;br&gt;&lt;br&gt;
  
  I'll use install4j to download some optional files for Sweet Home 3D and configure some program parameters, like memory 
  settings, system properties and default preferences files.
  &lt;br&gt;&lt;br&gt;
  
  I'll also show how to use the different installation modes and how to update the program automatically.</description>
      <category>install4j</category>
      <category>Tutorial</category>
      <pubDate>Tue, 14 Dec 2010 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2010/12/my-first-try-with-install4j/</guid>
      <dc:creator>Emmanuel</dc:creator>
      <dc:date>2010-12-14T08:00:57Z</dc:date>
    </item>
    <item>
      <title>More installation options with install4j</title>
      <link>https://www.ej-technologies.com/blog/2010/12/more-installation-options-with-install4j/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=tutorial"&gt;Tutorial&lt;/a&gt; &lt;/p&gt;
  &lt;div&gt;&lt;br&gt;&lt;br&gt;
    Last week, I explained &lt;a href="https://blog.ej-technologies.com/2010/12/my-first-try-with-install4j-tutorial.html"&gt;how to build an installer with install4j&lt;/a&gt;
    for Sweet Home 3D, that would behave as the one distributed on the website of the program.
    &lt;br&gt;&lt;br&gt;
    But &lt;a href="https://www.sweethome3d.com/"&gt;Sweet Home 3D&lt;/a&gt;
    and &lt;a href="https://www.ej-technologies.com/products/install4j/overview.html"&gt;install4j&lt;/a&gt;
    provide some options that could be nice to offer to end users at installation time like:
    &lt;br&gt;&lt;br&gt;&lt;/div&gt;
&lt;br&gt;&lt;br&gt;
    
    
  &lt;ul&gt;
    &lt;li&gt;
      keeping the language chosen at installation as the default language of the program,
    &lt;/li&gt;
    &lt;li&gt;
      configuring the max memory amount used by the program from the RAM available in the computer,
    &lt;/li&gt;
    &lt;li&gt;
      offering to download and install an optional program like the Furniture Library Editor,
    &lt;/li&gt;
    &lt;li&gt;
      downloading some optional files like archives containing 3D models,
    &lt;/li&gt;
    &lt;li&gt;
      offering special options when the program is installed on a USB key,
    &lt;/li&gt;
    &lt;li&gt;
      offering to delete program and configuration files during uninstallation,
    &lt;/li&gt;
    &lt;li&gt;
      translating the text of the special options added to the installer,
    &lt;/li&gt;
    &lt;li&gt;
      installing the program in unattended mode to speed up its deployment in&lt;br&gt;
      schools.
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;br&gt;&lt;br&gt;

  
  &lt;h4 class="mt-5"&gt;Storing the chosen language&lt;/h4&gt;


  In Sweet Home 3D, the user may change the language used in the graphic interface with the preferences panel displayed
  when he selects the &lt;i&gt;File &amp;gt; Preferences&lt;/i&gt;
  menu item. The persistence of his choice is managed with Java &lt;a href="https://download.oracle.com/javase/6/docs/api/java/util/prefs/Preferences.html"&gt;Preferences&lt;/a&gt;
  class which stores its values in the registry under Windows. install4j offers an action able to set the value of a Java
  preference and I'm going to use it to store the language used in the installer.
  &lt;br&gt;&lt;br&gt;

  As I want this action to occur after files were installed, I select &lt;i&gt;Installation&lt;/i&gt;
  node in install4j and choose &lt;i&gt;Add Action&lt;/i&gt;
  in its contextual menu.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SelectInstallationScreen-f5afd58e9e8ca2e13e5e9688171ff0.jpg" class="img-fluid" loading="lazy" width="600" height="564"&gt;&lt;/div&gt;


  &lt;br&gt;

  I type the the first letters of &amp;quot;&lt;code&gt;preferences&lt;/code&gt;
  &amp;quot; in the &lt;i&gt;Filter&lt;/i&gt;
  text field and select the &lt;i&gt;Set a key in the Java preference store&lt;/i&gt;
  action among the 5 actions dealing with preferences.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/JavaPreferenceStoreAction-dae5b7da4c356aec2922a947c338b8bf.png" class="img-fluid" loading="lazy" width="364" height="395"&gt;&lt;/div&gt;


  &lt;br&gt;

  Once I click on OK, I fill the Java preference properties of the action from the &lt;a href="https://sweethome3d.cvs.sourceforge.net/viewvc/sweethome3d/SweetHome3D/src/com/eteks/sweethome3d/io/FileUserPreferences.java?revision=1.52&amp;amp;view=markup#l177"&gt;matching value&lt;/a&gt;
  read in Sweet Home 3D. I set &lt;i&gt;Package name&lt;/i&gt;
  value to &amp;quot;&lt;code&gt;com.eteks.sweethome3d.io&lt;/code&gt;
  &amp;quot; and &lt;i&gt;Key&lt;/i&gt;
  value to &amp;quot;&lt;code&gt;language&lt;/code&gt;
  &amp;quot;.
  &lt;br&gt;

  The value of the &lt;i&gt;Value&lt;/i&gt;
  text field must be set according to the language currently used in the installer, something stored in one of the
  install4j variables. To find it out, I click on the button arrow at the right of the text field and select the &lt;i&gt;Insert Installer Runtime Variable&lt;/i&gt;
  option.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InsertInstallerRuntimeVariable-1a2fa4954e639e164b68c04fc97362a3.png" class="img-fluid" loading="lazy" width="478" height="294"&gt;&lt;/div&gt;


  &lt;br&gt;

  In the &lt;i&gt;Select Installer Runtime Variable&lt;/i&gt;
  dialog box, I filter variables with the first letters of &amp;quot;&lt;code&gt;language&lt;/code&gt;
  &amp;quot; and choose &lt;i&gt;sys.languageId &lt;/i&gt;
  variable.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SelectInstallerRuntimeVariable-5bb2599c1191ef602ddc2dc87554706f.png" class="img-fluid" loading="lazy" width="380" height="426"&gt;&lt;/div&gt;


  &lt;br&gt;

  Finally, I choose &lt;i&gt;User specific&lt;/i&gt;
  for &lt;i&gt;Preference root&lt;/i&gt;
  field.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SelectPreferenceRoot-a6bc635a2dda1415a812c01d285bfe29.png" class="img-fluid" loading="lazy" width="600" height="428"&gt;&lt;/div&gt;


  &lt;br&gt;

  
  &lt;h4 class="mt-5"&gt;Configuring the max memory of the program&lt;/h4&gt;


  Sweet Home 3D may require a lot of memory in some circumstances, and the default amount of maximum memory used by a Java
  Virtual Machine is generally not enough to let the program work correctly for big layouts. At the opposite, if too much
  memory is required, the program may slow down too much because the operating system will have to manage the missing RAM
  with disk swapping. A nice option could be to fix the maximum memory used by the JVM by program according to the
  available physical memory. This amount of memory is passed to the JVM with the option &lt;code&gt;-Xmaaaam&lt;/code&gt;
  where &lt;code&gt;aaaa&lt;/code&gt;
  matches the maximum memory in MB.
  &lt;br&gt;&lt;br&gt;

  I already set &lt;code&gt;-Xmx&lt;/code&gt;
  to &lt;code&gt;512m&lt;/code&gt;
  during the configuration of a launcher by setting the &lt;i&gt;VM parameters&lt;/i&gt;
  value at the fourth step of the launcher creation wizard.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/LauncherConfigureJavaInvocation-43e4ffac447fcbfce56b2d64eeb3158.jpg" class="img-fluid" loading="lazy" width="600" height="394"&gt;&lt;/div&gt;


  &lt;br&gt;

  To set this value according to the memory available on the end user computer, the easiest way is to remove the &lt;code&gt;-Xmx512m&lt;/code&gt;
  option from &lt;i&gt;VM parameters &lt;/i&gt;
  and add an action to update VM parameters when the installer is run. As this action should happen at the end of the
  installation, I select the &lt;i&gt;Installation &lt;/i&gt;
  node, click on the &lt;i&gt;Insert&lt;/i&gt;
  button (the button with a green plus) and select the &lt;i&gt;Add Action&lt;/i&gt;
  menu item.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallerAddActionToInstallation-f77ed79ed7d04df210c7f67dca215516.jpg" class="img-fluid" loading="lazy" width="600" height="567"&gt;&lt;/div&gt;


  &lt;br&gt;

  In the &lt;i&gt;Select an Installation Action&lt;/i&gt;
  dialog box, I choose the &lt;i&gt;Add VM Options&lt;/i&gt;
  action,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/AddVMOptionsAction-7f91d238336c23c1b15e4905a11dcdd.png" class="img-fluid" loading="lazy" width="302" height="324"&gt;&lt;/div&gt;


  &lt;br&gt;

  and once I click on OK, I edit the properties of the action to set &lt;i&gt;SweetHome3D&lt;/i&gt;
  as &lt;i&gt;Launcher&lt;/i&gt;
  value and enter the text &amp;quot;&lt;code&gt;${installer:xmx}&lt;/code&gt;
  &amp;quot; in &lt;i&gt;VM options&lt;/i&gt;
  text field.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SetVMOptions-e23ae62979d2dc2a672297ef521fd31c.png" class="img-fluid" loading="lazy" width="575" height="457"&gt;&lt;/div&gt;


  &lt;br&gt;

  This value references the &lt;i&gt;installer:xmx&lt;/i&gt;
  variable that will be evaluated at installation time, when the installer will be run. As I need to create this variable
  and give it a value, I click again on the &lt;i&gt;Insert&lt;/i&gt;
  button and select &lt;i&gt;Add Action&lt;/i&gt;
  menu item. This time, I choose the &lt;i&gt;Set a variable&lt;/i&gt;
  action in the &lt;i&gt;Select an Installation Action&lt;/i&gt;
  dialog box.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SetVariableAction-aabc9fe4cf49ab3e60923a32831945.png" class="img-fluid" loading="lazy" width="359" height="420"&gt;&lt;/div&gt;


  &lt;br&gt;

  Once I click on OK, I move the new action one row up before the &lt;i&gt;Add VM options&lt;/i&gt;
  action by clicking on the blue up arrow, edit the properties of the action to set the &amp;quot;&lt;code&gt;xmx&lt;/code&gt;
  &amp;quot; name of the new variable without its installer prefix, and click on the button with an ellipsis at the right of the &lt;i&gt;Script&lt;/i&gt;
  text field to edit its value.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SetVariableScript-32b28fd6b9995f4c4d718fbdfe3a8fb2.png" class="img-fluid" loading="lazy" width="575" height="458"&gt;&lt;/div&gt;


  &lt;br&gt;

  This opens a text editor where I have to enter a Java expression whose value will be saved to the &lt;i&gt;xmx&lt;/i&gt;
  variable.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditVariableScript-e5ef44e6fa8d62e08afc2923318ab83.png" class="img-fluid" loading="lazy" width="532" height="379"&gt;&lt;/div&gt;


  &lt;br&gt;

  The comment displayed by the editor suggests I can use the two &lt;i&gt;context&lt;/i&gt;
  and &lt;i&gt;action&lt;/i&gt;
  parameters if required, and the classes of these two parameters are &lt;a href="https://resources.ej-technologies.com/install4j/help/api/com/install4j/api/context/InstallerContext.html"&gt;com.install4j.api.context.InstallerContext&lt;/a&gt;
  and &lt;a href="https://resources.ej-technologies.com/install4j/help/api/com/install4j/api/context/InstallerContext.html"&gt;com.install4j.api.actions.InstallAction&lt;/a&gt;
  shown as hyperlinks to their respective &lt;a href="https://resources.ej-technologies.com/install4j/help/api/index.html"&gt;javadoc&lt;/a&gt;
  pages.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/Javadoc-17b5dd7ffd9a5e8c3c851c664a295310.jpg" class="img-fluid" loading="lazy" width="600" height="466"&gt;&lt;/div&gt;


  &lt;br&gt;

  The great thing is that editor offers auto completion when I press &lt;i&gt;Ctrl + space&lt;/i&gt;
  keys! For example, if I try to complete &amp;quot;&lt;code&gt;co&lt;/code&gt;
  &amp;quot; I'll get &amp;quot;&lt;code&gt;context&lt;/code&gt;
  &amp;quot; at the top of the suggested items and other items starting by &amp;quot;&lt;code&gt;co&lt;/code&gt;
  &amp;quot;.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditVariableScriptCompletion-19e047ab686464e328e06188d9445c6.png" class="img-fluid" loading="lazy" width="600" height="415"&gt;&lt;/div&gt;


  &lt;br&gt;

  I choose &lt;code&gt;context&lt;/code&gt;,
  type a dot to invoke a method of the &lt;code&gt;InstallerContext&lt;/code&gt;
  class, but there are so many choices that it's quite difficult to find out the method that returns the memory available
  in the computer where the installer runs (this value isn't available in Java SE 6 too).
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditVariableScriptContextCompletion-d4b8fa488b994d57858356f82d71b95e.png" class="img-fluid" loading="lazy" width="600" height="208"&gt;&lt;/div&gt;


  &lt;br&gt;

  Therefore I explore the help file, which seems pretty complete, since I find the information I need with a search of the
  &amp;quot;&lt;code&gt;memory&lt;/code&gt;
  &amp;quot; keyword which brings me to the method &lt;code&gt;getPhysicalMemory &lt;/code&gt;
  in the &lt;a href="https://resources.ej-technologies.com/install4j/help/api/com/install4j/api/SystemInfo.html"&gt;com.install4j.api.SystemInfo&lt;/a&gt;
  class.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/Help-838576a997b8d634953324f59db2d2cd.jpg" class="img-fluid" loading="lazy" width="600" height="659"&gt;&lt;/div&gt;


  &lt;br&gt;

  As this method is static, I finally enter the expression
  &lt;br&gt;&lt;code&gt;&amp;quot;-Xmx&amp;quot; + (SystemInfo.getPhysicalMemory() / 2 / 1024 / 1024) + &amp;quot;m&amp;quot;&lt;/code&gt;&lt;br&gt;

  and as the green square drawn at the end of line confirms, the syntax of my expression is correct,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditVariableScriptHalfPhysicalMemory-26fe34b566677171f7ded97982077dc.png" class="img-fluid" loading="lazy" width="502" height="78"&gt;&lt;/div&gt;


  &lt;br&gt;

  I click on OK, save my install4j project, build it and run the installer to check how it works.
  &lt;br&gt;&lt;br&gt;

  As setting this option won't change anything at the screen, I run &lt;i&gt;SweetHome3D.exe&lt;/i&gt;
  executable file in a command window with the option &lt;i&gt;/create-i4j-log&lt;/i&gt;
  that will create a temporary log file. To help me to find this log file, install4j displays an information dialog box
  recalling where it can be found.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/LogPath-64e4f296b6ec559988df88f82b1c877.png" class="img-fluid" loading="lazy" width="339" height="204"&gt;&lt;/div&gt;


  &lt;br&gt;

  Reading this file I can see a &lt;code&gt;vmoption&lt;/code&gt;
  line with &lt;code&gt;-Xmx755m&lt;/code&gt;
  option stating the half of the 1.5 GB memory of my computer might be occupied by the Java program.
  &lt;br&gt;

  
  &lt;h4 class="mt-5"&gt;Downloading an optional program&lt;/h4&gt;


  A program called the &lt;a href="https://www.sweethome3d.com/support/forum/viewthread_thread,1550"&gt;Furniture Library Editor&lt;/a&gt;
  was recently added as a separate application. It allows the user to import and edit faster the attributes of a group of
  3D models instead of importing them one by one in the program.
  &lt;br&gt;&lt;br&gt;

  This program is a Jar executable application and I want to suggest it as an option in the installer. As it is around 5
  MB large, it won't be bundled with the installer but downloaded if the user wants to install it.
  &lt;br&gt;&lt;br&gt;

  To make it a downloadable file, I have to add it to the installer &lt;i&gt;Files&lt;/i&gt;
  and then select it as a downloadable component in the &lt;i&gt;Media&lt;/i&gt;
  wizard. Therefore, I download &lt;a href="https://prdownloads.sourceforge.net/sweethome3d/FurnitureLibraryEditor-1.2.jar"&gt;FurnitureLibraryEditor-1.2.jar&lt;/a&gt;
  in the &lt;i&gt;Installer&lt;/i&gt;
  directory on my desktop, and add it to the &lt;i&gt;Installation&lt;/i&gt;
  directory node in the &lt;i&gt;Files&lt;/i&gt;
  screen as a single file with the &lt;i&gt;Insert&lt;/i&gt;
  button (the button with a green plus).
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/FilesAddFurnitureLibraryEditorJar-aeda81945feca055238ce3ab7f7c5b.jpg" class="img-fluid" loading="lazy" width="600" height="507"&gt;&lt;/div&gt;


  &lt;br&gt;

  Then I create a new launcher for the Furniture Library Editor as I did for Sweet Home 3D, by clicking on the &lt;i&gt;New launcher&lt;/i&gt;
  icon in &lt;i&gt;Launchers&lt;/i&gt;
  screen.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MyFirstTryWithInstall4j/NewLauncherIcon-9c79b4a33160d086c4b3b1e81591ef98.png" class="img-fluid" loading="lazy" width="89" height="61"&gt;&lt;/div&gt;


  &lt;br&gt;

  This time, I name the executable file as &lt;i&gt;FurnitureLibraryEditor&lt;/i&gt;,
  select the &lt;i&gt;Allow only a single running instance of the application&lt;/i&gt;
  option,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/LauncherConfigureExecutable-13a8d7b54f4c75455bcb27653a671fc.jpg" class="img-fluid" loading="lazy" width="600" height="368"&gt;&lt;/div&gt;


  &lt;br&gt;

  fill the Windows version info resource,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/LauncherConfigureWindowsVersionInfo-ee9629fd13d9c9a42c0d550e1bd9d.jpg" class="img-fluid" loading="lazy" width="600" height="353"&gt;&lt;/div&gt;


  &lt;br&gt;

  configure its &lt;a href="https://sweethome3d.cvs.sourceforge.net/viewvc/sweethome3d/FurnitureLibraryEditor/src/com/eteks/furniturelibraryeditor/swing/resources/aboutIcon.png?revision=1.1"&gt;icon&lt;/a&gt;
  in &lt;i&gt;&lt;/i&gt;
  the &lt;i&gt;Icon&lt;/i&gt;
  step,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/LauncherIcon-dc35c6453d73fc8d284c35228ffd6a8.jpg" class="img-fluid" loading="lazy" width="600" height="378"&gt;&lt;/div&gt;


  &lt;br&gt;

  configure program launch by adding &lt;i&gt;FurnitureLibraryEditor-1.2.jar&lt;/i&gt;
  archive in class path and using &lt;code&gt;com.eteks.furniturelibraryeditor.FurnitureLibraryEditorBootstrap&lt;/code&gt;
  as main class,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/LauncherConfigureJavaInvocation-2e1074205a11a484e3e62451e6fc7a78.jpg" class="img-fluid" loading="lazy" width="600" height="371"&gt;&lt;/div&gt;


  &lt;br&gt;

  and no splash screen. I finally see the new laucher item in install4j.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/FurnitureLibraryEditorLauncher-6c227bc11fe2706cb251dabf4ced58.png" class="img-fluid" loading="lazy" width="466" height="178"&gt;&lt;/div&gt;


  &lt;br&gt;

  To make &lt;i&gt;FurnitureLibraryEditor-1.2.jar&lt;/i&gt;
  and its launcher optional files, I then click on the &lt;i&gt;Installation Components&lt;/i&gt;
  tab to create components that group files by application. I click on the &lt;i&gt;Insert&lt;/i&gt;
  button, enter first the name of the basic component that will contain the Sweet Home 3D application files and click on
  OK.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/NewInstallationComponent-e1d68eb9712266b5d435cebebdc696.jpg" class="img-fluid" loading="lazy" width="600" height="443"&gt;&lt;/div&gt;


  &lt;br&gt;

  In the &lt;i&gt;Files&lt;/i&gt;
  tab, I select all the files except &lt;i&gt;FurnitureLibraryEditor-1.2.jar&lt;/i&gt;
  and its launcher,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallationComponentsSelectSweetHome3DFiles-a410cfc2c349c10625d278e4c70836a.png" class="img-fluid" loading="lazy" width="549" height="473"&gt;&lt;/div&gt;


  &lt;br&gt;

  Then I create a second component for the &lt;i&gt;FurnitureLibraryEditor-1.2.jar&lt;/i&gt;
  file that will be downloaded.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallationComponentsSelectFiles-831af7b0654dc42bb058ede84c966c18.png" class="img-fluid" loading="lazy" width="549" height="360"&gt;&lt;/div&gt;


  &lt;br&gt;

  In the &lt;i&gt;Options&lt;/i&gt;
  tab of that component, I unselect &lt;i&gt;Initially selected for installation&lt;/i&gt;
  option and select &lt;i&gt;Downloadable&lt;/i&gt;
  component
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallationComponentsSelectOptions-c9c119d181bed6fc9fc7fb4f91c8b865.png" class="img-fluid" loading="lazy" width="549" height="360"&gt;&lt;/div&gt;


  &lt;br&gt;

  As the launcher of the Furniture Library Editor won't be downloaded but will be bundled with the installer (launchers
  are small files of 250 KB), I create a third installation component named &lt;i&gt;Furniture Library Editor launcher&lt;/i&gt;
  for it, select &lt;i&gt;[Launcher] FurnitureLibraryEditor&lt;/i&gt;
  file and change the options to hide it to the end users, because it would be useless to ask them to check two options if
  they want to install the Furniture Library Editor.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallationComponentsSelectLauncherOptions-5d115562e3bd6b48548c8dce636f8fa1.png" class="img-fluid" loading="lazy" width="549" height="360"&gt;&lt;/div&gt;


  &lt;br&gt;

  Now that installation components are created, I go to the &lt;i&gt;Installer&lt;/i&gt;
  screen and select the &lt;i&gt;Installation components&lt;/i&gt;
  node, that will be displayed from now on since I created installation components.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallationComponentsScreen-28ce4df29a6829eb409926987f88cac.jpg" class="img-fluid" loading="lazy" width="600" height="582"&gt;&lt;/div&gt;


  &lt;br&gt;

  As I need to select the Furniture Library Editor launcher component if the Furniture Library Editor component is
  selected by the user, I click on the ellipsis button beside &lt;i&gt;Selection change script&lt;/i&gt;
  field and enter the matching Java statement
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallationComponentsScreenScript-3ba352e21165e2859c938591af105442.jpg" class="img-fluid" loading="lazy" width="600" height="385"&gt;&lt;/div&gt;


  &lt;br&gt;

  Each component, screen or action in install4j has a unique ID and I need to find the ID of the Furniture Library Editor
  launcher component to pass a correct value to &lt;code&gt;getInstallationComponentById&lt;/code&gt;
  method call. The IDs of install4j items can be displayed by clicking on the &lt;i&gt;Show IDs&lt;/i&gt;
  button &lt;img alt="Blog image" src="/assets/blog/MoreInstallOptionsWithInstall4j/ShowIDs-33869f77fd9d54dccbfef21be6d3dbff.png" class="" loading="lazy" width="26" height="26"&gt;
  found on many screens, but to avoid closing the editor window, I prefer here to click on the &lt;i&gt;Insert ID&lt;/i&gt;
  button to find the desired ID. This will open a dialog box where I enter the first letters of &amp;quot;&lt;code&gt;Furniture&lt;/code&gt;
  &amp;quot; and find the ID of the component is &lt;i&gt;376&lt;/i&gt;.

  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SelectID-1ecf3e04fab767f1520e27e379456b8.png" class="img-fluid" loading="lazy" width="331" height="266"&gt;&lt;/div&gt;


  &lt;br&gt;

  I click on OK to close the script window, and finally go to the &lt;i&gt;Media&lt;/i&gt;
  screen to update the &lt;i&gt;Windows&lt;/i&gt;
  media file
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/MediaScreen-5b48df8afe613851afe5c3b9e3fe5c.jpg" class="img-fluid" loading="lazy" width="600" height="572"&gt;&lt;/div&gt;


  &lt;br&gt;

  that requires to be completed with the URL &lt;i&gt;http://ovh.dl.sourceforge.net/project/sweethome3d/FurnitureLibraryEditor/&lt;/i&gt;
  where &lt;i&gt;FurnitureLibraryEditor-1.2.jar&lt;/i&gt;
  can be downloaded from.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/MediaInstallerDownloadURL-6ab125a1d802989ef407a875d3dc110.jpg" class="img-fluid" loading="lazy" width="600" height="266"&gt;&lt;/div&gt;


  &lt;br&gt;

  I build a new installer and test it. A new step is now displayed that will let me choose what I want to install.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SweetHome3DInstallerComponentsStep-c6b2258a86ac40d07bb8dfee87f8b386.png" class="img-fluid" loading="lazy" width="516" height="426"&gt;&lt;/div&gt;


  &lt;br&gt;

  I select the Furniture Library Editor option and check that the new application is available in &lt;i&gt;Sweet Home 3D&lt;/i&gt;
  group.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SweetHome3DShortcuts-c6dcfa864cff22b53d7ee331529e1523.png" class="img-fluid" loading="lazy" width="273" height="77"&gt;&lt;/div&gt;


  &lt;br&gt;

  
  &lt;h4 class="mt-5"&gt;Downloading other optional files&lt;/h4&gt;


  &lt;br&gt;
  &lt;div&gt;&lt;br&gt;&lt;br&gt;
    Sweet Home 3D lets the user import pieces of furniture one by one, but also by group of pieces from &lt;i&gt;.sh3f&lt;/i&gt;
    files (that the Furniture Library Editor can edit). At this time, four &lt;i&gt;.sh3f&lt;/i&gt;
    files are available to &lt;a href="https://www.blogger.com/post-edit.g?blogID=5618118655031293495&amp;amp;postID=6571047901551968788"&gt;download&lt;/a&gt;
    400 models separately, but I'm going to offer them as optional files during installation time.
    &lt;br&gt;&lt;br&gt;
    The 4 files to download are these ones:
    &lt;br&gt;&lt;br&gt;&lt;/div&gt;
&lt;br&gt;&lt;br&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href="https://ovh.dl.sourceforge.net/project/sweethome3d/SweetHome3D-models/3DModels-1.1.1/3DModels-Contributions-1.1.1.zip"&gt;Contributed models&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://ovh.dl.sourceforge.net/project/sweethome3d/SweetHome3D-models/3DModels-1.1.1/3DModels-Trees-1.1.1.zip"&gt;Trees&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://ovh.dl.sourceforge.net/project/sweethome3d/SweetHome3D-models/3DModels-1.1.1/3DModels-Scopia-1.1.1.zip"&gt;Scopia models&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://ovh.dl.sourceforge.net/project/sweethome3d/SweetHome3D-models/3DModels-1.1.1/3DModels-KatorLegaz-1.1.1.zip"&gt;Kator and Legaz models&lt;/a&gt;.

    &lt;/li&gt;
  &lt;/ul&gt;
&lt;br&gt;

  Once downloaded, these files should be unzipped in a private directory of Sweet Home 3D that depends on the target
  system. Under Windows 7 and Vista, it should be under the directory &lt;i&gt;C:UsersuserAppDataRoamingeTeksSweet Home 3Dfurniture&lt;/i&gt;
  and under previous versions of Windows &lt;i&gt;C:Documents and SettingsuserApplication DataeTeksSweet Home 3Dfurniture&lt;/i&gt;,
  where &lt;i&gt;user&lt;/i&gt;
  is the user's login name.
  &lt;br&gt;&lt;br&gt;

  This time, unlike during the previous part where I installed an optional program, I'll create &lt;i&gt;an Installation Components&lt;/i&gt;
  associated with no files, then use the &lt;i&gt;Download file&lt;/i&gt;
  and &lt;i&gt;Extract a ZIP file&lt;/i&gt;
  actions.
  &lt;br&gt;&lt;br&gt;

  Thus, I create four additional &lt;i&gt;Installation components&lt;/i&gt;
  in the proper tab of the &lt;i&gt;Files&lt;/i&gt;
  screen. To simplify the way to find them later, I create a custom ID for each of them with a value equal to its name.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallationComponentsInsertSH3FFiles-5b9dd12821f748ca25cadb422f5b3517.jpg" class="img-fluid" loading="lazy" width="600" height="444"&gt;&lt;/div&gt;


  &lt;br&gt;

  Then I unselect the &lt;i&gt;Initially selected for installation&lt;/i&gt;
  option and select the &lt;i&gt;Downloadable component&lt;/i&gt;
  option for the 4 new components.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallationComponentsSelectSH3FOptions-98eebec856db652d0d3383aa42feb7e.png" class="img-fluid" loading="lazy" width="548" height="360"&gt;&lt;/div&gt;


  &lt;br&gt;

  To manage the download of the optional files, I go to the &lt;i&gt;Installer&lt;/i&gt;
  screen, select the &lt;i&gt;Installation&lt;/i&gt;
  node and insert a &lt;i&gt;Download file&lt;/i&gt;
  action.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallerAddDownloadFileAction-7220d8e06ff89e8c94ccd403fe7a4f8.jpg" class="img-fluid" loading="lazy" width="600" height="574"&gt;&lt;/div&gt;


  &lt;br&gt;

  In the properties of the &lt;i&gt;Download file&lt;/i&gt;
  action, I set the &lt;i&gt;URL&lt;/i&gt;
  to &amp;quot;&lt;code&gt;http://ovh.dl.sourceforge.net/project/sweethome3d/SweetHome3D-models/3DModels-1.1.1/3DModels-Contributions-1.1.1.zip&lt;/code&gt;
  &amp;quot;, the &lt;i&gt;Target file&lt;/i&gt;
  to &amp;quot;&lt;code&gt;${installer:sys.workingDir}/3DModels-Contributions-1.1.1.zip&lt;/code&gt;
  &amp;quot; and select the &lt;i&gt;Delete downloaded file on exit&lt;/i&gt;
  since it won't be needed once unzipped.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallerConfigureDownloadFileAction-637fe2bd261f429adfd72f95ef55647.jpg" class="img-fluid" loading="lazy" width="600" height="387"&gt;&lt;/div&gt;


  &lt;br&gt;

  Then I click on the ellipsis button beside the &lt;i&gt;Control Flow / Condition expression&lt;/i&gt;
  field to enter the condition when this action should be executed
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditDownloadFileCondition-b9bde317965ffb2ed20834ec76977d7.png" class="img-fluid" loading="lazy" width="562" height="344"&gt;&lt;/div&gt;


  &lt;br&gt;

  To unzip the downloaded file to the right directory, I insert a &lt;i&gt;Extract a ZIP file&lt;/i&gt;
  action after the &lt;i&gt;Download&lt;/i&gt;
  action.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/ExtractZIPFileAction-caec823e32ec6226c47f53c33240feae.png" class="img-fluid" loading="lazy" width="318" height="348"&gt;&lt;/div&gt;


  &lt;br&gt;

  In the properties of the &lt;i&gt;Extract a ZIP file&lt;/i&gt;
  action, I set the Zip file to &amp;quot;&lt;code&gt;${installer:sys.workingDir}/3DModels-Contributions-1.1.1.zip&lt;/code&gt;
  &amp;quot; and enter a &lt;i&gt;File filter script&lt;/i&gt;
  condition that will extract only files ending with &lt;i&gt;.sh3f&lt;/i&gt;.

  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditFileFilter-ef7a39d1efd23c5b5e67bcbf637a.png" class="img-fluid" loading="lazy" width="539" height="361"&gt;&lt;/div&gt;


  &lt;br&gt;

  I enter &amp;quot;&lt;code&gt;${installer:privateDir}furniture&lt;/code&gt;
  &amp;quot; in &lt;i&gt;Destination directory&lt;/i&gt;
  field because the place where the application configuration data is stored varies from one operating system to the other,
  and set the value of the &lt;i&gt;privateDir&lt;/i&gt;
  variable with a new &lt;i&gt;Set a variable&lt;/i&gt;
  action, setting its script to the corresponding
  &lt;br&gt;&lt;a href="https://sweethome3d.cvs.sourceforge.net/viewvc/sweethome3d/SweetHome3D/src/com/eteks/sweethome3d/tools/OperatingSystem.java?revision=1.17&amp;amp;view=markup#l211"&gt;method&lt;/a&gt;
  in Sweet Home 3D.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditPrivateDirScript-c4d790c868ca3c87da56aa4577622e9.png" class="img-fluid" loading="lazy" width="574" height="531"&gt;&lt;/div&gt;


  &lt;br&gt;

  Finally, I move the &lt;i&gt;Set a variable&lt;/i&gt;
  action two rows up and I create the same &lt;i&gt;Download file&lt;/i&gt;
  / &lt;i&gt;Extract a ZIP file&lt;/i&gt;
  actions for the 3 other optional downloads. Installation screen runs 20 actions now!
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallationActions-941555d62793dfe263f6995bb269cde1.jpg" class="img-fluid" loading="lazy" width="578" height="617"&gt;&lt;/div&gt;


  &lt;br&gt;

  Once built, the new version of the installer displays the options to download the optional files,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SweetHome3DInstallerComponentsWithSh3fStep-ee6fefb5624f2b4c3d29fb61fd329e0.png" class="img-fluid" loading="lazy" width="516" height="343"&gt;&lt;/div&gt;


  &lt;br&gt;

  and if I check some of them, it will download them.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SweetHome3DInstallerDownloadStep-836c4d42a982727daa2b626a1384da4.png" class="img-fluid" loading="lazy" width="516" height="343"&gt;&lt;/div&gt;


  &lt;br&gt;

  
  &lt;h4 class="mt-5"&gt;Setting special options&lt;/h4&gt;


  From the previous parts, you understood that like many other applications, Sweet Home 3D stores its configuration data
  in private directories. But some users want to be able to move an application and its configuration around without
  bothering how to copy this data, and requested to make Sweet Home 3D portable (not across operating systems, but across
  different computers). This ended up by the new &lt;i&gt;com.eteks.sweethome3d.preferencesFolder&lt;/i&gt;
  and &lt;i&gt;com.eteks.sweethome3d.applicationFolders&lt;/i&gt;
  system properties that give the directories where Sweet Home 3D will store its configuration data.
  &lt;br&gt;&lt;br&gt;

  To spare end users the difficulty to set these properties, I'm going to add a new screen shown after the &lt;i&gt;Installation location&lt;/i&gt;
  screen where the user will be able to choose whether he wants to install Sweet Home 3D as a portable application or not,
  when he chose a removable drive as installation destination.
  &lt;br&gt;&lt;br&gt;

  To create this customized screen in install4j, I select the &lt;i&gt;Installation location&lt;/i&gt;
  node in &lt;i&gt;Installer&lt;/i&gt;
  screen, click on the &lt;i&gt;Insert&lt;/i&gt;
  button and choose &lt;i&gt;Add screen&lt;/i&gt;
  option.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallerAddScreen-a036f39930f92f39e1b9fa6a2ecf26.jpg" class="img-fluid" loading="lazy" width="600" height="564"&gt;&lt;/div&gt;


  &lt;br&gt;

  In the &lt;i&gt;Select an Installation Screen&lt;/i&gt;
  dialog box, I choose the &lt;i&gt;Configurable form&lt;/i&gt;
  item in the list of screens and check &lt;i&gt;Insert after selection&lt;/i&gt;
  at the bottom of the dialog box.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/ConfigurableFormScreen-552ae042aa951f63601053ce517fdf66.png" class="img-fluid" loading="lazy" width="290" height="434"&gt;&lt;/div&gt;


  &lt;br&gt;

  Once I click on OK, the new screen is added in the &lt;i&gt;Installer&lt;/i&gt;
  screen sequence.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/NewConfigurableFormScreen-eb30687e18e7fa9eb7c1ddf6bb55c1c2.png" class="img-fluid" loading="lazy" width="578" height="456"&gt;&lt;/div&gt;


  &lt;br&gt;

  I click first on the &lt;i&gt;Configure Form Components&lt;/i&gt;
  button to add a checkbox to the empty form. In the dialog box that appears, I click on the &lt;i&gt;Insert&lt;/i&gt;
  button and choose the &lt;i&gt;Add Form Component&lt;/i&gt;
  option.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/AddFormComponent-9f49632950addb7a3c566128b95e62a5.png" class="img-fluid" loading="lazy" width="556" height="515"&gt;&lt;/div&gt;


  &lt;br&gt;

  This will open another dialog box in which I can choose among more than 30 different components. I choose a &lt;i&gt;Check box&lt;/i&gt;
  component,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SelectCheckBoxComponent-1aed4b7684e9dc6f9442d56d10f729.png" class="img-fluid" loading="lazy" width="309" height="464"&gt;&lt;/div&gt;


  &lt;br&gt;

  and click on OK. In the properties list of the inserted checkbox, I enter &amp;quot;&lt;code&gt;Install as a portable application&lt;/code&gt;
  &amp;quot; as the text check box, enter &amp;quot;&lt;code&gt;portable&lt;/code&gt;
  &amp;quot; as the variable name associated to this check box and select the &lt;i&gt;Initially selected&lt;/i&gt;
  and &lt;i&gt;Request focus&lt;/i&gt;
  check boxes.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/CheckBoxProperties-68ee1b471a718615c8cbbe507339f9dc.png" class="img-fluid" loading="lazy" width="556" height="748"&gt;&lt;/div&gt;


  &lt;br&gt;

  As this new option isn't so easy to understand, I click on the ellipsis button of the &lt;i&gt;Help text&lt;/i&gt;
  field and enter a text that explains this option,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditHelpText-ba17bb35cdb72253611d97525b66756.png" class="img-fluid" loading="lazy" width="607" height="286"&gt;&lt;/div&gt;


  &lt;br&gt;

  and click on OK. Then, I click on the &lt;i&gt;Preview Form&lt;/i&gt;
  button at the top right of the dialog to check how the checkbox and its help text will be shown.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/PreviewHelpText-939eec2dce4a9cd781ae5b5f1f935527.png" class="img-fluid" loading="lazy" width="452" height="274"&gt;&lt;/div&gt;


  &lt;br&gt;

  This looks nice but the screen title and subtitle are still missing! I close the &lt;i&gt;Configure Form Components&lt;/i&gt;
  and click on the &lt;i&gt;Properties&lt;/i&gt;
  tab of the &lt;i&gt;Configurable form&lt;/i&gt;
  node,
  &lt;br&gt;

  where I enter &amp;quot;&lt;code&gt;Removable drive option&lt;/code&gt;
  &amp;quot; in &lt;i&gt;Screen title&lt;/i&gt;
  text field and &amp;quot;&lt;code&gt;Should application installation be portable?&lt;/code&gt;
  &amp;quot; in &lt;i&gt;Screen subtitle&lt;/i&gt;
  text field.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/ConfigurableFormProperties-96488ac61989dad950a1893dd51f8a.png" class="img-fluid" loading="lazy" width="578" height="463"&gt;&lt;/div&gt;


  &lt;br&gt;

  As this screen should be displayed only if the user chose a removable drive, I finally click on the ellipsis button of
  the &lt;i&gt;Condition expression&lt;/i&gt;
  property to enter the condition.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditScreenCondition-e8cd5988b3323ad1d812dece85fb2e9e.png" class="img-fluid" loading="lazy" width="536" height="376"&gt;&lt;/div&gt;


  &lt;br&gt;

  As this condition can be checked only under Windows I check first if the installer is running under Windows with a call
  to &lt;code&gt;Util.isWindows()&lt;/code&gt;,
  then I use the &lt;code&gt;getDriveType&lt;/code&gt;
  method of the &lt;a href="https://resources.ej-technologies.com/install4j/help/api/com/install4j/api/windows/WinFileSystem.html"&gt;WinFileSytem&lt;/a&gt;
  class to check if the installation directory chosen by the user is removable or not.
  &lt;br&gt;&lt;br&gt;

  The new screen is now configured, and I have to use the value of the &lt;i&gt;portable&lt;/i&gt;
  variable bound to the checkbox to configure Sweet Home 3D accordingly on the installation screen. As this variable
  won't exist if the new screen isn't displayed, I predefine it by clicking on the &lt;i&gt;Installer&lt;/i&gt;
  node, then on the &lt;i&gt;Configure Predefined Installer Variables&lt;/i&gt;
  button in the &lt;i&gt;Installer Variables&lt;/i&gt;
  tab.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallerVariables-cae1f07583e6d16ba5b1a6f226682dc.png" class="img-fluid" loading="lazy" width="578" height="560"&gt;&lt;/div&gt;


  &lt;br&gt;

  In the &lt;i&gt;Edit Installer Runtime Variables For &amp;quot;Installer&amp;quot;&lt;/i&gt;
  dialog box, I click on the &lt;i&gt;Insert&lt;/i&gt;
  button and choose the &lt;i&gt;Add New Predefined Installer Variable&lt;/i&gt;
  option.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/AddNewPredefinedInstallerVariable-dec2db788a9634a233e4a657a32c2fa.png" class="img-fluid" loading="lazy" width="481" height="407"&gt;&lt;/div&gt;


  &lt;br&gt;

  I set the name of the new variable as &amp;quot;&lt;code&gt;portable&lt;/code&gt;
  &amp;quot;, set its type to &lt;i&gt;Boolean&lt;/i&gt;
  and its default value to &lt;i&gt;false&lt;/i&gt;.

  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/AddPredefinedInstallerPortableVariable-12f16677e64c6e557b391ae41e1fdaea.png" class="img-fluid" loading="lazy" width="481" height="407"&gt;&lt;/div&gt;


  &lt;br&gt;

  I click on OK and use the &lt;i&gt;portable&lt;/i&gt;
  value in the &lt;i&gt;Installation&lt;/i&gt;
  node to add new VM options that will set the desired system preferences: I select the &lt;i&gt;Set a variable&lt;/i&gt;
  action that defines the &lt;i&gt;privateDir&lt;/i&gt;
  variable to add this new action after it, click on the &lt;i&gt;Insert&lt;/i&gt;
  button, select &lt;i&gt;Add Action&lt;/i&gt;
  option and choose the &lt;i&gt;Add VM options&lt;/i&gt;
  action.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/AddVMOptionsActionAfterSelection-94692edaae775661944c584a1e330bc.png" class="img-fluid" loading="lazy" width="578" height="459"&gt;&lt;/div&gt;


  &lt;br&gt;

  I confirm my choice, select &lt;i&gt;SweetHome3D&lt;/i&gt;
  launcher, enter the two lines
  &lt;br&gt;

  &amp;quot;&lt;code&gt;-Dcom.eteks.sweethome3d.preferencesFolder=${installer:privateDir}&lt;/code&gt;
  &amp;quot; and
  &lt;br&gt;

  &amp;quot;&lt;code&gt;-Dcom.eteks.sweethome3d.applicationFolders=${installer:privateDir}&lt;/code&gt;
  &amp;quot; in its &lt;i&gt;VM options&lt;/i&gt;
  text field, and set its condition expression as &amp;quot;&lt;code&gt;context.getBooleanVariable(&amp;quot;portable&amp;quot;)&lt;/code&gt;
  &amp;quot;
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditVMOptions-6530ff288e8c152341b1dfbec6e77515.png" class="img-fluid" loading="lazy" width="578" height="459"&gt;&lt;/div&gt;


  &lt;br&gt;

  These options reference the variable &lt;i&gt;privateDir&lt;/i&gt;
  whose value must take into account the value of the &lt;i&gt;portable&lt;/i&gt;
  variable, too. Therefore, I select the &lt;i&gt;Set a variable&lt;/i&gt;
  action that defines the &lt;i&gt;privateDir&lt;/i&gt;
  variable and click on the ellipsis beside its &lt;i&gt;Script&lt;/i&gt;
  field to update it.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditPrivateDirScript2-83d419ec7397e649668ba3f9dbadacb7.png" class="img-fluid" loading="lazy" width="591" height="597"&gt;&lt;/div&gt;


  &lt;br&gt;

  While editing this script, I got the &lt;code&gt;context.getVariable(&amp;quot;sys.installationDir&amp;quot;)&lt;/code&gt;
  Java expression that returns the value of the &lt;i&gt;sys.installationDir&lt;/i&gt;
  install4j variable by clicking on the &lt;i&gt;Insert Variable&lt;/i&gt;
  button, chosing &lt;i&gt;Insert Installer Runtime Variable&lt;/i&gt;
  item and selecting the &lt;i&gt;sys.installationDir&lt;/i&gt;
  variable.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SelectInstallerRuntimeVariableAsJavaExpression-77c9ba906366878287debf2b7541633.png" class="img-fluid" loading="lazy" width="500" height="540"&gt;&lt;/div&gt;


  &lt;br&gt;

  I build this updated configuration and try the new version of the installer that displays the new screen if I choose to
  install it on a USB key.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SweetHome3DInstallerPortableStep-887148c449f229994a0f8e188744b4d.png" class="img-fluid" loading="lazy" width="516" height="220"&gt;&lt;/div&gt;


  &lt;br&gt;

  
  &lt;h4 class="mt-5"&gt;Uninstalling a program and its configuration data&lt;/h4&gt;


  Sweet Home 3D stores user preferences and configuration data in private directories to help users to upgrade the
  installed version of the software without losing data. But sometimes some users want to really remove all information
  bound to the installed software. Installers built with install4j are highly configurable, and their uninstaller
  counterpart is as much configurable as the installer, so I'm going to add a screen that will ask the user whether he
  wants to delete Sweet Home 3D private files or not, and add some actions that will handle his answer.
  &lt;br&gt;&lt;br&gt;

  I select the &lt;i&gt;Uninstaller&lt;/i&gt;
  node in &lt;i&gt;Installer&lt;/i&gt;
  screen, click on the &lt;i&gt;Insert&lt;/i&gt;
  button, select the &lt;i&gt;Add Screen&lt;/i&gt;
  option and choose the &lt;i&gt;Additional confirmations&lt;/i&gt;
  screen.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/AdditionalConfirmationsScreen-73aaa289635f17226f1cd9de2f1cb3.jpg" class="img-fluid" loading="lazy" width="600" height="564"&gt;&lt;/div&gt;


  &lt;br&gt;

  Once I click on OK, I move the &lt;i&gt;Additional confirmations&lt;/i&gt;
  screen after &lt;i&gt;Uninstall Welcome&lt;/i&gt;
  screen with the blue arrow button, and click on the &lt;i&gt;Configure Form Components&lt;/i&gt;
  buttons.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/ConfigureFormComponents-3821a31dd7449c37aabba79f4388c65.png" class="img-fluid" loading="lazy" width="578" height="457"&gt;&lt;/div&gt;


  &lt;br&gt;

  In this form, I'm going to add a checkbox to confirm the deletion of Sweet Home 3D private data:
  &lt;br&gt;&lt;br&gt;

  I click on the &lt;i&gt;Insert&lt;/i&gt;
  button, select the &lt;i&gt;Add Form Component&lt;/i&gt;
  option and choose &lt;i&gt;Check box&lt;/i&gt;
  among the list of components.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/AddFormComponentUninstaller-b530cc3cf7b1a367278010b5b3744656.png" class="img-fluid" loading="lazy" width="556" height="511"&gt;&lt;/div&gt;


  &lt;br&gt;

  I enter &amp;quot;&lt;code&gt;Sweet Home 3D private data&lt;/code&gt;
  &amp;quot; as the displayed Text,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SetCheckBoxProperties-5ac4de6e546f7e6bb56386ff2f17f5fe.png" class="img-fluid" loading="lazy" width="556" height="510"&gt;&lt;/div&gt;


  &lt;br&gt;

  and click on the ellipsis beside &lt;i&gt;Help text&lt;/i&gt;
  field to detail what will be deleted.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditPrivateDataHelpText-42852f463b1214278375fbbbb201f5c.png" class="img-fluid" loading="lazy" width="600" height="261"&gt;&lt;/div&gt;


  &lt;br&gt;

  Finally, I enter &amp;quot;&lt;code&gt;privateData&lt;/code&gt;
  &amp;quot; in the &lt;i&gt;Variable name&lt;/i&gt;
  text field associated with this check box.
  &lt;br&gt;&lt;br&gt;

  I close the &lt;i&gt;Configure Form Components&lt;/i&gt;
  dialog box and click on &lt;i&gt;Unistallation&lt;/i&gt;
  node to add a new action to it.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/AddUninstallerAction-696ebd9470858faf6172fd132e2d246d.png" class="img-fluid" loading="lazy" width="578" height="457"&gt;&lt;/div&gt;


  &lt;br&gt;

  I filter the actions list with &amp;quot;&lt;code&gt;delete&lt;/code&gt;
  &amp;quot; and choose the &lt;i&gt;Delete a node or key in the Java preference store&lt;/i&gt;
  action.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/DeleteActions-a96a29651d7b56eb1b6316c138f5a1e6.png" class="img-fluid" loading="lazy" width="337" height="372"&gt;&lt;/div&gt;


  &lt;br&gt;

  I enter the &amp;quot;&lt;code&gt;com.eteks.sweethome3d&lt;/code&gt;
  &amp;quot; package in the properties list, unselect the &lt;i&gt;Only if empty&lt;/i&gt;
  check box and let the &lt;i&gt;Key&lt;/i&gt;
  field empty to delete all the preferences associated to this package node.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SetDeleteJavaPreferencesNodeProperties-de9914b4c34713e8101abfe9b9e3af7b.png" class="img-fluid" loading="lazy" width="578" height="457"&gt;&lt;/div&gt;


  &lt;br&gt;

  I click on the ellipsis beside the &lt;i&gt;Condition expression&lt;/i&gt;
  field, insert the value of the &lt;i&gt;privateData&lt;/i&gt;
  variable to check the condition, and confirm my choice.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditActionCondition-cbc4ec1573fe3f8bf1f0f57238b9af.png" class="img-fluid" loading="lazy" width="536" height="323"&gt;&lt;/div&gt;


  &lt;br&gt;

  To delete private files, I add a &lt;i&gt;Delete files and directories&lt;/i&gt;
  action to &lt;i&gt;Unistallation&lt;/i&gt;
  node with the same &lt;i&gt;Condition expression&lt;/i&gt;
  and select the &lt;i&gt;Recursive&lt;/i&gt;
  option.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SetDeleteFilesProperties-405895e1c107aaa9e7de4815cb6a73.png" class="img-fluid" loading="lazy" width="578" height="457"&gt;&lt;/div&gt;


  &lt;br&gt;

  The files to delete are in the directory referenced by the &lt;i&gt;privateDir&lt;/i&gt;
  variable created at installation time, but I need it also at uninstallation time. Like &lt;i&gt;privateData&lt;/i&gt;
  variable, the value of an installer variable is available in the uninstaller if it's predefined in the installer and
  marked as a response file variable. A &lt;a href="/assets/blog/MoreInstallOptionsWithInstall4j/response-73d496d12bdef5523d22e9df74cac6a.varfile" download="response.varfile"&gt;response file&lt;/a&gt;
  is a properties file that contains key-value pairs for installer variables. This file is created during installation
  process and is reused during uninstallation.
  &lt;br&gt;&lt;br&gt;

  All the variables bound to a form component like the &lt;i&gt;portable&lt;/i&gt;
  variable bound to the &lt;i&gt;Install as a portable application&lt;/i&gt;
  check box, are automatically saved in a response file. But the &lt;i&gt;privateDir&lt;/i&gt;
  variable isn't bound to any component, and I have to define it as a predefined variable and register it as a response
  file variable.
  &lt;br&gt;&lt;br&gt;

  Thus, I click on the &lt;i&gt;Installer&lt;/i&gt;
  node, select &lt;i&gt;Installer Variables&lt;/i&gt;
  and click on the &lt;i&gt;Configure Predefined Installer Variables&lt;/i&gt;
  button.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InstallerConfigurePredefinedVarialbes-477e817ad2db6afab81694aae688fe2.png" class="img-fluid" loading="lazy" width="578" height="593"&gt;&lt;/div&gt;


  &lt;br&gt;

  I click on the &lt;i&gt;Insert&lt;/i&gt;
  button, select the &lt;i&gt;Add Predefined Installer Variable&lt;/i&gt;
  option and enter the name &amp;quot;&lt;code&gt;privateDir&lt;/code&gt;
  &amp;quot;.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/AddPredefinedInstallerPortableDirVariable-5ad5bd7174fa8bd64a694102505228.png" class="img-fluid" loading="lazy" width="594" height="408"&gt;&lt;/div&gt;


  &lt;br&gt;

  I confirm my choice and add a new &lt;i&gt;Run script&lt;/i&gt;
  action to the &lt;i&gt;Startup&lt;/i&gt;
  node
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/RunScriptAction-b8869207de143a8744bc6c24f2287b7.png" class="img-fluid" loading="lazy" width="578" height="459"&gt;&lt;/div&gt;


  &lt;br&gt;

  that will register the &lt;i&gt;privateDir&lt;/i&gt;
  variable as a response file variable.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditRegisterResponseFileVariableScript-42f2a67d53f1ec8d484eab6748fc61.png" class="img-fluid" loading="lazy" width="533" height="346"&gt;&lt;/div&gt;


  &lt;br&gt;

  Finally, I select again the &lt;i&gt;Delete files and directories&lt;/i&gt;
  action, and complete its &lt;i&gt;Files and directories&lt;/i&gt;
  field by clicking on the ellipsis button beside it. In the &lt;i&gt;Edit Files&lt;/i&gt;
  dialog box, I click on the &lt;i&gt;Insert&lt;/i&gt;
  and edit the file name by clicking on the arrow button to select the installer &lt;i&gt;privateDir&lt;/i&gt;
  variable.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SelectFilesToDelete-19f15a851ca8484e806bfe2fc9befdc.png" class="img-fluid" loading="lazy" width="578" height="466"&gt;&lt;/div&gt;


  &lt;br&gt;

  Once done, I can build the media files to test the installer and uninstallers.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/UninstallationNode-7b9cba37cb07374efa72c3db311a8d9.png" class="img-fluid" loading="lazy" width="578" height="462"&gt;&lt;/div&gt;


  &lt;br&gt;

  When I uninstall Sweet Home 3D, I'll get a new screen showing the additional option.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SweetHome3DUninstallerAdditionalStep-1bf65195368182696b63e12898c5fcd.png" class="img-fluid" loading="lazy" width="536" height="428"&gt;&lt;/div&gt;


  &lt;br&gt;

  If I check the option, all the configuration data is deleted as expected.
  &lt;br&gt;&lt;br&gt;&lt;br&gt;

  
  &lt;h4 class="mt-5"&gt;Translating new options&lt;/h4&gt;


  Some texts in the screens and the options added during the two previous steps aren't predefined in install4j, and I'll
  have to translate them. Handling translation in install4j works similarly to &lt;a href="https://download.oracle.com/javase/6/docs/api/java/util/PropertyResourceBundle.html"&gt;Java&lt;/a&gt;
  with properties text files where each translated text is associated to a key. The differences in install4j are that it's
  not mandatory to add a language suffix to each translated properties file and these files can be saved in UTF-8 encoding
  if they use &lt;i&gt;utf8&lt;/i&gt;
  file extension (until Java 6, Java properties file supported only ISO-8859-1 encoding which forces you to write
  characters that don't exist in this encoding with &lt;code&gt;uxxxx&lt;/code&gt;
  sequence).
  &lt;br&gt;&lt;br&gt;

  The properties files used by the installer are defined in the &lt;i&gt;Languages&lt;/i&gt;
  tab of the &lt;i&gt;General Settings&lt;/i&gt;
  screen of the installer project, and after clicking on the &lt;i&gt;New&lt;/i&gt;
  button beside &lt;i&gt;Custom localization file&lt;/i&gt;
  field, I choose to name it &amp;quot;&lt;code&gt;InstallerTranslation.utf8&lt;/code&gt;
  &amp;quot;.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/GeneralSettingsLanguages-509b32c936dd4f7319c666ae1954d47.jpg" class="img-fluid" loading="lazy" width="600" height="551"&gt;&lt;/div&gt;


  &lt;br&gt;

  Once I click on the &lt;i&gt;Create&lt;/i&gt;
  button, a text editor is opened to let me define some properties or override existing ones in the installer. I close the
  editor and prefer to add the properties one by one, by editing the texts to translate where they are defined in the
  project. In the &lt;i&gt;Installer&lt;/i&gt;
  screen, I select the &lt;i&gt;Configurable form&lt;/i&gt;
  node and in its &lt;i&gt;Properties&lt;/i&gt;
  tab, copy to the clipboard the text of the &lt;i&gt;Screen title&lt;/i&gt;
  field, click on the arrow button beside it and select the &lt;i&gt;Insert I18N Message&lt;/i&gt;
  option (I18N means Internationalization, the 18 number matching the the number of letters between the first and the last
  letter of this long word).
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InsertI18NMessage-7da3caf4d5c9a66546ca6dbe282d890.jpg" class="img-fluid" loading="lazy" width="600" height="567"&gt;&lt;/div&gt;


  &lt;br&gt;

  In the &lt;i&gt;Select I18N Message&lt;/i&gt;
  dialog box, I click on the &lt;i&gt;Edit&lt;/i&gt;
  link to enter a new key/value pair in the &lt;i&gt;InstallerTranslation.utf8&lt;/i&gt;
  file.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SelectI18NMessage-eed0fed7812a8dcca6360b5bdd20.png" class="img-fluid" loading="lazy" width="319" height="345"&gt;&lt;/div&gt;


  &lt;br&gt;

  I enter the text &amp;quot;&lt;code&gt;portableScreenTitle=Removable drive option&lt;/code&gt;
  &amp;quot; in the editor,
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/EditI18NFile-a7b5fd21ccfdebe9d471aa881e14c5.png" class="img-fluid" loading="lazy" width="456" height="234"&gt;&lt;/div&gt;


  &lt;br&gt;

  click on OK, and select the new key that appears in the &lt;i&gt;Custom messages&lt;/i&gt;
  list.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/SelectI18NMessage2-cabd49e37c0efa2211bb2baea971485.png" class="img-fluid" loading="lazy" width="319" height="345"&gt;&lt;/div&gt;


  &lt;br&gt;

  Once done, the text of the &lt;i&gt;Screen title&lt;/i&gt;
  field is replaced by &lt;i&gt;${i18n:portableScreenTitle}&lt;/i&gt;.

  &lt;br&gt;&lt;br&gt;

  I perform the same operation for the other 5 new texts that need to be translated.
  &lt;br&gt;&lt;br&gt;

  The two &lt;i&gt;Help&lt;/i&gt;
  texts are replaced by clicking in the &lt;i&gt;Insert Variable&lt;/i&gt;
  button shown in their editor and choosing the &lt;i&gt;Insert I18N Message&lt;/i&gt;
  option.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/InsertI18NMessageForHelpText-f12414f7fb3ed69964aa6d24e55e2e13.jpg" class="img-fluid" loading="lazy" width="600" height="313"&gt;&lt;/div&gt;


  &lt;br&gt;

  Once done with the &lt;a href="/assets/blog/MoreInstallOptionsWithInstall4j/InstallerTranslation-8489d76395a584246c93a1268b5c52bf.utf8" download="InstallerTranslation.utf8"&gt;InstallerTranslation.utf8&lt;/a&gt;
  file, i just have to translate this file in each supported language and add them on the &lt;i&gt;Languages&lt;/i&gt;
  tab of the &lt;i&gt;General Settings&lt;/i&gt;
  screen. For example, I can translate the texts to French in a file &lt;a href="/assets/blog/MoreInstallOptionsWithInstall4j/InstallerTranslationFrench-4de8bb58d02056645bebbfe25445f6af.utf8" download="InstallerTranslationFrench.utf8"&gt;InstallerTranslationFrench.utf8&lt;/a&gt;
  and add it to project.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/FrenchTranslation-2dd03abf8a3389cdae3edab2ac1ae.png" class="img-fluid" loading="lazy" width="555" height="382"&gt;&lt;/div&gt;


  &lt;br&gt;

  
  &lt;h4 class="mt-5"&gt;Installing a program in console or unattended mode&lt;/h4&gt;


  Installing a program with a graphic user interface is nice for most users, but many environments offer only a command
  line interface. install4j offers such a mode without any additional change to the installer:
  &lt;br&gt;

  instead of answering questions with buttons, text fields and check boxes, the end user just uses the keyboard to answer.
  The console mode is used when the argument &lt;code&gt;-c&lt;/code&gt;
  is passed to the installer program. Under Windows XP / Vista / 7, Sweet Home 3D installer can be run with the following
  command:
  &lt;br&gt;
  &lt;pre&gt;start /wait SweetHome3D-3.0-windows.exe -c&lt;/pre&gt;
&lt;br&gt;

  which will give the following results.
  &lt;br&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/MoreInstallOptionsWithInstall4j/ConsoleMode-2af96e79bcfc16781cf1eed421d1ca3.jpg" class="img-fluid" loading="lazy" width="600" height="621"&gt;&lt;/div&gt;


  &lt;br&gt;

  install4j offers also an unattended mode, something that may be very handy when you have to install a program the same
  way on different computers. In that mode launched with a &lt;code&gt;-q&lt;/code&gt;
  argument passed to the installer program, the installation runs by itself until the end without asking any questions.
  The directory where the program should be installed can be specified with the &lt;code&gt;-dir&lt;/code&gt;
  argument and the answers to the installer questions that should be different from their default values can be specified
  in a response file by passing the &lt;code&gt;-varfile&lt;/code&gt;
  argument.
  &lt;br&gt;&lt;br&gt;

  The easiest way to generate such a response file is to run the program in another mode and retrieve the &lt;a href="/assets/blog/MoreInstallOptionsWithInstall4j/response-73d496d12bdef5523d22e9df74cac6a.varfile" download="response.varfile"&gt;response.varfile&lt;/a&gt;
  file created by the installer in the &lt;i&gt;.install4j&lt;/i&gt;
  subdirectory of the directory where program was installed. This file is a text file that contains installer variables
  and their values that may be edited with any text editor if needed. Under Windows XP / Vista / 7, Sweet Home 3D can be
  installed in unattended mode with the following command:
  &lt;br&gt;
  &lt;pre&gt;start /wait SweetHome3D-3.0-windows.exe -q -varfile response.varfile&lt;/pre&gt;
&lt;br&gt;

  
  &lt;h4 class="mt-5"&gt;Conclusion&lt;/h4&gt;


  install4j lets you customize your installer in many ways. You can configure it to install some optional items and
  perform some special operations. You can also use your Java skills to program customized conditions or any required
  piece of code, in an editor that supplies the great features of modern IDEs.</description>
      <category>install4j</category>
      <category>Tutorial</category>
      <pubDate>Tue, 21 Dec 2010 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2010/12/more-installation-options-with-install4j/</guid>
      <dc:creator>Emmanuel</dc:creator>
      <dc:date>2010-12-21T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Beyond installing</title>
      <link>https://www.ej-technologies.com/blog/2010/12/beyond-installing/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=tutorial"&gt;Tutorial&lt;/a&gt; &lt;/p&gt;

  In the two last articles, I showed &lt;a href="https://blog.ej-technologies.com/2010/12/my-first-try-with-install4j-tutorial.html"&gt;how to build an installer with install4j&lt;/a&gt; 
  for &lt;a href="https://www.sweethome3d.com/"&gt;Sweet Home 3D&lt;/a&gt;,
  then &lt;a href="https://blog.ej-technologies.com/2010/12/more-installation-options-with.html"&gt;improve it with various options&lt;/a&gt;.
  But a program lives, and more and more users are used to getting program updates automatically. As install4j includes an
  auto-update feature, I'm going to use it to update Sweet Home 3D when a new version is released. Finally, I'll provide 
  all the nice options that install4j offers for Mac OS X and Linux users by creating a cross platform installer.
  &lt;br&gt;
  
  
  
  &lt;h4 class="mt-5"&gt;Auto-updating&lt;/h4&gt;

  
  install4j offers various ways to check whether updates are available and to manage the launching of the updater. As I 
  want to provide auto-updating without modifying the Sweet Home 3D source code at this moment, I'm going to set options 
  in install4j that will check if a new version of the program is available when the program is launched. The auto-update 
  feature is informed about the availability of a new version thanks to an &lt;i&gt;updates.xml&lt;/i&gt; 
  file I'll have to host at a specified URL. Each time an installer is built, install4j creates a default &lt;i&gt;updates.xml&lt;/i&gt; 
  file in the output directory, and when a new version will be available, I'll just have to upload that file along with 
  the new version of the installer. For the version 3.0 of the installer, this file looks like this:
  &lt;br&gt;
  &lt;pre&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
  &amp;lt;updateDescriptor baseUrl=&amp;quot;&amp;quot;&amp;gt;
  &amp;lt;entry targetMediaFileId=&amp;quot;80&amp;quot; updatableVersionMin=&amp;quot;&amp;quot; updatableVersionMax=&amp;quot;&amp;quot;
    fileName=&amp;quot;SweetHome3D-3.0-windows.exe&amp;quot; newVersion=&amp;quot;3.0&amp;quot; newMediaFileId=&amp;quot;80&amp;quot;
    fileSize=&amp;quot;27361280&amp;quot; bundledJre=&amp;quot;windows-x86-1.6.0_23&amp;quot; archive=&amp;quot;false&amp;quot;&amp;gt;
  &amp;lt;comment language=&amp;quot;en&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;zh_CN&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;cs&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;fr&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;de&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;el&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;hu&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;it&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;ja&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;pl&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;pt_BR&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;ru&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;es&amp;quot; /&amp;gt;
  &amp;lt;comment language=&amp;quot;sv&amp;quot; /&amp;gt;
  &amp;lt;/entry&amp;gt;
  &amp;lt;/updateDescriptor&amp;gt;&lt;/pre&gt;
&lt;br&gt;
  
  To prepare future updates, I have to decide in this version where I'll host the &lt;i&gt;updates.xml&lt;/i&gt; 
  file. Thus, I enter the URL &amp;quot;&lt;code&gt;http://www.sweethome3d.com/download/updates.xml&lt;/code&gt;
  &amp;quot; in &lt;i&gt;Auto-Update Options&lt;/i&gt; 
  tab of the &lt;i&gt;Installer&lt;/i&gt; 
  screen.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/AutoUpdateOptions-638834b8fa663fc18caf1ab8e37f3a5.jpg" class="img-fluid" loading="lazy" width="600" height="416"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Then, in the &lt;i&gt;Screens &amp;amp; Actions&lt;/i&gt; 
  tab, I click on the &lt;i&gt;Insert&lt;/i&gt; 
  button and select the &lt;i&gt;Add Application&lt;/i&gt; 
  menu item.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/AddApplication-e7f104ce132d91ea4bfe03715e657d6.png" class="img-fluid" loading="lazy" width="578" height="456"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  In the &lt;i&gt;Select an Application Template&lt;/i&gt; 
  dialog box, I select the &lt;i&gt;Updater with silent version check&lt;/i&gt; 
  template.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/UpdaterWithSilentVersionCheck-f8b5518cdcd55246607d9af9f0cc4245.png" class="img-fluid" loading="lazy" width="323" height="332"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once I click on OK, a new node is added to &lt;i&gt;Installer&lt;/i&gt; 
  screen for the updater application and I name its &lt;i&gt;Executable&lt;/i&gt; 
  as &amp;quot;&lt;code&gt;SweetHome3DUpdater&lt;/code&gt;
  &amp;quot; in its &lt;i&gt;Properties&lt;/i&gt; 
  tab.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/UpdaterWithSilentVersionCheckProperties-131d715ae8395a4c128d6eedc25f0b4.jpg" class="img-fluid" loading="lazy" width="600" height="387"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  To run this updater automatically when &lt;i&gt;Sweet Home 3D&lt;/i&gt; 
  or &lt;i&gt;Furniture Library Editor&lt;/i&gt; 
  are launched, I click on the &lt;i&gt;Launcher Integration&lt;/i&gt; 
  tab, select the &lt;i&gt;Start automatically when launcher is executed&lt;/i&gt; 
  option and choose to &lt;i&gt;Always&lt;/i&gt; 
  run the updater.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/UpdaterWithSilentVersionCheckLauncherIntegration-451170489cfbec0ad5b8733eddbacb.jpg" class="img-fluid" loading="lazy" width="600" height="387"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Minimum auto-updating is now integrated and I just have to build a new installer to make it available for a future 
  version of the program.
  &lt;br&gt;&lt;br&gt;
  
  To test it, I immediately install version 3.0 of the program, generate an installer with a fake 3.0.1 higher version 
  number,
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/GeneralSettingsFakeVersion-dc29af3d8568cc91a026bb70b9b66b.jpg" class="img-fluid" loading="lazy" width="600" height="488"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  and upload &lt;i&gt;SweetHome3D-3.0.1-windows.exe&lt;/i&gt; 
  and &lt;i&gt;updates.xml&lt;/i&gt; 
  to &lt;i&gt;http://www.sweethome3d.com/download&lt;/i&gt; 
  after adding a small comment in default language to &lt;i&gt;updates.xml&lt;/i&gt; 
  file.
  &lt;br&gt;
  &lt;pre&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
  &amp;lt;updateDescriptor baseUrl=&amp;quot;&amp;quot;&amp;gt;
  &amp;lt;entry targetMediaFileId=&amp;quot;80&amp;quot; updatableVersionMin=&amp;quot;&amp;quot; updatableVersionMax=&amp;quot;&amp;quot;
    fileName=&amp;quot;SweetHome3D-3.0.1-windows.exe&amp;quot; newVersion=&amp;quot;3.0.1&amp;quot; newMediaFileId=&amp;quot;80&amp;quot;
    fileSize=&amp;quot;27427328&amp;quot; bundledJre=&amp;quot;windows-x86-1.6.0_23&amp;quot; archive=&amp;quot;false&amp;quot;&amp;gt;
  &amp;lt;comment&amp;gt;Fixed minor bugs&amp;lt;/comment/&amp;gt;
  &amp;lt;/entry&amp;gt;
  &amp;lt;/updateDescriptor&amp;gt;&lt;/pre&gt;
&lt;br&gt;
  
  Then, a few seconds after I launch Sweet Home 3D version 3.0, the updater is launched and offers to download Sweet Home 
  3D version 3.0.1.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/UpdaterStep1-8694b3604168e9c7c05b1db424f29.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  If I click on the &lt;i&gt;Show comments&lt;/i&gt; 
  link, I get the comments entered in the &lt;i&gt;updates.xml&lt;/i&gt; 
  file.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/UpdaterComment-e96e89372aad6affdfb4cb6f64a95a6.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Otherwise the download of the new version is started.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/UpdaterStep2-1f2017df442e8a4732401d7d68462f0.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once downloaded, I choose to execute the downloaded installer.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/UpdaterStep3-f0223e51e220a76240c2f6a826dc1e8c.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Because the installer detects that a previous version is installed on my computer, it asks me whether to update or to 
  install it in another location before performing the installation.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/UpdaterStep4-ed52ba99c6599d7bb93683e57a4fbe.png" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Managing cross platform installers&lt;/h4&gt;

  
  Since install4j is a Java program itself, it's easy to prepare installers for each operating system where JVMs are 
  available. If an application shares the same list of files (which is generally the case), I would just have to create a 
  different media for each targeted operating system with its dedicated JRE. It's a little more complicated for Sweet Home
  3D since it requires different Java 3D DLLs for different platforms. Therefore, I download Java 3D zip binaries for &lt;a href="https://download.java.net/media/java3d/builds/release/1.5.2/j3d-1_5_2-macosx.zip"&gt;Mac OS X&lt;/a&gt;,
 &lt;a href="https://download.java.net/media/java3d/builds/release/1.5.2/j3d-1_5_2-linux-i586.zip"&gt;Linux 32 bits&lt;/a&gt; 
  and &lt;a href="https://download.java.net/media/java3d/builds/release/1.5.2/j3d-1_5_2-linux-amd64.zip"&gt;Linux 64 bits&lt;/a&gt; 
  at &lt;a href="https://java3d.dev.java.net/binary-builds.html"&gt;Java 3D release builds page&lt;/a&gt;.
  Each of these zipped files contains a &lt;i&gt;j3d-jre.zip&lt;/i&gt; 
  file, and each &lt;i&gt;j3d-jre.zip&lt;/i&gt; 
  file contains the three &lt;i&gt;j3dcore.jar&lt;/i&gt;,
 &lt;i&gt;vectmath.jar&lt;/i&gt; 
  and &lt;i&gt;j3dutils.jar&lt;/i&gt; 
  files which are the same as the Windows ones I have already, plus some DLLs like &lt;i&gt;libj3dcore-ogl.so&lt;/i&gt; 
  under Linux that I have to keep. Under Mac OS X, Java 3D works thanks to &lt;a href="https://kenai.com/projects/jogl/"&gt;JOGL&lt;/a&gt; 
  library, that I &lt;a href="https://download.java.net/media/jogl/builds/archive/jsr-231-1.1.1/jogl-1.1.1-macosx-universal.zip"&gt;download&lt;/a&gt; 
  too.
  &lt;br&gt;
  
  Once I retrieve all these files, I copy the ones required by Java 3D in a &lt;i&gt;lib&lt;/i&gt; 
  subdirectory of &lt;i&gt;Install&lt;/i&gt; 
  directory and reorganize them to avoid any name conflict.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/Java3DDLLs-545a6835fb9e25f20157e010884e84.png" class="img-fluid" loading="lazy" width="236" height="267"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  These files will have to be copied in the &lt;i&gt;lib&lt;/i&gt; 
  subdirectory of the destination directory where program will be installed. To copy only the Java 3D files required for a
  given operating system, I'm going to create one file set for each system in install4j. In the &lt;i&gt;Files&lt;/i&gt; 
  screen, I click first on the &lt;i&gt;Insert&lt;/i&gt; 
  button and choose the &lt;i&gt;New File Set&lt;/i&gt; 
  option.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/NewFileSet-8b1ac26b8c0eef4d0d92058a8342cd4.jpg" class="img-fluid" loading="lazy" width="600" height="531"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I enter the general name &amp;quot;&lt;code&gt;Windows&lt;/code&gt;
  &amp;quot;,
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/WindowsFileSet-3a1f06a563d9b2aab2ae43cf69505b.png" class="img-fluid" loading="lazy" width="400" height="155"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  and renew the &lt;i&gt;New File Set&lt;/i&gt; 
  operation for Mac OS X, Linux 32 bits and Linux 64 bits.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/NewFileSets-15a45a12a987e01551cbbc81eb4d7.png" class="img-fluid" loading="lazy" width="484" height="493"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Then, for each of these file sets, I create a new &lt;i&gt;lib&lt;/i&gt; 
  folder by clicking on the &lt;i&gt;Insert&lt;/i&gt; 
  button and choosing the &lt;i&gt;New Folder&lt;/i&gt; 
  option.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/LibSubDirectories-96682be2183c422515ad6c7632cbfb.png" class="img-fluid" loading="lazy" width="169" height="193"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once the &lt;i&gt;lib&lt;/i&gt; 
  subdirectories are ready, I select the one in &lt;i&gt;Windows&lt;/i&gt; 
  file set, click on the &lt;i&gt;Insert&lt;/i&gt; 
  button and choose &lt;i&gt;Add Files and Directories&lt;/i&gt; 
  option.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/AddFilesAndDirectories-116737b2ea431496d14f9ff91a1238bd.png" class="img-fluid" loading="lazy" width="484" height="318"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  In the &lt;i&gt;Add Files and Directories&lt;/i&gt; 
  dialog box, I choose the &lt;i&gt;Single files&lt;/i&gt; 
  option,
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/SelectSingleFiles-4de54f3822163dbee46790178e6cf24d.png" class="img-fluid" loading="lazy" width="590" height="317"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  click on the &lt;i&gt;Next&lt;/i&gt; 
  button, and select the four Java 3D DLLs for Windows in &lt;i&gt;C:Program Files (x86)Sweet Home 3D 3.0lib&lt;/i&gt; 
  directory.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/SelectWindowsFiles-a7952e9312a0dd137bf5f9139ea4d887.png" class="img-fluid" loading="lazy" width="590" height="363"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I confirm my choice, and repeat the same operation to add the Java 3D files that depends on Mac OS X, Linux 32 bits and 
  Linux 64 bits.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/Java3DFileSets-46ae85cfaa9c284c71cb816f451fadd.png" class="img-fluid" loading="lazy" width="600" height="468"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  To get consistent file sets, I also have to remove the Java 3D DLLs from &lt;i&gt;Default file set&lt;/i&gt;
  : I select the &lt;i&gt;Content of C:Program Files (x86)Sweet Home 3D 3.0lib into subdirectory lib&lt;/i&gt; 
  node, click on the &lt;i&gt;Edit Entry&lt;/i&gt; 
  button,
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/EditEntry-e222b9ad7994f4f1b253afd2e2f73.png" class="img-fluid" loading="lazy" width="600" height="368"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  and in the &lt;i&gt;Modify Entry in the Distribution Tree&lt;/i&gt; 
  dialog box, I change the entry type to &lt;i&gt;Single files&lt;/i&gt; 
  and select all the files in &lt;i&gt;C:Program Files (x86)Sweet Home 3D 3.0lib&lt;/i&gt; 
  directory except the four DLLs.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/SelectSweetHome3DFiles-e1a510c5d5584dc4da91d0392334986.png" class="img-fluid" loading="lazy" width="600" height="434"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once I chose these JAR files, I move them to the &lt;i&gt;lib&lt;/i&gt; 
  subdirectory of the installation directory.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/MoveFilesToLibSubdirectory-497b46c68c5be0e9d70e59ddaae0d1.png" class="img-fluid" loading="lazy" width="600" height="337"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Finally, I click on the &lt;i&gt;Installation Components&lt;/i&gt; 
  tab, select the &lt;i&gt;Sweet Home 3D component&lt;/i&gt; 
  and include &lt;i&gt;Windows&lt;/i&gt;,
 &lt;i&gt;Mac OS X&lt;/i&gt;,
 &lt;i&gt;Linux 32 bits&lt;/i&gt; 
  and &lt;i&gt;Linux 64 bits&lt;/i&gt; 
  file sets.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/InstallationComponentsFileSets-19f18d7e5cf9d18f32cc5d56f6d6e2.png" class="img-fluid" loading="lazy" width="611" height="522"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Now that file sets are ready, I'm going to use them in the &lt;i&gt;Windows&lt;/i&gt; 
  existing media file and in the new media files for Mac OS X and Linux. I go to the &lt;i&gt;Media&lt;/i&gt; 
  screen,
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/MediaScreen-ce5d92205b40c6b2f7da87bb4d514b2e.png" class="img-fluid" loading="lazy" width="600" height="528"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  and double-click on the &lt;i&gt;Windows&lt;/i&gt; 
  media file to exclude the file sets that are not needed for Windows.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/ExcludedFilesInWindowsMedia-9e41e0513ce81172f045bdfa94a06c3.png" class="img-fluid" loading="lazy" width="593" height="343"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Then, I click on &lt;i&gt;New media file&lt;/i&gt; 
  icon to create Linux 32 bits media file. In the &lt;i&gt;Installer type&lt;/i&gt; 
  combo box, I choose &lt;i&gt;Unix/Linux GUI installer&lt;/i&gt;,

  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/LinuxMediaFileType-37bd5f661e23df575bd86c618502712.jpg" class="img-fluid" loading="lazy" width="592" height="408"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  and click on the &lt;i&gt;Next&lt;/i&gt; 
  button until the &lt;i&gt;Data files&lt;/i&gt; 
  step where I enter the same download URL &lt;i&gt;http://ovh.dl.sourceforge.net/project/sweethome3d/FurnitureLibraryEditor/&lt;/i&gt; 
  for the &lt;i&gt;Furniture Library Editor&lt;/i&gt; 
  as I did for &lt;i&gt;Windows&lt;/i&gt; 
  media.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/LinuxMediaFileDataFiles-c44126e55652665548f3866094ab7d89.png" class="img-fluid" loading="lazy" width="592" height="364"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  In the &lt;i&gt;Bundled JRE&lt;/i&gt; 
  step, I click on the &lt;i&gt;Download JREs&lt;/i&gt; 
  button,
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/LinuxMediaFileBundledJRE2-3c5ff4b9cddaaf30271172f4aaab130.png" class="img-fluid" loading="lazy" width="592" height="486"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  to download &lt;i&gt;Linux (x86) 1.6.0_23 JRE&lt;/i&gt;.

  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/SelectJREForDownload-2dd12ac65a2341a643f97ad4dec3f94e.png" class="img-fluid" loading="lazy" width="535" height="302"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once downloaded, I choose this JRE,
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/LinuxMediaFileBundledJRE2-3c5ff4b9cddaaf30271172f4aaab130.png" class="img-fluid" loading="lazy" width="592" height="486"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  customize the installer by setting the media file name to &amp;quot;&lt;code&gt;${compiler:sys.shortName}-${compiler:sys.version}-linux-32bits&lt;/code&gt;
  &amp;quot;
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/LinuxMediaFileName-102e2063131c54328c697f5e69d063cf.png" class="img-fluid" loading="lazy" width="592" height="363"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  and by excluding the file sets of the other operating systems.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/LinuxMediaFileExcludedFiles-a5476ebea3e25f87f37176e87d0fee9.png" class="img-fluid" loading="lazy" width="592" height="364"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Once the &lt;i&gt;Media&lt;/i&gt; 
  wizard is finished for Linux 32 bits, I create similarly the media file for Linux 64 bits, and rename them as &lt;i&gt;Linux 32 bits&lt;/i&gt; 
  and &lt;i&gt;Linux 64 bits&lt;/i&gt; 
  with the &lt;i&gt;Rename Media File&lt;/i&gt; 
  menu item available in their contextual menu, to be able to distinguish more easily.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/RenameMediaFile-aa77ca2abdfa8974663e1f14a25cd47.png" class="img-fluid" loading="lazy" width="422" height="172"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Mac OS X installer is very similar to the other installers except it doesn't need to download a JRE and it requires an 
  additional VM option to run: as Mac OS X provides its own JRE with the Java 3D 1.3.1 library in extension directory, I 
  have to change the &lt;i&gt;java.ext.dirs&lt;/i&gt; 
  system property to ensure the Java 3D 1.5.2 library installed with Sweet Home 3D will have a higher priority. To set 
  this VM option that should replace the &lt;i&gt;-Djava.library.path=lib&lt;/i&gt; 
  existing one, I create the &lt;i&gt;java3dDllsVMOption&lt;/i&gt; 
  compiler variable by clicking on the &lt;i&gt;Insert&lt;/i&gt; 
  button in the &lt;i&gt;Compiler Variables&lt;/i&gt; 
  tab of the &lt;i&gt;General Settings&lt;/i&gt; 
  screen and enter &amp;quot;&lt;code&gt;-Djava.library.path=lib&lt;/code&gt;
  &amp;quot; as its default value.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/NewCompilerVariable-2bb814e879f8087398819d38defb59.jpg" class="img-fluid" loading="lazy" width="600" height="466"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Then in the Java invocation step of &lt;i&gt;SweetHome3D&lt;/i&gt; 
  launcher, I update the text of the VM Parameters field with &lt;i&gt;${compiler:java3dDllsVMOption}&lt;/i&gt;.

  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/SweetHome3DLauncherJavaInvocation-65ad67489f6fd39a3b74d9f861bb48.jpg" class="img-fluid" loading="lazy" width="600" height="389"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  Finally, I click on &lt;i&gt;New media file&lt;/i&gt; 
  icon, choose &lt;i&gt;Mac OS X folder Installer&lt;/i&gt; 
  type,
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/MacOSXMediaFileType-39719bbdc8caf449b7389541e7e7a4aa.jpg" class="img-fluid" loading="lazy" width="592" height="409"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  update the download URL, exclude the file sets of the other operating systems and in &lt;i&gt;Compiler variables&lt;/i&gt; 
  step, override &lt;i&gt;java3dDllsVMOption&lt;/i&gt; 
  variable with the value
  &lt;br&gt;&lt;code&gt;-Djava.ext.dirs=lib:/Library/Java/Extensions:/System/Library/Java/Extensions:&lt;br&gt;
    /System/Library/Frameworks/JavaVM.framework/Versions/1.5/Home/lib/ext&lt;/code&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/MacOSXMediaFileCompilerVariables-35b81d98e2184c283eadbef8efea5715.png" class="img-fluid" loading="lazy" width="592" height="328"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  I can now build the 4 installers and test them on each operating system.
  &lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/WindowsInstaller-cee49a1066af72ae512e44f555d389b7.jpg" class="img-fluid" loading="lazy" width="516" height="428"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/MacOSXInstaller-a7ee8a8fb55b4f1fce3583d286a16e34.jpg" class="img-fluid" loading="lazy" width="501" height="413"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/Linux32bitsInstaller-8aaa8d4ace78d3c6cf985e923c4e8a.jpg" class="img-fluid" loading="lazy" width="510" height="420"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/BeyondInstalling/Linux64bitsInstaller-f2e3f282e18991503e8096d29895b278.jpg" class="img-fluid" loading="lazy" width="510" height="420"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  
  
  &lt;h4 class="mt-5"&gt;Conclusion&lt;/h4&gt;

  
  install4j offers many options to help with auto-updating installed software and to deliver Java cross platform 
  installers and uninstallers. install4j can create installers for all supported platforms on any supported platform, so 
  on a Linux build server you can create installers for Windows and Mac OS X as well.</description>
      <category>install4j</category>
      <category>Tutorial</category>
      <pubDate>Fri, 31 Dec 2010 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2010/12/beyond-installing/</guid>
      <dc:creator>Emmanuel</dc:creator>
      <dc:date>2010-12-31T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Methods statistics and exceptional method runs</title>
      <link>https://www.ej-technologies.com/blog/2011/02/methods-statistics-and-exceptional-method-runs/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I explain how to analyze exceptionally slow invocations of frequently invoked methods. By using
    the method statistics and exceptional method run features in JProfiler, the slowest invocations are shown separately in 
    the call tree. &lt;br&gt;&lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/lD7p31WbA-4" title="Play video 'Methods statistics and exceptional method runs'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/lD7p31WbA-4-c26f7c3e9c4e2057b54b3f1b3c6a43d.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    The test class that is profiled in this screen cast is given below:
  &lt;/p&gt;

  
  &lt;pre&gt;
import java.util.Random;
  
public class MethodStatisticsTest {

    private static Random random = new Random(0);

    public static void main(String[] args) {
        while (true) {
            doCriticalTask();
        }
    }

    private static void doCriticalTask() {
        if (random.nextInt(1000) % 999 == 0) {
            implOne();
        } else {
            implTwo();
        }
    }

    private static void implOne() {
        for (int i = 0; i &amp;lt; 100000; i++) {
            Math.sqrt(i);
        }
    }

    private static void implTwo() {
        for (int i = 0; i &amp;lt; 1000; i++) {
            Math.sqrt(i);
        }
    }
}&lt;/pre&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Sat, 12 Feb 2011 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/02/methods-statistics-and-exceptional-method-runs/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-02-12T08:00:57Z</dc:date>
    </item>
    <item>
      <title>CPU profiling: Sampling and instrumentation</title>
      <link>https://www.ej-technologies.com/blog/2011/08/cpu-profiling-sampling-and-instrumentation/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In this screencast, I explain the two modes of CPU profiling, sampling and instrumentation and how they are activated in
    the JProfiler GUI. Choosing and understanding these modes is important for getting good results.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/XMUNKBxdQYk" title="Play video 'CPU profiling: Sampling and instrumentation'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/XMUNKBxdQYk-3bb4c8f21f7b7e6cbd96675ef3d3fd0.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Mon, 29 Aug 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/08/cpu-profiling-sampling-and-instrumentation/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-08-29T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Probes overview</title>
      <link>https://www.ej-technologies.com/blog/2011/08/probes-overview/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screen cast below, I give a short overview of the capabilities of probes and the built-in probes that are 
    included in JProfiler 7.0.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/4HISYU4A1hM" title="Play video 'Probes overview'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/4HISYU4A1hM-b27343cc6182ca58ddea1313b54d2fb7.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 30 Aug 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/08/probes-overview/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-08-30T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Analyzing long-running AWT events with JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2011/08/analyzing-long-running-awt-events-with-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I show how &lt;a href="https://blog.ej-technologies.com/2011/02/methods-statistics-and-exceptional.html"&gt;exceptional method recording&lt;/a&gt;
    and &lt;a href="https://blog.ej-technologies.com/2011/08/request-tracking.html"&gt;request tracking&lt;/a&gt;
    are combined for analyzing long-running AWT events in JProfiler.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/aQ488qqvQQM" title="Play video 'Analyzing long-running AWT events with JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/aQ488qqvQQM-beefae46c564b9b5e31bb06e4d7536dc.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 31 Aug 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/08/analyzing-long-running-awt-events-with-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-08-31T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Request tracking</title>
      <link>https://www.ej-technologies.com/blog/2011/08/request-tracking/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In this screencast, I explain what request tracking is and how to use it taking the example of executors in the 
    java.util.concurrent package.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/VhJpo96iWm0" title="Play video 'Request tracking'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/VhJpo96iWm0-623e68223d1393d8d2662336e05b6f42.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 31 Aug 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/08/request-tracking/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-08-31T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Filtering in the reference view of the heap walker</title>
      <link>https://www.ej-technologies.com/blog/2011/09/filtering-in-the-reference-view-of-the-heap-walker/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast below, I show the powerful filtering capabilities in the outgoing reference view of the heap walker 
    that allow you to find objects based on primitive field values, outgoing references or code snippets.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/NRP4qAC7ESs" title="Play video 'Filtering in the reference view of the heap walker'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/NRP4qAC7ESs-d12fb3c9d98b6c6f399532a60f524bd.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Thu, 01 Sep 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/09/filtering-in-the-reference-view-of-the-heap-walker/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-09-01T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Heap walker graph: Finding paths between selected instances</title>
      <link>https://www.ej-technologies.com/blog/2011/09/heap-walker-graph-finding-paths-between-selected-instances/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In this screencast, I discuss the graph view of the heap walker (new in JProfiler 7.0) and how to search for reference 
    paths between two selected objects. Also, I show how to resolve transitive references in the biggest objects view with 
    the help of the graph view.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/yivxfFSKqO4" title="Play video 'Heap walker graph: Finding paths between selected instances'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/yivxfFSKqO4-e5e90b5db5e47efd85a24d93a42bd5.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 02 Sep 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/09/heap-walker-graph-finding-paths-between-selected-instances/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-09-02T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Inspections in the heap walker</title>
      <link>https://www.ej-technologies.com/blog/2011/09/inspections-in-the-heap-walker/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In this screencast, I show what inspections are available in in JProfiler's heap walker and what they are capable of. 
    Also featured is the powerful custom grouping inspection that lets you group object sets with a code snippet that is 
    directly entered in the JProfiler GUI.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/cuL--YlWOuM" title="Play video 'Inspections in the heap walker'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/cuL--YlWOuM-4dfdbe4aedb0512ed4463c5a3565d483.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Sun, 04 Sep 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/09/inspections-in-the-heap-walker/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-09-04T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Creating a custom probe</title>
      <link>https://www.ej-technologies.com/blog/2011/09/creating-a-custom-probe/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This version is outdated. There is a &lt;a href="https://www.ej-technologies.com/blog/2022/08/how-to-configure-a-script-probe-in-jprofiler/"&gt;newer version&lt;/a&gt;
    of this screen cast.
  &lt;/p&gt;

  
  &lt;p&gt;
    In this screen cast I show how to create a simple custom probe that measures how often the paint method of the &amp;quot;Animated
    Bezier Curve&amp;quot; demo is called together with clip bounds information. The example custom probe features events, 
    telemetries and hot spots view.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/p3LHp0tDyNw" title="Play video 'Creating a custom probe'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/p3LHp0tDyNw-34fa84bc105042ecb3ea1edae0b84735.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 06 Sep 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/09/creating-a-custom-probe/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-09-06T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Using the "Run interceptor script" trigger action</title>
      <link>https://www.ej-technologies.com/blog/2011/09/using-the-run-interceptor-script-trigger-action/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In the screen cast below I show how to use the &amp;quot;Run interceptor script&amp;quot; trigger action in a method trigger to print out 
    some internal state of the application for debugging purposes. This is done without recompiling or restarting the 
    application.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/n2viW0vGTJQ" title="Play video 'Using the &amp;quot;Run interceptor script&amp;quot; trigger action'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/n2viW0vGTJQ-502bf77ea81b794d4a9cd1bf1922d70.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 07 Sep 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/09/using-the-run-interceptor-script-trigger-action/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-09-07T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Sampling vs. Instrumentation</title>
      <link>https://www.ej-technologies.com/blog/2011/10/sampling-vs-instrumentation/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  Fabian Lange from codecentric has written an &lt;a href="https://blog.codecentric.de/en/2011/10/measure-java-performance-sampling-or-instrumentation/"&gt;excellent article&lt;/a&gt; 
  on the differences between sampling and instrumentation.
  &lt;br&gt;&lt;br&gt;
  
  Sampling and instrumentation are the two modes how methods are measured for CPU profiling. Both have advantages and 
  disadvantages and it depends on the use case which is better for you.
  &lt;br&gt;&lt;br&gt;
  
  This decision is already prominently featured in JProfiler when you start a new session for the first time, as shown in 
  this &lt;a href="https://blog.ej-technologies.com/2011/08/cpu-profiling-sampling-and.html"&gt;screen cast&lt;/a&gt;.</description>
      <category>JProfiler</category>
      <pubDate>Sat, 08 Oct 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/10/sampling-vs-instrumentation/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-10-08T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Java profiling comes to Linux ARM</title>
      <link>https://www.ej-technologies.com/blog/2011/10/java-profiling-comes-to-linux-arm/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  Up to now, there was no good solution for profiling Java code on embedded systems. With the 7.0.1 release of JProfiler, 
  we have introduced support for the Linux ARM platform. The native agent libraries in the &lt;code&gt;bin/linux-arm&lt;/code&gt; 
  directory work with the official &lt;a href="https://www.oracle.com/technetwork/java/embedded/overview/getstarted/index.html"&gt;Java SE for embedded&lt;/a&gt; 
  from Oracle.
  
  &lt;br&gt;&lt;br&gt;

  On the embedded device, you just add the VM parameter &lt;code&gt;-agentpath:[path to libjprofilerti.dll]&lt;/code&gt; 
  to the profiled JVM. In the JProfiler GUI on your development machine, you create a session of type &amp;quot;Attach to profiled 
  JVM&amp;quot; to start profiling.
  &lt;br&gt;&lt;br&gt;
  &lt;div&gt;&lt;/div&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/s640/remoteSession-9f7c70d339182e19608272ed8fe9c10.png" class="img-fluid" loading="lazy" width="591" height="640"&gt;&lt;/div&gt;

  
  &lt;br&gt;</description>
      <category>JProfiler</category>
      <pubDate>Fri, 14 Oct 2011 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/10/java-profiling-comes-to-linux-arm/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-10-14T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling with IntelliJ IDEA 11</title>
      <link>https://www.ej-technologies.com/blog/2011/12/profiling-with-intellij-idea-11/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  As always, we try to provide an &lt;a href="https://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt; 
  plugin immediately when a new major version of IDEA is released.
  &lt;br&gt;&lt;br&gt;
  
  Most of the time, a release of IDEA does not coincide with a JProfiler release, so we release the plugin separately in 
  the plugin manager. To install the JProfiler plugin in IDEA (both community and ultimate editions), click on &amp;quot;Browse 
  repositories&amp;quot; in the plugin manager and look for &amp;quot;JProfiler&amp;quot;.
  &lt;br&gt;&lt;br&gt;
  
  The plugin will be bundled in the upcoming JProfiler 7.1 release.
  &lt;br&gt;&lt;br&gt;&lt;b&gt;Update (2012-01-16)&lt;/b&gt;
  : By mistake, the plugin version (different from the JProfiler version) decreased from 10.3 to 10.2, so many update 
  problems were caused by this. Now the plugin version has been increased to 11.0 and the update should work if you had 
  10.2 or 10.3 installed previously.
  &lt;br&gt;&lt;br&gt;</description>
      <category>JProfiler</category>
      <pubDate>Fri, 09 Dec 2011 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2011/12/profiling-with-intellij-idea-11/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2011-12-09T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling JPA/Hibernate</title>
      <link>https://www.ej-technologies.com/blog/2012/01/profiling-jpa-hibernate/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    The screen cast below shows the capabilities of the JPA/Hibernate probe in JProfiler. It presents the events view of the
    probe that shows a chronological progression of persistence operations as well as the hot spots view that shows back 
    traces and associated JDBC statements.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/2C4NfjNcKl8" title="Play video 'Profiling JPA/Hibernate'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/2C4NfjNcKl8-62279f228b545e4c247db9686ff8e226.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Thu, 26 Jan 2012 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2012/01/profiling-jpa-hibernate/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2012-01-26T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Using the probe tracker</title>
      <link>https://www.ej-technologies.com/blog/2012/01/using-the-probe-tracker/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how the probe tracker can be used to record fine-grained chronological information for selected 
    hot spots and control objects, such as JDBC connections. The probe tracker is available for all probes in JProfiler.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/0tDjbWjN5OE" title="Play video 'Using the probe tracker'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/0tDjbWjN5OE-cbaf7a72bf32a7e8d91e0db61f0fe81.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 27 Jan 2012 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2012/01/using-the-probe-tracker/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2012-01-27T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Attaching to Windows services for Java profiling</title>
      <link>https://www.ej-technologies.com/blog/2012/02/attaching-to-windows-services-for-java-profiling/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  Several profilers can attach to running JVMs, but only JProfiler can attach to Windows services. It is very easy to do:
  &lt;br&gt;&lt;br&gt;
  
  1.Start &amp;quot;Quick attach&amp;quot;:
  &lt;br&gt;&lt;br&gt;
  &lt;div&gt;&lt;/div&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/pictures/quick_attach-2331496216751e9db3c5c635296a8448.png" class="img-fluid" loading="lazy" width="444" height="379"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;
  
  2. All JVMs are shown that run with your user account. Select the &amp;quot;Show services&amp;quot; button at the top:
  &lt;br&gt;&lt;br&gt;
  &lt;div&gt;&lt;/div&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/pictures/attach_no_services-733db178eeeaed1c9df849c231a7202.png" class="img-fluid" loading="lazy" width="496" height="400"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;
  &lt;div&gt;
    3. Select your service:
  
  &lt;/div&gt;
&lt;br&gt;&lt;br&gt;
  &lt;div&gt;&lt;/div&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/pictures/attach_services-6dc7a0bdf8cac3588e25c7b9ff7e144.png" class="img-fluid" loading="lazy" width="496" height="400"&gt;&lt;/div&gt;

  
  &lt;br&gt;&lt;br&gt;
  &lt;div&gt;
    4. Profile!
  
  &lt;/div&gt;</description>
      <category>JProfiler</category>
      <pubDate>Wed, 15 Feb 2012 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2012/02/attaching-to-windows-services-for-java-profiling/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2012-02-15T08:00:57Z</dc:date>
    </item>
    <item>
      <title>All screen casts now with HTML5 video</title>
      <link>https://www.ej-technologies.com/blog/2012/06/all-screen-casts-now-with-html5-video/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;/p&gt;

  We've just converted all our screen casts to HTML with MP4 and WebM codecs so you can enjoy them on mobile and other 
  Flash-less devices.
  &lt;br&gt;&lt;br&gt;
  
  There still is a Flash fallback for ancient browsers that do not support the &amp;quot;video&amp;quot; tag. Some older browsers (such as 
  Firefox 3) that support the video-tag but do not support either the MP4 or the WebM video codec may show an error. In 
  that case, please go to our &lt;a href="https://www.youtube.com/user/IngoKegel/videos"&gt;youtube channel&lt;/a&gt; 
  to watch the screen casts.
  &lt;br&gt;&lt;br&gt;
  
  --- Update 2013-07-24
  &lt;br&gt;&lt;br&gt;
  
  Since Firefox 21, MP4 is supported on Firefox if you're on Windows 7 or higher. There may be problems with colors that 
  are resolved if you go to about:config and set
  &lt;br&gt;&lt;br&gt;
  
  media.windows-media-foundation.use-dxva=false</description>
      <category>General</category>
      <pubDate>Mon, 18 Jun 2012 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2012/06/all-screen-casts-now-with-html5-video/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2012-06-18T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Migrating to install4j 5.1</title>
      <link>https://www.ej-technologies.com/blog/2012/06/migrating-to-install4j-5-1/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=migration"&gt;Migration&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    The following new features in the install4j 5.1 require consideration when migrating from 5.0:
  &lt;/p&gt;
 
   
  
  
  &lt;h4 class="mt-5"&gt;New architecture for elevated privileges&lt;/h4&gt;
  
  
  
  &lt;p&gt;
    install4j 5.1 introduces a new architecture for elevated privileges. Under some circumstances this can create backwards 
    compatibility problems with your existing projects that are discussed below.
  &lt;/p&gt;

  
  &lt;p&gt;
    Prior to install4j 5.1, the the &amp;quot;Request privileges&amp;quot; action could restart the entire installer process and run the 
    installer GUI and all the actions with elevated privileges. This was the default setting on Windows and also available 
    on Mac OS X. The unelevated process was kept around only for starting launchers and other executables without 
    privileges. On Mac OS X, the default mode for the &amp;quot;Request privileges&amp;quot; action was to start an elevated helper process 
    that was used internally by some actions - such as the service actions. The strategy of running the GUI without elevated
    privileges is a lot better, but our helper process had very limited capabilities and so it could not be made the default
    on Windows.
  &lt;/p&gt;

  
  &lt;p&gt;
    Enter install4j 5.1: We have now removed the &amp;quot;restart&amp;quot; and beefed up the elevated helper process considerably. Single 
    actions can now be executed in the elevated helper process. To this end, we have added an &amp;quot;Action elevation type&amp;quot; 
    property to all actions in the install4j IDE. Unless the action declares a different default value, it is set to 
    &amp;quot;Inherit from parent&amp;quot;. The &amp;quot;Action elevation type&amp;quot; is also configurable on screens, installer applications, screen 
    groups and action groups, and determines the default value for the contained actions.
  &lt;/p&gt;

  
  &lt;p&gt;
    If an action is set to be executed with maximum available privileges and an elevated helper process has been started by 
    the &amp;quot;Request privileges&amp;quot; action, the action is serialized to the elevated helper process, executed there and then 
    serialized back to the unelevated process. In the elevated helper process, it has access to all installer variables and 
    it can interact with the GUI through the methods in the &lt;code&gt;com.install4j.api.Util&lt;/code&gt;
    class. Elevated actions in console installers can use all methods in the provided &lt;code&gt;com.install4j.api.screens.Console&lt;/code&gt;
    object to interact with the user.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/pictures/elevation-d315c2dc18d3e6759acb412c582368b1.png" class="img-fluid" loading="lazy" width="353" height="464"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    If you are just using standard actions, migrating to install4j 5.1 should not break anything. If you use custom code, 
    the two-process architecture and the changed default privileges might impact your installer. Here are the points that 
    you should look at:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;
      Using static state in elevated actions may have unintended consequences, since static state is not synchronized between 
      the two processes. Only use installer variables for saving state.
    &lt;/li&gt;
    &lt;li&gt;
      Elevated actions must be serializable. The base interface for actions now extends &lt;code&gt;java.io.Serializable&lt;/code&gt;,
      but all contained objects must be serializable as well, otherwise a fatal error will occur.
    &lt;/li&gt;
    &lt;li&gt;
      Installer variable values should be serializable. If you place a non-serializable value into an installer variable, you 
      will not be able to use it in elevated actions.
    &lt;/li&gt;
    &lt;li&gt;
      If your action previously assumed that it would have full privileges, you have to set its &amp;quot;Action elevation type&amp;quot; to 
      &amp;quot;Elevate to maximum available privileges&amp;quot; manually. For example, a &amp;quot;Run script&amp;quot; action that modifies a file with your 
      own code may not work on a file in the installation directory unless you elevate the action. For custom actions, you can
      call &lt;code&gt;setFullPrivilegesRequired&lt;/code&gt;
      or &lt;code&gt;setDefaultActionElevationType&lt;/code&gt;
      in your action bean info in order to automatically set the correct elevation type in the install4j IDE when the action 
      is inserted.
    &lt;/li&gt;
    &lt;li&gt;
      Some methods in the API do not work in the elevated helper process. They have been marked to throw &lt;code&gt;NotSupportedInElevationException&lt;/code&gt;
      in the API javadoc. Mainly this concerns methods in the context that change the control flow (i.e. jump to another 
      screen) or methods that modify the GUI. If your action needs to use these methods while at the same time requiring 
      elevation, you can always use &lt;code&gt;context.runElevated(...)&lt;/code&gt;
      to push a piece of code to the elevated helper process.
    &lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;p&gt;
    The key advantages of the new architecture are:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;
      Unified privileges architecture for Windows and Mac OS X
    &lt;/li&gt;
    &lt;li&gt;
      No more problems due to user change on authentication
    &lt;/li&gt;
    &lt;li&gt;
      Privileges can reasonably be requested at any point in the installer, not only at the beginning
    &lt;/li&gt;
    &lt;li&gt;
      Better desktop integration of the installer GUI, for example for drag and drop
    &lt;/li&gt;
  &lt;/ul&gt;
 
  
  
  &lt;h4 class="mt-5"&gt;Support for OpenJDK on Mac OS X&lt;/h4&gt;
  
  
  
  &lt;p&gt;
    OpenJDK is the way forward for Java applications on Mac OS X. However, the following points need your attention:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;
      It is not possible to deliver an installer or a single bundle archive that support both the old Apple JRE as well as 
      OpenJDK. The stubs are different and you choose either option in the media wizard. Old projects will keep the Apple JRE 
      option, so nothing will change by default
    &lt;/li&gt;
    &lt;li&gt;
      JRE bundling on Mac OS X is only supported for Open JDK
    &lt;/li&gt;
    &lt;li&gt;
      The minimum Java version for OpenJDK is Java 7 and the minimum Mac OS X version is 10.7.3. So you can currently target 
      only newer systems and only if your application supports Java 7.
    &lt;/li&gt;
  &lt;/ul&gt;
 
  
  
  &lt;h4 class="mt-5"&gt;Code signing for Windows and Mac OS X&lt;/h4&gt;
  
  
  
  &lt;p&gt;
    Code signing on Windows and Mac OS X is now implemented in pure Java code which works on any supported platform. 
    Previously, install4j only offered a hook for inserting an external code signing tool for Windows which would be 
    executed for each launcher and installer application. This functionality is still available for Windows media files and 
    is now called &amp;quot;Executable processing&amp;quot;. So your existing solution for code signing will still work and there is no 
    immediate need for action.
  &lt;/p&gt;

  
  &lt;p&gt;
    However, if you have .pvk and .spc files for your code signing certificate, you can enter them on the General 
    Settings-&amp;gt;Code Signing tab and enable Windows code signing there. You then have to remove the external code signing 
    command on the &amp;quot;Executable processing&amp;quot; step of the media wizard.
  &lt;/p&gt;</description>
      <category>install4j</category>
      <category>Migration</category>
      <pubDate>Mon, 18 Jun 2012 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2012/06/migrating-to-install4j-5-1/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2012-06-18T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling class loaders and solving related memory leaks</title>
      <link>https://www.ej-technologies.com/blog/2013/07/profiling-class-loaders-and-solving-related-memory-leaks/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=memory+leak"&gt;Memory Leak&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how the class loaders probe can be used to debug class loading and to solve class loader memory 
    leaks.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/j-C6zV2rdho" title="Play video 'Profiling class loaders and solving related memory leaks'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/j-C6zV2rdho-f2e586175c4337c1543bfb937ecf49.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <category>Memory Leak</category>
      <pubDate>Wed, 24 Jul 2013 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2013/07/profiling-class-loaders-and-solving-related-memory-leaks/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2013-07-24T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling MongoDB</title>
      <link>https://www.ej-technologies.com/blog/2013/07/profiling-mongodb/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to use the MongoDB probe in JProfiler that has been added in JProfiler 8.0. The profiled 
    application is the vert.x web demo application that uses mongodb as a storage option. MongoDB events are correlated to 
    the the activity in the web application and it is shown how the exclusion of primitive data leads to a useful definition
    of hots spots.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/RSQQsRQ02Ik" title="Play video 'Profiling MongoDB'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/RSQQsRQ02Ik-aff54daa8c707ff844dd45e1cac82560.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Thu, 25 Jul 2013 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2013/07/profiling-mongodb/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2013-07-25T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Java profiling across JVM boundaries</title>
      <link>https://www.ej-technologies.com/blog/2013/07/java-profiling-across-jvm-boundaries/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows &amp;quot;Remote request tracking&amp;quot; in JProfiler. It makes it possible to profile business transactions 
    that span multiple JVMs. Here, a web service call to another JVM is shown and profiled in isolation of other requests 
    that are handled by the server. In addition, JProfiler supports remote request tracking for RMI and remote EJB calls.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/vgqTRDrpNz4" title="Play video 'Java profiling across JVM boundaries'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/vgqTRDrpNz4-1deecfde813e224224f97c33f0d73591.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 30 Jul 2013 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2013/07/java-profiling-across-jvm-boundaries/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2013-07-30T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Introducing perfino</title>
      <link>https://www.ej-technologies.com/blog/2014/06/introducing-perfino/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;/p&gt;
  &lt;div&gt;
    &lt;div&gt;&lt;/div&gt;

    Today we're releasing a major new product: &lt;a href="https://www.ej-technologies.com/products/perfino/overview.html"&gt;perfino &lt;/a&gt;
    is a JVM monitoring tool for in-production use. Over the years, we have lost count of the number of times that our 
    customers have asked us on how to best deploy JProfiler in production. While our standard response was to recommend a 
    monitoring tool, our customers were not so easily dissuaded. They wanted the power of JProfiler to solve their 
    particular problems.
  
  &lt;/div&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2014/06/icon-ttl-perfino-56c63256595252cf2d1e3263f640b1.png" class="img-fluid" loading="lazy" width="85" height="87"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  &lt;div&gt;
    Out of this dilemma, the idea for perfino was born. Would it be possible to develop a monitoring tool that could be used
    in production, yet provide a way to escalate from monitoring to profiling if necessary? We are firmly convinced that 
    perfino succeeds with respect to this original goal and provides you with a layered defence in depth. When a problem 
    becomes more difficult to solve with monitoring techniques, perfino offers low-risk, low-overhead native JVMTI sampling 
    to get a picture of the entire JVM. If even that is not enough, perfino offers an easy way to attach JProfiler to a 
    problematic JVM. At that point, you have the full arsenal of a Java profiler at your disposal.
  
  &lt;/div&gt;
&lt;br&gt;
  &lt;div&gt;
    However, the much larger part of perfino is not its emergency handling, but its monitoring capabilities. Here, we wanted
    to make a difference as well. perfino uses a Java agent with ultra-low overhead and measures what is called &amp;quot;business 
    transactions&amp;quot; in the APM space. Business transactions capture important method calls with specially constructed names 
    that help you to interpret what is going on in your application.
  
  &lt;/div&gt;
&lt;br&gt;
  &lt;div&gt;
    For business transactions, we brought in successful concepts from the profiling space and integrated them into perfino. 
    For example, transactions are shown in a call tree and you can see hot spots of transactions. With perfino, it is 
    possible to define many transactions that are nested. This gives you more informational depth and correspondingly more 
    insight than just the list of top-level business transactions that is common for APM tools.
  
  &lt;/div&gt;
&lt;br&gt;
  &lt;div&gt;
    The amount of useful information in an APM tool is directly related to the amount and quality of the recorded business 
    transactions. This is why we expended a lot of energy on the business transaction engine and the configuration of 
    business transactions in the perfino UI. Also, we wanted to make it really easy to define business transactions directly
    in your code. The DevOps annotations offered by perfino are a great way to achieve this. Rather than thinking about 
    monitoring as external to the application, you just annotate methods of interest.
  
  &lt;/div&gt;
&lt;br&gt;
  &lt;div&gt;
    The features mentioned above rotate around measuring method calls. Of course, a monitoring tool needs to do a lot more 
    and we’ve strived to make perfino great in all these aspects: Telemetries, policies, triggers, alerts, end user 
    experience monitoring and lots more. Take a look at the &lt;a href="https://www.ej-technologies.com/products/perfino/features.html"&gt;feature list &lt;/a&gt;
    or - even better - try it out in our &lt;a href="https://www.ej-technologies.com/products/perfino/demo.html"&gt;live demo&lt;/a&gt;
    or on your own machines. Tell us what you think and what you would like to see in future versions.
    &lt;br&gt;
    &lt;div&gt;&lt;/div&gt;
&lt;br&gt;
    &lt;div&gt;&lt;/div&gt;
  &lt;/div&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2014/06/K0e45veXZpwdoF63FLu67H5hx4ltpEpA3uW3G1eCuhX-9c42f3f58861dc08543ff6c871277d5.png" class="img-fluid" loading="lazy" width="800" height="650"&gt;&lt;/div&gt;

  
  &lt;br&gt;
  &lt;div&gt;
    perfino is a powerful APM solution today, but our vision for perfino is not done yet. There are many more things to come
    and we hope you’ll bear with us.
  
  &lt;/div&gt;</description>
      <category>General</category>
      <pubDate>Tue, 03 Jun 2014 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2014/06/introducing-perfino/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2014-06-03T07:00:57Z</dc:date>
    </item>
    <item>
      <title>The v2 signature scheme for application bundles on Mac OS X 10.9.5+</title>
      <link>https://www.ej-technologies.com/blog/2014/09/the-v2-signature-scheme-for-application-bundles-on-mac-os-x-10-9-5/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Apple has decided to introduce a new signing scheme in the upcoming Mac OS X 10.9.5 maintenance release.
  &lt;/p&gt;

  
  &lt;p&gt;
    The good news is that the new signature is much better from a security point of view. The utility of the old signature 
    was highly questionable, because it allowed unsigned and modifiable files in the application bundle. An attacker could 
    change the JAR files in the application bundle and the signature of the application bundle would remain valid.
  &lt;/p&gt;

  
  &lt;p&gt;
    The bad news is that &lt;b&gt;all existing signatures are going to break&lt;/b&gt;.
    Only applications with a v2 signature will be accepted by Gatekeeper starting with Mac OS X 10.9.5. On the upside, the 
    v2 signature is backwards compatible with older versions of Mac OS X. The means that if your application bundle is 
    signed with the new scheme it will work in Mac OS 10.8, 10.9 and 10.10 - and hopefully even with future versions of Mac 
    OS X.
  &lt;/p&gt;
 
  
  
  &lt;p&gt;
    We have implemented v2 signatures in install4j 5.1.13, so you can already create application bundles that will work with
    the upcoming disruptive releases of Mac OS X.
  &lt;/p&gt;

  
  &lt;p&gt;
    However, this change may have consequences for your install4j projects:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;
      The application bundle that is installed by a &amp;quot;Mac OS X single bundle&amp;quot; &lt;b&gt;installer &lt;/b&gt;
      cannot be signed anymore. The installer installs variable files into the bundle and of course it cannot update the 
      signature of the bundle. Previously all these files did not influence the signature (you can see that this was a bad 
      idea), but now everything in the bundle must be signed. If you really need a signed launcher, you have to switch to the 
      &amp;quot;Mac OS X single bundle&amp;quot; &lt;b&gt;archive&lt;/b&gt;.

    &lt;/li&gt;
    &lt;li&gt;
      Info.plist files and .vmoptions files in signed bundles cannot be changed anymore without breaking the signature. If you
      rely on the validity of the signature of the application bundle, you have to ensure that these files remain untouched. 
      This applies to single bundle and folder archives as well as to the folder installer with signed launchers enabled.
    &lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;p&gt;
    To make the correct decisions, you have to understand that a signature is only required for the file that user downloads
    from the internet. An installer can install application bundles that are unsigned, because those will not be checked by 
    Gatekeeper.
  &lt;/p&gt;

  
  &lt;p&gt;
    A signature on an installed application bundle is only required if you need access to restricted services, such as 
    iCloud storage or the notification center. In addition, signed application bundles are treated preferentially in some 
    cases. For example, if the user enables the firewall, unsigned application bundles can only receive incoming connections
    after the user confirms a question from the firewall.
  &lt;/p&gt;</description>
      <category>install4j</category>
      <pubDate>Mon, 08 Sep 2014 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2014/09/the-v2-signature-scheme-for-application-bundles-on-mac-os-x-10-9-5/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2014-09-08T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Migrating to install4j 6</title>
      <link>https://www.ej-technologies.com/blog/2014/11/migrating-to-install4j-6/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=migration"&gt;Migration&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In nearly all cases, migrating to install4j 6 usually just involves opening and saving your project with the install4j 6 IDE.
    Nevertheless, there are some considerations with respect to backward compatibility and some behavioral changes.
  &lt;/p&gt;

  
  
  &lt;ul&gt;
    &lt;li&gt;
      The minimum Java version for launchers is now Java 6. If your launchers must run with Java 1.4 or Java 5, you have to
      stick with install4j 5.
    &lt;/li&gt;
    &lt;li&gt;
      The minimum Java version for the install4j IDE and the compiler is now Java 7. If your build machine only has Java 6
      installed, you have to install a Java 7 JRE. On Windows and Mac OS X, Java 7 JREs are bundled in the install4j
      downloads.
    &lt;/li&gt;
    &lt;li&gt;
      The install4j API has been generified and old-style enums have been converted to language enums. Theses changes are
      binary and source compatible. The only exception is that enums do no longer extend &lt;code&gt;com.install4j.api.SerializableEnum&lt;/code&gt;.
      In the unlikely case that you use this class in your custom code, you will have to replace it with the actual enum
      class.
    &lt;/li&gt;
    &lt;li&gt;
      Installer variables loaded by the &amp;quot;Load response file&amp;quot; action or the -varfile command line parameter are now
      automatically registered as response file variables. The eliminates problems with fast-path upgrade installations where
      response file variables would be lost if their form components were not be shown. If this change impacts on your logic,
      the &amp;quot;Load response file&amp;quot; action now has a &amp;quot;Register variables for response file&amp;quot; property that you can deselect to
      revert to the old behavior.
    &lt;/li&gt;
    &lt;li&gt;
      By default, the &amp;quot;Load response file&amp;quot; action will no longer overwrite installer variables that have been set explicitly
      on the command line with the -Vvariable=value option. This is the intuitive behavior and makes installer variables more
      flexible. If this change impacts on your logic, the new &amp;quot;Overwrite strategy&amp;quot; property of the &amp;quot;Load response file&amp;quot; action
      can be set to &amp;quot;Do not overwrite existing&amp;quot;.
    &lt;/li&gt;
    &lt;li&gt;
      Mac OS X archives are now generated in DMG format. This means that the generated media file name will change between
      install4j 5 and install4j 6 and you have to adjust download links on your website. If you would like to keep the .tgz
      format, you can change the corresponding option on the &amp;quot;Installer options&amp;quot; step of the media wizard.
    &lt;/li&gt;
    &lt;li&gt;
      Invisible form components are no longer validated. A validation error would leave the user with no clue what to do, so
      this was really a mistake in previous versions. However, bound installer variables are set during the validation phase
      and that will no longer happen for invisible components. If you rely on the installer variables to be defined, you
      should predefine them in the &amp;quot;Installer variables&amp;quot; section of the installer or custom installer application.
    &lt;/li&gt;
    &lt;li&gt;
      Several installer variables that were previously only defined on Windows are now defined on multiple platforms. New
      cross-platform installer variables are &amp;quot;sys.desktopDir&amp;quot; and &amp;quot;sys.docsDir&amp;quot;. The installer variables &amp;quot;sys.appDataDir&amp;quot;,
      &amp;quot;sys.localAppdataDir&amp;quot;, &amp;quot;sys.docsDir&amp;quot;, &amp;quot;sys.fontsDir&amp;quot; and &amp;quot;sys.programsDir&amp;quot; are now also defined on Mac OS X. If your
      code checks if any of these installer variables is null, it may no longer work correctly.
    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;Reboot computer&amp;quot; action and &lt;code&gt;Context#triggerReboot&lt;/code&gt;
      now work on Mac OS X as well. If you rely on the previous behavior of not doing anything on Mac OS X, this may not be
      what you want. In that case, you have to add platform-specific checks in your project.
    &lt;/li&gt;
    &lt;li&gt;
      The ICNS icon for Mac OS X launchers is now generated from cross-platform images. If you previously had no ICNS icon
      defined but the &amp;quot;Add icon to launcher&amp;quot; check box was selected, the maximum resolution of your icon files might be too
      low. You need at least a 128x128 image for the icon to look good on Mac OS X. The old default ICNS icon is still
      available under resource/macos/app.icns, so you can specify it explicitly to restore the old behavior.
    &lt;/li&gt;
    &lt;li&gt;
      The name of the uninstaller on Mac OS X has changed if your project is localized. Previously the file name of the
      uninstaller application bundle was set to the localized name. In install4j 6, the file name is always set in the
      principle language and the localization is provided by the application bundle. You will see the localized name in the
      Finder, but not in the terminal.
    &lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;p&gt;
    If you notice anything else, please let us know!
  &lt;/p&gt;</description>
      <category>install4j</category>
      <category>Migration</category>
      <pubDate>Mon, 03 Nov 2014 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2014/11/migrating-to-install4j-6/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2014-11-03T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Tracking JavaScript calls into your Java backend</title>
      <link>https://www.ej-technologies.com/blog/2015/06/tracking-javascript-calls-into-your-java-backend/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to split your Java call tree for different JavaScript XHR calls. By installing the JProfiler 
    Chrome plugin, a locally running JProfiler GUI will be notified of XHR calls in the browser and show an event 
    description and a stack trace without further configuration. In this way, you can identify the sources of your CPU load 
    beyond the granularity of your URLs and analyze the call tree in isolation for specific browser events.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/ZlEYNwj0f84" title="Play video 'Tracking JavaScript calls into your Java backend'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/ZlEYNwj0f84-db9a2e18806eb27f24ef56e5d93444.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 09 Jun 2015 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/06/tracking-javascript-calls-into-your-java-backend/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-06-09T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Multi-level HTTP request splitting</title>
      <link>https://www.ej-technologies.com/blog/2015/06/multi-level-http-request-splitting/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how JProfiler can split HTTP requests by the return values of scripts into multiple levels. This
    functionality allows you to both get a better overview as well as a more fine-grained analysis that can be adapted to
    your particular problem-related use cases. All the information in the &lt;code&gt;HttpServletRequest&lt;/code&gt;
    object can be used for that purpose. In the screen cast, splitting by different usernames is demonstrated.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/9Fl7V8X-ghs" title="Play video 'Multi-level HTTP request splitting'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/9Fl7V8X-ghs-fd8f8b493be6d5b72638a37398f392a.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 10 Jun 2015 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/06/multi-level-http-request-splitting/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-06-10T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Method splitting by parameter values</title>
      <link>https://www.ej-technologies.com/blog/2015/06/method-splitting-by-parameter-values/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to split selected methods in the call tree by their parameter values. Directly in the call 
    tree, you can select methods and set up scripts whose return values are used for grouping. The splitting nodes in the 
    call tree provide insight into the distribution of your parameter values and give you the possibility to analyze the 
    recorded method calls separately for special cases.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/bVtvI4QgbCw" title="Play video 'Method splitting by parameter values'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/bVtvI4QgbCw-fec6b26b781e1a8da2eb99b27e52cb5.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Thu, 11 Jun 2015 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/06/method-splitting-by-parameter-values/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-06-11T07:00:57Z</dc:date>
    </item>
    <item>
      <title>JProfiler's MBean browser</title>
      <link>https://www.ej-technologies.com/blog/2015/06/jprofilers-mbean-browser/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler has an MBean browser that shows you MBean attributes and operations. Many frameworks and libraries publish 
    statistics and expose configuration interfaces via JMX. With JProfiler, no configuration of JMX connectors is required, 
    the browser just works out of the box and is very easy to use.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/BvgOwWeiTgo" title="Play video 'JProfiler's MBean browser'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/BvgOwWeiTgo-a7acceda95b46275e774d87384911b94.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 12 Jun 2015 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/06/jprofilers-mbean-browser/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-06-12T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Custom telemetries in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2015/06/custom-telemetries-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to quickly add new telemetries to JProfiler. MBean telemetries draw their data from numeric 
    attributes of MBeans that are published in the profiled JVM. Script telemetries are built with a script that can call 
    static methods in the profiled code to return a value of type long. Telemetries can have multiple data lines and are 
    persistent for the profiled session.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/jPzSopohkMk" title="Play video 'Custom telemetries in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/jPzSopohkMk-6e43ae7fae6e52ede6707bcba8dbe5bf.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 16 Jun 2015 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/06/custom-telemetries-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-06-16T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Finding JDBC connection leaks</title>
      <link>https://www.ej-technologies.com/blog/2015/11/finding-jdbc-connection-leaks/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to detect JDBC connection leaks and find out where they're coming from. JDBC connection leak 
    analysis is integrated into JProfiler's JDBC probe and has its own view. If a connection leak is detected, the stack 
    trace and other information will help you to pinpoint the origin of the leak.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/7UGW6cUwdIE" title="Play video 'Finding JDBC connection leaks'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/7UGW6cUwdIE-d5395a3c352ade0de1ba9bb8688a4f.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Thu, 19 Nov 2015 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/11/finding-jdbc-connection-leaks/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-11-19T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Remote profiling through an SSH tunnel</title>
      <link>https://www.ej-technologies.com/blog/2015/11/remote-profiling-through-an-ssh-tunnel/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler has built-in SSH tunneling for direct and multi-hop SSH connections. This is useful for situations where you 
    do not have a direct network connection to the machine where the profiled JVM is running. The screen cast shows how to 
    configure the SSH tunnel and prepare the remote Java process for profiling.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/ip5cnXLnTwM" title="Play video 'Remote profiling through an SSH tunnel'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/ip5cnXLnTwM-6f1e78753cdf99ae98fe0b7bf9ac32e.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 20 Nov 2015 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/11/remote-profiling-through-an-ssh-tunnel/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-11-20T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Collapsing recursions in the call tree</title>
      <link>https://www.ej-technologies.com/blog/2015/11/collapsing-recursions-in-the-call-tree/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to use the &amp;quot;Collapse recursions&amp;quot; call tree analysis to better understand recursive call 
    trees. Recursive calls are stitched back to the topmost call of a method. Recursive call counts, merged stack counts as 
    well as moved parts of the call tree are marked in the analysis view.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/r-EKR9yu4lo" title="Play video 'Collapsing recursions in the call tree'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/r-EKR9yu4lo-2d2ddf5ae586255f4a375d542e26ae7.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 24 Nov 2015 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/11/collapsing-recursions-in-the-call-tree/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-11-24T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Analyzing incoming and outgoing calls of a method</title>
      <link>https://www.ej-technologies.com/blog/2015/11/analyzing-incoming-and-outgoing-calls-of-a-method/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to use the call tree analyses to analyze both the cumulated outgoing calls of all top-level 
    invocations of a selected method as well as to calculate the back traces of all its invocations. The results of the 
    analyses are compared with the call graph that shows a combined view of incoming and outgoing calls.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/xJLHSB2uNqw" title="Play video 'Analyzing incoming and outgoing calls of a method'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/xJLHSB2uNqw-c0438db0251a4f1245b8d50ee68783f.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 25 Nov 2015 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/11/analyzing-incoming-and-outgoing-calls-of-a-method/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-11-25T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Analyzing specific parts of the call tree</title>
      <link>https://www.ej-technologies.com/blog/2015/11/analyzing-specific-parts-of-the-call-tree/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how the &amp;quot;Set root&amp;quot; action is used to analyze a specific part of your code. The &amp;quot;Set root&amp;quot; action 
    in the call tree view is used to select the call stack of interest. The hot spot view and the call graph then only show 
    data for the selected part of the call tree.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/K_VPyBbRnqI" title="Play video 'Analyzing specific parts of the call tree'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/K_VPyBbRnqI-79db64521d3e5d1783d5992e0da101.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Thu, 26 Nov 2015 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2015/11/analyzing-specific-parts-of-the-call-tree/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2015-11-26T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Comparing install4j to other deployment solutions</title>
      <link>https://www.ej-technologies.com/blog/2016/10/comparing-install4j-to-other-deployment-solutions/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  Samuel Ruggieri from Voyager Games has written an &lt;a href="https://voyagergames.com/distributing-a-desktop-java-application/"&gt;interesting article&lt;/a&gt; 
  comparing install4j against Java Web Start and other installer builders. His conclusion is this:
  &lt;br&gt;&lt;br&gt;  
  
  
  &lt;blockquote class="blockquote my-4 ps-4 border-start border-3"&gt;
    &amp;quot;At the end of this adventure, I have another experience that demonstrates the old adage that it’s cheaper to buy software than to build it. In this case, it’s cheaper and better. Software engineer hours are expensive, and for a non-trivial Java application, you’ll burn scores of them if you try to build a custom deployment and auto-update solution. At the end of that development, whatever you’ve built will almost certainly be inferior to what install4j can give you with a bare minimum of expense, both in terms of time and effort.&amp;quot;
  &lt;/blockquote&gt;
  
  
  &lt;br&gt;
  
  If you're thinking about comparing different deployment solutions for your Java application, maybe his article can 
  provide some shortcuts.</description>
      <category>install4j</category>
      <pubDate>Thu, 06 Oct 2016 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2016/10/comparing-install4j-to-other-deployment-solutions/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2016-10-06T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Zero-configuration remote attach</title>
      <link>https://www.ej-technologies.com/blog/2017/03/zero-configuration-remote-attach/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to attach to a remote JVM with zero configuration on the remote side. The only requirement is
    an SSH connection to the remote machine. Remote JVMs are listed in the JProfiler UI and a JVM can be selected for 
    profiling.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/tYieP2s34YI" title="Play video 'Zero-configuration remote attach'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/tYieP2s34YI-2fb03a18fea5a06c78659b926ec5c5d.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Mon, 20 Mar 2017 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2017/03/zero-configuration-remote-attach/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2017-03-20T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Complexity analysis in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2017/03/complexity-analysis-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Complexity analysis in JProfiler is a tool for experimentally determining the Big-O behavior of algorithms based on the 
    execution times of single selected methods. A bubble chart with curve fits of common complexities visualizes the results
    of the analysis.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/mFuBsCjbz9c" title="Play video 'Complexity analysis in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/mFuBsCjbz9c-6b476e4bab44484b15a2e3b81adfb.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 21 Mar 2017 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2017/03/complexity-analysis-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2017-03-21T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Finding a memory leak with JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2017/03/finding-a-memory-leak-with-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=memory+leak"&gt;Memory Leak&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screencast explains a basic strategy for solving memory leaks with JProfiler.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/032aTGa-1XM" title="Play video 'Finding a memory leak with JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/032aTGa-1XM-5d9575c8c584126c431dfba1f949a9e9.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;

  
  &lt;p&gt;
    There is an &lt;a href="https://www.ej-technologies.com/blog/2009/04/23/finding-a-memory-leak-with-jprofiler-old/"&gt;older version&lt;/a&gt;
    of this screencast from 2009 that is not accurate for the heap walker anymore but that shows other useful features in 
    JProfiler.
  &lt;/p&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <category>Memory Leak</category>
      <pubDate>Wed, 22 Mar 2017 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2017/03/finding-a-memory-leak-with-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2017-03-22T08:00:57Z</dc:date>
    </item>
    <item>
      <title>JProfiler's integration into IntelliJ IDEA</title>
      <link>https://www.ej-technologies.com/blog/2017/03/jprofilers-integration-into-intellij-idea/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows the JProfiler plugin for IntelliJ IDEA. A run configuration is profiled, source code navigation is
    discussed and the call graph data display in the IDE is shown.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/XTq1VWEDygg" title="Play video 'JProfiler's integration into IntelliJ IDEA'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/XTq1VWEDygg-319c8b19de7e95ffc73f08c2c8d4d21.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Thu, 23 Mar 2017 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2017/03/jprofilers-integration-into-intellij-idea/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2017-03-23T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Migrating to install4j 7</title>
      <link>https://www.ej-technologies.com/blog/2017/07/migrating-to-install4j-7/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=migration"&gt;Migration&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In nearly all cases, migrating to install4j 7 usually just involves opening and saving your project with the install4j 7 IDE.
    Nevertheless, there are some considerations with respect to backward compatibility and some behavioral changes.
  &lt;/p&gt;

  
  
  &lt;ul&gt;
    &lt;li&gt;&lt;b&gt;The minimum supported Java version is now Java 7 up from Java 6 for install4j 6.&lt;/b&gt;
      This also means that the old Java 6 Apple JRE is no longer available as a separate type on the Bundled &amp;quot;JRE&amp;quot; step of the
      macOS media wizard. The launcher runtime still supports Java 6 and you can set the compiler variable &lt;code&gt;sys.ext.forceMinJavaVersion&lt;/code&gt;
      to &lt;code&gt;true&lt;/code&gt;
      in order to allow &amp;quot;1.6&amp;quot; as a minimum version. Note that no classes in the API can be called from Java 6.
    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;native splash screen&amp;quot; feature for Windows has been removed. This went back to the pre-Java 6 days when Java did not
      offer splash screen functionality and was missing several important features. If you had this feature selected for one
      of your launchers, it now uses the regular Java splash screen
    &lt;/li&gt;
    &lt;li&gt;
      When a rollback terminates at a rollback barrier, the exit code of an installer application is now 0. To restore the old
      exit code of 1, you can set the &amp;quot;Exit code&amp;quot; child property of the &amp;quot;Rollback barrier&amp;quot; property to 1
    &lt;/li&gt;
    &lt;li&gt;
      In the &amp;quot;Key validation expression&amp;quot; script property of text components, the &amp;quot;keyCode&amp;quot; parameter has been removed. It was
      always 0 before and did not serve a useful purpose.
    &lt;/li&gt;
    &lt;li&gt;
      If you develop your own screens with the API, the methods &lt;code&gt;isShowIndex&lt;/code&gt;,
 &lt;code&gt;hasTitlePanel&lt;/code&gt;,
 &lt;code&gt;hasDefaultInsets&lt;/code&gt;
      and &lt;code&gt;hasDefaultButtons&lt;/code&gt;
      have been removed from the interface &lt;code&gt;com.install4j.api.screens.Screen&lt;/code&gt;
      and so your existing implementation of these methods will no longer be called by install4j. This functionality is now
      covered by styles which are much more flexible than the previous limited styling capabilities.
    &lt;/li&gt;
    &lt;li&gt;
      In the API, methods with Object[] arguments for variable parameter lists have been converted to varargs. This should not
      cause source or binary incompatibilities but may show warnings in your code if you call such methods.
    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;Create a quick launch icon&amp;quot; action has been removed with no replacement. The last OS where it had any effect was
      Windows Vista.
    &lt;/li&gt;
    &lt;li&gt;
      If you have not set a maximum Java version, and do not use a bundled JRE, any installed Java 9 JRE will be used. Java 9
      has backward compatibility issues that may prevent your application from working unless you explicitly support it.
      Consider limiting the maximum Java version to &amp;quot;1.8&amp;quot; in that case.
    &lt;/li&gt;
    &lt;li&gt;
      If the &amp;quot;Request privileges&amp;quot; action fails, an installation directory in the user home directory is set. To restore the
      old behavior of keeping the default installation directory deselect the &amp;quot;Fall back to user specific installation
      directory&amp;quot; property on the &amp;quot;Request privileges&amp;quot; action.
    &lt;/li&gt;
    &lt;li&gt;
      
      &lt;p&gt;
        With install4j 7, you cannot use the deprecated &lt;code&gt;com.apple.eawt.Application.Application.getApplication().addApplicationListener(...)&lt;/code&gt;
        in the macOS EAWT API anymore, you have to use the new API methods, for example
      &lt;/p&gt;

      
      &lt;pre&gt;
Application.getApplication().setQuitHandler((quitEvent, quitResponse) -&amp;gt; {
        quitResponse.cancelQuit();
// TODO add your code
});&lt;/pre&gt;

      
      &lt;p&gt;for the quit handler.&lt;/p&gt;

    &lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;p&gt;
    If you notice anything else, please let us know!
  &lt;/p&gt;</description>
      <category>install4j</category>
      <category>Migration</category>
      <pubDate>Thu, 13 Jul 2017 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2017/07/migrating-to-install4j-7/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2017-07-13T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Stricter time-stamp validation on macOS 10.14</title>
      <link>https://www.ej-technologies.com/blog/2018/06/stricter-time-stamp-validation-on-macos-10-14/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Today we released an install4j emergency release for macOS 10.14 that fixes a problem with code signing. Previous 
    versions of install4j used time stamp validation during code-signing in such a way that it's no longer recognized by 
    macOS 10.14.
  &lt;/p&gt;
 
    
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2018/06/filezilla-3d6379e2e485f1cf0ac207f8aeade4a.png" class="img-fluid" loading="lazy" width="532" height="271"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    Whenever code signatures are invalid, macOS does not report any specific errors, but just informs the user that the 
    archive is damaged and suggests to move it to the trash, like this: &lt;br&gt;&lt;br&gt;
    If you use install4j for deploying to macOS, you probably do use code-signing, so we highly recommend to update to 
    install4j 7.0.6 to avoid problems for users on macOS 10.14.
  &lt;/p&gt;

  
  &lt;p&gt;
    As an added benefit, the new release can scale splash screens under fractional HiDPI on Windows, so they no longer 
    appear to be to small.
  &lt;/p&gt;</description>
      <category>install4j</category>
      <pubDate>Mon, 11 Jun 2018 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2018/06/stricter-time-stamp-validation-on-macos-10-14/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2018-06-11T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Development Sneak Peek: Dark Mode and HiDPI</title>
      <link>https://www.ej-technologies.com/blog/2018/06/development-sneak-peak-dark-mode-and-hidpi/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    A system-wide dark mode is coming to both &lt;a href="https://www.macworld.co.uk/how-to/mac/dark-mode-mac-3670701/"&gt;macOS&lt;/a&gt;
    and &lt;a href="https://bgr.com/2018/05/09/windows-10-dark-mode-file-explorer-how-to/"&gt;Windows&lt;/a&gt;.
    That's why we're working on a dark mode for JProfiler as well. Based on the excellent Darcula Look and Feel from our 
    friends at JetBrains, JProfiler will soon fit into this new world of dark background colors:
  &lt;/p&gt;
 
    
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2018/06/dark_mode3-13ac10c4d034baae765b5940d1a9dbb4.png" class="img-fluid" loading="lazy" width="757" height="558"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    Moreover, support for fractional HiDPI is coming for Windows. If you are using a 4K monitor, you will be happy to hear 
    that the blurry upscaled UI will be a thing of the past. This is not only true for dark mode: We will also be using the 
    light look and feel from IntelliJ IDEA together with the &lt;a href="https://confluence.jetbrains.com/display/JRE/JetBrains+Runtime"&gt;JetBrains Runtime&lt;/a&gt;
    in order to provide the best experience for high screen resolutions. The light mode will be the new default look and 
    feel for JProfiler.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2018/06/light_mode-3d1c4e1f688dc46a2dd91ec0eb257c.png" class="img-fluid" loading="lazy" width="757" height="637"&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <pubDate>Tue, 19 Jun 2018 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2018/06/development-sneak-peak-dark-mode-and-hidpi/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2018-06-19T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Automation sandboxing in macOS 10.14</title>
      <link>https://www.ej-technologies.com/blog/2018/10/automation-sandboxing-in-macos-10-14/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    macOS 10.14 introduces &lt;a href="https://www.felix-schwarz.org/blog/2018/08/new-apple-event-apis-in-macos-mojave"&gt;automation sandboxing&lt;/a&gt;
    as part of a new push for security. This change impacts installers generated with install4j prior to 7.0.8, because they
    use AppleScript to perform a variety of tasks. The authorization dialogs from the new sandboxing mechanims are 
    undesirable for an installer and once a permission is denied it is difficult to reauthorize it.
  &lt;/p&gt;
 
  
  
  &lt;p&gt;
    To solve this problem, nearly all affected operations have been re-implemented as native code in install4j 7.0.8. As 
    part of this work we have fixed a long-standing issue on macOS: When requesting elevated privileges, the password dialog
    notified the user that &amp;quot;install4j&amp;quot; wants to make changes.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2018/10/Privileges-old-5078b370627fca699cf66a4e2ed83f43.png" class="img-fluid" loading="lazy" width="555" height="344"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    However, users most likely do not know the name &amp;quot;install4j&amp;quot; and could be tempted to cancel the dialog. Starting with 
    install4j 7.0.8, the full name that is configured in your project is displayed instead:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2018/10/Privileges-new-6864f13424e377a55a2334b6e7a59.png" class="img-fluid" loading="lazy" width="555" height="344"&gt;&lt;/div&gt;</description>
      <category>install4j</category>
      <pubDate>Tue, 16 Oct 2018 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2018/10/automation-sandboxing-in-macos-10-14/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2018-10-16T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Migrating to install4j 8</title>
      <link>https://www.ej-technologies.com/blog/2019/06/migrating-to-install4j-8/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=migration"&gt;Migration&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In nearly all cases, migrating to install4j 8 usually just involves opening and saving your project with the install4j 8 IDE.
    Nevertheless, there are some considerations with respect to backward compatibility and some behavioral changes.
  &lt;/p&gt;

  
  
  &lt;ul&gt;
    &lt;li&gt;
      The unattended installer does not ignore file installation failures anymore but fails at the first file installation
      failure. To get the old behavior, start the installer with the &lt;code&gt;-nofilefailures&lt;/code&gt;
      argument. To permanently set this mode, add &lt;code&gt;-Dinstall4j.noFileFailures=true&lt;/code&gt;
      to the &amp;quot;VM parameters&amp;quot; property of the installer.
    &lt;/li&gt;
    &lt;li&gt;
      When using the VM parameters &lt;code&gt;-Dinstall4j.alternativeLogFile=&amp;lt;path&amp;gt;&lt;/code&gt;
      and its new alias &lt;code&gt;-Dinstallj4.log=&amp;lt;path&amp;gt;&lt;/code&gt;&lt;br&gt;
      now imply &lt;code&gt;-Dinstall4j.keepLog=true&lt;/code&gt;,
      meaning that the log file is no longer deleted in case of a successful execution of the installer application.
    &lt;/li&gt;
    &lt;li&gt;
      The default file name of the error log for Windows installers has changed from &lt;code&gt;error.log&lt;/code&gt;
      to &lt;code&gt;${compiler:sys.mediaFileName}_error.log&lt;/code&gt;.
      You can restore the old file name with the new &amp;quot;Log file for stderr&amp;quot; property of the installer.
    &lt;/li&gt;
    &lt;li&gt;
      In bean properties with an array type, installer variables with collection values are expanded as separate array
      elements. Previously this was only implemented if the installer variables had array values. In the API, this new
      behavior affects the &lt;code&gt;AbstractBean.replaceVariables(...)&lt;/code&gt;
      methods with array parameters. If you rely on the &lt;code&gt;toString()&lt;/code&gt;
      replacement of collections, you have to change the types of the related installer variables.
    &lt;/li&gt;
    &lt;li&gt;
      Variable names for all built-in variable systems can no longer contain the character sequence &lt;code&gt;?:&lt;/code&gt;
      which is now used for specifying default values for missing variables.
    &lt;/li&gt;
    &lt;li&gt;&lt;code&gt;FormEnvironment.getId(...)&lt;/code&gt;
      now returns the display ID of the form component rather than the automatic ID. If you were checking for an explicit
      automatic ID and also defined a custom ID for a form component, that code will now fail.
    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;Read text from file&amp;quot; action will now fail if an error occurred. Previously it always succeeded.
    &lt;/li&gt;
    &lt;li&gt;
      The compiler variable &lt;code&gt;sys.platform&lt;/code&gt;
      now contains the value &lt;code&gt;windows-x32&lt;/code&gt;
      for 32-bit Windows media files instead of &lt;code&gt;windows&lt;/code&gt;.
      For 64-bit Windows media files it remains &lt;code&gt;windows-x64&lt;/code&gt;.

    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;Customize project defaults-&amp;gt;Installer custom script&amp;quot; step of the Unix/Linux GUI installer media wizard has been
      removed. The custom script is now configured on the installer in the &amp;quot;Installer-&amp;gt;Screens &amp;amp; Actions&amp;quot; step. The simple
      case where there is only one Unix/Linux GUI installer is migrated correctly. However, if you used different
      customizations for different Unix/Linux GUI installers, the migration will be incomplete and you have to solve it with
      compiler variables.
    &lt;/li&gt;
    &lt;li&gt;
      For Linux/Unix installers, the umask is now set to 0022 to allow execution by all users. This can be changed by setting
      the compiler variable &lt;code&gt;sys.ext.installerUmask&lt;/code&gt;
      to another mask value or to &lt;code&gt;false&lt;/code&gt;
      to prevent executing any &lt;code&gt;umask&lt;/code&gt;
      command in the installer script.
    &lt;/li&gt;
  &lt;/ul&gt;</description>
      <category>install4j</category>
      <category>Migration</category>
      <pubDate>Fri, 28 Jun 2019 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2019/06/migrating-to-install4j-8/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2019-06-28T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Support for macOS Apple Silicon</title>
      <link>https://www.ej-technologies.com/blog/2020/11/support-for-macos-on-arm-apple-m1/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Please note: Several JDK providers now offer the macos-aarch64 architecture and there is no need anymore to create the 
    bundle yourself, install4j can do this for you automatically.
  &lt;/p&gt;

  
  &lt;p&gt;
    (Edited on 2021-01-07 to include changes for install4j 8.0.10)
  &lt;/p&gt;

  
  &lt;p&gt;
    Apple machines with the new ARM architecture are now available. While you can run existing x64 binaries for on ARM 
    machines through Rosetta, the performance may be impacted significantly. install4j 8.0.9 addresses this concern with 
    support for native ARM binaries.
  &lt;/p&gt;
 
  
  
  &lt;p&gt;
    At the time of writing, the JRE port to macOS ARM has not landed in OpenJDK yet. Currently, only the JetBrains JDK 
    provider includes a release with the macos-aarch64 architecture (11.0.9.1-b1244.2).
  &lt;/p&gt;

  
  &lt;p&gt;
    In addition, Azul provides &lt;a href="https://www.azul.com/downloads/zulu-community/?os=macos&amp;amp;architecture=arm-64-bit&amp;amp;package=jdk"&gt;distributions for macos ARM for several JDK versions&lt;/a&gt;.
    These JDKs can be processed with the &amp;quot;Project-&amp;gt;Create a JRE bundle&amp;quot; command in the install4j IDE or the &lt;code&gt;createbundle&lt;/code&gt;
    command line tool. This creates a &amp;quot;pre-created&amp;quot; JRE bundle that can be selected on the &amp;quot;Bundled JRE&amp;quot; step of the media 
    wizard. An Azul JDK provider that would download these JDKs automatically and in a cross-platform way is planned for 
    install4j 9.
  &lt;/p&gt;

  
  &lt;p&gt;
    After you have prepared a JRE bundle for macOS ARM, you can select the architecture in the macOS media wizard. You will 
    still need an additional media file for Intel-based Macs, because ARM binaries do not run there.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2020/11/macos_architecture-9-8f6b346ed561bdfce73a940f15b16.png" class="img-fluid" loading="lazy" width="684" height="521"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    Finally, select the pre-created bundle in the &amp;quot;Bundled JRE&amp;quot; step.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2020/11/macos_arm_bundle-f5542ae2f4b645ea9e24d4fb3fc28931.png" class="img-fluid" loading="lazy" width="684" height="521"&gt;&lt;/div&gt;</description>
      <category>General</category>
      <pubDate>Thu, 26 Nov 2020 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2020/11/support-for-macos-on-arm-apple-m1/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2020-11-26T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Migrating to install4j 9</title>
      <link>https://www.ej-technologies.com/blog/2021/02/migrating-to-install4j-9/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=migration"&gt;Migration&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In nearly all cases, migrating to install4j 9 usually just involves opening and saving your project with the install4j 9 IDE.
    Nevertheless, there are some considerations with respect to backward compatibility and some behavioral changes.
  &lt;/p&gt;

  
  
  &lt;ul&gt;
    &lt;li&gt;
      The minimum Java version for the install4j runtime is now Java 1.8. Java 1.7 is no longer supported.
    &lt;/li&gt;
    &lt;li&gt;
      The install4j compiler and IDE now require at least Java 11. This is only relevant on Linux and Unix where no JRE is
      bundled.
    &lt;/li&gt;
    &lt;li&gt;
      &amp;quot;Install files&amp;quot; action: The &amp;quot;Update bundled&amp;quot; JRE property has been removed. A bundled JREs is now always updated if the
      update installer also includes a bundled JRE. The ability to switch this off offers no benefit and has the potential to
      create severe problems during sequential upgrades. If you had this property selected, you can restore the previous
      behavior by defining the VM parameter &lt;code&gt;-Dinstall4j.preventJreBundleUpdate=true&lt;/code&gt;
      in the installer.
    &lt;/li&gt;
    &lt;li&gt;
      &amp;quot;HTTP request&amp;quot; action: In previous versions, if an error occurred, the response code variable and the response header
      variables were not set. This error has been corrected in install4j 9, but it changes the semantics of the installer
      variables.
    &lt;/li&gt;
    &lt;li&gt;
      The installer variable &lt;code&gt;sys.appdataDir&lt;/code&gt;
      was previously undefined on Unix, it now returns the value of the environment variable &lt;code&gt;XDG_DATA_HOME&lt;/code&gt;
      (&lt;code&gt;~/.local/share&lt;/code&gt;
      ) on Unix.
    &lt;/li&gt;
    &lt;li&gt;
      Shared JREs (Windows and Unix) now have a sharing ID. This has become necessary because there is no universal definition
      of a JRE anymore so the scope of sharing has to be restricted. Consequently, shared JREs are now installed in different
      locations than before. Also, the user-specific root directories have changed to &lt;code&gt;~/.local/share/i4j_jres&lt;/code&gt;
      on Unix and &lt;code&gt;%APPDATA%\Local\Programs\Common\i4j_jres&lt;/code&gt;
      on Windows. Shared JREs are now preferred to public JREs on Unix.
    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;Execute launcher&amp;quot; action always executed the selected launcher without elevation. This does not work for launchers
      that require privileges themselves. Since install4j 9, the action respects the &amp;quot;Action elevation type&amp;quot; property of the
      action. This changes the behavior of the action if you have changed the &amp;quot;Action elevation type&amp;quot; property from its
      default value of &amp;quot;Do not elevate&amp;quot; to another property value.
    &lt;/li&gt;
    &lt;li&gt;
      The auto-update integration for background update downloaders in the launcher wizard behaves differently if the
      &amp;quot;Unattended mode with progress dialog&amp;quot; mode is selected: It now shows errors and alerts in the update installer where
      previously any error would lead to a silent failure. If this change is not acceptable for you, you can add the VM
      parameter &lt;code&gt;-Dinstall4j.noAlerts=true&lt;/code&gt;
      to the &amp;quot;VM parameters&amp;quot; property of the installer.
    &lt;/li&gt;
    &lt;li&gt;
      Installer applications that have not been started in-process by launchers now set the system property &lt;code&gt;jdk.lang.Process.allowAmbiguousCommands=false&lt;/code&gt;
      to avoid cmd.exe injections. In unattended and console mode, installers applications already behaved that way because
      they use a security manager. Some quoting strategies or arguments that worked before might stop working in GUI mode
      because of that change. To revert to the previous behavior, set the VM parameter -D&lt;code&gt;jdk.lang.Process.allowAmbiguousCommands=true&lt;/code&gt;
      for the installer application.
    &lt;/li&gt;
    &lt;li&gt;
      The JRE version cache on Linux/Unix is now located in &lt;code&gt;.cache/install4j/jres&lt;/code&gt;
      instead of the file &lt;code&gt;~/.install4j&lt;/code&gt;.

    &lt;/li&gt;
    &lt;li&gt;
      Config files, cached files and pre-crated JRE bundles have new platform-specific locations instead of being stored in &lt;code&gt;~/.install4j&amp;lt;version&amp;gt;&lt;/code&gt;.
      On Windows, all directories are located below &lt;code&gt;%LOCALAPPDATA%/install4j/v&amp;lt;version&amp;gt;&lt;/code&gt;.
      On macOS, &lt;code&gt;~/Library/Application Support/install4j/v&amp;lt;version&amp;gt;&lt;/code&gt;
      is used for config files as well as pre-created JRE bundles and &lt;code&gt;~/Library/Caches/install4j/v&amp;lt;version&amp;gt;&lt;/code&gt;
      is used for cached files. On Linux and Unix, &lt;code&gt; .config/install4j/v&amp;lt;version&amp;gt;&lt;/code&gt;
      is used for config files, &lt;code&gt;.caches/install4j/v&amp;lt;version&amp;gt;&lt;/code&gt;
      for caches and &lt;code&gt;.local/share/install4j/v&amp;lt;version&amp;gt;&lt;/code&gt;
      for pre-created JRE bundles. The environment variables &lt;code&gt;XDG_CONFIG_HOME&lt;/code&gt;,
 &lt;code&gt;XDG_CACHE_HOME &lt;/code&gt;
      and &lt;code&gt;XDG_DATA_HOME &lt;/code&gt;
      modify the roots of these directories, respectively.
    &lt;/li&gt;
    &lt;li&gt;
      In previous versions, Linux/Unix installers created the installation directory with the default umask. Since install4j 9,
      the default Unix directory mode configured in the &amp;quot;Files-&amp;gt;File Options&amp;quot; view or the overridden mode configured for the
      &amp;quot;Installation directory&amp;quot; node in the distribution tree is used.
    &lt;/li&gt;
  &lt;/ul&gt;</description>
      <category>install4j</category>
      <category>Migration</category>
      <pubDate>Fri, 19 Feb 2021 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2021/02/migrating-to-install4j-9/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2021-02-19T08:00:57Z</dc:date>
    </item>
    <item>
      <title>New web license service and improvements for the on-premises server</title>
      <link>https://www.ej-technologies.com/blog/2021/06/new-web-license-server-and-improvements-for-the-on-premises-server/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Customers with floating licenses now have more flexibility: Starting with with the most recent releases of JProfiler and
    install4j, &lt;b&gt;we now offer a web license service,&lt;/b&gt;
    so you do not have to install a license server yourself. If you choose that option, you will receive a license key that 
    can be distributed to all developers and is entered just like a single license key. This option requires the ability to 
    make an outgoing HTTP request to our license server.
  &lt;/p&gt;

  
  &lt;p&gt;
    Going forward, we will be offering both the web as well as the the on-premises solution. For the time being, the 
    on-premises option remains the default and you can &lt;a href="https://www.ej-technologies.com/company/contact"&gt;contact us&lt;/a&gt;
    if you would like to switch to the web option.
  &lt;/p&gt;
 
  
  
  &lt;p&gt;
    There is also good news for the &lt;b&gt;on-premises license server&lt;/b&gt;
    with two great improvements that are available in the latest release:
  &lt;/p&gt;

  
  &lt;p&gt;&lt;b&gt;Remote checkout&lt;/b&gt;&lt;/p&gt;

  
  &lt;p&gt;
    When you take your computer offsite where you don't have access to the license server, you can check out a license for a
    number of days in the license dialog (Help-&amp;gt;Enter License Key):
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2021/06/remote_checkout-46ebfcd35ce6af8edd53c551663a7d46.png" class="img-fluid" loading="lazy" width="561" height="308"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    The maximum allowed number of days is configurable in the license server configuration and is set to 1 by default. If 
    you return early, you can give the license back to the license server so it becomes available for other team members:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2021/06/remote_checkout_early_return-795c6e6f15a158e4a363df7884d8713.png" class="img-fluid" loading="lazy" width="561" height="308"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;&lt;b&gt;Encryption and Authentication&lt;/b&gt;&lt;/p&gt;

  
  &lt;p&gt;
    Previously, you could either choose an unencrypted direct connection suitable for local networks or an SSH connection 
    suitable for use over the internet. However, the latter required SSH server access to the license server machine.
  &lt;/p&gt;

  
  &lt;p&gt;
    With the latest releases, you can enable encryption in the license server configuration and connect directly over the 
    internet with mutual authentication and TLS encryption. The license server creates a file &lt;kbd&gt;encryption/client.ks&lt;/kbd&gt;
    at startup (if it does not exist) that must be distributed to users and entered in the license dialog:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2021/06/encrypted-f5daf0e04c14fbd93d8eb73be33410ce.png" class="img-fluid" loading="lazy" width="561" height="308"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    Without that file, no connection to the license server is possible. To reset the authentication, simply delete the 
    &amp;quot;encryption&amp;quot; folder in the license server installation and restart the license server. A new authentication file will 
    then be generated.
  &lt;/p&gt;</description>
      <category>General</category>
      <pubDate>Thu, 24 Jun 2021 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2021/06/new-web-license-server-and-improvements-for-the-on-premises-server/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2021-06-24T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Migrating to install4j 10</title>
      <link>https://www.ej-technologies.com/blog/2022/07/migrating-to-install4j-10-0/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=migration"&gt;Migration&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In nearly all cases, migrating to install4j 10 usually just involves opening and saving your project with the install4j 10 IDE.
    Nevertheless, there are some considerations with respect to backward compatibility and some behavioral changes.
  &lt;/p&gt;

  

  
  &lt;h4 class="mt-5"&gt;Compile-time requirement for associations in archives on macOS&lt;/h4&gt;


  
  &lt;p&gt;
    Starting with ARM-based macOS machines, the Info.plist files of launchers cannot be modified at runtime without breaking
    the signature, so all content must be generated at compile time. This means that it is not possible to conditionally add
    file associations or URL handlers at runtime anymore. In earlier versions of install4j, the related behavior was
    different for Intel and ARM-based macOS machines, which was inconsistent.
  &lt;/p&gt;

  
  &lt;p&gt;
    To provide a way of configuring this information, the &amp;quot;Executable info-&amp;gt;macOS options&amp;quot; step of the launcher wizard now
    contains a list of file associations and URL handler definitions that are translated into the corresponding entries of
    the Info.plist file of the installer. Previously, archives would process the definitions of selected &amp;quot;Create a file
    association&amp;quot; and the &amp;quot;Register a URL handler&amp;quot; actions in the &amp;quot;Installer-&amp;gt;Screens &amp;amp; actions&amp;quot; section.
  &lt;/p&gt;


  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2022/07/associations_macos_step-139bdecd7f7d1faa6f36bcef852cf9c.png" class="img-fluid" loading="lazy" width="634" height="510"&gt;&lt;/div&gt;


  
  &lt;p&gt;
    You can either add a file association or a URL handler. A file association is defined by its extension, a description
    and an optional icon file. The role indicates whether the application just displays files or also edits their content.
  &lt;/p&gt;


  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2022/07/associations_macos_file-4e3264fe198d29ef69b131b29dcdee.png" class="img-fluid" loading="lazy" width="487" height="292"&gt;&lt;/div&gt;


  
  &lt;p&gt;
    The URL handler is defined by the URL scheme, so for a scheme of &amp;quot;hello&amp;quot; it handles requests in the browser that start
    with &amp;quot;hello://&amp;quot;.
  &lt;/p&gt;


  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2022/07/associations_macos_url_handler-bad596975ffd776d3ef3384aa569099.png" class="img-fluid" loading="lazy" width="486" height="262"&gt;&lt;/div&gt;


  
  &lt;p&gt;
    The &amp;quot;Create a file association&amp;quot; and the &amp;quot;Register a URL handler&amp;quot; actions now only work for Windows and Linux. If you
    open projects that were saved with previous versions of install4j, the information from these actions is migrated into
    the new settings for macOS in the launcher wizard.
  &lt;/p&gt;


  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2022/07/file_association_action_macos-8ec59438312417b99c4e31f7ce58501f.png" class="img-fluid" loading="lazy" width="581" height="554"&gt;&lt;/div&gt;


  
  &lt;p&gt;
    In situations where file associations were added conditionally, this migration may fail to produce the correct results,
    so you should check the migrated associations on the &amp;quot;Executable info-&amp;gt;macOS options&amp;quot; step of the launcher wizard after
    opening the project in install4j 10.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;Retirement of user-selectable MSI scope&lt;/h4&gt;


  
  &lt;p&gt;
    Creating MSI installers that can conditionally be installed for all users or for a selected user by passing ALLUSERS=1
    on the command line are no longer supported in new projects. We have found that the interaction of install4j-specific
    features with the user-selectable mode raises a number of undesirable behaviors and pitfalls that cannot be fixed within
    the architecture underlying install4j installers.
  &lt;/p&gt;

  
  &lt;p&gt;
    If you have already configured this setting, it will continue to work in the same way in install4j 10. However, you
    should switch to the per-machine or the per-user MSI scope.
  &lt;/p&gt;


  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2022/07/msi_options_new-c2bff023a1ee3b4630ef953ccc8d23.png" class="img-fluid" loading="lazy" width="663" height="449"&gt;&lt;/div&gt;</description>
      <category>install4j</category>
      <category>Migration</category>
      <pubDate>Tue, 26 Jul 2022 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/07/migrating-to-install4j-10-0/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-07-26T07:00:57Z</dc:date>
    </item>
    <item>
      <title>How to configure a script probe in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2022/08/how-to-configure-a-script-probe-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to configure a script probe for a Java profiling session in JProfiler.
  &lt;/p&gt;

  
  &lt;p&gt;
    Script probes are custom probes that intercept selected methods and construct payload strings with Java scripts that are
    entered directly in the JProfiler UI.
  &lt;/p&gt;

  
  &lt;p&gt;
    You then get a payload call tree, payload hot spots with back traces, telemetries for probe event counts and event 
    durations as well as the ability to inspect single events with their threads and stack traces.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/-Ri_rKmzPrs" title="Play video 'How to configure a script probe in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/-Ri_rKmzPrs-9888a6f73e6581da7b97321aa0653d95.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Mon, 01 Aug 2022 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/08/how-to-configure-a-script-probe-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-08-01T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Working with merged reference trees in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2022/08/working-with-merged-reference-trees-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to analyze memory leaks in Java applications or reduce memory consumption in general if the 
    objects of interest are not all referenced in the same way.
  &lt;/p&gt;

  
  &lt;p&gt;
    Analyzing a single object and finding the path to a garbage collector root is not enough in that case and the merged 
    incoming references view as well as the merged dominating reference view are helpful in finding out about the 
    distribution of the actual incoming references and how to make a maximum of objects eligible for garbage collection. &lt;br&gt;&lt;/p&gt;

  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/aBua8XF2zdY" title="Play video 'Working with merged reference trees in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/aBua8XF2zdY-6a6834b49fabe56999ba7148250bd2.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 05 Aug 2022 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/08/working-with-merged-reference-trees-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-08-05T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling HTTP calls and tracking them between JVMs</title>
      <link>https://www.ej-technologies.com/blog/2022/09/profiling-http-calls-and-tracking-them-between-jvms/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to profile HTTP calls with the HTTP client probe and use the HTTP remote request tracking 
    feature to follow HTTP calls from one JVM into another.
  &lt;/p&gt;

  
  &lt;p&gt;
    A simple Spring Boot project with two application is profiled: A gateway server that serves static files and proxies API
    request to a second server that handles REST calls.
  &lt;/p&gt;

  
  &lt;p&gt;
    You can see how JProfiler tracks calls from the browser including the JavaScript stack trace through the gateway server 
    into the REST server. The HTTP client probe with its various views is shown and its profiling settings are discussed.
  &lt;/p&gt;

  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/2qoNfW49C_o" title="Play video 'Profiling HTTP calls and tracking them between JVMs'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/2qoNfW49C_o-36351fd555f25fa23bfd250adf546ab.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Thu, 22 Sep 2022 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/09/profiling-http-calls-and-tracking-them-between-jvms/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-09-22T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Inlining asynchronous executions in JProfiler's call tree</title>
      <link>https://www.ej-technologies.com/blog/2022/10/inlining-asynchronous-executions-in-jprofilers-call-tree/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows how to use the &amp;quot;Inline async executions&amp;quot; call tree analysis to get a unified call tree across 
    thread boundaries
  &lt;/p&gt;

  
  &lt;p&gt;
    This is made possible by JProfiler &amp;quot;request tracking&amp;quot; feature. In the screencast, a simple example with Spring WebFlux 
    is profiled that creates permutations of a specified word.
  &lt;/p&gt;

  
  &lt;p&gt;
    Most reactive stream frameworks use the executor service JDK API for asynchronous execution. JProfiler can track tasks 
    that are submitted to an executor service and stitch them back into a single call tree when the &amp;quot;Inline async 
    executions&amp;quot; call tree analysis is invoked. This is essential when analyzing performance bottlenecks in asynchronous 
    programming models.
  &lt;/p&gt;

  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/NYPzjbuUmlI" title="Play video 'Inlining asynchronous executions in JProfiler's call tree'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/NYPzjbuUmlI-ae1e1117b5259d5a8618e948ba31c2a.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 05 Oct 2022 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/10/inlining-asynchronous-executions-in-jprofilers-call-tree/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-10-05T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling a Netty server</title>
      <link>https://www.ej-technologies.com/blog/2022/11/profiling-a-netty-server/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler's support for Netty covers many modern web frameworks that use Netty under hood, like Vert.x, Micronaut, Ktor 
    or Spring WebFlux.
  &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to profile a Netty server with customized URL splitting and gives an overview of the HTTP 
    server probe.
  &lt;/p&gt;

  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/eXSl_LS-_Cc" title="Play video 'Profiling a Netty server'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/eXSl_LS-_Cc-b34f5fea47529f2c861c99c74f9effb.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 02 Nov 2022 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/11/profiling-a-netty-server/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-11-02T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Using flame graphs when profiling Java applications</title>
      <link>https://www.ej-technologies.com/blog/2022/11/using-flame-graphs-when-profiling-java-applications/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Flame graphs are a great way to get an overview of the entire call tree and to visualize performance characteristics. 
    This screen cast shows how the &lt;a href="https://github.com/ingokegel/jclasslib"&gt;jclasslib bytecode viewer&lt;/a&gt;
    is profiled. A class file is opened and the parsing of the class file is analyzed with the flame graph.
  &lt;/p&gt;

  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/2a0vF404xgA" title="Play video 'Using flame graphs when profiling Java applications'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/2a0vF404xgA-9e39d6f3a54b7df7f0c6d07af0933b16.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 09 Nov 2022 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/11/using-flame-graphs-when-profiling-java-applications/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-11-09T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Using sunburst diagrams for understanding Java memory consumption</title>
      <link>https://www.ej-technologies.com/blog/2022/11/using-sunburst-diagrams-for-understanding-java-memory-consumption/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows how to use the sunburst diagram in the biggest objects view of JProfiler's heap walker to 
    visualize memory consumption of your Java application.
  &lt;/p&gt;

  
  &lt;p&gt;
    The sunburst diagrams shows a ring with the biggest objects and multiple reference levels of dominated objects in 
    successive outer rings. See &lt;a href="https://www.ej-technologies.com/resources/jprofiler/help/doc/main/heapWalker.html"&gt;the documentation&lt;/a&gt;
    to read about the dominator analysis and the biggest objects view.
  &lt;/p&gt;

  
  &lt;p&gt;
    In the screencast, a memory snapshot of the eclipse IDE is analyzed and the class loader and classes groupings of the 
    biggest object view are shown.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/kbL-GTHD1ik" title="Play video 'Using sunburst diagrams for understanding Java memory consumption'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/kbL-GTHD1ik-1a4d3acc2b141bfb3b54c6693171a2b.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 22 Nov 2022 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/11/using-sunburst-diagrams-for-understanding-java-memory-consumption/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-11-22T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling Java applications in Docker containers</title>
      <link>https://www.ej-technologies.com/blog/2022/12/profiling-java-applications-in-docker-containers/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows how to use JProfiler to profile a JVM that is running in a Docker container. JProfiler has 
    dedicated zero-configuration support for attaching to local and remote Docker containers and both cases are shown in the
    screencast.
  &lt;/p&gt;

  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/c4lMP2h5ezI" title="Play video 'Profiling Java applications in Docker containers'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/c4lMP2h5ezI-87d36bf6a349852899f447e220cc7e.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Mon, 05 Dec 2022 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/12/profiling-java-applications-in-docker-containers/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-12-05T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling Java applications in a Kubernetes cluster</title>
      <link>https://www.ej-technologies.com/blog/2022/12/profiling-java-applications-in-a-kubernetes-cluster/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows how you can profile JVMs running in Kubernetes cluster with JProfiler. A profiling session with a 
    note taking demo application sessions is started from the IDE, which provides additional benefits, like source code 
    navigation and the automatic detection of profiled packages. Also, a standalone session is started, where an additional 
    SSH connection is required to reach the kubectl command that can connect to the cluster.
  &lt;/p&gt;

  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/SkbpGan-W4Q" title="Play video 'Profiling Java applications in a Kubernetes cluster'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/SkbpGan-W4Q-b7f462df87b1cbf7d98c42d3aaad6c5.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 21 Dec 2022 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2022/12/profiling-java-applications-in-a-kubernetes-cluster/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2022-12-21T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling JEE/Spring applications</title>
      <link>https://www.ej-technologies.com/blog/2023/01/profiling-jee-spring-applications/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screencast showcases JProfiler's support for JEE and Spring, in particular the JEE/Spring component detection and 
    the JEE/Spring aggregation level in the call tree and hot spot views.
  &lt;/p&gt;

  
  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/IEs85B8eIlY" title="Play video 'Profiling JEE/Spring applications'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/IEs85B8eIlY-56fd153680ef3eb5382c695bb21a9bd.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 04 Jan 2023 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2023/01/profiling-jee-spring-applications/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2023-01-04T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Improved Kubernetes authentication handling in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2023/03/improved-kubernetes-authentication-handling-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Since version 13, JProfiler supports profiling on Kubernetes clusters with no extra configuration.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2023/02/kube1-d1f8ef19a55488b398f277859f98fb.png" class="img-fluid" loading="lazy" width="686" height="513"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    JProfiler 13.0.6 added an important improvement for profiling a JVM in Kubernetes clusters where authentication is set 
    up in such a way that the &lt;b&gt;authentication plugin prints instructions on stdout&lt;/b&gt;.

  &lt;/p&gt;

  
  
  &lt;p&gt;
    For example, when the Azure Kubernetes Service (AKS) is configured to authenticate with Active Directory (AD), users 
    will be required to authenticate their identity using the kubelogin authentication plugin. The plugin will initiate a 
    multi-factor authentication (MFA) process by prompting the user to open a URL and enter a one-time code. Previously, the
    information was not visible when JProfiler was making a connection to a Kubernetes cluster.
  &lt;/p&gt;

  
  &lt;p&gt;
    Since JProfiler 13.0.6, the progress dialog will be expanded if such output is detected. The command line output is then
    shown in a text area where text can be copied to the clipboard and links can be opened directly the system web browser:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2023/02/kube2-97663c89a4979240ecf444f724de5e92.png" class="img-fluid" loading="lazy" width="822" height="322"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    After completing the instructions, the connection will be made and the pods in the cluster will be listed.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2023/02/kube3-d5cb4f793821f48574bc39f5eb1c919.png" class="img-fluid" loading="lazy" width="486" height="542"&gt;&lt;/div&gt;</description>
      <category>General</category>
      <pubDate>Fri, 17 Mar 2023 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2023/03/improved-kubernetes-authentication-handling-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2023-03-17T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Customizing telemetries in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2023/09/customizing-telemetries-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Telemetries are an essential feature for a profiler, they help you get an idea about when things happen in the profiled 
    JVM, and how various subsystems are correlated.
  &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows how to customize the telemetries section in JProfiler by adding probe telemetries. It discusses 
    bookmarks, recording actions and setting time range filters for probe events in probe telemetries.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/mGBUunt1jG4" title="Play video 'Customizing telemetries in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/mGBUunt1jG4-5cae784ebdb1d2f288a0f1eeb747daf2.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 12 Sep 2023 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2023/09/customizing-telemetries-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2023-09-12T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Working with probe events in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2023/09/working-with-probe-events-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Probe events are of great help in debugging specific performance problems. To find events of interest, JProfiler gives 
    you a lot of tools to narrow down the set of displayed events.
  &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows the HTTP server and HTTP client probes, the JDBC and JPA/Hibernate probes as well as the socket 
    probe when profiling a real-world application. The various ways of filtering probe events as well as duration and 
    throughput histograms are explained.
  &lt;/p&gt;

  
  &lt;p&gt;
    The profiled application is the &lt;a href="https://github.com/Athou/commafeed"&gt;CommaFeed RSS reader&lt;/a&gt;.

  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/JB7o3M9Td1M" title="Play video 'Working with probe events in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/JB7o3M9Td1M-cd8f5d96b54251d87d1c675309dca.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 15 Sep 2023 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2023/09/working-with-probe-events-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2023-09-15T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Enhanced JFR snapshot analysis with JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2023/09/enhanced-jfr-snapshot-analysis-with-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler has excellent support for viewing JFR snapshots. This screencast focuses on the event browser, which is 
    specific to JFR snapshots, and also gives an overview of the other view sections that offer some of the same views as 
    regular profiling sessions.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/lK48imWrzdA" title="Play video 'Enhanced JFR snapshot analysis with JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/lK48imWrzdA-02e3c4eab514f4bf7c39a0b21315dd.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Mon, 18 Sep 2023 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2023/09/enhanced-jfr-snapshot-analysis-with-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2023-09-18T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Recording JFR snapshots with JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2023/09/recording-jfr-snapshots-with-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Recording JFR snapshots with JProfiler
  &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows JProfiler's versatile functionality as a JFR recording controller. As an example, a JFR recording 
    on a Kubernetes cluster is recorded and the resulting snapshot is shown in JProfiler. In this context, you can see the 
    wizard for configuring JFR recording settings. In addition, JFR recordings of terminated JVMs and the handling of 
    externally started JFR recordings are demonstrated.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/9JSLhh9LfSY" title="Play video 'Recording JFR snapshots with JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/9JSLhh9LfSY-9fa52ad4af1937c23b613da290a6993c.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 20 Sep 2023 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2023/09/recording-jfr-snapshots-with-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2023-09-20T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Garbage collector analysis in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2023/09/garbage-collector-analysis-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows how to use the garbage collector probe in JProfiler. Having access to detailed information about 
    the overall activity of the GC, as well as the single garbage collections, is crucial for tuning the garbage collector 
    and achieving an optimal performance for your application.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/NVHNxmSpkYw" title="Play video 'Garbage collector analysis in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/NVHNxmSpkYw-68d8c3971bdacf8b6edadcb419a761a9.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 22 Sep 2023 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2023/09/garbage-collector-analysis-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2023-09-22T07:00:57Z</dc:date>
    </item>
    <item>
      <title>How invokedynamic makes lambdas fast</title>
      <link>https://www.ej-technologies.com/blog/2024/01/how-invokedynamic-makes-lambdas-fast/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Recently, we have been at work rewriting our website in Kotlin. Instead of a view technology that uses string templates 
    with embedded logic, we now use the Kotlin HTML builder to develop views as pure Kotlin code. This has a number of 
    advantages, like being able to easily refactor common code. Also, the performance of such views is much better than that
    of string templates, which contain interpreted code snippets.
  &lt;/p&gt;

  
  &lt;p&gt;
    When measuring the performance, we noticed that a lot of anonymous classes were created for our views and their loading 
    time was significant. Code that uses the Kotlin HTML builder is very lambda-heavy and as of Kotlin 1.9, lambdas are 
    implemented as anonymous classes. The JVM has a sophisticated mechanism to avoid creating classes at compile time that 
    was introduced in Java 8 - the &lt;code&gt;LambdaMetafactory &lt;/code&gt;
    and &lt;code&gt;invokedynamic&lt;/code&gt;.
    The JVM developers also claimed that the performance would be better than anonymous classes. So why does Kotlin not use 
    that?
  &lt;/p&gt;

  
  
  &lt;p&gt;
    As it turns out, Kotlin can optionally compile lambdas with invokedynamic in the same way that Java does, by passing &lt;code&gt;-Xlambdas=indy&lt;/code&gt;
    to the Kotlin compiler. This has been supported since Kotlin 1.5 and will become the default in the upcoming Kotlin 2.0 
    release. The great thing about having both compilation strategies available, is that we can compare how anonymous 
    classes and invokedynamic compare in a real-world example.
  &lt;/p&gt;

  
  &lt;p&gt;
    First of all, the number of classes for our entire website project was reduced by 60% (!) when compiling with &lt;code&gt;-Xlambdas=indy&lt;/code&gt;.
    Here you can see the list of classes for our store view with both compilation modes:
  &lt;/p&gt;
 
  
    
  
  
  &lt;p&gt;
    For that particular view,&lt;b&gt; the cold rendering time was improved by 20%&lt;/b&gt;.
    This was simply measured by wrapping the rendering with a measurement function. How about the warmed-up rendering time? 
    The times there are much shorter, and we need to introduce some statistics by making many invocations. This is easily 
    done &lt;a href="https://www.ej-technologies.com/products/jprofiler/overview.html"&gt;with JProfiler&lt;/a&gt;
    and has the added benefit that we can also compare the internal call structure.
  &lt;/p&gt;

  
  &lt;p&gt;
    With the default compilation to anonymous classes, we recorded 50 invocations after warm-up and got 12.0 ms per 
    rendering:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/anonymous_calltree-e79f9f574a893cb915523bacc5843bd8.png" class="img-fluid" loading="lazy" width="720" height="416"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    With invokedynamic compilation, the time per rendering was 10.6 ms:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/indy_calltree-611d24ccd10c06f5be34eff7a2449b8.png" class="img-fluid" loading="lazy" width="720" height="416"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;&lt;b&gt;This is an improvement of 12%&lt;/b&gt;
    which is surprisingly large. This test does not measure the difference between the invocation mechanisms in isolation, 
    but it includes the actual work that is done to render the store view. Against that baseline duration, a speed-up of 12%,
    - just by changing the compilation mode for lambdas - is quite impressive. Many DSL-based libraries in Kotlin are 
    lambda-heave, so other use cases may also produce similar numbers.
  &lt;/p&gt;

  
  &lt;p&gt;
    By looking at the call tree, we can see that the version with anonymous classes makes 3 calls, instead of one: First, it
    instantiates the anonymous class and passes all the captured parameters:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/anonymous_calltree_constructor-1-40931fc9159f40a4c26e96e394dbedac.png" class="img-fluid" loading="lazy" width="722" height="462"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    Then it calls a bridge method without the captured parameters, which in turn calls the actual implementation:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/anonymous_lambda_calltree-2560ef86ab61f4b1a697678dd4048c4.png" class="img-fluid" loading="lazy" width="724" height="452"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    Looking at the bytecode, we can see that a number of instructions are required to store the captures parameters into 
    fields, and the bridge method also contains instructions that add to the overhead.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/anonymous_call_constructor-1-95d97ecc20ec412aa0f857285ffdcb27.png" class="img-fluid" loading="lazy" width="918" height="536"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    With invokedynamic compilation, the generated lambda methods are in the same class:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/indy_lambda_calltree-6e23cdb8a3bdd68ef3bc168c89ec12d7.png" class="img-fluid" loading="lazy" width="724" height="454"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    This works because the lambda instances are created by invokedynamic calls to so-called &lt;b&gt;bootstrap methods. &lt;/b&gt;&lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/indy_call-2-69be79e79386904d8c5abe763e19ba21.png" class="img-fluid" loading="lazy" width="918" height="536"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    Bootstrap methods are structures in the class file that contain signature information for the lambda and a method handle
    reference to a static method. The &lt;code&gt;LambdaMetafactory &lt;/code&gt;
    then efficiently creates an instance for the lambda.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/bootstrap_methods-2-1d75bfabc38453aa53e44a5f3c5e7e2.png" class="img-fluid" loading="lazy" width="918" height="479"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    This intricate mechanism makes lambda calls on the JVM as fast as they are - and from Kotlin 2.0 on this will be &lt;a href="https://youtrack.jetbrains.com/issue/KT-45375"&gt;the default for Kotlin as well&lt;/a&gt;.

  &lt;/p&gt;</description>
      <category>General</category>
      <pubDate>Wed, 10 Jan 2024 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2024/01/how-invokedynamic-makes-lambdas-fast/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2024-01-10T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Why JVMTI sampling is better than async sampling on modern JVMs</title>
      <link>https://www.ej-technologies.com/blog/2024/02/why-jvmti-sampling-is-better-than-async-sampling-on-modern-jvms/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In recent years, &amp;quot;async sampling&amp;quot; has been hyped as a better way of CPU profiling on the JVM. While this has been true 
    for some time, it is no longer the case. This blog post explains the history of sampling and the current state of the 
    art.
  &lt;/p&gt;

  

  
  &lt;h4 class="mt-5"&gt;The problem&lt;/h4&gt;
  
  
  
  &lt;p&gt;
    The fundamental operation of a CPU profiler is to associate time measurements with call stacks. To obtain call stacks 
    from all live threads, most CPU profilers perform &lt;b&gt;sampling&lt;/b&gt;.
    Sampling means that data is measured periodically rather than continuously. However, this measurement is not trivial 
    because the JVM does not store call stack information for easy access via an API.
  &lt;/p&gt;

  
  &lt;p&gt;
    The JVM compiles Java bytecode to native code for hot execution paths. The stack traces now have a native part that 
    needs to be retranslated to Java in order to be useful. Also, it is not possible to ask a running thread what it's 
    currently doing, but you have to interrupt it to get a defined state. Depending on how you do it, this introduces an 
    observer effect that can severely alter the execution of the program.
  &lt;/p&gt;

  
  &lt;p&gt;
    Historically, sampling could only be done at a &lt;b&gt;global safepoint&lt;/b&gt;.
    Global safepoints are states where the JVM can pause all threads for operations that require a consistent view of 
    memory. At a safepoint, all Java threads are paused, ensuring they are not in the middle of modifying shared data. While
    safepoints originated from the &lt;b&gt;stop-the-world&lt;/b&gt;
    phase of garbage collectors, they could also be used for other purposes, such as code deoptimization, class redefinition,
    and finally to safely get all stack traces for the purposes of sampling.
  &lt;/p&gt;

  
  &lt;p&gt;
    In contrast to garbage collector activity, sampling is performed quite frequently, on the order of once per millisecond.
    Requesting a global safepoint so many times per second can cause substantial overhead and a severe distortion of the 
    observed hot spots. The adverse effects of global safepoints are especially pronounced for heavily multithreaded 
    applications, where safepoints can limit concurrency, reduce thread cooperation and increase contention and 
    synchronization overhead. The observed hot spots will then be skewed towards the safepoints, an effect known as &lt;b&gt;safepoint bias&lt;/b&gt;.

  &lt;/p&gt;
 
  
  
  &lt;h4 class="mt-5"&gt;Async profiling to the rescue&lt;/h4&gt;
  
  
  
  &lt;p&gt;
    Unhappy with this state of affairs, the HotSpot JVM developers added the experimental &lt;code&gt;AsyncGetStackTrace&lt;/code&gt;
    API that allowed profilers to get the stack trace of threads without requiring a safepoint. On Unix systems, profilers 
    can use various signal mechanisms to periodically interrupt the running thread and execute a handler on the interrupted 
    thread and call this API.
  &lt;/p&gt;

  
  &lt;p&gt;
    While this adds minimal overhead, it unfortunately is not an ideal solution. The main problem is that the interrupted 
    thread and the JVM in general are in an unsafe state. The handler must be very careful not to perform any operation 
    which might crash the process. These restrictions, especially regarding memory access and allocations make some advanced
    features of a profiler unfeasible. Also, the retranslation of the stack traces back to the Java stack trace results in a
    lot of stack traces being truncated or otherwise invalid. In addition, async sampling is also sampling from the pool of 
    all live threads, so rarely scheduled threads will sometimes be missed completely.
  &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler supports JVMTI sampling as well as async sampling, and as part of our tests we perform a lot of data 
    comparisons. While async sampling is near-zero overhead and eliminates safepoint bias, it introduces a certain 
    &amp;quot;trashiness&amp;quot; to the data and places limits on which features are possible to implement. For a long time, it seemed like 
    an unavoidable trade-off with only bad options. One could choose one or the other sampling method based on the type of 
    application and accept the corresponding drawbacks.
  &lt;/p&gt;
 
  
  
  &lt;h4 class="mt-5"&gt;ZGC and thread-local handshakes&lt;/h4&gt;
  
  
  
  &lt;p&gt;
    In the quest for an ultra-low latency garbage collector, the JVM developers needed a way to perform operations on 
    individual threads without requiring a global VM safepoint. In Java 10, &lt;a href="https://openjdk.org/jeps/312"&gt;JEP 312&lt;/a&gt;
    was delivered with no concrete use cases. While intriguing at the time, we were unable to make any use of this feature 
    because it was internal to the JVM and not available for profiling agents.
  &lt;/p&gt;

  
  &lt;p&gt;
    The only publicly mentioned purpose in JEP 312 was that it blocked &lt;a href="https://openjdk.org/jeps/333"&gt;JEP 333&lt;/a&gt;
    for the Z Garbage Collector (ZGC). In Java 11, ZGC was delivered as one of the big-ticket items, and thread-local 
    handshakes helped it push maximum GC pause times below 10ms.
  &lt;/p&gt;

  
  &lt;p&gt;
    ZGC continued to be improved, and &lt;a href="https://openjdk.org/jeps/376"&gt;JEP 376&lt;/a&gt;
    aimed to evict its last major work item from global safepoints: The processing of thread-related GC roots was moved to a
    concurrent phase. That JEP included a goal to &lt;b&gt;&amp;quot;provide a mechanism by which other HotSpot subsystems can lazily process stacks&amp;quot; &lt;/b&gt;
    and issues like &lt;a href="https://bugs.openjdk.org/browse/JDK-8248362"&gt;https://bugs.openjdk.org/browse/JDK-8248362&lt;/a&gt;
    added this capability to the JVMTI, the interface that is used by native profiling agents.
  &lt;/p&gt;
 
  
  
  &lt;h4 class="mt-5"&gt;JVMTI sampling strikes back&lt;/h4&gt;
  
  
  
  &lt;p&gt;
    With Java 16, JEP 376 was delivered, and it was possible for profiling agents to use the lazy stack processing based on 
    thread-local handshakes and avoid global safepoints for sampling. JVMTI sampling (called &amp;quot;full sampling&amp;quot; in JProfiler), 
    is now comparable in overhead with async sampling and, given the frequency of local safepoints, the remaining local 
    safepoint bias is irrelevant for the vast majority of applications.
  &lt;/p&gt;

  
  &lt;p&gt;
    Let's compare a real-world use case. A multithreaded Maven compilation for a medium-sized project was recorded with both
    JVMTI sampling and async sampling. The overhead is not measurably different, and the hot spot distribution is very 
    similar. See the &amp;quot;Hot spots&amp;quot; view in JProfiler below, first for JVMTI sampling:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/sampling_jvmti-f0ea80b996991ecd1f778ad167ea45ea.png" class="img-fluid" loading="lazy" width="1394" height="880"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    … and then for async sampling:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/sampling_async-2005671f8d2b63f1582dd725229624.png" class="img-fluid" loading="lazy" width="1394" height="882"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    Is the difference the remaining safepoint bias? Not necessarily so, and most probably not. There are two other important
    factors at play: First, async sampling measures &lt;b&gt;threads that are actually running&lt;/b&gt;
    while JVMTI sampling measures &lt;b&gt;if threads are scheduled for execution&lt;/b&gt;,
    that is if they are &amp;quot;runnable&amp;quot;. The JProfiler UI reflects this in the labelling of the thread status.
  &lt;/p&gt;

  
  &lt;p&gt;
    Second, async sampling operations do not work all the time. The technical &amp;quot;outages&amp;quot; are summed up at the bottom of the 
    call tree without contributing to the total percentage:
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/async_misses-1-ad251f8deb28c66585a373785fa4f3.png" class="img-fluid" loading="lazy" width="1392" height="350"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    These are substantial times and they do contribute some skew. So while async sampling measures actual CPU times, they 
    are only &lt;b&gt;partial CPU times&lt;/b&gt;
    and not a more useful measure than the runnable time measured by JVMTI sampling.
  &lt;/p&gt;

  
  &lt;p&gt;
    As an example of a feature that async sampling cannot provide, try to change the thread state to &amp;quot;Waiting&amp;quot;, &amp;quot;Blocking&amp;quot; 
    or &amp;quot;Net I/O&amp;quot;. With async sampling, these are not available, unlike with JVMTI sampling.
  &lt;/p&gt;
  
  
  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/2024/01/async_thread_states-1-6d6e99eaef9ef91dd9690d26ae637f.png" class="img-fluid" loading="lazy" width="1392" height="320"&gt;&lt;/div&gt;

  
  
  &lt;p&gt;
    When working with databases or REST services, having access to the &amp;quot;Net I/O&amp;quot; state is an invaluable benefit, though, 
    because these are the times waiting for the external service.
  &lt;/p&gt;

  
  &lt;p&gt;
    What remains for async sampling? Async sampling can profile native stack traces, so if you are interested in that, it 
    remains a useful tool. Other than that, full sampling is now by far the better alternative, in terms of data quality and
    available features, without compromising on overhead.
  &lt;/p&gt;

  
  &lt;p&gt;
    We invite you to try it out in the &lt;a href="https://www.ej-technologies.com/download/jprofiler/files"&gt;latest JProfiler release&lt;/a&gt;.
    Happy profiling!
  &lt;/p&gt;</description>
      <category>General</category>
      <category>JProfiler</category>
      <pubDate>Thu, 01 Feb 2024 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2024/02/why-jvmti-sampling-is-better-than-async-sampling-on-modern-jvms/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2024-02-01T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Namespace awareness of XML actions in install4j</title>
      <link>https://www.ej-technologies.com/blog/2024/08/namespace-awareness-of-xml-actions-in-install4j/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This post explains an exceptional backward-incompatibility in the install4j 10.0.9 release. This was necessary due to a
    change in install4j 10.0.8 that was intended to fix the corruption of namespaced XML documents by modifying XML actions.
  &lt;/p&gt;

  
  
  &lt;p&gt;
    install4j provides a number of actions that work with XML files, like reading values, inserting fragments or removing nodes.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/xmlNamespaceActions/xml_actions_registry-2fa790f45f547eec9a5697d8edd74ba.png" class="img-fluid" loading="lazy" width="488" height="460"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    Most of these actions require that you enter an &lt;a href="https://en.wikipedia.org/wiki/XPath"&gt;XPath expression&lt;/a&gt; to select the parts of
    the document to operate on. In versions prior to install4j 10.0.9, the XML parser used by the actions was &lt;b&gt;not namespace-aware&lt;/b&gt;, so
    the XPath expressions did not require any namespaces.
  &lt;/p&gt;

  
  &lt;p&gt;
    This typically works well for reading values from an XML file, and it continues to be the default for install4j 10.0.9+, where the
    &amp;quot;XPath expression&amp;quot; property now has a new &amp;quot;Namespace-aware&amp;quot; child property that is initially deselected.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/xmlNamespaceActions/read_xml_value_xpath-24ab907593b6cc415fad3daef4f2105a.png" class="img-fluid" loading="lazy" width="864" height="449"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    However, when modifying XML documents, the XML file needs to be written again, and using a non-namespace-aware XML parser means that the
    &lt;b&gt;namespaces would be lost&lt;/b&gt;. To fix this problem, we turned on namespace-awareness for all XML actions in install4j 10.0.8. However, this
    meant that there was no way of specifying XPath expressions that matched namespaced elements anymore.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/xmlNamespaceActions/remove_xml_nodes_namespaces-2229949b188555f15ef0d01e88669e14.png" class="img-fluid" loading="lazy" width="864" height="438"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    This is why the &amp;quot;XPath expression&amp;quot; property of all modifying XML actions has an &lt;b&gt;&amp;quot;XML namespaces&amp;quot; child property&lt;/b&gt; since install4j 10.0.9.
  &lt;/p&gt;

  
  &lt;p&gt;
    Here you can specify namespaces and their prefixes in a separate dialog and then use the namespace prefixes in your XPath expression.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/xmlNamespaceActions/xml_namespaces_dialog-8bf63d8ffa84b01b8d8145301f2af079.png" class="img-fluid" loading="lazy" width="434" height="283"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    If you used XML documents &lt;b&gt;without namespaces, no changes are required&lt;/b&gt; if you have configured XML actions in earlier versions of install4j.
    While the &amp;quot;Read value from XML file&amp;quot; and the &amp;quot;Count nodes in XML file&amp;quot; actions continue to work with namespaced elements as before,
    the following actions require changes to the XPath expression if they match namespaced elements with their &amp;quot;XPath expression&amp;quot; properties:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;&amp;quot;Insert XML fragment into XML files&amp;quot; action&lt;/li&gt;
    &lt;li&gt;&amp;quot;Remove nodes from XML files&amp;quot; action&lt;/li&gt;
    &lt;li&gt;&amp;quot;Replace text in XML files&amp;quot; action&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;p&gt;
    Each node test in the XPath expression that required a &lt;b&gt;qualified name (QName) must now include the appropriate namespace prefix&lt;/b&gt; that
    matches an entry in the &amp;quot;XML namespaces&amp;quot; child property. For example, in the XML document
  &lt;/p&gt;

  
  &lt;pre&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot; ?&amp;gt;
&amp;lt;config xmlns=&amp;quot;http://mycorp/cluster&amp;quot; xmlns:ext=&amp;quot;http://mycorp/server&amp;quot;&amp;gt;
  &amp;lt;cluster&amp;gt;
    &amp;lt;ext:server name=&amp;quot;production&amp;quot; port=&amp;quot;8000&amp;quot;/&amp;gt;
    &amp;lt;ext:server name=&amp;quot;staging&amp;quot; port=&amp;quot;7000&amp;quot;/&amp;gt;
  &amp;lt;/cluster&amp;gt;
&amp;lt;/config&amp;gt;&lt;/pre&gt;

  
  &lt;p&gt;
    the non-namespaced XPath expression to match the server port of the production server is
  &lt;/p&gt;

  
  &lt;pre&gt;
//cluster/server[name='production']/@port&lt;/pre&gt;

  
  &lt;p&gt;
    For the modifying XML actions, this XPath has to be changed to
  &lt;/p&gt;

  
  &lt;pre&gt;
/c:cluster/ext:server[name='production']/@port&lt;/pre&gt;

  
  &lt;p&gt;
    with the namespace definitions
  &lt;/p&gt;

  
  &lt;pre&gt;
c=http://mycorp/cluster
ext:http://mycorp/server&lt;/pre&gt;

  
  &lt;p&gt;
    in the &amp;quot;XML namespaces&amp;quot; child property.
  &lt;/p&gt;

  
  &lt;p&gt;
    While the &amp;quot;cluster&amp;quot; element in the source document is not written with a prefix, it is in a default namespace that must be specified
    just like the explicit namespaces to ensure the XPath expression matches it correctly.
  &lt;/p&gt;</description>
      <category>install4j</category>
      <pubDate>Wed, 21 Aug 2024 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2024/08/namespace-awareness-of-xml-actions-in-install4j/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2024-08-21T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Migrating to install4j 11</title>
      <link>https://www.ej-technologies.com/blog/2024/09/migrating-to-install4j-11-0/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=migration"&gt;Migration&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In most cases, migrating to install4j 11 usually just involves opening and saving your project with the install4j 11 IDE.
    Nevertheless, there are some considerations with respect to backward compatibility and some behavioral changes.
  &lt;/p&gt;

  
  
  &lt;ul&gt;
    &lt;li&gt;
      Notarization now uses the App Store Connect API. Previously, install4j could only perform notarization when building on macOS using the
      &lt;code&gt;notarytool&lt;/code&gt; command line tool for which an Apple ID was required in the configuration. That mode is no longer supported in
      install4j 11. For the App Store Connect API, you need to specify issuer ID, key ID and the downloaded private key file.
    &lt;/li&gt;
    &lt;li&gt;
      The install4j IDE and command line compiler now require Java 21. The runtime requirement for the generated installers and launchers remains
      Java 8. The install4j downloads for Windows, macOS and Linux x64 contain a suitable JRE. If you download the Unix media files, you have to make
      sure to install Java 21 on your build server first.
    &lt;/li&gt;
    &lt;li&gt;
      The list of releases from JDK providers is now requested from URLs below &lt;code&gt;https://www.ej-technologies.com/jreprovider/&lt;/code&gt;.
      This allows us to respond to API changes without breaking older versions of install4j and to introduce fixups for erroneous
      releases from JDK providers. The actual downloads are still performed from the URLs that are published by the JDK providers.
      If you have added exceptions to your firewalls, you need to take this into account.
    &lt;/li&gt;
    &lt;li&gt;
      
      &lt;p&gt;
        As announced in the 10.x series, the macOS single bundle installer has been removed. The macOS single bundle archive should be used as
        a replacement. However, the macOS single bundle installer media files are not migrated automatically because it may take some consideration
        as to which actions you would like to run when the launcher is started for the first time.
      &lt;/p&gt;

      
      &lt;p&gt;
        On the &amp;quot;Launcher&amp;quot; tab of the media file wizard, you can select a &amp;quot;setup application&amp;quot; from the list of custom installer applications that are
        defined in the &amp;quot;Installer-&amp;gt;Screens &amp;amp; Actions&amp;quot; step. In that custom installer application you can link to screens and actions, or
        screen groups and action groups to avoid duplicating configuration.
      &lt;/p&gt;

      
      &lt;p&gt;
        This removal was necessary due to signature and notarization requirements, which made the bundle directory unmodifiable at runtime.
        This installer type has been non-functional in recent macOS releases.
      &lt;/p&gt;

    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;Sign all launchers&amp;quot; option for macOS media files has been removed as launchers are now always signed to comply with notarization
      requirements.
    &lt;/li&gt;
    &lt;li&gt;
      For the &amp;quot;Add VM options&amp;quot; and the &amp;quot;Modify classpath&amp;quot; actions, the property &amp;quot;Target file on macOS&amp;quot; was removed.  It offered an option to
      write the .vmoptions file into the application bundle, which is no longer possible due to current notarization requirements. These files are
      now always created next to the application bundle.
    &lt;/li&gt;
    &lt;li&gt;
      
      &lt;p&gt;
        install4j 11 has removed support for dynamic JRE downloads and shared JRE installations. Modern JREs that are linked to a minimum required module set
        do not match with these features and lead to various problems at runtime. Also, the concept of pre-installed JREs that could be found is no
        longer a mainstream concept.
      &lt;/p&gt;

      
      &lt;p&gt;
        Instead, we have expanded support for the use case where the initial download contains the JRE and updates should not include a JRE for small
        downloads and fast installations:
      &lt;/p&gt;

      
      &lt;ol&gt;
        &lt;li&gt;
          The new &amp;quot;Previous installations&amp;quot; search sequence entry type on the &amp;quot;General Settings-&amp;gt;JRE Bundles-&amp;gt;Search Sequence&amp;quot; step helps you
          to reuse the installed JRE in update installers. Only installations with the same application ID are considered for the search sequence
          entry type.
        &lt;/li&gt;
        &lt;li&gt;
          The &amp;quot;Install files&amp;quot; action now copies a JDK from a different installation directory if it was found by the &amp;quot;Previous installations&amp;quot;
          search sequence entry. This prevents issues that would arise if the other installation is uninstalled.
        &lt;/li&gt;
        &lt;li&gt;
          Update downloaders can now make decisions based on the JRE version of the update installer by inspecting
          &lt;code&gt;com.install4j.api.update.UpdateDescriptorEntry#getJreMinVersion&lt;/code&gt; and &lt;code&gt;#getJreMaxVersion&lt;/code&gt;. If the JRE version
          matches the currently used JRE, you can download a media file without a bundled JRE, otherwise a media file with a JRE should
          be downloaded.
        &lt;/li&gt;
      &lt;/ol&gt;

    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;Open PDF viewer&amp;quot; action and the &amp;quot;PDF display&amp;quot; form component now require at least Java 11.
    &lt;/li&gt;
    &lt;li&gt;
      Custom names of screens, actions and form components are no longer written to the runtime configuration, and only bean IDs are annotated
      into stack traces. These names were not usable programmatically and could expose unintended text. When inspecting
      stack traces, use the &amp;quot;Search ID&amp;quot; feature on the &amp;quot;Installer-&amp;gt;Screens &amp;amp; actions&amp;quot; step to locate the corresponding beans.
    &lt;/li&gt;
    &lt;li&gt;
      There are breaking changes in the Gradle plugin configuration. All properties are now typed correctly and use the Gradle provider mechanism.
      This was necessary to enable compatibility with the configuration cache where extensions and projects cannot be accessed at execution time.
      Also, the deprecated &lt;code&gt;variableFile&lt;/code&gt; property was removed.
    &lt;/li&gt;
    &lt;li&gt;
      Keyboard shortcut changes in generated installers on macOS: To move to the previous or next installer screen, use
      &lt;kbd&gt;Ctrl+Option+Left Arrow&lt;/kbd&gt; and &lt;kbd&gt;Ctrl+Option+Right Arrow&lt;/kbd&gt;. The previous keyboard shortcuts did not work in text fields.
      On Windows and Linux, the shortcuts remain &lt;kbd&gt;Ctrl+Left Arrow&lt;/kbd&gt; and &lt;kbd&gt;Ctrl-Right Arrow&lt;/kbd&gt; respectively.
    &lt;/li&gt;
    &lt;li&gt;
      The &amp;quot;Installation type&amp;quot; screen now behaves differently if the selected installation type is user-configurable and the user does not change
      the installation type in an upgrade installer. In this case, the selected components retain their previous installation state, and are not
      reset to the default set of the installation type.
    &lt;/li&gt;
    &lt;li&gt;
      For generated GUI launchers for which the &amp;quot;Uses SWT or QT&amp;quot; option has been selected on the &amp;quot;Executable info&amp;quot; step of the launcher wizard,
      installer applications - such as the update downloader - can only be started in a new process. This is necessary to avoid deadlocks.
      For automatic launcher integrations this is enforced automatically regardless of the settings on the &amp;quot;Launcher Integrations&amp;quot; tab of the
      custom installer application. Programmatic invocation through &lt;code&gt;ApplicationLauncher.launchApplicationInProcess&lt;/code&gt; will throw a
      &lt;code&gt;IllegalStateException&lt;/code&gt; in this case. Use &lt;code&gt;ApplicationLauncher.launchApplication&lt;/code&gt; instead.
    &lt;/li&gt;
  &lt;/ul&gt;</description>
      <category>install4j</category>
      <category>Migration</category>
      <pubDate>Mon, 02 Sep 2024 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2024/09/migrating-to-install4j-11-0/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2024-09-02T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Refreshed JProfiler IDEA plugin for the new UI</title>
      <link>https://www.ej-technologies.com/blog/2024/09/refreshed-jprofiler-idea-plugin-for-the-new-ui/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Kotlin 2.0 features a &lt;a href="https://kotlinlang.org/docs/whatsnew20.html#kotlin-k2-compiler"&gt;total rewrite of the Kotlin compiler&lt;/a&gt;
    known as &amp;quot;Kotlin K2&amp;quot;. IntelliJ IDEA will remove support for the old compiler in version 2024.3 impacting all plugins that depend on the
    Kotlin plugin, such as the JProfiler IDEA plugin.
  &lt;/p&gt;

  
  &lt;p&gt;
    The newest version of the JProfiler IDEA plugin for IntelliJ IDEA &lt;b&gt;now includes support for Kotlin K2 mode&lt;/b&gt;. This means that the JProfiler
    plugin no longer prevents switching to K2 mode in IntelliJ IDEA 2024.2 and is now ready for IntelliJ IDEA 2024.3 where K2 mode
    will be the default and plugins depending on the old API will no longer be loaded.
  &lt;/p&gt;

  
  &lt;p&gt;
    We took this opportunity to align the JProfiler plugin with another recent major change in IntelliJ IDEA: The &lt;b&gt;new UI&lt;/b&gt;, which became the
    default in &lt;a href="https://blog.jetbrains.com/blog/2024/07/08/the-new-ui-becomes-the-default-in-2024-2/"&gt;IntelliJ IDEA 2024.2&lt;/a&gt;.
    It is impractical for IDEA plugins to support both the old and the new UI, so we decided to change the UI once the new UI became widely used.
  &lt;/p&gt;

  
  
  &lt;p&gt;
    Plugin icons have been adjusted to the style of the new UI in IDEA. The action to profile the selected run configuration with JProfiler continues
    to be available in the dropdown menu of the run widget:
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/profile_action-bc4c72b375cbc71a5602f1a7cd88cb0.png" class="img-fluid" loading="lazy" width="693" height="561"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The JProfiler plugin adds additional settings to run configurations which are not immediately visible. To access these settings, select the
    &amp;quot;Profile&amp;quot; option in the &amp;quot;Modify options&amp;quot; dropdown. All other profiling settings can be configured in the startup dialog of the JProfiler window.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/profiling_settings-e71772565a5be4fdd696bd4df3ac04d.png" class="img-fluid" loading="lazy" width="926" height="882"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    Once the profiling session is started, the output appears in a separate JProfiler tool window. That tool window displays the console output like
    the regular run tool window, along with a &amp;quot;JProfiler&amp;quot; tab that can be used after you connect with the JProfiler UI:
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/profiling_startup-599cc65aafbbb3afaddc568db9abb5aa.png" class="img-fluid" loading="lazy" width="693" height="561"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The &amp;quot;JProfiler&amp;quot; tab contains actions to start and stop data recording for CPU data, allocation data and probe events. Additionally, an action
    allows you to switch to the JProfiler window. The JProfiler window includes a similar action for switching back to the IDEA window, so that
    it becomes convenient to work with the two separate windows.
  &lt;/p&gt;

  
  &lt;p&gt;
    Profiling information is typically displayed in the JProfiler window, but the CPU graph data is also integrated in the IntelliJ IDEA UI
    because it makes sense to show this data directly in the source code. Use the &amp;quot;Apply graph&amp;quot; action in IntelliJ IDEA or generate a CPU
    graph in JProfiler to display CPU data within IntelliJ IDEA.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/profiling_controls-197e6bcaf49ca626f0b296f15d6bb1b.png" class="img-fluid" loading="lazy" width="693" height="561"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    Once the CPU data has been applied, the &amp;quot;JProfiler&amp;quot; tab displays a list of recorded methods. Double-clicking on a method will take you to the
    source code. In the gutter of the source code editor, arrows for incoming and outgoing calls are added.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/profiling_hotspots-d39dc5d10373f315c16ae6e425b4.png" class="img-fluid" loading="lazy" width="1123" height="561"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    Clicking on a gutter icon displays the incoming or outgoing methods in a popup window, along with a bar chart showing the recorded times.
    Clicking on rows in the popup will navigate to the corresponding methods.
  &lt;/p&gt;

  
  &lt;p&gt;
    Also, the total recorded time and the invocation count for the target method will be shown at the bottom of the popup. The &amp;quot;Show in JProfiler&amp;quot;
    drop down in the bottom-right corner of the popup provides context-dependent navigation actions into the JProfiler UI.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/profiling_gutter_icons-4627401542204fcf179ce86fbf177954.png" class="img-fluid" loading="lazy" width="1123" height="561"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The same navigation actions are also available in the context menu of the method table in the &amp;quot;JProfiler&amp;quot; tab:
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/hotspot_context_menu-1c8c7d156f88f331768186c63199d4c.png" class="img-fluid" loading="lazy" width="800" height="561"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    One major change in the new IntelliJ IDEA UI is that plugins no longer add actions to the main toolbar. Instead, plugins can provide
    &amp;quot;toolbar quick actions&amp;quot; that are shown when you choose the &amp;quot;Add to Main Toolbar&amp;quot; action in the context menu of the main toolbar.
  &lt;/p&gt;

  
  &lt;p&gt;
    In the new JProfiler plugin there is now a toolbar quick action for the &amp;quot;Attach to JVM with JProfiler&amp;quot; action. With that action you can
    attach to a process that is already running and still get source code navigation from the JProfiler UI into IntelliJ IDEA as well as inline CPU
    graph data in source code editors:
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/add_to_tool_bar-cbf62d587ab32dae364482dd50dc2e.png" class="img-fluid" loading="lazy" width="693" height="561"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    This is how the action button looks like once it has been added:
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/attach_action-ce3979415b377a6a04833ecdf4725e8.png" class="img-fluid" loading="lazy" width="693" height="561"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The key bindings for all actions in JProfiler can be customized in the &amp;quot;Keymap&amp;quot; settings in IntelliJ IDEA. Given the limited availability of
    non-conflicting keyboard shortcuts, the navigation actions from the source code editor to the JProfiler UI are chained shortcuts where you first
    hit &lt;kbd&gt;Ctrl-Alt-Shift-O&lt;/kbd&gt; and then another key to select the navigation action. If you frequently use this functionality, you may want to
    assign simpler keyboard shortcuts.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/ideaPluginRefresh/key_bindings-f81c7ec9e3c6d57b6eb741ffa3581f.png" class="img-fluid" loading="lazy" width="900" height="700"&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <pubDate>Mon, 23 Sep 2024 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2024/09/refreshed-jprofiler-idea-plugin-for-the-new-ui/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2024-09-23T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Improvements for macOS App Store submissions in install4j 11.0.2</title>
      <link>https://www.ej-technologies.com/blog/2025/01/improvements-for-macos-app-store-submissions/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    install4j 11.0.2 introduces several new features to simplify macOS App Store submissions, including automated entitlement handling for TestFlight,
    improved support for local testing with development provisioning profiles, and dynamic bundle versioning for easier resubmission of builds.
  &lt;/p&gt;

  
  
  &lt;h4 class="mt-5"&gt;Background&lt;/h4&gt;

  
  &lt;p&gt;
    Submitting a Java app to the Mac App Store can be a daunting task. Understanding the involved concepts and fulfilling
    the many requirements set by Apple is much easier when you have install4j to help you reach the finish line.
  &lt;/p&gt;

  
  &lt;p&gt;
    Since install4j 10.0, &amp;quot;the single bundle archive&amp;quot; media file type in install4j has an App Store submission mode that generates
    a .pkg installer that supports an optional &amp;quot;provisioning profile&amp;quot;.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/macosAppStore/media_wizard-c2a6e45cd51d258e4ba7eedd4e65f2.png" class="img-fluid" loading="lazy" width="809" height="503"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    In addition, the launcher has several settings that are relevant for a successful App Store submission.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/macosAppStore/launcher_options-255fb323ff62ee62a1cd342da925edfd.png" class="img-fluid" loading="lazy" width="809" height="542"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    To be able to submit an application, the bundle identifier for the launcher must match the configured ID in App Store Connect.
    Since apps in the App Store run in a sandbox, they cannot even open a file without requesting the appropriate &amp;quot;entitlement&amp;quot;. These
    fine-grained permissions can be requested in the entitlements file. Finally, the application category is a required attribute
    for an App Store submission.
  &lt;/p&gt;

  
  &lt;h4 class="mt-5"&gt;Provisioning profiles&lt;/h4&gt;

  
  &lt;p&gt;
    To complicate things, Apple has two different sets of entitlements. Some entitlements such as &amp;quot;com.apple.developer.applesignin&amp;quot; and
    &amp;quot;com.apple.developer.icloud-service&amp;quot; require a provisioning profile. This is an artifact that you create in your Apple Developer
    Account under &amp;quot;Certificates, Identifiers &amp;amp; Profiles&amp;quot;.
  &lt;/p&gt;

  
  &lt;p&gt;
    In addition, using TestFlight is only possible when a provisioning profile is specified and the same &amp;quot;com.apple.application-identifier&amp;quot;
    and &amp;quot;com.apple.developer.team-identifier&amp;quot; attributes are also present in the entitlements file. Starting with install4j 11.0.2,
    these values are automatically copied to the entitlements by install4j, so using TestFlight is enabled as long as you use a provisioning profile.
  &lt;/p&gt;

  
  &lt;h4 class="mt-5"&gt;Code signing certificates&lt;/h4&gt;

  
  &lt;p&gt;
    Code signing for the App Store is further complicated by the fact that you need certificates of the types &amp;quot;Mac App Distribution&amp;quot; (for the app)
    and &amp;quot;Mac Installer Distribution&amp;quot; (for the .pkg installer). For each certificate, you have to generate a certificate signing request in the
    Keychain app, create the appropriate certificate in the Apple Developer Account, and import the certificate in Keychain.
  &lt;/p&gt;

  
  &lt;p&gt;
    When exporting from your Keychain, you have to add these certificates together with their private keys and specify the PKCS#12 file in install4j.
    If you also distribute non-App Store builds, you will also need to include an &amp;quot;Apple Developer ID&amp;quot; certificate. install4j automatically
    chooses the correct certificate from the specified PKCS#12 keystore.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/macosAppStore/certificates-6c64811387646520879da72c80a7e5d9.png" class="img-fluid" loading="lazy" width="894" height="620"&gt;&lt;/div&gt;

  
  &lt;h4 class="mt-5"&gt;Local testing&lt;/h4&gt;

  
  &lt;p&gt;
    If you want to test the sandboxed environment of your app, you may want to install the generated .pkg file before submitting it to the App Store.
    However, if you use an App Store provisioning profile, such an installation will fail.
  &lt;/p&gt;

  
  &lt;p&gt;
    Instead, you have to use a &amp;quot;macOS App Development&amp;quot; provisioning profile and install it on your local machine. A development provisioning
    profile is associated with certificates of the type &amp;quot;Apple Development&amp;quot; or &amp;quot;Mac Development&amp;quot;. This means that you have to change both the
    provisioning profile and the code signing certificate to create a development
    build.
  &lt;/p&gt;

  
  &lt;p&gt;
    Before install4j 11.0.2, using certificate types other than &amp;quot;Mac App Distribution&amp;quot; or &amp;quot;Mac Installer Distribution&amp;quot; for App Store code
    signing was not supported, so using development provisioning profiles was not possible.
  &lt;/p&gt;

  
  &lt;p&gt;
    If you do not require the special entitlements that are only available via provisioning profiles and you do not need to use TestFlight for
    testing, you can opt to not use a provisioning profile at all. In that case, the generated .pkg will be installable on your local machine even
    when signed with the distribution certificates.
  &lt;/p&gt;

  
  &lt;h4 class="mt-5"&gt;Resubmitting builds&lt;/h4&gt;

  
  &lt;p&gt;
    Another App Store-related improvement in install4j 11.0.2 is that the CFBundleVersion attribute is now set to a timestamp to allow submitting
    multiple builds with the same version to the App Store. Previously, you would have to change the user-facing version if a build was rejected
    by the App Store.
  &lt;/p&gt;

  
  &lt;hr&gt;

  
  &lt;p&gt;
    Ready to simplify your macOS App Store submissions? &lt;a href="https://www.ej-technologies.com/install4j/download"&gt;Download the current version&lt;/a&gt;
    of install4j and try it yourself.
  &lt;/p&gt;</description>
      <category>install4j</category>
      <pubDate>Tue, 14 Jan 2025 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/01/improvements-for-macos-app-store-submissions/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-01-14T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Cross-platform JRE bundle creation under threat from JEP 493</title>
      <link>https://www.ej-technologies.com/blog/2025/04/cross-platform-jre-bundle-creation-under-threat-from-jep-493/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    One of the most valuable capabilities introduced with the Java module system in Java 9 is its support for creating custom runtime
    images with &lt;code&gt;jlink&lt;/code&gt;. Developers can include only the modules they need, resulting in lightweight JRE bundles tailored to the
    requirements of their applications. Using the &lt;code&gt;--module-path &lt;/code&gt; option, it has even been possible to generate those runtime
    images for different operating systems from a single host machine.
  &lt;/p&gt;

  
  &lt;p&gt;
    With Java 24, &lt;a href="https://openjdk.org/jeps/493"&gt;JEP 493&lt;/a&gt; introduces a change that significantly impacts this workflow.
    JDK vendors can now configure builds without &lt;code&gt;.jmod&lt;/code&gt; files, as &lt;code&gt;jlink&lt;/code&gt; can optionally extract the required resources
    from the &lt;code&gt;lib/modules&lt;/code&gt; jimage file. While this change reduces the size of the JDK by about 25%, it also removes critical support
    for cross-platform linking.
  &lt;/p&gt;

  

  
  &lt;h4 class="mt-5"&gt;The impact on deployment workflows&lt;/h4&gt;

  
  &lt;p&gt;
    Cross-platform linking is essential for developers who build installation packages or runtime bundles targeting multiple operating systems.
    Without &lt;code&gt;.jmod&lt;/code&gt; files in the JDK, the &lt;code&gt;--module-path&lt;/code&gt; option of the &lt;code&gt;jlink&lt;/code&gt; tool can no longer be used to
    link bundles for another target platform. This is because binary resources like executables and native libraries are extracted from
    &lt;code&gt;.jmod&lt;/code&gt; files. In the jmod-less mode, these resources can only be extracted from the current JDK.
  &lt;/p&gt;

  
  &lt;p&gt;
    This change affects tools such as &lt;a href="https://www.ej-technologies.com/install4j"&gt;install4j&lt;/a&gt;, the
    &lt;a href="https://github.com/beryx/badass-runtime-plugin"&gt;Badass Runtime Plugin&lt;/a&gt;,
    and &lt;a href="https://github.com/moditect/moditect"&gt;Moditect&lt;/a&gt;, which rely on the availability of &lt;code&gt;.jmod&lt;/code&gt; files to build
    minimal, cross-platform runtime images. Their functionality is either limited or entirely blocked when &lt;code&gt;.jmod&lt;/code&gt; files are not available.
  &lt;/p&gt;

  
  &lt;p&gt;
    For example, in install4j, users can select a JDK provider to build platform-specific runtime bundles directly within the project configuration:
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jep493/provider-9e85cafdfe414d1d26ed4868f85481ba.png" class="img-fluid" loading="lazy" width="812" height="610"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    Later in the process, the media wizard allows developers to bundle additional modules that are needed for the target platform:
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jep493/media-60d9569cfc38f4ca4a4e52719119d6dc.png" class="img-fluid" loading="lazy" width="788" height="594"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;Current state across JDK distributions&lt;/h4&gt;

  
  &lt;p&gt;
    Adoptium has adopted JEP 493 for Eclipse Temurin in full, and its Java 24 builds no longer include &lt;code&gt;.jmod&lt;/code&gt; files. This decision
    aligns with the goals of the JEP. To their credit, the Adoptium team has been very transparent and responsive in community discussions,
    and a solution to provide &lt;code&gt;.jmod&lt;/code&gt; files as a separate download is currently being discussed.
  &lt;/p&gt;

  
  &lt;p&gt;
    As of Java 24.0, JDK distributions such as Azul Zulu, Amazon Corretto, and BellSoft Liberica continue to provide &lt;code&gt;.jmod&lt;/code&gt; files in
    their Java 24 builds, maintaining compatibility with existing tools and workflows. It is hoped that other JDK vendors adopting JEP 493 will also
    recognize that &lt;code&gt;.jmod&lt;/code&gt; files still need to be provided one way or another.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;Proposed solution&lt;/h4&gt;

  
  &lt;p&gt;
    The simplest and most practical solution is to publish &lt;code&gt;.jmod&lt;/code&gt; files as an optional artifact alongside the standard jmod-less builds.
    This would preserve support for deployment tooling without compromising the goals of JEP 493.
  &lt;/p&gt;

  
  &lt;p&gt;
    Maintaining &lt;code&gt;.jmod&lt;/code&gt; builds ensures that developers have the flexibility to choose between minimized JDK distributions and
    full-featured ones that support cross-platform deployment.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;Community feedback matters&lt;/h4&gt;

  
  &lt;p&gt;
    If your build is affected by this change, it is important to share your experience. The
    &lt;a href="https://github.com/adoptium/adoptium-support/issues/1271"&gt;Adoptium issue&lt;/a&gt; is open, and the maintainers are actively
    listening to feedback.
  &lt;/p&gt;

  
  &lt;p&gt;
    The ability to build platform-specific runtime images remains a crucial requirement for many real-world Java projects.
    Let’s ensure that continues to be possible.
  &lt;/p&gt;</description>
      <category>install4j</category>
      <pubDate>Tue, 08 Apr 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/04/cross-platform-jre-bundle-creation-under-threat-from-jep-493/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-04-08T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Caching auto-provisioned install4j distributions in CI pipelines</title>
      <link>https://www.ej-technologies.com/blog/2025/04/caching-auto-provisioned-install4j-distributions-in-ci-pipelines/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Starting with install4j 11.0, integrating install4j into your build system has become much easier:
    The Gradle, Maven, and Ant plugins can now auto-provision the install4j distribution.
    This means the plugins will download and cache the appropriate install4j version automatically,
    so you no longer need to install install4j manually.
  &lt;/p&gt;


  

  
  &lt;p&gt;
    Since 11.0.3, the distribution is cached in OS-specific locations using sensible defaults for each build system:
  &lt;/p&gt;


  
  &lt;ul&gt;
    &lt;li&gt;&lt;b&gt;Gradle&lt;/b&gt; caches to the Gradle user home (e.g. &lt;code&gt;~/.gradle&lt;/code&gt;)&lt;/li&gt;
    &lt;li&gt;&lt;b&gt;Maven&lt;/b&gt; and &lt;b&gt;Ant&lt;/b&gt; cache to OS-specific locations:
      &lt;code&gt;%LOCALAPPDATA%/install4jDist&lt;/code&gt; on Windows,
      &lt;code&gt;$HOME/Library/Caches/install4jDist&lt;/code&gt; on macOS, and
      either &lt;code&gt;$XDG_CACHE_HOME/install4jDist&lt;/code&gt; or
      &lt;code&gt;$HOME/.cache/install4jDist&lt;/code&gt; on Linux.
    &lt;/li&gt;
  &lt;/ul&gt;


  
  &lt;p&gt;
    While this works well for local development, it’s less ideal for CI environments where you often want full
    control over the caching location to speed up builds and avoid redundant downloads. That’s why in the upcoming
    &lt;b&gt;install4j 11.0.4&lt;/b&gt; release, we're introducing the optional
    &lt;code&gt;autoProvisioningCacheDir&lt;/code&gt; property.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;Quick plugin usage examples&lt;/h4&gt;


  &lt;b&gt;Gradle (Kotlin DSL)&lt;/b&gt;
  
  &lt;pre&gt;
plugins {
  id(&amp;quot;com.install4j.gradle&amp;quot;) version &amp;quot;11.0.4&amp;quot;
}

install4j {
    // New optional global and task-level property in 11.0.4+
    autoProvisioningCacheDir = layout.buildDirectory.dir(&amp;quot;custom-install4j-dist-cache&amp;quot;).get().asFile
}

register&amp;lt;Install4jTask&amp;gt;(&amp;quot;install4j&amp;quot;) {
    projectFile = file(&amp;quot;resources/main/installer/myProject.install4j&amp;quot;)
}&lt;/pre&gt;


  &lt;b&gt;Maven&lt;/b&gt;
  
  &lt;pre&gt;
&amp;lt;plugin&amp;gt;
  &amp;lt;groupId&amp;gt;com.install4j&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;install4j-maven-plugin&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;11.0.4&amp;lt;/version&amp;gt;
  &amp;lt;executions&amp;gt;
      &amp;lt;execution&amp;gt;
        &amp;lt;id&amp;gt;compile-installers&amp;lt;/id&amp;gt;
        &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;
        &amp;lt;goals&amp;gt;
          &amp;lt;goal&amp;gt;compile&amp;lt;/goal&amp;gt;
        &amp;lt;/goals&amp;gt;
        &amp;lt;configuration&amp;gt;
          &amp;lt;!-- New optional property in 11.0.4+ --&amp;gt;
          &amp;lt;autoProvisioningCacheDir&amp;gt;${project.build.directory}/custom-install4j-dist-cache&amp;lt;/autoProvisioningCacheDir&amp;gt;
          &amp;lt;projectFile&amp;gt;${project.basedir}/resources/main/installer/myProject.install4j&amp;lt;/projectFile&amp;gt;
        &amp;lt;/configuration&amp;gt;
      &amp;lt;/execution&amp;gt;
  &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;&lt;/pre&gt;


  &lt;b&gt;Ant&lt;/b&gt;
  
  &lt;pre&gt;
&amp;lt;taskdef name=&amp;quot;install4j&amp;quot;
         classname=&amp;quot;com.install4j.Install4JTask&amp;quot;
         classpath=&amp;quot;ant.jar&amp;quot;/&amp;gt;

&amp;lt;target name=&amp;quot;media&amp;quot;&amp;gt;
  &amp;lt;!-- New optional task property in 11.0.4+ --&amp;gt;
  &amp;lt;install4j projectFile=&amp;quot;myProject.install4j&amp;quot;
         autoProvisioningCacheDir=&amp;quot;${basedir}/custom-install4j-dist-cache&amp;quot;/&amp;gt;
&amp;lt;/target&amp;gt;&lt;/pre&gt;


  
  &lt;h4 class="mt-5"&gt;Caching in GitHub Actions&lt;/h4&gt;

  
  &lt;p&gt;
    If you're using GitHub Actions for CI, you can ensure that the downloaded install4j distribution is cached across runs.
    Here's a simple example with a Gradle build using the default cache location:
  &lt;/p&gt;


  
  &lt;pre&gt;
name: Build with install4j

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'

      - name: Cache install4j distribution
        uses: actions/cache@v4
        with:
          path: ~/.gradle/install4jDist
          key: install4j-${{ runner.os }}-${{ hashFiles('**/build.gradle.kts') }}

      - name: Build
        run: ./gradlew build&lt;/pre&gt;


  
  &lt;p&gt;To use a custom cache directory, define it as an environment variable:&lt;/p&gt;

  
  &lt;pre&gt;
env:
  INSTALL4J_CACHE_DIR: ${{ runner.temp }}/install4j-cache

...

- name: Cache install4j distribution
  uses: actions/cache@v4
  with:
    path: ${{ env.INSTALL4J_CACHE_DIR }}
    key: install4j-${{ runner.os }}-${{ hashFiles('**/build.gradle.kts') }}&lt;/pre&gt;


  
  &lt;p&gt;And reference it in your Gradle build script:&lt;/p&gt;

  
  &lt;pre&gt;
install4j {
  autoProvisioningCacheDir = file(System.getenv(&amp;quot;INSTALL4J_CACHE_DIR&amp;quot;))
}&lt;/pre&gt;


  
  &lt;p&gt;
    This setup not only speeds up GitHub Actions builds, but also applies to any CI system where you can persist
    directories between runs, such as GitLab CI, Jenkins, or CircleCI.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;Summary&lt;/h4&gt;

  
  &lt;p&gt;
    While the auto-provisioning feature simplifies local development, the new &lt;code&gt;autoProvisioningCacheDir&lt;/code&gt;
    option gives you full control in CI pipelines. With the 11.0.4 release, you’ll be able to manage where your install4j
    distributions are cached across all three supported build systems. This provides consistent and efficient builds
    across both developer and CI environments.
  &lt;/p&gt;</description>
      <category>install4j</category>
      <pubDate>Mon, 14 Apr 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/04/caching-auto-provisioned-install4j-distributions-in-ci-pipelines/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-04-14T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Bringing JProfiler to VS Code with Kotlin Multi-Platform</title>
      <link>https://www.ej-technologies.com/blog/2025/04/bringing-jprofiler-to-vs-code-with-kotlin-multi-platform/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    At ej-technologies, we've long provided &lt;a href="https://www.ej-technologies.com/jprofiler"&gt;JProfiler&lt;/a&gt; integrations for Java IDEs
    like IntelliJ, Eclipse, and NetBeans. These plugins share a significant amount of logic: profiler configuration, session management,
    and communication with the JProfiler backend, all written in Kotlin.
  &lt;/p&gt;

  
  &lt;p&gt;
    When we decided to add support for VS Code, we faced a problem: VS Code extensions run on Node.js, not the JVM.
    Rewriting the plugin from scratch in TypeScript would have been inefficient. Instead, we turned to &lt;b&gt;Kotlin Multi-Platform (KMP)&lt;/b&gt;,
    allowing us to reuse our existing Kotlin code while adapting to the JavaScript ecosystem.
  &lt;/p&gt;


  

  
  &lt;h4 class="mt-5"&gt;The Challenge of Cross-Platform Code&lt;/h4&gt;


  
  &lt;p&gt;
    To support platform-specific functionality in shared code, Kotlin Multi-Platform uses the expect/actual mechanism. In the common source set,
    an &lt;code&gt;expect&lt;/code&gt; declaration defines a function, class, or property without an implementation. Then, in each platform-specific source set
    (JVM, JS, etc.), an &lt;code&gt;actual&lt;/code&gt; declaration provides the corresponding implementation. This lets the shared code call into
    platform-specific functionality without relying on reflection or dynamic dispatch.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/vs_code_kmp/kmp-50d89d4623785ab08ba060bb72bd9754.svg" class="img-fluid" loading="lazy" width="400" height="280"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The core of our plugin was already in Kotlin but moving it to &lt;i&gt;common&lt;/i&gt; Kotlin code meant replacing all JVM-specific dependencies.
  &lt;/p&gt;


  
  &lt;h5 class="mt-4"&gt;Replacing the JRE&lt;/h5&gt;

  
  &lt;p&gt;
    For example, Kotlin common code can't rely on &lt;code&gt;java.io&lt;/code&gt; for file access or &lt;code&gt;java.lang.ProcessBuilder&lt;/code&gt; for OS processes.
    To migrate these two APIs, we used:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;&lt;a href="https://github.com/Kotlin/kotlinx-io"&gt;kotlinx-io&lt;/a&gt; for file operations and I/O&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/05nelsonm/kmp-process"&gt;kmp-process&lt;/a&gt; for process management (a critical piece, since JProfiler launches external processes)&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;p&gt;
    For example, consider the following JVM code that writes some text to a file:
  &lt;/p&gt;

  
  &lt;pre&gt;
java.io.File(&amp;quot;file.txt&amp;quot;).writeText(&amp;quot;Hello&amp;quot;)&lt;/pre&gt;

  
  &lt;p&gt;
    With kotlinx-io, we defined the following extension function to achieve the same effect:
  &lt;/p&gt;

  
  &lt;pre&gt;
// Multi-platform file write using kotlinx-io
fun kotlinx.io.files.Path.writeText(text: String) {
    kotlinx.io.files.SystemFileSystem.sink(this).buffered().use { it.writeText(text) }
}&lt;/pre&gt;

  
  &lt;p&gt;
    For anyone migrating JVM code to Kotlin common code, JetBrains offers a useful site for finding Kotlin Multi-Platform
    libraries: &lt;a href="https://klibs.io"&gt;https://klibs.io&lt;/a&gt;.
  &lt;/p&gt;


  
  &lt;p&gt;
    These libraries worked as expected but required careful adjustments, especially around error handling and platform-specific quirks.
  &lt;/p&gt;


  
  &lt;h5 class="mt-4"&gt;Serialization: From Kryo to kotlinx.serialization&lt;/h5&gt;

  
  &lt;p&gt;
    Our existing plugins used &lt;a href="https://github.com/EsotericSoftware/kryo"&gt;Kryo&lt;/a&gt; for communication between the IDE and JProfiler.
    Kryo relies on JVM functionality. To support Kotlin/JS, we migrated to &lt;b&gt;kotlinx.serialization&lt;/b&gt;.
  &lt;/p&gt;

  
  &lt;p&gt;
    This wasn't just a drop-in replacement. Kryo's runtime reflection and &lt;code&gt;kotlinx.serialization&lt;/code&gt;'s compile-time approach
    demanded changes to our data classes. However, we managed to annotate them in a way that both frameworks could serialize the same objects,
    ensuring backward compatibility with older JProfiler versions.
  &lt;/p&gt;


  
  &lt;h5 class="mt-4"&gt;Coroutines Instead of Threads&lt;/h5&gt;

  
  &lt;p&gt;
    The original plugin used multithreading for tasks like background communication with the profiler. In KMP, we replaced this with
    &lt;b&gt;Kotlin coroutines&lt;/b&gt;, which work seamlessly across JVM and JavaScript.
  &lt;/p&gt;

  
  &lt;p&gt;
    This shift wasn't trivial. Coroutines require a different mindset, but the result is clean and maintainable.
  &lt;/p&gt;


  
  &lt;h5 class="mt-4"&gt;Adapting jclasslib for Multi-Platform&lt;/h5&gt;


  
  &lt;p&gt;
    In our plugin code, we need to read class files to resolve line numbers and other debug information. We use the &lt;b&gt;jclasslib&lt;/b&gt; library
    for this purpose, which we maintain in-house. As part of the KMP migration, we adapted jclasslib's data structures module into a
    Kotlin Multi-Platform library. This allowed us to keep the same class file parsing logic while making it available to both our JVM and Node.js
    platforms.
  &lt;/p&gt;

  
  &lt;p&gt;
    That migration can be seen in &lt;a href="https://github.com/ingokegel/jclasslib/commit/28d23a79d09767ebb984636234adbd86be65da77"&gt;this single commit&lt;/a&gt;
    and mostly involves getting rid of Java-specific class references and migrating I/O to kotlinx-io. Note that we only migrated the data structures
    module. Migrating the bytecode viewer would be more challenging, but with
    &lt;a href="https://www.jetbrains.com/de-de/compose-multiplatform/"&gt;Compose Multiplatform&lt;/a&gt;, it looks feasible.
  &lt;/p&gt;

  
  &lt;p&gt;
    As an upside, jclasslib is now also listed on &lt;a href="https://klibs.io/project/ingokegel/jclasslib"&gt;klibs.io&lt;/a&gt;, so you can use it in
    your own Kotlin Multi-Platform projects.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;Bridging Kotlin and TypeScript&lt;/h4&gt;


  
  &lt;p&gt;
    While most of our logic could live in Kotlin, the VS Code extension still needed a &lt;b&gt;TypeScript layer&lt;/b&gt; to interact with VS Code's APIs.
  &lt;/p&gt;


  
  &lt;h5 class="mt-4"&gt;The Limits of Kotlin/JS Interop&lt;/h5&gt;

  
  &lt;p&gt;
    Ideally, Kotlin Multi-Platform should generate bindings for JavaScript libraries, but &lt;b&gt;TypeScript integration isn't yet available&lt;/b&gt;.
    JetBrains started developing &lt;a href="https://github.com/Kotlin/dukat"&gt;Dukat&lt;/a&gt;, a tool for generating Kotlin declarations from TypeScript,
    but it currently remains stalled and non-functional for non-trivial use cases.
  &lt;/p&gt;

  
  &lt;p&gt;
    Since this means that the VS Code API is not discoverable in Kotlin MP, using it would require a lot of manual work.
    Fortunately, TypeScript feels familiar to Kotlin developers, so this wasn't a major hurdle.
  &lt;/p&gt;

  
  &lt;p&gt;
    Another issue was the blurred line between Node.js and browser targets in Kotlin/JS. This is something we hope will improve with
    &lt;a href="https://youtrack.jetbrains.com/issue/KT-47038/KJS-MPP-Split-JS-target-into-JsBrowser-and-JsNode"&gt;future KMP updates&lt;/a&gt;.
  &lt;/p&gt;


  
  &lt;h5 class="mt-4"&gt;Sharing Interface Definitions&lt;/h5&gt;

  
  &lt;p&gt;
    One pleasant surprise was how well Kotlin's &lt;b&gt;interface definitions&lt;/b&gt; translated to TypeScript. We could define contracts
    (like RPC messages) in Kotlin and consume them in TypeScript with minimal friction. The reverse (using TypeScript types
    in Kotlin) was a lot harder, requiring manual type mappings.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;The Result&lt;/h4&gt;

  
  &lt;p&gt;
    Today, JProfiler's &lt;a href="https://marketplace.visualstudio.com/items?itemName=ejtech.jprofiler"&gt;VS Code extension&lt;/a&gt; offers
    the same core features as our other IDE plugins, thanks to Kotlin Multi-Platform.
    Developers can profile their applications directly from VS Code, with most of the logic shared across all supported platforms.
  &lt;/p&gt;

  
  &lt;p&gt;
    Along the way, we have learned the following lessons:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;&lt;b&gt;KMP is powerful but demands adaptation&lt;/b&gt;. Replacing JVM APIs requires research and testing.&lt;/li&gt;
    &lt;li&gt;&lt;b&gt;Coroutines simplify cross-platform concurrency&lt;/b&gt;, but migrating from threads takes effort.&lt;/li&gt;
    &lt;li&gt;&lt;b&gt;TypeScript interop works best one-way&lt;/b&gt; (Kotlin → TypeScript). For now, manual bridging is still necessary.&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;p&gt;
    If you're a Kotlin developer exploring multi-platform possibilities to prevent a full rewrite, our experience shows that
    even niche use cases like IDE plugins can benefit from KMP.
  &lt;/p&gt;</description>
      <category>JProfiler</category>
      <pubDate>Wed, 16 Apr 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/04/bringing-jprofiler-to-vs-code-with-kotlin-multi-platform/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-04-16T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling Kafka #1 – Message Flow &amp; Hot Spots</title>
      <link>https://www.ej-technologies.com/blog/2025/04/profiling-kafka-applications-with-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;Kafka-based applications are notoriously hard to profile. Message flow happens in background threads, stack traces don’t reveal the full picture, and it’s hard to know which topic contributes to which hot spot.&lt;/p&gt;

  
  &lt;p&gt;JProfiler’s Kafka probes give you deep insight: producers, consumers, and message-level details are all captured and correlated with performance data.&lt;/p&gt;

  
  &lt;p&gt;This screencast walks through profiling a Spring Kafka application, showing how:&lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;consumer call trees are split by topic&lt;/li&gt;
    &lt;li&gt;producers link directly into probe views&lt;/li&gt;
    &lt;li&gt;you can correlate CPU hot spots with Kafka topics&lt;/li&gt;
    &lt;li&gt;Kafka events are filterable, inspectable, and aggregatable&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/y5cdBHSVoIo" title="Play video 'Profiling Kafka #1 – Message Flow &amp;amp; Hot Spots'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/y5cdBHSVoIo-917cf626bbd146dbc496d4f6f11f8f19.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Tue, 22 Apr 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/04/profiling-kafka-applications-with-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-04-22T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Advanced Kafka probe configuration in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2025/04/advanced-kafka-probe-configuration-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In our &lt;a href="/blog/2025/04/profiling-kafka-applications-with-jprofiler/"&gt;first Kafka screencast&lt;/a&gt;, we looked at how JProfiler correlates
    message flow and CPU usage through producers, consumers, and topic-level call trees.
  &lt;/p&gt;

  
  &lt;p&gt;In this follow-up, we go deeper, showing how to configure custom naming for Kafka messages based on their content.&lt;/p&gt;

  
  &lt;p&gt;This enables you to:&lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;split call trees by semantic message types&lt;/li&gt;
    &lt;li&gt;track specific event types in probe views&lt;/li&gt;
    &lt;li&gt;add value-level details to single event descriptions&lt;/li&gt;
    &lt;li&gt;visualize outliers in event duration histograms&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;p&gt;We also trigger a Kafka message spike via an API call and analyze its impact, all without changing the application code.&lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/Gs0vOwsulqQ" title="Play video 'Advanced Kafka probe configuration in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/Gs0vOwsulqQ-48334daaa388cd9196361da3695287.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 23 Apr 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/04/advanced-kafka-probe-configuration-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-04-23T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling Java applications in VS Code with JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2025/04/profiling-java-applications-in-vs-code-with-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler now integrates directly into VS Code, bringing the powerful profiling tool into your everyday development workflow.
  &lt;/p&gt;

  
  &lt;p&gt;
    In this screencast, we profile the Spring Pet Clinic demo and walk through the features of the JProfiler extension for VS Code, including:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;Toggling profiling mode&lt;/li&gt;
    &lt;li&gt;Automatic setup of profiled packages&lt;/li&gt;
    &lt;li&gt;Source code navigation from profiling views&lt;/li&gt;
    &lt;li&gt;Attach mode for unsupported launch methods (like Maven)&lt;/li&gt;
    &lt;li&gt;Built-in Gradle integration&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/cXZNTCHp5Hg" title="Play video 'Profiling Java applications in VS Code with JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/cXZNTCHp5Hg-cee6679b35c18dc696acdf94fb5f14.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;

  
  &lt;p&gt;
    If you're using a launch method in VS Code that isn't currently supported, let us know, we’re always looking to expand support.
  &lt;/p&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 25 Apr 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/04/profiling-java-applications-in-vs-code-with-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-04-25T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Advanced SSH remote profiling with JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2025/04/advanced-ssh-remote-profiling-with-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Remote profiling can be challenging when SSH access involves custom setups, proxies, or cloud authentication plugins.
    JProfiler 15 introduces advanced SSH connection features that remove these obstacles, enabling profiling in complex environments
    without manual setup.
  &lt;/p&gt;

  
  &lt;p&gt;
    This screen cast shows how to profile remote JVMs even in situations where the built-in SSH client is insufficient,
    using AWS Session Manager as an example.
  &lt;/p&gt;

  
  &lt;p&gt;
    Along the way, you will see how to:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;Use OpenSSH mode for remote profiling&lt;/li&gt;
    &lt;li&gt;Connect with ProxyCommand and the AWS CLI&lt;/li&gt;
    &lt;li&gt;Handle SSH port forwarding restrictions with netcat mode&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/fj8H9d8SZ0s" title="Play video 'Advanced SSH remote profiling with JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/fj8H9d8SZ0s-405cfe1628222597570e98ecd7bfaed.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Mon, 28 Apr 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/04/advanced-ssh-remote-profiling-with-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-04-28T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Capturing and comparing MBean states with JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2025/04/capturing-and-comparing-mbean-states-with-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    MBeans expose a wide range of runtime metrics and management operations that are essential for understanding the internal
    state of Java applications. Traditionally, JProfiler has supported live inspection of MBeans during a profiling session.
  &lt;/p&gt;

  
  &lt;p&gt;
    With the new MBean snapshot feature in JProfiler 15, it is now possible to capture the complete MBean state, compare snapshots, and
    analyze metrics offline, even after the application has shut down.
  &lt;/p&gt;

  
  &lt;p&gt;
    This screencast demonstrates the new functionality with a small Hazelcast application that performs random map operations
    and registers a custom MBean for triggering cleanup operations.
  &lt;/p&gt;

  
  &lt;p&gt;
    Along the way, you will see how to:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;Capture and compare MBean snapshots manually&lt;/li&gt;
    &lt;li&gt;Trigger MBean snapshots programmatically with method triggers&lt;/li&gt;
    &lt;li&gt;Restrict the snapshot scope to specific MBeans&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/W13gjuo-KA4" title="Play video 'Capturing and comparing MBean states with JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/W13gjuo-KA4-a8aaf8a489ef3a52ec9ef21be1f9eb52.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 30 Apr 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/04/capturing-and-comparing-mbean-states-with-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-04-30T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Heap Walker scripting for snapshot analysis</title>
      <link>https://www.ej-technologies.com/blog/2025/05/filtering-and-grouping-in-the-heap-walker-for-snapshot-analysis/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Previously, JProfiler's heap walker only offered advanced filtering and grouping features in live sessions.
    With JProfiler 15, the heap walker introduces full support for filtering and grouping in snapshots. A new API lets you write
    scripts to filter objects or define custom grouping logic based on dumped object data.
  &lt;/p&gt;

  
  &lt;p&gt;
    This screencast demonstrates the new functionality with a small Hibernate-based demo that creates different types of query cache entries.
    Hibernate’s second-level cache can quickly fill up with unexpected entries, and identifying what’s taking up space is key to resolving
    memory issues. JProfiler now makes it possible to answer such questions with snapshots.
  &lt;/p&gt;

  
  &lt;p&gt;
    The screencast shows how you can:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;Group cache keys by query structure to compare memory impact&lt;/li&gt;
    &lt;li&gt;Use object set filter scripts to isolate problematic cache entries&lt;/li&gt;
    &lt;li&gt;Use merged dominating references to understand why objects are retained&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/5d_AIS4kPpY" title="Play video 'Heap Walker scripting for snapshot analysis'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/5d_AIS4kPpY-cd7e5c5578bd232b91040974a97b471.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 02 May 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/05/filtering-and-grouping-in-the-heap-walker-for-snapshot-analysis/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-05-02T07:00:57Z</dc:date>
    </item>
    <item>
      <title>JVM performance watch roundup April 2025</title>
      <link>https://www.ej-technologies.com/blog/2025/05/jvm-performance-watch-roundup-april-2025/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=roundup"&gt;Roundup&lt;/a&gt; &lt;/p&gt;

  &lt;img alt="Blog image" src="/assets/blog/roundup_news-7f106869a6539c0dbea80be25103095.png" class="float-start" loading="lazy" width="140" height="125"&gt;
  &lt;p&gt;
          I post notes on JVM performance-related news on social media whenever a patch, JEP, or benchmark catches my eye.
          This blog post collects everything shared in April 2025. Each section rewrites the original thread in plain text.
        &lt;/p&gt;
  &lt;p&gt;Follow me on &lt;a href="https://www.linkedin.com/in/ingokegel/" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on LinkedIn"&gt; &lt;i class="icon icon-linkedin" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://www.youtube.com/@IngoKegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on YouTube"&gt; &lt;i class="icon icon-youtube" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://x.com/IngoKegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on X"&gt; &lt;i class="icon icon-twitter-x" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://mastodon.social/@ingokegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on Mastodon"&gt; &lt;i class="icon icon-mastodon" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://bsky.app/profile/ingokegel.bsky.social" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on Bluesky"&gt; &lt;i class="icon icon-bluesky" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt; to get these updates as soon as they go out.&lt;/p&gt;
  &lt;div class="clearfix"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;1. JFR to gain CPU-time-aware sampling&lt;/h4&gt;

  
  &lt;p&gt;
    A new &lt;a href="https://openjdk.org/jeps/509"&gt;JEP draft&lt;/a&gt; proposes CPU-time profiling in JFR via a new &lt;code&gt;jdk.CPUTimeSample&lt;/code&gt; event.
    Unlike today’s JFR sampling, which can’t distinguish between running and waiting threads, this upgrade measures actual
    CPU time consumed between timestamps.
  &lt;/p&gt;

  
  &lt;p&gt;
    Samples will include thread ID, timing, and CPU delta, and can be configured by interval or frequency. This allows more accurate attribution
    of CPU usage in profiling tools.
  &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler will use this to highlight real CPU hot spots in JFR snapshots by identifying code that was actually executing rather
    than just present in stack traces.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;2. Scoped values finalized in Java 25&lt;/h4&gt;

  
  &lt;p&gt;
    Scoped values are replacing ThreadLocal as a safer and faster way to pass context, especially in structured concurrency
    and virtual threads. Finalized by &lt;a href="https://openjdk.org/jeps/506"&gt;JEP 506&lt;/a&gt; after five previews, they arrive in Java 25.
  &lt;/p&gt;

  
  &lt;p&gt;
    Unlike ThreadLocal, scoped values are immutable and don’t require copying to child threads. This eliminates overhead in virtual
    thread hierarchies and prevents bugs caused by unintended sharing of mutable state.
  &lt;/p&gt;

  
  &lt;p&gt;
    They also reduce the risk of memory leaks. ThreadLocal often leads to memory leaks when large objects or class loaders are accidentally retained.
    Scoped values avoid this pattern by enforcing scoped, immutable context.
  &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler’s heap walker already includes an inspection for thread-local leaks. Scoped value support is planned for a future version.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;3. Compact Object Headers proposed as production feature&lt;/h4&gt;

  
  &lt;p&gt;
    JEP 450 introduced Compact Object Headers in Java 24 as an experimental feature: shrinking object headers to 64 bits on 64‑bit systems.
    A new &lt;a href="https://openjdk.org/jeps/8354672"&gt;JEP draft&lt;/a&gt; now proposes promoting it to a product feature.
  &lt;/p&gt;

  
  &lt;p&gt;
    This change cuts live heap usage by 10–20%, improves cache locality, and reduces GC frequency and duration. In production tests
    (for example at Amazon), it led to:
  &lt;/p&gt;

  
  &lt;ul&gt;
    &lt;li&gt;20%+ heap reduction (SPECjbb2015)&lt;/li&gt;
    &lt;li&gt;8–10% lower CPU usage&lt;/li&gt;
    &lt;li&gt;15% fewer GCs&lt;/li&gt;
  &lt;/ul&gt;

  
  &lt;p&gt;
    The mechanism packs class metadata and hash code into a compact field. The trade-off is more complex GC and locking logic in exchange
    for memory savings in large heaps.
  &lt;/p&gt;</description>
      <category>Roundup</category>
      <pubDate>Tue, 06 May 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/05/jvm-performance-watch-roundup-april-2025/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-05-06T07:00:57Z</dc:date>
    </item>
    <item>
      <title>JProfiler tips roundup April 2025</title>
      <link>https://www.ej-technologies.com/blog/2025/05/jprofiler-tips-roundup-april-2025/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=roundup"&gt;Roundup&lt;/a&gt; &lt;/p&gt;

  &lt;img alt="Blog image" src="/assets/blog/roundup_tips-77baf5cfd55ca635e599751fe7610b2.png" class="float-start" loading="lazy" width="140" height="125"&gt;
  &lt;p&gt;
          I regularly share practical advice and insights on JProfiler and install4j on social media, covering features, shortcuts, and use cases.
          This blog post collects everything shared in April 2025. Each section rewrites the original thread in plain text.
        &lt;/p&gt;
  &lt;p&gt;Follow me on &lt;a href="https://www.linkedin.com/in/ingokegel/" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on LinkedIn"&gt; &lt;i class="icon icon-linkedin" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://www.youtube.com/@IngoKegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on YouTube"&gt; &lt;i class="icon icon-youtube" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://x.com/IngoKegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on X"&gt; &lt;i class="icon icon-twitter-x" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://mastodon.social/@ingokegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on Mastodon"&gt; &lt;i class="icon icon-mastodon" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://bsky.app/profile/ingokegel.bsky.social" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on Bluesky"&gt; &lt;i class="icon icon-bluesky" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt; to catch future tips as they’re posted.&lt;/p&gt;
  &lt;div class="clearfix"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;1. Comparing snapshots to explain performance changes&lt;/h4&gt;

  
  &lt;p&gt;
    Snapshot comparisons in JProfiler help you answer questions like whether memory usage increased, I/O operations became more frequent,
    or a specific method slowed down.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202504/compare_snapshots-7eb2baae67071e4a497e250359465ba.png" class="img-fluid" loading="lazy" width="586" height="392"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    JProfiler provides four dedicated comparison views: CPU, memory, probe, and telemetry. These views let you analyze performance regressions
    or behavior differences between snapshots.
  &lt;/p&gt;

  
  &lt;p&gt;
    Each comparison type has its own wizard to help configure the baseline and target snapshots. Once set up, JProfiler presents a
    tailored UI for each case. For example, telemetry comparisons graph time series data such as heap usage across snapshots,
    making it easy to correlate metric shifts with changes in application behavior.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202504/telemetry_comparison-1861cd721d69bce6bc8e19c557878df.png" class="img-fluid" loading="lazy" width="685" height="489"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;2. Visualizing Java locking behavior in real time&lt;/h4&gt;

  
  &lt;p&gt;
    JProfiler offers a real-time view into Java synchronization by recording and analyzing both intrinsic locks (synchronized) and
    &lt;code&gt;java.util.concurrent&lt;/code&gt; locks. Locking events include blocking durations, involved threads, and the specific monitor or lock objects,
    making it easier to debug deadlocks or optimize concurrency.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202504/locking_graph-8faf6405c9aea8926b22f1424a64953.png" class="img-fluid" loading="lazy" width="685" height="394"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    To reduce noise, JProfiler applies configurable thresholds so that only events above a certain duration are recorded.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202504/monitor_thresholds-7a44ff74962653b0cd2175dc8767c8.png" class="img-fluid" loading="lazy" width="685" height="384"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The monitor history view provides a searchable table with durations and stack traces for both the waiting and owning threads.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202504/monitor_table_view-ebcd4dd323ae63ae9e5adfb7ca3d755.png" class="img-fluid" loading="lazy" width="685" height="464"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The locking graph is a visual representation of thread interactions via monitors and locks.
    Nodes represent threads or locks, and edges show the interactions. You can mark specific threads or locks to restrict
    navigation to relevant events using the event switcher.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202504/nodes_of_interest-35b7af1af7e62c721ea1d13afffe92e.png" class="img-fluid" loading="lazy" width="685" height="384"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;3. Detecting runtime spikes with the outlier view&lt;/h4&gt;

  
  &lt;p&gt;
    JProfiler’s outlier detection view highlights methods with rare but significant runtime spikes, cases that can be missed
    when focusing only on total or average execution time. Instead of just aggregating performance data, it computes an outlier coefficient:
  &lt;/p&gt;

  
  &lt;pre&gt;
(max time - avg time) / avg time&lt;/pre&gt;

  
  &lt;p&gt;
    This lets you find methods that usually behave well but occasionally take much longer. Typical examples include intermittent
    network latency, caching failures, or blocking I/O in rarely used code paths.
  &lt;/p&gt;

  
  &lt;p&gt;
    The view filters out low-impact cases by default, showing only methods with more than 10 invocations and a maximum duration above 10 ms.
    These thresholds are configurable.
  &lt;/p&gt;

  
  &lt;p&gt;
    Start CPU recording, open the outlier detection view, and sort by the outlier coefficient to pinpoint erratic behavior.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202504/outlier_view-30ce9adaa1e23c58b5c188ff26396.png" class="img-fluid" loading="lazy" width="685" height="314"&gt;&lt;/div&gt;</description>
      <category>Roundup</category>
      <pubDate>Thu, 08 May 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/05/jprofiler-tips-roundup-april-2025/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-05-08T07:00:57Z</dc:date>
    </item>
    <item>
      <title>JVM performance watch roundup May 2025</title>
      <link>https://www.ej-technologies.com/blog/2025/06/jvm-performance-watch-roundup-may-2025/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=roundup"&gt;Roundup&lt;/a&gt; &lt;/p&gt;

  &lt;img alt="Blog image" src="/assets/blog/roundup_news-7f106869a6539c0dbea80be25103095.png" class="float-start" loading="lazy" width="140" height="125"&gt;
  &lt;p&gt;
          I post notes on JVM performance-related news on social media whenever a patch, JEP, or benchmark catches my eye.
          This blog post collects everything shared in May 2025. Each section rewrites the original thread in plain text.
        &lt;/p&gt;
  &lt;p&gt;Follow me on &lt;a href="https://www.linkedin.com/in/ingokegel/" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on LinkedIn"&gt; &lt;i class="icon icon-linkedin" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://www.youtube.com/@IngoKegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on YouTube"&gt; &lt;i class="icon icon-youtube" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://x.com/IngoKegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on X"&gt; &lt;i class="icon icon-twitter-x" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://mastodon.social/@ingokegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on Mastodon"&gt; &lt;i class="icon icon-mastodon" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://bsky.app/profile/ingokegel.bsky.social" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on Bluesky"&gt; &lt;i class="icon icon-bluesky" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt; to get these updates as soon as they go out.&lt;/p&gt;
  &lt;div class="clearfix"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;1. Streamlined ahead-of-time caching with single-step command-line option&lt;/h4&gt;

  
  &lt;p&gt;
    &lt;a href="https://openjdk.org/jeps/514"&gt;JEP 514&lt;/a&gt; proposes a streamlined command-line interface for generating ahead-of-time (AOT) caches in
    the JVM. Until now, AOT cache creation requires a two-step process: first recording with -XX:AOTMode=record, then generating the cache
    using -XX:AOTMode=create. The new -XX:AOTCacheOutput=&amp;lt;file&amp;gt; option simplifies this by combining both steps into a single JVM invocation.
  &lt;/p&gt;

  
  &lt;p&gt;
    This integrated approach automatically manages a temporary config file for the training phase. Additionally, the new
    &lt;code&gt;JDK_AOT_VM_OPTIONS&lt;/code&gt; environment variable will allow developers to customize the cache creation phase independently of the
    training phase. This is useful for scenarios where cache generation might benefit from different hardware or memory configurations.
  &lt;/p&gt;

  
  &lt;p&gt;
    The existing two-step workflow remains supported, making it possible to record on a small instance and then create the cache on a
    more powerful machine.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;2. JFR stack sampling overhaul with cooperative safepoint sampling&lt;/h4&gt;

  
  &lt;p&gt;
    JFR stack sampling is undergoing a significant rewrite aimed at improving safety, reliability, and scalability in production environments.
    &lt;a href="https://openjdk.org/jeps/518"&gt;JEP 518&lt;/a&gt; introduces a cooperative stack sampling mechanism that eliminates the old crash-prone
    asynchronous heuristics in favor of sampling at safepoints.
  &lt;/p&gt;

  
  &lt;p&gt;
    In the current implementation, JFR forcibly stops threads at arbitrary points and guesses the call stack. This approach often resulted
    in invalid traces and occasional JVM crashes, particularly when classes were unloaded during sampling. The new design instead marks threads
    and lets them stop at the next safepoint. At that point, JFR records just the program counter and stack pointer, deferring the actual stack
    reconstruction to the thread itself at a safe location.
  &lt;/p&gt;

  
  &lt;p&gt;
    This change allows JFR to allocate memory safely during stack parsing. While some limitations such as incomplete traces for intrinsics
    or native methods remain, the risk of JVM crashes is effectively removed.
  &lt;/p&gt;

  
  &lt;p&gt;
    For JProfiler, this improvement means JFR recordings will become a more interesting data source, which is especially useful in environments
    where native agents are restricted.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;3. Generational Shenandoah GC is graduating from experimental to production&lt;/h4&gt;

  
  &lt;p&gt;
    Generational Shenandoah is moving from experimental to production status. Initially introduced as an experimental feature in JEP 404 (JDK 24),
    generational Shenandoah aims to improve throughput and pause times for allocation-heavy workloads by dividing the heap into young and
    old generations.
  &lt;/p&gt;

  
  &lt;p&gt;
    Currently, enabling generational mode required using experimental flags:
  &lt;/p&gt;

  
  &lt;pre&gt;
-XX:+UseShenandoahGC
-XX:+UnlockExperimentalVMOptions
-XX:ShenandoahGCMode=generational&lt;/pre&gt;

  
  &lt;p&gt;
    According to &lt;a href="https://openjdk.org/jeps/521"&gt;JEP 521&lt;/a&gt;, generational Shenandoah is now considered stable enough to drop
    the &lt;code&gt;+UnlockExperimentalVMOptions&lt;/code&gt; flag requirement, thereby simplifying its activation. However, single-generation Shenandoah
    remains the default.
  &lt;/p&gt;

  
  &lt;p&gt;
    Benchmarks like DaCapo, SPECjbb2015, and Heapothesys have reported encouraging results. For memory-sensitive or low-latency workloads,
    generational mode is worth evaluating.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;4. JFR method-level timing and tracing&lt;/h4&gt;

  
  &lt;p&gt;
    &lt;a href="https://openjdk.org/jeps/520"&gt;JEP 520&lt;/a&gt; introduces method-level timing and tracing to JDK Flight Recorder (JFR) via
    JVM-managed bytecode instrumentation, starting with Java 25. With the &lt;code&gt;jdk.MethodTiming&lt;/code&gt; and &lt;code&gt;jdk.MethodTrace&lt;/code&gt; events,
    developers can now record exact invocation counts, execution times, and stack traces for targeted methods. Targets are configured using
    class names, method references, or annotations.
  &lt;/p&gt;

  
  &lt;p&gt;
    This feature is particularly useful for pinpointing performance bottlenecks in critical or infrequently called code such as startup logic,
    connection pools, or custom endpoints. Filters allow multiple selection types: class, method, or annotation. For example,
    &lt;code&gt;::&amp;lt;clinit&amp;gt;&lt;/code&gt; targets all static initializers, and annotations like &lt;code&gt;@RequestMapping&lt;/code&gt; can be used to track selected
    methods.
  &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler users benefit from JEP 520 by gaining some high-resolution CPU data when analyzing JFR snapshots. This aligns with JProfiler’s existing
    support for both agent-based instrumentation and JVMTI sampling.
  &lt;/p&gt;</description>
      <category>Roundup</category>
      <pubDate>Tue, 03 Jun 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/06/jvm-performance-watch-roundup-may-2025/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-06-03T07:00:57Z</dc:date>
    </item>
    <item>
      <title>JProfiler tips roundup May 2025</title>
      <link>https://www.ej-technologies.com/blog/2025/06/jprofiler-tips-roundup-may-2025/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=roundup"&gt;Roundup&lt;/a&gt; &lt;/p&gt;

  &lt;img alt="Blog image" src="/assets/blog/roundup_tips-77baf5cfd55ca635e599751fe7610b2.png" class="float-start" loading="lazy" width="140" height="125"&gt;
  &lt;p&gt;
          I regularly share practical advice and insights on JProfiler and install4j on social media, covering features, shortcuts, and use cases.
          This blog post collects everything shared in May 2025. Each section rewrites the original thread in plain text.
        &lt;/p&gt;
  &lt;p&gt;Follow me on &lt;a href="https://www.linkedin.com/in/ingokegel/" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on LinkedIn"&gt; &lt;i class="icon icon-linkedin" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://www.youtube.com/@IngoKegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on YouTube"&gt; &lt;i class="icon icon-youtube" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://x.com/IngoKegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on X"&gt; &lt;i class="icon icon-twitter-x" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://mastodon.social/@ingokegel" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on Mastodon"&gt; &lt;i class="icon icon-mastodon" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt;&lt;a href="https://bsky.app/profile/ingokegel.bsky.social" target="_blank" class="alert-link text-decoration-none ms-1 me-2" data-bs-toggle="tooltip" data-bs-title="Follow Ingo Kegel on Bluesky"&gt; &lt;i class="icon icon-bluesky" style="font-size: 18px;width:18px"&gt;&lt;/i&gt; &lt;/a&gt; to catch future tips as they’re posted.&lt;/p&gt;
  &lt;div class="clearfix"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;1. Correlating XHR calls with backend activity in JProfiler&lt;/h4&gt;

  
  &lt;p&gt;
    JProfiler supports correlating JavaScript &lt;code&gt;XMLHttpRequest&lt;/code&gt; and &lt;code&gt;fetch()&lt;/code&gt; calls with backend server activity through
    XHR origin tracking. This feature helps identify which user interaction triggered a particular backend request.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/xhr_tracking-9a9b15ad92b688a9acd96c1eaaa8acc.png" class="img-fluid" loading="lazy" width="685" height="394"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    To enable this functionality, install the JProfiler origin tracker Chrome extension. When active, it intercepts XHR calls in the browser
    and links them to the running JProfiler session. In JProfiler’s JavaScript XHR view, you’ll find a combined call tree of all tracked XHR calls
    handled by the profiled JVM.
  &lt;/p&gt;

  
  &lt;p&gt;
    This view shows JavaScript stack traces with source files and line numbers and hyperlinks to the corresponding server-side call tree.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/xhr_view-872b9f5250ab6e8a607dd5c0cb3ed2bb.png" class="img-fluid" loading="lazy" width="1200" height="673"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    In the call tree, XHR nodes are grouped by the triggering browser event (e.g., click, submit), the DOM element, and the JavaScript call stack.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/xhr_call_tree-d37b3231a4ee693d2e92929d6a6a477.png" class="img-fluid" loading="lazy" width="1200" height="673"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    For projects using popular JavaScript frameworks, the extension traverses the DOM tree to locate meaningful splitting attributes.
    You can also manually specify an attribute by adding &lt;code&gt;data-jprofiler=&amp;quot;...&amp;quot;&lt;/code&gt; to any DOM element.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;2. JProfiler’s integrated MBean browser&lt;/h4&gt;

  
  &lt;p&gt;
    JProfiler includes a built-in MBean browser that allows you to explore, edit, and visualize JMX data directly,
    without needing remote JMX access.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/mbean_overview-d4a657c483c5333eae7389f4bb19fc71.png" class="img-fluid" loading="lazy" width="1379" height="793"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    MBeans provide a standard way to expose runtime data and modify configuration in Java applications. They are published by app servers like
    Tomcat, frameworks like Apache Kafka, or by internal JVM metrics. JProfiler’s MBean browser automatically discovers all MBeans registered
    in the JVM being profiled.
  &lt;/p&gt;

  
  &lt;p&gt;
    If an attribute is editable, an edit icon allows direct modification of arrays or simple types.
  &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler also supports defining custom telemetries from numeric MBean attributes. A custom telemetry can be created for any numeric
    value via the context menu, including nested fields in composite or tabular data.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/mbean_telemetry-e343028544fb8d497e7234ff4799673.png" class="img-fluid" loading="lazy" width="1377" height="791"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    MBean operations are available too. You can invoke operations with parameters and see the structured return value.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/mbean_operation-c6577f5038cf938e4f5a3266abea38e4.png" class="img-fluid" loading="lazy" width="1377" height="791"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;3. Analyzing native HPROF and PHD heap snapshots in JProfiler&lt;/h4&gt;

  
  &lt;p&gt;
    JProfiler can open native HPROF and PHD heap snapshots from any JVM, including HotSpot, Android, and IBM J9.
  &lt;/p&gt;

  
  &lt;p&gt;
    Use &lt;code&gt;Session -&amp;gt; Open Snapshot&lt;/code&gt; in JProfiler to analyze HPROF or PHD files. The heap walker is fully available for
    in-depth memory analysis.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/hprof_overview-d7bb7bf9e8d41144cd67d9cbdcefd134.png" class="img-fluid" loading="lazy" width="1200" height="750"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    These native heap snapshots are saved directly by the JVM or command-line tools, allowing you to capture the heap state without attaching
    the JProfiler agent. This is helpful in production environments where agents are not allowed.
  &lt;/p&gt;

  
  &lt;p&gt;
    Note that native heap snapshots support fewer features than JProfiler snapshots. Allocation call stacks are not available, and only
    the heap walker is enabled. All other sections are grayed out.
  &lt;/p&gt;

  
  &lt;p&gt;
    You can also create HPROF or PHD heap snapshots from a live session in JProfiler, either through the menu or by setting up trigger actions.
    A common use case is saving a heap snapshot automatically on &lt;code&gt;OutOfMemoryError&lt;/code&gt;.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/hprof_trigger_action-56fb19df5f9f24497be6f29f9c7f9ae.png" class="img-fluid" loading="lazy" width="1200" height="861"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    JProfiler supports taking HPROF snapshots without loading the profiling agent, both locally and remotely, directly from the attach dialog.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/hprof_attach_mode-bba656f6ecd52bc73f97f2d5ed39647f.png" class="img-fluid" loading="lazy" width="1200" height="904"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    For command-line workflows, JProfiler ships with &lt;code&gt;bin/jpdump&lt;/code&gt;, an alternative to &lt;code&gt;jmap&lt;/code&gt; that handles process selection,
    Windows services, mixed 32/64-bit JVMs, and auto-numbers files.
  &lt;/p&gt;

  
  &lt;p&gt;
    HPROF snapshots can include thread dumps. If the dump was triggered by an &lt;code&gt;OutOfMemoryError&lt;/code&gt;, JProfiler highlights the responsible
    thread, making it easier to identify what was happening at the time.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/jtips202505/hprof_thread-4414c3bf6132be67a04439184136f766.png" class="img-fluid" loading="lazy" width="1379" height="793"&gt;&lt;/div&gt;</description>
      <category>Roundup</category>
      <pubDate>Wed, 04 Jun 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/06/jprofiler-tips-roundup-may-2025/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-06-04T07:00:57Z</dc:date>
    </item>
    <item>
      <title>JEP 493 follow-up: install4j 11.0.4 is ready for separate JMOD bundles in Eclipse Temurin 24.0.2</title>
      <link>https://www.ej-technologies.com/blog/2025/06/jep-493-follow-up-install4j-11-0-4-is-ready-for-separate-jmod-bundles-in-eclipse-temurin-24-0-2/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Two months ago, I wrote about
    &lt;a href="https://www.ej-technologies.com/blog/2025/04/cross-platform-jre-bundle-creation-under-threat-from-jep-493/"&gt;how JEP 493 threatened cross-platform JRE bundle creation&lt;/a&gt;
    by allowing JDK vendors to omit JMOD files from their distributions. Without JMOD files, tools like install4j cannot build cross-platform
    runtime images. This had the potential to seriously disrupt functionality for our users.
  &lt;/p&gt;

  
  
  &lt;p&gt;
    The first JDK vendor to implement this change was
    Adoptium, which started releasing without JMOD files starting with their 24.0.0 release.
  &lt;/p&gt;

  
  &lt;p&gt;
    Now the problem is about to be solved: The Eclipse Temurin project
    &lt;a href="https://github.com/adoptium/adoptium-support/issues/1271"&gt;plans to publish separate JMOD downloads&lt;/a&gt;
    starting with version 24.0.2. This means that developers using install4j will again be able to build modularized JRE bundles for recent
    releases of Eclipse Temurin.
  &lt;/p&gt;

  
  &lt;p&gt;
    &lt;a href="https://www.ej-technologies.com/install4j/changelog#11.0.4"&gt;install4j 11.0.4&lt;/a&gt;
    is already prepared for this change. It fully supports the upcoming separate JMOD archive downloads in Eclipse Temurin 24.0.2.
    With these minimum versions of install4j and Eclipse Temurin, developers can build modularized JRE bundles again.
    With Eclipse Temurin 24.0.0 and 24.0.1, the only option was to include everything, resulting in unnecessarily large runtime bundles.
  &lt;/p&gt;

  
  &lt;p&gt;
    &#x1f64f; Thanks to the team at Adoptium for listening and making this happen so quickly!
  &lt;/p&gt;</description>
      <category>install4j</category>
      <pubDate>Thu, 05 Jun 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/06/jep-493-follow-up-install4j-11-0-4-is-ready-for-separate-jmod-bundles-in-eclipse-temurin-24-0-2/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-06-05T07:00:57Z</dc:date>
    </item>
    <item>
      <title>All our artifacts are now published on Maven Central</title>
      <link>https://www.ej-technologies.com/blog/2025/06/all-our-artifacts-are-now-published-on-maven-central/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    We have migrated all of our public Maven artifacts to &lt;a href="https://central.sonatype.com/"&gt;Maven Central&lt;/a&gt;.
    Previously, these artifacts were available from our own Maven repository, which will remain online for older releases.
    New releases will be published exclusively on Maven Central.
  &lt;/p&gt;

  
  
  &lt;p&gt;
    Maven Central is the default repository for Maven and also present in most Gradle builds. Not having to add a custom repository makes
    using our libraries a lot more straightforward.
  &lt;/p&gt;


  
  &lt;p&gt;Here’s a list of the published artifacts in the format &lt;code&gt;groupId:artifactId&lt;/code&gt;:&lt;/p&gt;


  
  &lt;h5 class="mt-4"&gt;JProfiler&lt;/h5&gt;

  
  &lt;ul&gt;
    &lt;li&gt;
      &lt;a href="https://central.sonatype.com/artifact/com.jprofiler/jprofiler-controller"&gt;&lt;code&gt;com.jprofiler:jprofiler-controller&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
      Controller API for managing profiling recordings in-process.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;a href="https://central.sonatype.com/artifact/com.jprofiler/jprofiler-mbean"&gt;&lt;code&gt;com.jprofiler:jprofiler-mbean&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
      MBean API for managing profiling recordings via JMX.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;a href="https://central.sonatype.com/artifact/com.jprofiler/jprofiler-probe-injected"&gt;&lt;code&gt;com.jprofiler:jprofiler-injected&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
      API for developing probes by injecting measurement calls into third-party libraries and frameworks.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;a href="https://central.sonatype.com/artifact/com.jprofiler/jprofiler-probe-embedded"&gt;&lt;code&gt;com.jprofiler:jprofiler-embedded&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
      API for developing probes by embedding measurement calls directly in the application code.
    &lt;/li&gt;
  &lt;/ul&gt;


  
  &lt;h5 class="mt-4"&gt;perfino&lt;/h5&gt;

  
  &lt;ul&gt;
    &lt;li&gt;
      &lt;a href="https://central.sonatype.com/artifact/com.jprofiler/perfino-api"&gt;&lt;code&gt;com.jprofiler:perfino-api&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
      The API library for integrating with perfino.
    &lt;/li&gt;
  &lt;/ul&gt;


  
  &lt;h5 class="mt-4"&gt;install4j&lt;/h5&gt;

  
  &lt;ul&gt;
    &lt;li&gt;
      &lt;a href="https://central.sonatype.com/artifact/com.install4j/install4j-runtime"&gt;&lt;code&gt;com.install4j:install4j-runtime&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
      API classes for install4j.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;a href="https://central.sonatype.com/artifact/com.install4j/install4j-jdk-provider"&gt;&lt;code&gt;com.install4j:install4j-jdk-provider&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
      API for developing a custom JDK provider for install4j.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;a href="https://central.sonatype.com/artifact/com.install4j/install4j-maven"&gt;&lt;code&gt;com.install4j:install4j-maven&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
      The Maven plugin for invoking the install4j compiler.
    &lt;/li&gt;
  &lt;/ul&gt;


  
  &lt;p&gt;
    If you’re currently using our custom Maven repository, simply remove that entry from your build files.
    The group and artifact coordinates remain the same, so no other changes are necessary.
  &lt;/p&gt;

  
  &lt;p&gt;
    If you are using a Gradle build without direct or proxied access to Maven Central, you can add it to your build script:
  &lt;/p&gt;

  
  &lt;pre&gt;
repositories {
    mavenCentral()
}&lt;/pre&gt;</description>
      <category>General</category>
      <pubDate>Fri, 06 Jun 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/06/all-our-artifacts-are-now-published-on-maven-central/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-06-06T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Website refresh: Visual updates, dark mode, and semantic search for docs</title>
      <link>https://www.ej-technologies.com/blog/2025/07/website-refresh-visuals-dark-mode-and-semantic-search-for-docs/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=general"&gt;General&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    We have just rolled out significant changes to our website. They include many visual updates and important infrastructure updates that speed up
    loading times in many locations across the globe.
  &lt;/p&gt;

  
  &lt;p&gt;
    In addition, there are three functional changes that we would like to highlight:
  &lt;/p&gt;

  
  
  &lt;p&gt;
    &lt;b&gt;Dark/Light mode&lt;/b&gt; is now available for the entire website. It detects your OS setting automatically and can be toggled manually in the
    top-right corner.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/websiteRefresh/dark_mode_dark-1fc8b3a3c0d8f49a9e49b4e74da6378.png" class="img-fluid dark-image" loading="lazy" width="800" height="329"&gt;&lt;img alt="Blog figure" src="/assets/blog/websiteRefresh/dark_mode-b110601524207a7a2e76685fcce6cb85.png" class="img-fluid light-image" loading="lazy" width="800" height="329"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The documentation for all our products
    (&lt;a href="https://www.ej-technologies.com/resources/jprofiler/help/doc/main/introduction.html"&gt;JProfiler&lt;/a&gt;,
    &lt;a href="https://www.ej-technologies.com/resources/install4j/help/doc/main/introduction.html"&gt;install4j&lt;/a&gt; and
    &lt;a href="https://www.ej-technologies.com/resources/perfino/help/doc/main/introduction.html"&gt;perfino&lt;/a&gt;)
    is now &lt;b&gt;served directly from the website&lt;/b&gt;. The rendering is improved considerably and the dark/light mode
    setting of the website uniformly applies to the documentation as well.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/websiteRefresh/help_website_dark-54bd1181ad461267145669797f581c.png" class="img-fluid dark-image" loading="lazy" width="800" height="493"&gt;&lt;img alt="Blog figure" src="/assets/blog/websiteRefresh/help_website-db5f14585aafdcbf1ea84af94749f.png" class="img-fluid light-image" loading="lazy" width="800" height="493"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The documentation now features &lt;b&gt;semantic search&lt;/b&gt;. Using the search box in the header, you can search for concepts and terms.
    The search results directly link to the relevant sections in the documentation.
  &lt;/p&gt;

  
  &lt;p&gt;
    Search is also available for localized variants of the JProfiler documentation
    (&lt;a href="https://www.ej-technologies.com/resources/jprofiler/help_zh_CN/doc/main/introduction.html"&gt;Chinese&lt;/a&gt;,
    &lt;a href="https://www.ej-technologies.com/resources/jprofiler/help_ja_JP/doc/main/introduction.html"&gt;Japanese&lt;/a&gt; and
    &lt;a href="https://www.ej-technologies.com/resources/jprofiler/help_ko_KR/doc/main/introduction.html"&gt;Korean&lt;/a&gt;).
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/websiteRefresh/help_search_results_dark-6587941d4d226f4101fbe34b6a6de1.png" class="img-fluid dark-image" loading="lazy" width="799" height="656"&gt;&lt;img alt="Blog figure" src="/assets/blog/websiteRefresh/help_search_results-aedc27d2939df6503d437ae97442050.png" class="img-fluid light-image" loading="lazy" width="799" height="656"&gt;&lt;/div&gt;</description>
      <category>General</category>
      <pubDate>Mon, 07 Jul 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/07/website-refresh-visuals-dark-mode-and-semantic-search-for-docs/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-07-07T07:00:57Z</dc:date>
    </item>
    <item>
      <title>The power of async tracking in JVM profiling</title>
      <link>https://www.ej-technologies.com/blog/2025/07/the-power-of-async-tracking-in-jvm-profiling/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Async operations can speed up applications and improve responsiveness, but they also introduce complexity.
    Especially in the context of profiling, understanding what really happened and why can be surprisingly tricky.
    This post shows how JProfiler's async tracking feature helps fix hard performance problems in your application.
  &lt;/p&gt;

  

  
  &lt;h4 class="mt-5"&gt;Why are async calls important?&lt;/h4&gt;

  
  &lt;p&gt;
    Unless you are fortunate enough to have virtual threads at your disposal, making async calls is the only way to stop blocking the current
    thread while a task is being executed. Many systems and frameworks have a canonical way of doing this, such as submitting a
    &lt;code&gt;CompletableFuture&lt;/code&gt; to an &lt;code&gt;ExecutorService&lt;/code&gt;. In an async call, the task is executed by a different thread, and the result
    (if one is even needed) can be processed by a callback.
  &lt;/p&gt;

  
  &lt;p&gt;
    UI systems are typically built in such a way that there is a single event dispatch thread that can modify and repaint UI components. Web browsers
    are built this way, but also all common JVM UI toolkits, like Swing, SWT and JavaFX.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;The problem&lt;/h4&gt;

  
  &lt;p&gt;
    A common problem with async calls is that a stack trace from the deferred task has no connection to the thread that initiated the task.
    This makes debugging notoriously difficult (&amp;quot;callback hell&amp;quot;), and it's an even greater problem for profiling. In most cases, you don't
    look at methods in isolation, but you always want to attribute the cumulative measured time of any method to the parents in the call stack.
    In this way, you find out &lt;b&gt;who is responsible&lt;/b&gt; for a performance problem which helps you to fix it.
  &lt;/p&gt;

  
  &lt;p&gt;
    Let's look at an example. The call tree below shows the install4j UI while the user hovers over a single item in the view selector without any
    visual change. The consumed times are quite a bit more than we would expect. The root node in the call tree is the event dispatch thread
    and contains unprofiled classes in its internal machinery. Below it, we directly see the &lt;code&gt;NavigationTree.paintComponent&lt;/code&gt; method
    that runs on the event dispatch thread. There is no indication of who triggered this method, either via an &lt;code&gt;EventQueue.invokeLater&lt;/code&gt; or
    an &lt;code&gt;EventQueue.invokeAndWait&lt;/code&gt; call.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/asyncTracking/call_tree_dark-c6f68e859121875a4a5b2e59c652e2a.png" class="img-fluid dark-image" loading="lazy" width="967" height="562"&gt;&lt;img alt="Blog figure" src="/assets/blog/asyncTracking/call_tree-54f94a61fbaebe2f82a7683174bdd5f.png" class="img-fluid light-image" loading="lazy" width="967" height="562"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;Enter async tracking&lt;/h4&gt;

  
  &lt;p&gt;
    With JProfiler, you have a tool at your disposal that can stitch together async call sites with async execution sites. In the profiled example,
    async tracking for AWT was active. This is off by default, so you need to switch on the particular kind of tracking that's
    useful for your application by clicking on the tracking icon in the status bar or showing it in the &amp;quot;Profiling&amp;quot; menu.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/asyncTracking/async_tracking_dialog_dark-e9349e34bb3cb36728c54d497ff95.png" class="img-fluid dark-image" loading="lazy" width="488" height="394"&gt;&lt;img alt="Blog figure" src="/assets/blog/asyncTracking/async_tracking_dialog-cb23cc3db92092fec8ca17e5f9879c55.png" class="img-fluid light-image" loading="lazy" width="488" height="394"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    When async tracking is enabled, a hyperlink label is shown above the call tree. When you click on it, JProfiler calculates a call tree
    where all tracked async calls are inlined.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/asyncTracking/async_call_tree_dark-bae371bfb67757d992357a77e9cc373.png" class="img-fluid dark-image" loading="lazy" width="965" height="539"&gt;&lt;img alt="Blog figure" src="/assets/blog/asyncTracking/async_call_tree-1fb52f4414cecaa59adddc9af512dfd.png" class="img-fluid light-image" loading="lazy" width="965" height="539"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    The &amp;quot;Add async execution time to tree&amp;quot; checkbox above the call tree is important. If you select it, the time spent in the async
    execution is added to the parent node in the call tree. It then effectively treats async calls as if they were blocking calls.
    This is very useful to find hot paths in the async execution sites by starting from the top of the tree.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;Fixing the problem&lt;/h4&gt;

  
  &lt;p&gt;
    In the async call tree, we see that the &lt;code&gt;mouseMoved&lt;/code&gt; method of the &lt;code&gt;MouseMotionListener&lt;/code&gt; in
    &lt;code&gt;NavigationComponentHelper&lt;/code&gt; issues a lot of repaints. We can now check the source code of that method and prevent unneeded repaints
    where the visual representation of the view selector does not change.
  &lt;/p&gt;

  
  &lt;p&gt;
    This example translates to many real-world scenarios with the other supported tracking types. Async support in your profiling tool is a
    crucial feature that enables you to productively fix performance problems in your application.
    Try it out with the &lt;a href="https://www.ej-technologies.com/jprofiler/download"&gt;latest JProfiler version&lt;/a&gt; and convince yourself of
    the power of async tracking!
  &lt;/p&gt;</description>
      <category>JProfiler</category>
      <pubDate>Fri, 25 Jul 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/07/the-power-of-async-tracking-in-jvm-profiling/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-07-25T07:00:57Z</dc:date>
    </item>
    <item>
      <title>With Temurin 24.0.2, Adoptium JDKs can again be modularized by install4j</title>
      <link>https://www.ej-technologies.com/blog/2025/08/with-temurin-24-0-2-adoptium-jdks-can-again-be-modularized-by-install4j/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    This year we had some dramatic moments starting in April with the release of Temurin 24.0.0 from Adoptium, our default JDK bundle provider.
    In this blog post we celebrate the happy conclusion of this incident.
  &lt;/p&gt;

  
  
  &lt;p&gt;
    The problem began when Adoptium started to take advantage of the new flexibility in JEP 493
    &lt;a href="https://www.ej-technologies.com/blog/2025/04/cross-platform-jre-bundle-creation-under-threat-from-jep-493/"&gt;to remove JMOD files&lt;/a&gt;
    from their JDK distributions. However, without those JMOD files, install4j could no longer use jlink to modularize JDK bundles for other
    platforms. There was no build failure with Temurin 24.0.0 and Temurin 24.0.1, and these versions were treated like pre-Java 9 JDKs, which could
    not be modularized. This means that the entire JDK was included in a JDK bundle with your installer if you configured one of those JDK versions.
    Consequently, media file sizes increased by &lt;b&gt;100 MB and more&lt;/b&gt;.
  &lt;/p&gt;

  
  &lt;p&gt;
    We do offer several other JDK bundle providers and could have removed Adoptium as a last resort. However, this was very undesirable: What if
    the other JDK providers went the same way?
  &lt;/p&gt;

  
  &lt;p&gt;
    Fortunately, the Adoptium team was &lt;a href="https://github.com/adoptium/adoptium-support/issues/1271"&gt;very responsive to our use case&lt;/a&gt;, and by
    June they had an alternative solution in place, providing
    &lt;a href="https://www.ej-technologies.com/blog/2025/06/jep-493-follow-up-install4j-11-0-4-is-ready-for-separate-jmod-bundles-in-eclipse-temurin-24-0-2/"&gt;JMOD files as a separate artifact&lt;/a&gt;.
  &lt;/p&gt;

  
  &lt;p&gt;
    On the 23rd of July 2025, &lt;a href="https://adoptium.net/temurin/releases?version=24&amp;amp;os=any&amp;amp;arch=any&amp;amp;mode=filter"&gt;Temurin 24.0.2&lt;/a&gt;
    was released as the first version with this additional artifact. With install4j 11.0.4+, Temurin 24.0.2+ can now be modularized again.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/adoptium_jmod_download_dark-28d0a7e2545c49f9b144fe8f190f040.png" class="img-fluid dark-image" loading="lazy" width="828" height="637"&gt;&lt;img alt="Blog figure" src="/assets/blog/adoptium_jmod_download-24fdbae31c5f535c4d46822dd0ee25d0.png" class="img-fluid light-image" loading="lazy" width="828" height="637"&gt;&lt;/div&gt;

  
  &lt;p&gt;
    Non-LTS Java versions are used less frequently, but Java 25 LTS is around the corner, so we are glad that this situation was resolved
    in time. If you are using an older version of install4j and want to bundle Temurin 24+,
    &lt;a href="https://www.ej-technologies.com/install4j/download"&gt;upgrade now&lt;/a&gt;.
  &lt;/p&gt;</description>
      <category>install4j</category>
      <pubDate>Mon, 04 Aug 2025 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/08/with-temurin-24-0-2-adoptium-jdks-can-again-be-modularized-by-install4j/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-08-04T07:00:57Z</dc:date>
    </item>
    <item>
      <title>Migrating to install4j 12</title>
      <link>https://www.ej-technologies.com/blog/2025/10/migrating-to-install4j-12-0/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=install4j"&gt;install4j&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=migration"&gt;Migration&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    In most cases, migrating to install4j 12 usually just involves opening and saving your project with the install4j 12 IDE.
    Nevertheless, there are some considerations with respect to backward compatibility and some behavioral changes.
  &lt;/p&gt;

  
  
  &lt;ul&gt;
    &lt;li&gt;
      
      &lt;p&gt;
        As part of the evolution of the &amp;quot;Update alert&amp;quot; form component into the &amp;quot;Streamlined installation&amp;quot; chooser form component,
        the installer variable &lt;code&gt;sys.confirmedUpdateInstallation&lt;/code&gt; has been renamed to &lt;code&gt;sys.streamlinedInstallation&lt;/code&gt;.
        When the project is migrated, it is replaced in the entire project file.
      &lt;/p&gt;

      
      &lt;p&gt;
        However, if you use this variable in custom code, you need to update it accordingly.
      &lt;/p&gt;

    &lt;/li&gt;
    &lt;li&gt;
      
      &lt;p&gt;
        The way that install4j determines the previous installation directory has been redesigned. See the
        &lt;a href="/install4j/whatsnew12"&gt;What's new&lt;/a&gt; page for more details. Project migration to install4j 12 involves the following
        automatic changes to the project so that the resulting behavior closely corresponds to what happened in previous versions of install4j:
      &lt;/p&gt;

      
      &lt;ul&gt;
        &lt;li&gt;
          A &amp;quot;Set installation directory&amp;quot; action is added to the startup node, either after an existing &amp;quot;Request privileges&amp;quot; action or as first action.
          Its &amp;quot;Search for previous installation&amp;quot; property is selected if the &amp;quot;Detect previous installation directory&amp;quot; setting on the
          &amp;quot;Installer-&amp;gt;Update options&amp;quot; was previously selected. That setting has been removed.
          By default, the scope is set to &amp;quot;For all users if directory is writable&amp;quot;. If a &amp;quot;Request privileges&amp;quot; action is used in the installer, but not
          in the startup node, the scope is set to &amp;quot;Installation directory for all users&amp;quot; instead.
        &lt;/li&gt;
        &lt;li&gt;
          A &amp;quot;Set installation directory&amp;quot; action is added after each &amp;quot;Request privileges&amp;quot; action used in screens. The &amp;quot;Installation scope&amp;quot; of the action
          is set to &amp;quot;For all users if directory is writable&amp;quot; and the search for update installations is disabled.
        &lt;/li&gt;
      &lt;/ul&gt;

      
      &lt;p&gt;
        However, the previous way the installation directory was set involved hidden logic and some heuristics that are not replicated
        by the new setup. In certain edge cases, the result can now be different. With the flexibility of the &amp;quot;Set installation directory&amp;quot; action
        you can achieve any desired behavior, but you will have to make it explicit in your project.
      &lt;/p&gt;

    &lt;/li&gt;
    &lt;li&gt;
      
      &lt;p&gt;
        The non-public installer variable &lt;code&gt;sys.resolveUserSpecificInstallationDir&lt;/code&gt; has been removed. It was previously set by the
        &amp;quot;Request privileges&amp;quot; action if a fallback to a user-specific installation directory was necessary. In install4j 12, this functionality
        has been moved to the new &amp;quot;Set installation directory&amp;quot; action which sets the boolean &lt;code&gt;sys.installForAllUsers&lt;/code&gt; installer variable.
      &lt;/p&gt;

      
      &lt;p&gt;
        In the unlikely case that you use &lt;code&gt;sys.resolveUserSpecificInstallationDir&lt;/code&gt;, you have to migrate it to the
        negated &lt;code&gt;sys.installForAllUsers&lt;/code&gt; installer variable.
      &lt;/p&gt;

    &lt;/li&gt;
    &lt;li&gt;
      
      &lt;p&gt;
        The &amp;quot;AdoptOpenJDK&amp;quot; and &amp;quot;AdoptOpenJDK (OpenJ9)&amp;quot; JDK providers have been deprecated. The associated API has been deprecated for a long time.
        Migrate to Adoptium for Temurin JDKs and the new Semeru provider for OpenJ9 JDKs instead.
      &lt;/p&gt;

      
      &lt;p&gt;
        If your project is configured to use a deprecated JDK provider, it is still shown in the JDK provider chooser. However, it
        cannot be selected for new projects anymore.
      &lt;/p&gt;

    &lt;/li&gt;
    &lt;li&gt;
      
      &lt;p&gt;
        install4j now requires a POSIX-compatible shell for Unix/Linux media files. The only case where this is a problem is Solaris 10.
        Solaris 10 has been EOL since early 2024.
      &lt;/p&gt;

      
      &lt;p&gt;
        If you still need support for Solaris 10, define the compiler variable &lt;code&gt;sys.ext.solaris10Compatible&lt;/code&gt; to add a workaround that
        executes &lt;code&gt;/usr/xpg4/bin/sh&lt;/code&gt; on Solaris 10.
      &lt;/p&gt;

    &lt;/li&gt;
    &lt;li&gt;
      
      &lt;p&gt;
        For macOS single bundle media files with the archive format set to &amp;quot;.pkg for App Store submission&amp;quot;,
        additional top-level files are now added to the .pkg file. Previously, any configured additional top-level files were ignored in that
        case.
      &lt;/p&gt;

    &lt;/li&gt;
  &lt;/ul&gt;</description>
      <category>install4j</category>
      <category>Migration</category>
      <pubDate>Fri, 31 Oct 2025 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2025/10/migrating-to-install4j-12-0/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2025-10-31T08:00:57Z</dc:date>
    </item>
    <item>
      <title>JProfiler 16: Profiling Agentic Java Applications</title>
      <link>https://www.ej-technologies.com/blog/2026/02/jprofiler-16-profiling-agentic-java-applications/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  
  &lt;h4 class="mt-5"&gt;Why AI Needs Profiling&lt;/h4&gt;

  
  &lt;p&gt;
    Traditional profiling focuses on the JVM's internal execution, like method durations, memory allocation, and thread synchronization issues.
    One of JProfiler's main innovations of the past is grounded in its probes: Measurements of higher-level systems, like HTTP, JDBC, and RPC calls.
    With LLM frameworks like LangChain4j and Spring AI, a new performance challenge has emerged. LLM interactions introduce highly non-deterministic
    latency and substantial resource costs that standard CPU profiling cannot put into context.
    JProfiler is in a unique position to bridge this gap by treating AI interactions as a data source for a new probe.
  &lt;/p&gt;

  

  
  &lt;h4 class="mt-5"&gt;The AI Probe: Observability for LLM Workflows&lt;/h4&gt;

  
  &lt;p&gt;
    The centerpiece of JProfiler 16 is the new AI Probe. It provides a way to observe how your application interacts with LLMs,
    and delivers context-aware metrics that help you optimize two important problems: performance and cost.
  &lt;/p&gt;

  
  &lt;p&gt;
    While probes have previously only focused on duration of events, JProfiler 16 introduces switchable primary metrics. With the AI probe,
    these include input tokens and output tokens. This allows you to identify which prompts are driving up costs or causing latency spikes.
  &lt;/p&gt;

  
  &lt;p&gt;
    In the probe events view, you can inspect the entire contents of each prompt. This is potentially a massive amount of data. We've used
    this opportunity to advance JProfiler's event system from the original role as a debugging helper to a file-backed high-performance
    data store in this release. This enables event-centric views such as the AI probe and benefits all other existing probes.
  &lt;/p&gt;

  
  &lt;p&gt;
    The events view can now be the control center when working with a probe: With its advanced filtering capabilities you can trim the set
    of events across multiple dimensions and use the secondary views at the bottom to inspect hot spots, call trees, distribution histograms
    and timelines.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/aiProbe16/ai_probe_events_filter_dark-42e1e030e61e25fa28642ebf69656a.png" class="img-fluid dark-image" loading="lazy" width="782" height="531"&gt;&lt;img alt="Blog figure" src="/assets/blog/aiProbe16/ai_probe_events_filter-4d60c8317440fca5393e37a61de8e7e2.png" class="img-fluid light-image" loading="lazy" width="782" height="531"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;Scripting and Custom Hot Spots&lt;/h4&gt;

  
  &lt;p&gt;
    For many probes, the most useful perspective is to look at its hot spots. For example, the JDBC probe shows you cumulative data for
    all measured prepared statements. With the AI probe, it is less obvious how to extract a &amp;quot;hot spot&amp;quot; string for multiple concurrent requests
    and how to name them.
  &lt;/p&gt;

  
  &lt;p&gt;
    By default, JProfiler shows the model name. This is a valid hot spot perspective, especially if you work with multiple models, but
    falls short for many other use cases and problem scenarios.
  &lt;/p&gt;

  
  &lt;p&gt;
    Once again, JProfiler's extensive support for scripting comes to the rescue: In a modern Java editor with code completion, inspections,
    quick fixes and refactorings, you can enter a script to extract a string that classifies the LLM request. To help you extract the required
    data, JProfiler includes an API that models the request.
  &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler will compile the script and transfer it to the profiled JVM. Each time a call is made, the script will be run and data for the
    cumulative hot spots view will be calculated.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/aiProbe16/ai_probe_script_dark-bc90bacf85c3e80838aea75823067c0.png" class="img-fluid dark-image" loading="lazy" width="800" height="676"&gt;&lt;img alt="Blog figure" src="/assets/blog/aiProbe16/ai_probe_script-8d9b80c03a4f64b1d9be9ffa5020b5cd.png" class="img-fluid light-image" loading="lazy" width="800" height="676"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;Practical Exploration: The LLM Demo&lt;/h4&gt;

  
  &lt;p&gt;
    For developers who are considering working on agentic applications, we have included a demo app in this release.
    It allows you to explore the features of the AI probe without access to a real-world application.
  &lt;/p&gt;

  
  &lt;p&gt;
    Matching the theme of the AI probe, it downloads article summaries from the arXiv pre-print server and extracts keywords from them.
    After processing a batch of articles, it consolidates similar keywords.
  &lt;/p&gt;

  
  &lt;p&gt;
    With this demo, you can also see how to use the HTTP Client probe in tandem with the AI probe to inspect a workflow at different
    processing stages.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/aiProbe16/llm_demo_dark-a9ab211191b81d3b99eb7a45ba17fc92.png" class="img-fluid dark-image" loading="lazy" width="588" height="494"&gt;&lt;img alt="Blog figure" src="/assets/blog/aiProbe16/llm_demo-7a11515ce993f0c94ace63891d7d2b75.png" class="img-fluid light-image" loading="lazy" width="588" height="494"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;Foundations for the Future&lt;/h4&gt;

  
  &lt;p&gt;
    The three main topics of this release are AI observability, massive scalability for probe events, and deep support for modern JVMs.
  &lt;/p&gt;

  
  &lt;p&gt;
    But we don't stop here. With JProfiler 16, our innovation has accelerated and it will continue to do so.
    Today, JProfiler provides the raw visibility needed to interpret the interactions between deterministic code and probabilistic models.
    Behind the scenes, we are laying the groundwork for future versions to move from pure observation to automated, AI-assisted performance
    heuristics. Stay tuned!
  &lt;/p&gt;</description>
      <category>JProfiler</category>
      <pubDate>Fri, 27 Feb 2026 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2026/02/jprofiler-16-profiling-agentic-java-applications/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2026-02-27T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Profiling AI: LangChain4j and Spring AI</title>
      <link>https://www.ej-technologies.com/blog/2026/03/ai-probe-events-and-telemetries/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Agentic applications introduce unique profiling challenges. Beyond standard CPU usage, performance and costs are determined by
    the complex structure of prompts, RAG retrievers, and tool calls that remain hidden behind framework abstractions.
  &lt;/p&gt;

  
  &lt;p&gt;
    To avoid vendor lock-in, most developers use frameworks like LangChain4j or Spring AI. JProfiler’s AI probe provides deep visibility into
    these frameworks.
  &lt;/p&gt;

  
  &lt;p&gt;
    This screencast walks through profiling a LangChain4j customer support agent, showing how the AI probe
    visualizes prompt compositions, isolates token-heavy outliers, and projects resource costs directly onto the recorded call tree.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/jirhNbQARik" title="Play video 'Profiling AI: LangChain4j and Spring AI'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/jirhNbQARik-6df3d47313aba565b7a09453b16ba786.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Wed, 04 Mar 2026 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2026/03/ai-probe-events-and-telemetries/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2026-03-04T08:00:57Z</dc:date>
    </item>
    <item>
      <title>Breaking the LLM Black Box: Custom Categorization in JProfiler</title>
      <link>https://www.ej-technologies.com/blog/2026/03/breaking-the-llm-blackbox-custom-categorization-in-jprofiler/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;a href="https://www.ej-technologies.com/blog/filter?c=screencast"&gt;Screencast&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Modern agentic applications often perform a wide range of logical tasks through a single interface.
    While these operations have vastly different performance and cost profiles, they appear as an
    undifferentiated call tree in traditional profilers.
  &lt;/p&gt;

  
  &lt;p&gt;
    By default, JProfiler groups these requests by model name, which provides a high-level overview
    but lacks the granularity needed to distinguish between different functional workloads.
  &lt;/p&gt;

  
  &lt;p&gt;
    This screencast shows how to move beyond this predefined perspective with scripts that define your own
    categorization rules based on internal metadata, instruction structure, or application state.
  &lt;/p&gt;

  
  &lt;div class="my-4"&gt;&lt;a href="https://youtu.be/cK0fYXiF1Po" title="Play video 'Breaking the LLM Black Box: Custom Categorization in JProfiler'"&gt;&lt;img alt="Video preview" src="/assets/blog/youtube/cK0fYXiF1Po-ca68b926b6328da54880e903688e0.jpg" class="img-fluid" width="1280" height="720"&gt;&lt;/a&gt;&lt;/div&gt;</description>
      <category>JProfiler</category>
      <category>Screencast</category>
      <pubDate>Fri, 06 Mar 2026 08:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2026/03/breaking-the-llm-blackbox-custom-categorization-in-jprofiler/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2026-03-06T08:00:57Z</dc:date>
    </item>
    <item>
      <title>JProfiler 16.1: AI Agents Can Now Profile Your Java Applications</title>
      <link>https://www.ej-technologies.com/blog/2026/04/jprofiler-16-1-ai-agents-can-now-profile-your-java-applications/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    Since JProfiler 1.0, profiling has been something a developer does with a GUI. You start a session, navigate views, and interpret data.
    In practice, this means that performance analysis only happens when a problem is serious enough to justify the context switch, and
    many issues ship to production without ever being profiled.
  &lt;/p&gt;

  
  &lt;p&gt;
    With JProfiler 16.1, we are changing how profiling works: AI coding agents can now profile your Java applications, analyze the results,
    and act on them. This is the biggest change in how developers use profiling since we started.
  &lt;/p&gt;

  
  &lt;p&gt;
    The new JProfiler MCP server, available as the &lt;code&gt;@ej-technologies/jprofiler-mcp&lt;/code&gt; npm package, exposes JProfiler's
    profiling and heap analysis capabilities through the
    &lt;a href="https://modelcontextprotocol.io/"&gt;Model Context Protocol&lt;/a&gt;. It works with Claude Code, Cursor, Codex,
    Gemini CLI and any other MCP-compatible AI coding tool.
  &lt;/p&gt;

  

  
  &lt;h4 class="mt-5"&gt;The Problem: AI Agents Are Blind to Runtime Behavior&lt;/h4&gt;

  
  &lt;p&gt;
    AI coding agents excel at reading code, generating implementations, and running tests. But they cannot see what happens at runtime.
    When you ask an agent to fix a performance problem, it can only guess based on code patterns. It cannot see which methods are
    actually slow, which database queries dominate execution time, or where memory is being consumed.
  &lt;/p&gt;

  
  &lt;p&gt;
    JProfiler 16.1 closes this gap by exposing profiling data through MCP, giving AI agents the same performance visibility that JProfiler
    has always provided to human developers.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/mcpServer161/architecture-723dfab4be22cdfd2287733a54366ad2.svg" class="img-fluid" loading="lazy" width="1085" height="490"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;From Hotspots to Root Causes&lt;/h4&gt;

  
  &lt;p&gt;
    Agents can close the loop: an agent profiles an application, discovers that JDBC queries dominate execution
    time, and identifies the specific queries responsible. It then modifies the code to eliminate redundant database calls, re-profiles
    to verify the improvement, and presents a before-and-after comparison with concrete numbers. A complete performance engineering
    cycle, from diagnosis to verified fix, without the developer having to open the JProfiler GUI.
  &lt;/p&gt;

  
  &lt;p&gt;
    The agent works with actual runtime data and not by guessing. And because it can compare snapshots, it can prove that its fix actually worked.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/mcpServer161/hotspots_dark-c193faf6f1cc63daa078641dd44150.png" class="img-fluid dark-image" loading="lazy" width="825" height="510"&gt;&lt;img alt="Blog figure" src="/assets/blog/mcpServer161/hotspots-f6fe7726ad8ff3bcbffd3ae8a6f88387.png" class="img-fluid light-image" loading="lazy" width="825" height="510"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;A Guided Workflow That Agents Actually Follow&lt;/h4&gt;

  
  &lt;p&gt;
    Building an MCP server that agents use correctly is harder than it looks. We have carefully crafted and tested the tools so that
    agents reliably follow a profiling workflow that mirrors how an expert would use JProfiler. The agent first sets up profiling
    for the target application. After the test run completes, it checks for data availability. Then it retrieves the initial aggregated
    hotspot view to understand where time is being spent. From there, it drills into specific hotspots, following the call chain to
    the root cause. Each step naturally leads to the next.
  &lt;/p&gt;

  
  &lt;p&gt;
    The data at each step is carefully filtered so agents see what matters without being overwhelmed, whether they are analyzing CPU
    hotspots, JDBC and JPA queries, HTTP calls, MongoDB operations, or heap dumps. Beyond live profiling of local and containerized
    JVMs, agents can also load existing JProfiler, HPROF, or JFR snapshots for analysis.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/mcpServer161/workflow_dark-db3ec94ff2e7823181fdc587cfe798b.png" class="img-fluid dark-image" loading="lazy" width="825" height="510"&gt;&lt;img alt="Blog figure" src="/assets/blog/mcpServer161/workflow-76eea968527509a98e25de1adac40a6.png" class="img-fluid light-image" loading="lazy" width="825" height="510"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;Getting Started&lt;/h4&gt;

  
  &lt;p&gt;
    The setup is zero-friction: the MCP server auto-installs the JProfiler binary on first use and handles licensing through the
    MCP protocol. For Claude Code, it takes a single command:
  &lt;/p&gt;

  
  &lt;pre&gt;claude mcp add jprofiler -- npx -y @ej-technologies/jprofiler-mcp@latest&lt;/pre&gt;

  
  &lt;p&gt;
    The &lt;a href="/jprofiler/mcp"&gt;MCP setup page&lt;/a&gt; has instructions for Codex, Gemini CLI, Junie
    and other MCP-compatible tools.
  &lt;/p&gt;

  
  &lt;p&gt;
    Performance problems have always demanded that developers leave their flow, switch tools, and build up context from scratch.
    With JProfiler 16.1, your AI agent does this for you. It profiles, diagnoses, fixes, and verifies, in the same
    conversation where you described the problem. We will be publishing detailed walkthroughs of real profiling sessions in upcoming posts.
  &lt;/p&gt;</description>
      <category>JProfiler</category>
      <pubDate>Thu, 09 Apr 2026 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2026/04/jprofiler-16-1-ai-agents-can-now-profile-your-java-applications/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2026-04-09T07:00:57Z</dc:date>
    </item>
    <item>
      <title>The Hotspot Claude Would Never Have Found by Reading the Code</title>
      <link>https://www.ej-technologies.com/blog/2026/04/the-hotspot-claude-would-never-have-found-by-reading-the-code/</link>
      <description>&lt;p&gt;Categories: &lt;a href="https://www.ej-technologies.com/blog/filter?c=jprofiler"&gt;JProfiler&lt;/a&gt; &lt;/p&gt;

  
  &lt;p&gt;
    &lt;a href="https://github.com/Athou/commafeed"&gt;CommaFeed&lt;/a&gt; is my daily RSS reader. It is open source, and its
    creator runs a free public instance at &lt;a href="https://www.commafeed.com"&gt;commafeed.com&lt;/a&gt;. Every time I
    refresh my feeds, someone else's server does the work. So when I wondered where all that work actually goes, I pointed Claude Code and the
    JProfiler MCP at it.
  &lt;/p&gt;

  
  &lt;p&gt;
    As a result, a database optimization was merged into CommaFeed. The fix itself was not complicated, but
    Claude would never have come up with it from the source code alone. I asked afterward, and it confirmed as much: its natural first
    attempt would have fixed the wrong thing. Read on for how Claude Code, connected to the
    &lt;a href="https://www.ej-technologies.com/jprofiler/mcp"&gt;JProfiler MCP server&lt;/a&gt;, took me from curiosity to a merged PR.
  &lt;/p&gt;

  

  
  &lt;h4 class="mt-5"&gt;Finding the Hotspot&lt;/h4&gt;

  
  &lt;p&gt;
    I started CommaFeed locally and pointed Claude Code at the running process. Then I ran a unit test to set up feeds and refresh them.
    The first thing the agent did was ask for the JDBC hotspots. One query dominated the ranking:
    a per-entry &lt;code&gt;guidHash&lt;/code&gt; existence check inside &lt;code&gt;FeedEntryDAO.findExisting&lt;/code&gt;.
  &lt;/p&gt;

  
  &lt;p&gt;
    The cumulative time was 141 ms. That is not alarming by itself. What stood out was the count:
    &lt;b&gt;580 JDBC queries for 400 checks&lt;/b&gt;. Something was being checked again.
    The caller was &lt;code&gt;FeedRefreshUpdater.addEntry&lt;/code&gt;, which runs once per entry during every feed refresh.
  &lt;/p&gt;

  
  &lt;p&gt;
    No static analyzer flags &amp;quot;400 checks but 580 JDBC queries&amp;quot; because the ratio only exists at runtime. An agent reading
    &lt;code&gt;FeedRefreshUpdater&lt;/code&gt; sees a reasonable-looking loop calling a reasonable-looking DAO method. Reading the source,
    there is nothing obviously wrong.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;The Fix&lt;/h4&gt;

  
  &lt;p&gt;
    The agent diagnosed a classic N+1 query pattern. Every entry in the parsed feed
    triggered its own database round trip to check existence. The proposed fix was to fetch the existing GUIDs
    for a feed upfront in a single query, filter new entries in memory, and only enter the per-entry loop for new entries.
    The original per-entry check stayed in place as a concurrency safety net.
  &lt;/p&gt;

  
  &lt;p&gt;
    The agent then re-profiled to verify. The &lt;code&gt;guidHash&lt;/code&gt; check dropped from 580 to 400 calls (-31%) and from 141 ms to 93 ms
    (-34%). The remaining 400 calls are the unavoidable safety-net invocations for genuinely new entries during the initial refresh.
    I submitted the change as &lt;a href="https://github.com/Athou/commafeed/pull/2089"&gt;a pull request&lt;/a&gt;.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/mcpServer161/hotspots_dark-c193faf6f1cc63daa078641dd44150.png" class="img-fluid dark-image" loading="lazy" width="825" height="510"&gt;&lt;img alt="Blog figure" src="/assets/blog/mcpServer161/hotspots-f6fe7726ad8ff3bcbffd3ae8a6f88387.png" class="img-fluid light-image" loading="lazy" width="825" height="510"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;The Review&lt;/h4&gt;

  
  &lt;p&gt;
    The maintainer, &lt;a href="https://github.com/Athou"&gt;Athou&lt;/a&gt;, raised a concern. CommaFeed
    lets users disable entry cleanup entirely by setting &lt;code&gt;commafeed.database.cleanup.entries-max-age&lt;/code&gt; and
    &lt;code&gt;max-feed-capacity&lt;/code&gt; to zero. For those users, a single feed can accumulate millions of entries over the years. Fetching
    all of them upfront on every refresh would cause a memory spike.
  &lt;/p&gt;

  
  &lt;p&gt;
    His suggestion was to not fetch all existing GUIDs, but only the GUIDs that are actually present in the current feed XML,
    using a SQL &lt;code&gt;IN&lt;/code&gt; clause, and batch it with 1000 entries per batch.
  &lt;/p&gt;

  
  &lt;p&gt;
    The profiling data mattered here too. The fix was based on measurements and not on speculation about code, so the
    review was about how to scale the approach safely, not about whether the diagnosis was correct. The memory-spike concern was
    a constraint that required the maintainer's domain-specific knowledge, and so the PR process worked as intended.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/claudeHotSpot/review_comment_dark-d3b8972dcc2941bbf8b8b63821c4d7.png" class="img-fluid dark-image" loading="lazy" width="908" height="634"&gt;&lt;img alt="Blog figure" src="/assets/blog/claudeHotSpot/review_comment-4e8819afcadfed37877e21a941c144.png" class="img-fluid light-image" loading="lazy" width="908" height="634"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;Round Two&lt;/h4&gt;

  
  &lt;p&gt;
    I fed the maintainer's review back to Claude Code. The agent changed the method signature from
    &lt;code&gt;findExistingGuids(Feed feed)&lt;/code&gt; to &lt;code&gt;findExistingGuids(Feed feed, Set&amp;lt;String&amp;gt; guidHashes)&lt;/code&gt;, added the
    &lt;code&gt;IN&lt;/code&gt; clause with &lt;code&gt;Lists.partition&lt;/code&gt; batching, and updated the caller to pass in the hashes of the entries
    currently being processed. It also added an integration test that refreshes an already-populated feed and verifies that no
    duplicate entries are created.
  &lt;/p&gt;

  
  &lt;pre&gt;public Set&amp;lt;String&amp;gt; findExistingGuids(Feed feed, Set&amp;lt;String&amp;gt; guidHashes) {
    if (guidHashes.isEmpty()) {
        return Set.of();
    }
    Set&amp;lt;String&amp;gt; result = new HashSet&amp;lt;&amp;gt;();
    for (List&amp;lt;String&amp;gt; batch : Lists.partition(new ArrayList&amp;lt;&amp;gt;(guidHashes), IN_CLAUSE_BATCH_SIZE)) {
        result.addAll(query().select(ENTRY.guidHash)
            .from(ENTRY)
            .where(ENTRY.feed.eq(feed), ENTRY.guidHash.in(batch))
            .fetch());
    }
    return result;
}&lt;/pre&gt;

  
  &lt;p&gt;
    Before pushing the update, the agent re-profiled the test. Splitting a single
    query into batched &lt;code&gt;IN&lt;/code&gt; lookups could have reintroduced overhead that would have reverted the original gain.
    The measurement showed it did not: the batched version stayed within a few percent of the original one-query approach on the
    feeds I tested, and the per-entry check count stayed at the new lower baseline. Only runtime data could confirm that.
  &lt;/p&gt;

  
  &lt;p&gt;
    The PR was merged the same day.
  &lt;/p&gt;

  
  &lt;div class="my-4 text-center"&gt;&lt;img alt="Blog figure" src="/assets/blog/claudeHotSpot/merged_pr_dark-655a26156ddfd25dd8c9520a940ea.png" class="img-fluid dark-image" loading="lazy" width="908" height="254"&gt;&lt;img alt="Blog figure" src="/assets/blog/claudeHotSpot/merged_pr-4c7ee7d23534d1be6ceba83af29221e2.png" class="img-fluid light-image" loading="lazy" width="908" height="254"&gt;&lt;/div&gt;


  
  &lt;h4 class="mt-5"&gt;What Would Have Happened Without the MCP&lt;/h4&gt;

  
  &lt;p&gt;
    After the PR was merged, I asked the agent what it would have tried if it only had the source code to work with. Its answer:
    the natural attempt would have been enabling Hibernate batch inserts, a setting that speeds up individual inserts.
    That would have had zero effect on this problem. The bottleneck was query &lt;i&gt;count&lt;/i&gt;, not query speed. The agent would have
    recommended the wrong fix.
  &lt;/p&gt;

  
  &lt;p&gt;
    I then asked for a short testimonial. In the agent's own words:
  &lt;/p&gt;

  
  &lt;blockquote class="blockquote my-4 ps-4 border-start border-3"&gt;
    
    &lt;p&gt;
      JProfiler's JDBC and persistence probes revealed a pattern that timing alone would never surface: redundant per-entry
      database checks firing on every refresh cycle, even when nothing had changed. Without that probe data, I would have optimized
      the wrong thing entirely.
    &lt;/p&gt;

  &lt;/blockquote&gt;

  
  &lt;p&gt;
    Every feed refresh on commafeed.com costs its creator resources. A substantial reduction in the most expensive query during
    refresh allows more users on the same hardware.
  &lt;/p&gt;


  
  &lt;h4 class="mt-5"&gt;Try It on Your Own Code&lt;/h4&gt;

  
  &lt;p&gt;
    The same approach works on any Java application. Every codebase has hotspots you cannot see by reading the source.
    An N+1 query that hides behind a DAO, a serializer that allocates millions of short-lived objects, a retry policy buried in
    an HTTP client that silently triples your outbound calls. Reading the code will not find them, runtime data will.
  &lt;/p&gt;

  
  &lt;p&gt;
    Setup takes a single command. Point your AI agent at your application and ask it where the time is spent. The
    &lt;a href="/jprofiler/mcp"&gt;JProfiler MCP page&lt;/a&gt; has instructions for Claude Code, Cursor, Codex, and any other MCP-compatible tool.
  &lt;/p&gt;</description>
      <category>JProfiler</category>
      <pubDate>Fri, 17 Apr 2026 07:00:57 GMT</pubDate>
      <guid isPermaLink="false">https://www.ej-technologies.com/blog/2026/04/the-hotspot-claude-would-never-have-found-by-reading-the-code/</guid>
      <dc:creator>Ingo Kegel</dc:creator>
      <dc:date>2026-04-17T07:00:57Z</dc:date>
    </item>
  </channel>
</rss>
