tag:blogger.com,1999:blog-305876332024-02-03T22:14:05.108+05:30My WikiJaikiran's technical blog
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.comBlogger76125tag:blogger.com,1999:blog-30587633.post-88016484202782618562023-10-05T19:11:00.009+05:302023-10-16T18:54:43.889+05:30Using JAXB in custom Ant tasks on recent Java versions<head>
<style>
.console, .sourceCode {
width: 80ch;
display: block;
word-wrap: break-word !important;
white-space : pre-wrap !important;
}
</style>
</head>
<p>Apache Ant 1.10.14 was released a few weeks ago <a href="https://lists.apache.org/thread/9vhk51nkw9wjxzm7xk2q9xm6s803prmr">https://lists.apache.org/thread/9vhk51nkw9wjxzm7xk2q9xm6s803prmr</a>. Like noted in that announcement, apart from the regular bug fixes, this release also has an important change which allows it to be used in the recently released Java 21 <a href="https://inside.java/2023/09/19/the-arrival-of-java-21/">https://inside.java/2023/09/19/the-arrival-of-java-21/</a>. One major goal of Ant project is to make sure that it can be used to build projects using latest versions of Java. As such, the Ant project team keeps a watch on any changes in the Java releases that could affect Ant and does necessary changes in Ant and releases them in its 1.10.x release series.</p>
<p>The announcement of 1.10.14 and this changelog <a href="https://github.com/apache/ant/blob/rel/1.10.14/WHATSNEW">https://github.com/apache/ant/blob/rel/1.10.14/WHATSNEW</a> contains the details of what’s exactly changed in this release, so I won’t go into those details again. In this post I’ll however go through one interesting issue that was brought to my notice by more than one projects, when using recent versions of Java. The issue specifically relates to custom Ant tasks that use JAXB. However, in general, it applies to some of the APIs that have been removed from recent versions of Java (details in <a href="https://openjdk.org/jeps/320">https://openjdk.org/jeps/320</a>)</p>
<p>JAXB as noted in the reference doc <a href="https://docs.oracle.com/javase/tutorial/jaxb/intro/arch.html">https://docs.oracle.com/javase/tutorial/jaxb/intro/arch.html</a> is an API and implementation for XML binding. Up until Java 11, JAXB API and implementation classes were shipped as part of the Java runtime. What it meant was that any application code, like custom developed Ant tasks, could just use the JAXB APIs in their code without having to explicitly specific any external library dependency. In Java 11, JAXB along with few other modules was removed from the JDK. The release notes of JDK 11 lists this change <a href="https://www.oracle.com/java/technologies/javase/11-relnote-issues.html#JDK-8190378">https://www.oracle.com/java/technologies/javase/11-relnote-issues.html#JDK-8190378</a>. Additionally, JEP-320 <a href="https://openjdk.org/jeps/320">https://openjdk.org/jeps/320</a> has all the details related to this removal. When using JAXB APIs, the usage of these modules from the JDK was transparent to the application. So although the application may not explicitly have referred to these module names, it was still reliant on them because they were providing public APIs which the application had references to. Effectively, if a project was using some Ant task which used JAXB, then those projects when they switch to any Java version >= 11 will now start seeing issues due to missing compile and runtime dependency on JAXB. Let’s now consider a simple custom Ant task and see what kind of errors it might encounter. But if you are just interested in the shorter answer and some sample code to fix these classloading issues with JAXB, then please check the end of this article, starting <a href="#fix">here</a>. For the complete details, please read on.</p>
<p>We will use a trivial custom Ant task implemented by a class called <code>org.myapp.HelloTask</code>, which looks like:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode java"><code class="sourceCode java"><span id="cb1-1"><a aria-hidden="true" href="#cb1-1" tabindex="-1"></a></span>
<span id="cb1-2"><a aria-hidden="true" href="#cb1-2" tabindex="-1"></a><span class="kw">package</span><span class="im"> org</span><span class="op">.</span><span class="im">myapp</span><span class="op">;</span></span>
<span id="cb1-3"><a aria-hidden="true" href="#cb1-3" tabindex="-1"></a></span>
<span id="cb1-4"><a aria-hidden="true" href="#cb1-4" tabindex="-1"></a><span class="kw">import</span> <span class="im">org</span><span class="op">.</span><span class="im">apache</span><span class="op">.</span><span class="im">tools</span><span class="op">.</span><span class="im">ant</span><span class="op">.</span><span class="im">Task</span><span class="op">;</span></span>
<span id="cb1-5"><a aria-hidden="true" href="#cb1-5" tabindex="-1"></a><span class="kw">import</span> <span class="im">javax</span><span class="op">.</span><span class="im">xml</span><span class="op">.</span><span class="im">bind</span><span class="op">.</span><span class="im">JAXBContext</span><span class="op">;</span></span>
<span id="cb1-6"><a aria-hidden="true" href="#cb1-6" tabindex="-1"></a><span class="kw">import</span> <span class="im">javax</span><span class="op">.</span><span class="im">xml</span><span class="op">.</span><span class="im">bind</span><span class="op">.</span><span class="im">JAXBException</span><span class="op">;</span></span>
<span id="cb1-7"><a aria-hidden="true" href="#cb1-7" tabindex="-1"></a></span>
<span id="cb1-8"><a aria-hidden="true" href="#cb1-8" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> HelloTask <span class="kw">extends</span> Task <span class="op">{</span></span>
<span id="cb1-9"><a aria-hidden="true" href="#cb1-9" tabindex="-1"></a></span>
<span id="cb1-10"><a aria-hidden="true" href="#cb1-10" tabindex="-1"></a> <span class="kw">private</span> <span class="bu">String</span> message<span class="op">;</span></span>
<span id="cb1-11"><a aria-hidden="true" href="#cb1-11" tabindex="-1"></a></span>
<span id="cb1-12"><a aria-hidden="true" href="#cb1-12" tabindex="-1"></a> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">setMessage</span><span class="op">(</span><span class="dt">final</span> <span class="bu">String</span> message<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-13"><a aria-hidden="true" href="#cb1-13" tabindex="-1"></a> <span class="kw">this</span><span class="op">.</span><span class="fu">message</span> <span class="op">=</span> message<span class="op">;</span></span>
<span id="cb1-14"><a aria-hidden="true" href="#cb1-14" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb1-15"><a aria-hidden="true" href="#cb1-15" tabindex="-1"></a></span>
<span id="cb1-16"><a aria-hidden="true" href="#cb1-16" tabindex="-1"></a> <span class="at">@Override</span></span>
<span id="cb1-17"><a aria-hidden="true" href="#cb1-17" tabindex="-1"></a> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">execute</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-18"><a aria-hidden="true" href="#cb1-18" tabindex="-1"></a> <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb1-19"><a aria-hidden="true" href="#cb1-19" tabindex="-1"></a> <span class="dt">final</span> <span class="bu">JAXBContext</span> context <span class="op">=</span> <span class="bu">JAXBContext</span><span class="op">.</span><span class="fu">newInstance</span><span class="op">(</span>DataContainer<span class="op">.</span><span class="fu">class</span><span class="op">);</span></span>
<span id="cb1-20"><a aria-hidden="true" href="#cb1-20" tabindex="-1"></a> <span class="bu">System</span><span class="op">.</span><span class="fu">out</span><span class="op">.</span><span class="fu">println</span><span class="op">(</span><span class="st">"Created JAXB context "</span> <span class="op">+</span> context<span class="op">);</span></span>
<span id="cb1-21"><a aria-hidden="true" href="#cb1-21" tabindex="-1"></a> <span class="op">}</span> <span class="cf">catch</span> <span class="op">(</span><span class="bu">JAXBException</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-22"><a aria-hidden="true" href="#cb1-22" tabindex="-1"></a> <span class="cf">throw</span> <span class="kw">new</span> <span class="bu">RuntimeException</span><span class="op">(</span>e<span class="op">);</span></span>
<span id="cb1-23"><a aria-hidden="true" href="#cb1-23" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb1-24"><a aria-hidden="true" href="#cb1-24" tabindex="-1"></a></span>
<span id="cb1-25"><a aria-hidden="true" href="#cb1-25" tabindex="-1"></a> <span class="bu">System</span><span class="op">.</span><span class="fu">out</span><span class="op">.</span><span class="fu">println</span><span class="op">(</span><span class="kw">this</span><span class="op">.</span><span class="fu">message</span><span class="op">);</span></span>
<span id="cb1-26"><a aria-hidden="true" href="#cb1-26" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb1-27"><a aria-hidden="true" href="#cb1-27" tabindex="-1"></a></span>
<span id="cb1-28"><a aria-hidden="true" href="#cb1-28" tabindex="-1"></a> <span class="kw">private</span> <span class="dt">static</span> <span class="kw">class</span> DataContainer <span class="op">{</span></span>
<span id="cb1-29"><a aria-hidden="true" href="#cb1-29" tabindex="-1"></a> <span class="kw">private</span> <span class="bu">String</span> data<span class="op">;</span></span>
<span id="cb1-30"><a aria-hidden="true" href="#cb1-30" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb1-31"><a aria-hidden="true" href="#cb1-31" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The <code>HelloTask</code> is just here for demonstration and in practice doesn’t provide any real value. This task allows for a <code>message</code> attribute to be specified. Furthermore, in its <code>execute()</code> method it creates a <code>javax.xml.bind.JAXBContext</code> for the application specific <code>DataContainer</code> class and just prints that context. Additionally, it also prints the <code>message</code> that was set when the task is launched. Let’s assume that this task has been compiled and packaged as a jar file and made available to the build process. Now consider this trivial <code>build.xml</code> file which declares this task and then launches it:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode xml"><code class="sourceCode xml"><span id="cb2-1"><a aria-hidden="true" href="#cb2-1" tabindex="-1"></a></span>
<span id="cb2-2"><a aria-hidden="true" href="#cb2-2" tabindex="-1"></a><<span class="kw">project</span><span class="ot"> default=</span><span class="st">"invoke-task"</span>></span>
<span id="cb2-3"><a aria-hidden="true" href="#cb2-3" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"build.dir"</span><span class="ot"> value=</span><span class="st">"build"</span>/></span>
<span id="cb2-4"><a aria-hidden="true" href="#cb2-4" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"jar.name"</span><span class="ot"> value=</span><span class="st">"hellotask.jar"</span>/></span>
<span id="cb2-5"><a aria-hidden="true" href="#cb2-5" tabindex="-1"></a></span>
<span id="cb2-6"><a aria-hidden="true" href="#cb2-6" tabindex="-1"></a> <<span class="kw">taskdef</span><span class="ot"> name=</span><span class="st">"hello"</span><span class="ot"> classname=</span><span class="st">"org.myapp.HelloTask"</span>></span>
<span id="cb2-7"><a aria-hidden="true" href="#cb2-7" tabindex="-1"></a> <<span class="kw">classpath</span>></span>
<span id="cb2-8"><a aria-hidden="true" href="#cb2-8" tabindex="-1"></a> <<span class="kw">pathelement</span><span class="ot"> location=</span><span class="st">"${build.dir}/${jar.name}"</span>/></span>
<span id="cb2-9"><a aria-hidden="true" href="#cb2-9" tabindex="-1"></a> </<span class="kw">classpath</span>> </span>
<span id="cb2-10"><a aria-hidden="true" href="#cb2-10" tabindex="-1"></a> </<span class="kw">taskdef</span>> </span>
<span id="cb2-11"><a aria-hidden="true" href="#cb2-11" tabindex="-1"></a></span>
<span id="cb2-12"><a aria-hidden="true" href="#cb2-12" tabindex="-1"></a> <<span class="kw">target</span><span class="ot"> name=</span><span class="st">"invoke-task"</span><span class="ot"> description=</span><span class="st">"invokes the HelloTask"</span>></span>
<span id="cb2-13"><a aria-hidden="true" href="#cb2-13" tabindex="-1"></a> <<span class="kw">hello</span><span class="ot"> message=</span><span class="st">"hello world"</span>/></span>
<span id="cb2-14"><a aria-hidden="true" href="#cb2-14" tabindex="-1"></a> </<span class="kw">target</span>> </span>
<span id="cb2-15"><a aria-hidden="true" href="#cb2-15" tabindex="-1"></a></span>
<span id="cb2-16"><a aria-hidden="true" href="#cb2-16" tabindex="-1"></a></<span class="kw">project</span>></span></code></pre></div>
<p>There’s not much in this <code>build.xml</code>. All it does is, use a <code>taskdef</code> to define the <code>HelloTask</code> with the classpath containing (just the) jar file containing the <code>HelloTask</code>. Then in the <code>invoke-task</code> target we launch this <code>hello</code> task by passing it a message.</p>
<p>Let’s now run this build against Java 8:</p>
<pre class="console"><code>export JAVA_HOME=<path-to-JDK-8>
ant invoke-task</code></pre>
<p>When you run this (on Java 8) you should see the output similar to:</p>
<pre class="console"><code>
invoke-task:
[hello] Created JAXB context jar:file:/<path-to-jdk-8>/jre/lib/rt.jar!/com/sun/xml/internal/bind/v2/runtime/JAXBContextImpl.class Build-Id: ...
[hello] Classes known to this context:
[hello] [B
[hello] boolean
[hello] byte
[hello] char
[hello] com.sun.xml.internal.bind.api.CompositeStructure
[hello] double
[hello] float
[hello] int
...
[hello] long
[hello] org.myapp.HelloTask$DataContainer
[hello] short
[hello] void
[hello]
[hello] hello world</code></pre>
<p>You’ll see that the JAXB usage in the task was successful and the build completed successfully and we didn’t have to configure any classpath to include any JAXB jar files. As noted previously, this is because the Java 8 runtime ships with the relevant JAXB API and implementation classes.</p>
<p>Now, without changing any code in the task or in the build.xml, let’s just switch to a recent Java version. Let’s say Java 17 and run the build:</p>
<pre class="console"><code>export JAVA_HOME=<path-to-JDK-17>
ant invoke-task</code></pre>
<p>When you do this, you will now see:</p>
<pre class="console"><code>BUILD FAILED
build.xml:5: taskdef A class needed by class org.myapp.HelloTask cannot be found: javax/xml/bind/JAXBException
using the classloader AntClassLoader[build/hellotask.jar]</code></pre>
<p>You’ll notice that the build now fails and the error message states that the class <code>javax/xml/bind/JAXBException</code> cannot be found in the classpath which as defined in the <code>build.xml</code> only included the <code>hellotask.jar</code> (which just has the <code>org.myapp.HelloTask</code>). As noted previously, this is because the JAXB API and implementation is no longer shipped in the JDK. Applications, like this project, are expected to now include the JAXB API and implementation jars in the application classpath. JEP-320 <a href="https://openjdk.org/jeps/320">https://openjdk.org/jeps/320</a> lists the potential Maven co-ordinates to find such jar(s). In case of JAXB it suggests the JAXB reference implementation available in Maven central repo <code>com.sun.xml.bind:jaxb-ri</code> as a potential candidate. Do note that, just like several other Java EE APIs and implementations, JAXB too has several vendors which implement the JAXB API. A “reference implementation” as the name states is meant to demonstrate the implementation of the specified API. There can, and are, several other vendor implementations for such APIs. It’s upto the applications to choose the ones that they desire to use. In this demonstration, we will use the <code>2.3.8</code> version of <code>com.sun.xml.bind:jaxb-ri</code> dependency (available at <a href="https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-ri/2.3.8/">https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-ri/2.3.8/</a>). There’s no specific reason for my choice of this specific version - it’s only for demo.</p>
<p>Now that we have this dependency made available, let’s include it in the classpath of the <code>taskdef</code> of <code>HelloTask</code> and our build.xml (snippet) will now look like:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode xml"><code class="sourceCode xml"><span id="cb7-1"><a aria-hidden="true" href="#cb7-1" tabindex="-1"></a>...</span>
<span id="cb7-2"><a aria-hidden="true" href="#cb7-2" tabindex="-1"></a> <<span class="kw">taskdef</span><span class="ot"> name=</span><span class="st">"hello"</span><span class="ot"> classname=</span><span class="st">"org.myapp.HelloTask"</span>></span>
<span id="cb7-3"><a aria-hidden="true" href="#cb7-3" tabindex="-1"></a> <<span class="kw">classpath</span>></span>
<span id="cb7-4"><a aria-hidden="true" href="#cb7-4" tabindex="-1"></a> <<span class="kw">pathelement</span><span class="ot"> location=</span><span class="st">"${build.dir}/${jar.name}"</span>/></span>
<span id="cb7-5"><a aria-hidden="true" href="#cb7-5" tabindex="-1"></a> <span class="co"><!-- JAXB dependencies --></span></span>
<span id="cb7-6"><a aria-hidden="true" href="#cb7-6" tabindex="-1"></a> <<span class="kw">pathelement</span><span class="ot"> location=</span><span class="st">"${lib.dir}/jakarta.activation.jar"</span>/></span>
<span id="cb7-7"><a aria-hidden="true" href="#cb7-7" tabindex="-1"></a> <<span class="kw">pathelement</span><span class="ot"> location=</span><span class="st">"${lib.dir}/jakarta.xml.bind-api.jar"</span>/></span>
<span id="cb7-8"><a aria-hidden="true" href="#cb7-8" tabindex="-1"></a> <<span class="kw">pathelement</span><span class="ot"> location=</span><span class="st">"${lib.dir}/jaxb-impl.jar"</span>/></span>
<span id="cb7-9"><a aria-hidden="true" href="#cb7-9" tabindex="-1"></a> </<span class="kw">classpath</span>> </span>
<span id="cb7-10"><a aria-hidden="true" href="#cb7-10" tabindex="-1"></a> </<span class="kw">taskdef</span>> </span>
<span id="cb7-11"><a aria-hidden="true" href="#cb7-11" tabindex="-1"></a>...</span></code></pre></div>
<p>You’ll notice that the classpath of the <code>taskdef</code> now includes the JAXB related dependency jars. Now let’s rerun the build on Java 17, like previously:</p>
<pre class="console"><code>export JAVA_HOME=<path-to-JDK-17>
ant invoke-task</code></pre>
<p>When you run this, you will now see something that starts like this:</p>
<pre class="console"><code>
BUILD FAILED
build.xml:17: java.lang.RuntimeException: javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory]
at org.myapp.HelloTask.execute(Unknown Source)
</code></pre>
<p>So the build still fails, but unlike previously where it had failed when trying to define the <code>HelloTask</code> itself, this time it fails in the <code>execute()</code> implementation of the <code>HelloTask</code>. </p>
<p>So why does it fail even with the JAXB jars in the classpath. This has to do with JAXB (and several other Java EE APIs), which rely on thread context classloader. Several of these APIs, including this call to:</p>
<pre><code>final JAXBContext context = JAXBContext.newInstance(DataContainer.class);</code></pre>
<p>relies on thread context classloader to find the JAXB related classes and resources. It expects the thread context classloader, whichever it is, to be able to load these JAXB classes. Thread context classloaders are specific to the thread that is currently executing the code. So let’s quickly see which classloaders are in play in the <code>execute()</code> method of the <code>HelloTask</code>. To see that, let’s add some trivial debug messages in the code, whose snippet will now look like:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode java"><code class="sourceCode java"><span id="cb12-1"><a aria-hidden="true" href="#cb12-1" tabindex="-1"></a></span>
<span id="cb12-2"><a aria-hidden="true" href="#cb12-2" tabindex="-1"></a> <span class="at">@Override</span></span>
<span id="cb12-3"><a aria-hidden="true" href="#cb12-3" tabindex="-1"></a> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">execute</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-4"><a aria-hidden="true" href="#cb12-4" tabindex="-1"></a> <span class="bu">System</span><span class="op">.</span><span class="fu">out</span><span class="op">.</span><span class="fu">println</span><span class="op">(</span>HelloTask<span class="op">.</span><span class="fu">class</span> <span class="op">+</span> <span class="st">" was loaded by classloader: "</span> <span class="op">+</span> HelloTask<span class="op">.</span><span class="fu">class</span><span class="op">.</span><span class="fu">getClassLoader</span><span class="op">());</span></span>
<span id="cb12-5"><a aria-hidden="true" href="#cb12-5" tabindex="-1"></a> <span class="dt">final</span> <span class="bu">ClassLoader</span> tccl <span class="op">=</span> <span class="bu">Thread</span><span class="op">.</span><span class="fu">currentThread</span><span class="op">().</span><span class="fu">getContextClassLoader</span><span class="op">();</span></span>
<span id="cb12-6"><a aria-hidden="true" href="#cb12-6" tabindex="-1"></a> <span class="bu">System</span><span class="op">.</span><span class="fu">out</span><span class="op">.</span><span class="fu">println</span><span class="op">(</span><span class="st">"Context classloader of current thread is "</span> <span class="op">+</span> tccl<span class="op">);</span></span>
<span id="cb12-7"><a aria-hidden="true" href="#cb12-7" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>tccl <span class="kw">instanceof</span> java<span class="op">.</span><span class="fu">net</span><span class="op">.</span><span class="fu">URLClassLoader</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-8"><a aria-hidden="true" href="#cb12-8" tabindex="-1"></a> <span class="co">// let's additionally print the classpath of the URLClassLoader</span></span>
<span id="cb12-9"><a aria-hidden="true" href="#cb12-9" tabindex="-1"></a> <span class="dt">final</span> java<span class="op">.</span><span class="fu">net</span><span class="op">.</span><span class="fu">URL</span><span class="op">[]</span> classpath <span class="op">=</span> <span class="op">((</span>java<span class="op">.</span><span class="fu">net</span><span class="op">.</span><span class="fu">URLClassLoader</span><span class="op">)</span> tccl<span class="op">).</span><span class="fu">getURLs</span><span class="op">();</span></span>
<span id="cb12-10"><a aria-hidden="true" href="#cb12-10" tabindex="-1"></a> <span class="bu">System</span><span class="op">.</span><span class="fu">out</span><span class="op">.</span><span class="fu">println</span><span class="op">(</span><span class="st">"Context classloader's classpath is "</span> <span class="op">+</span> java<span class="op">.</span><span class="fu">util</span><span class="op">.</span><span class="fu">Arrays</span><span class="op">.</span><span class="fu">toString</span><span class="op">(</span>classpath<span class="op">));</span></span>
<span id="cb12-11"><a aria-hidden="true" href="#cb12-11" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb12-12"><a aria-hidden="true" href="#cb12-12" tabindex="-1"></a> <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb12-13"><a aria-hidden="true" href="#cb12-13" tabindex="-1"></a> <span class="dt">final</span> <span class="bu">JAXBContext</span> context <span class="op">=</span> <span class="bu">JAXBContext</span><span class="op">.</span><span class="fu">newInstance</span><span class="op">(</span>DataContainer<span class="op">.</span><span class="fu">class</span><span class="op">);</span></span>
<span id="cb12-14"><a aria-hidden="true" href="#cb12-14" tabindex="-1"></a> <span class="bu">System</span><span class="op">.</span><span class="fu">out</span><span class="op">.</span><span class="fu">println</span><span class="op">(</span><span class="st">"Created JAXB context "</span> <span class="op">+</span> context<span class="op">);</span></span>
<span id="cb12-15"><a aria-hidden="true" href="#cb12-15" tabindex="-1"></a> <span class="op">}</span> <span class="cf">catch</span> <span class="op">(</span><span class="bu">JAXBException</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-16"><a aria-hidden="true" href="#cb12-16" tabindex="-1"></a> <span class="cf">throw</span> <span class="kw">new</span> <span class="bu">RuntimeException</span><span class="op">(</span>e<span class="op">);</span></span>
<span id="cb12-17"><a aria-hidden="true" href="#cb12-17" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb12-18"><a aria-hidden="true" href="#cb12-18" tabindex="-1"></a></span>
<span id="cb12-19"><a aria-hidden="true" href="#cb12-19" tabindex="-1"></a> <span class="bu">System</span><span class="op">.</span><span class="fu">out</span><span class="op">.</span><span class="fu">println</span><span class="op">(</span><span class="kw">this</span><span class="op">.</span><span class="fu">message</span><span class="op">);</span></span>
<span id="cb12-20"><a aria-hidden="true" href="#cb12-20" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
<p>So what we have done here is that added a few <code>System.out.println</code> messages which prints the classloader which loaded the <code>HelloTask</code> and also prints the current thread’s context classloader. Additionally if the context classloader is a <code>java.net.URLClassLoader</code>, we even print the classpath used by the <code>URLClassLoader</code>. The goal of these debug messages is to see what classloaders are in play when using that JAXB API. Let’s rerun the build again on Java 17 - it’s still expected to fail like previously, but this time we should see these debug messages:</p>
<pre class="console"><code>export JAVA_HOME=<path-to-JDK-17>
ant invoke-task</code></pre>
<p>This fails with the same exception stacktrace as previously, but this time you should also see, something like:</p>
<pre class="console"><code>
[hello] class org.myapp.HelloTask was loaded by classloader: AntClassLoader[build/hellotask.jar:lib/jakarta.activation.jar:lib/jakarta.xml.bind-api.jar:lib/jaxb-impl.jar]
[hello] Context classloader of current thread is java.net.URLClassLoader@6d6f6e28
[hello] Context classloader's classpath is [file:/apache-ant-1.10.14/lib/ant-commons-net.jar, file:/apache-ant-1.10.14/lib/ant-xz.jar, file:/apache-ant-1.10.14/lib/ant-junit4.jar, file:/apache-ant-1.10.14/lib/ant-jai.jar, file:/apache-ant-1.10.14/lib/ant-apache-resolver.jar, file:/apache-ant-1.10.14/lib/ant-jdepend.jar, file:/apache-ant-1.10.14/lib/ant-apache-regexp.jar, file:/apache-ant-1.10.14/lib/ant-apache-log4j.jar, file:/apache-ant-1.10.14/lib/ant-javamail.jar, file:/apache-ant-1.10.14/lib/ant-apache-bcel.jar, file:/apache-ant-1.10.14/lib/ant.jar, file:/apache-ant-1.10.14/lib/ant-netrexx.jar, file:/apache-ant-1.10.14/lib/ant-swing.jar, file:/apache-ant-1.10.14/lib/ant-jsch.jar, file:/apache-ant-1.10.14/lib/ant-junitlauncher.jar, file:/apache-ant-1.10.14/lib/ant-jakartamail.jar, file:/apache-ant-1.10.14/lib/ant-junit.jar, file:/apache-ant-1.10.14/lib/ant-imageio.jar, file:/apache-ant-1.10.14/lib/ant-launcher.jar, file:/apache-ant-1.10.14/lib/ant-antlr.jar, file:/apache-ant-1.10.14/lib/ant-testutil.jar, file:/apache-ant-1.10.14/lib/ant-apache-oro.jar, file:/apache-ant-1.10.14/lib/ant-jmf.jar, file:/apache-ant-1.10.14/lib/ant-apache-xalan2.jar, file:/apache-ant-1.10.14/lib/ant-apache-bsf.jar, file:/apache-ant-1.10.14/lib/ant-commons-logging.jar]</code></pre>
<p>You’ll see that the <code>HelloTask</code> was loaded using an instance of <code>AntClassLoader</code> (which is internal implementation detail of the Ant project) and this classloader has the relevant JAXB jars in its classpath (as seen in the message above). You’ll also notice in the log message that the thread’s context classloader is an instance of <code>URLClassLoader</code>:</p>
<pre><code>[hello] Context classloader of current thread is java.net.URLClassLoader@6d6f6e28</code></pre>
<p>and this instance of <code>URLClassLoader</code> has a classpath which has only Ant specific jars and <i>nothing</i> related to JAXB jars. Now when the specific call to <code>JAXBContext.newInstance(...)</code> gets made it ends up using the <code>URLClassLoader</code> (since it is the thread context classloader) which doesn’t have JAXB jars. Effectively, you end up seeing the classloading failures and the build fails.</p>
<p id="fix">So how do we fix this. The important bit here is that the thread context classloader should be the one which has the JAXB classes available, so that it can load them. Java’s <code>java.lang.Thread</code> class allows the context classloader to be changed/switched. In fact, in the Java EE ecosystem, frameworks, servers and other implementations (typically not the application code), switch the thread’s context classloader to a “relevant” classloader at the “right place” and then switch it back to the old context classloader when the operation completes. We will need a similar implementation here in the custom task’s <code>execute()</code> method. Here’s what the snippet will now look like (we no longer need the debug logging, so that’s now been removed):</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode java"><code class="sourceCode java"><span id="cb16-1"><a aria-hidden="true" href="#cb16-1" tabindex="-1"></a><span class="at">@Override</span></span>
<span id="cb16-2"><a aria-hidden="true" href="#cb16-2" tabindex="-1"></a> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">execute</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb16-3"><a aria-hidden="true" href="#cb16-3" tabindex="-1"></a> <span class="co">// get the current context classloader</span></span>
<span id="cb16-4"><a aria-hidden="true" href="#cb16-4" tabindex="-1"></a> <span class="dt">final</span> <span class="bu">ClassLoader</span> tccl <span class="op">=</span> <span class="bu">Thread</span><span class="op">.</span><span class="fu">currentThread</span><span class="op">().</span><span class="fu">getContextClassLoader</span><span class="op">();</span></span>
<span id="cb16-5"><a aria-hidden="true" href="#cb16-5" tabindex="-1"></a> <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb16-6"><a aria-hidden="true" href="#cb16-6" tabindex="-1"></a> <span class="co">// change the thread context classloader to this task's classloader</span></span>
<span id="cb16-7"><a aria-hidden="true" href="#cb16-7" tabindex="-1"></a> <span class="co">// before using the JAXB API</span></span>
<span id="cb16-8"><a aria-hidden="true" href="#cb16-8" tabindex="-1"></a> <span class="bu">Thread</span><span class="op">.</span><span class="fu">currentThread</span><span class="op">().</span><span class="fu">setContextClassLoader</span><span class="op">(</span>HelloTask<span class="op">.</span><span class="fu">class</span><span class="op">.</span><span class="fu">getClassLoader</span><span class="op">());</span></span>
<span id="cb16-9"><a aria-hidden="true" href="#cb16-9" tabindex="-1"></a> <span class="dt">final</span> <span class="bu">JAXBContext</span> context <span class="op">=</span> <span class="bu">JAXBContext</span><span class="op">.</span><span class="fu">newInstance</span><span class="op">(</span>DataContainer<span class="op">.</span><span class="fu">class</span><span class="op">);</span></span>
<span id="cb16-10"><a aria-hidden="true" href="#cb16-10" tabindex="-1"></a> <span class="bu">System</span><span class="op">.</span><span class="fu">out</span><span class="op">.</span><span class="fu">println</span><span class="op">(</span><span class="st">"Created JAXB context "</span> <span class="op">+</span> context<span class="op">);</span></span>
<span id="cb16-11"><a aria-hidden="true" href="#cb16-11" tabindex="-1"></a> <span class="op">}</span> <span class="cf">catch</span> <span class="op">(</span><span class="bu">JAXBException</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-12"><a aria-hidden="true" href="#cb16-12" tabindex="-1"></a> <span class="cf">throw</span> <span class="kw">new</span> <span class="bu">RuntimeException</span><span class="op">(</span>e<span class="op">);</span></span>
<span id="cb16-13"><a aria-hidden="true" href="#cb16-13" tabindex="-1"></a> <span class="op">}</span> <span class="cf">finally</span> <span class="op">{</span></span>
<span id="cb16-14"><a aria-hidden="true" href="#cb16-14" tabindex="-1"></a> <span class="co">// restore back the old context classloader</span></span>
<span id="cb16-15"><a aria-hidden="true" href="#cb16-15" tabindex="-1"></a> <span class="bu">Thread</span><span class="op">.</span><span class="fu">currentThread</span><span class="op">().</span><span class="fu">setContextClassLoader</span><span class="op">(</span>tccl<span class="op">);</span></span>
<span id="cb16-16"><a aria-hidden="true" href="#cb16-16" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb16-17"><a aria-hidden="true" href="#cb16-17" tabindex="-1"></a></span>
<span id="cb16-18"><a aria-hidden="true" href="#cb16-18" tabindex="-1"></a> <span class="bu">System</span><span class="op">.</span><span class="fu">out</span><span class="op">.</span><span class="fu">println</span><span class="op">(</span><span class="kw">this</span><span class="op">.</span><span class="fu">message</span><span class="op">);</span></span>
<span id="cb16-19"><a aria-hidden="true" href="#cb16-19" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
<p>Notice that we get hold of the current context classloader and then before calling <code>JAXBContext.newInstance(...)</code> we change the context classloader to the <code>HelloTask</code>’s classloader. The <code>HelloTask</code>’s classloader, as we have seen so far, has the necessary JAXB jars (since we defined it in the classpath of the taskdef in the build.xml) from which it should be able to load the JAXB classes. Finally, and very importantly, in a <code>finally</code> block we restore the context classloader to whatever it was previously - that way rest of the code isn’t impacted by switching the thread context classloader. Let’s now build the project again on Java 17:</p>
<pre class="console"><code>export JAVA_HOME=<path-to-JDK-17>
ant invoke-task</code></pre>
<p>When you now run this, you should see:</p>
<pre class="console"><code>invoke-task:
[hello] Created JAXB context jar:file:/lib/jaxb-impl.jar!/com/sun/xml/bind/v2/runtime/JAXBContextImpl.class Build-Id: 2.3.8
[hello] Classes known to this context:
[hello] [B
[hello] boolean
[hello] byte
[hello] char
[hello] com.sun.xml.bind.api.CompositeStructure
[hello] double
[hello] float
[hello] int
...
[hello] org.myapp.HelloTask$DataContainer
[hello] short
[hello] void
[hello]
[hello] hello world
</code></pre>
<p>So the build now succeeds.</p>
<p>To summarize, recent versions of JDK have removed certain APIs from the JDK. Some of such APIs are available as external libraries which can be configured in the application classpath. In context of Ant, if a task that is shipped by Ant makes use of such APIs, then the Ant release note and the manual of that task will make a note of such change and will also note what needs to be done to get that task functional. In other cases, where custom tasks are involved and depend on APIs that are no longer part of the JDK, on most occasions they will need to update their build files to include those dependencies in their taskdef’s classpath. In some additional cases, like this very specific JAXBContext API usage, they might even have to do changes to the task’s code to use the right classloader. Do note that I decided to use this specific API of JAXB only to demonstrate the classloader change that would be needed in the task. Not all tasks that use JAXB would need this change in the task’s code - the build.xml classpath changes are expected. Also note that switching of classloaders shouldn’t be done blindly as it can cause other classloading issues. It should only be done when the specific API call in question has semantics which specify the use of a context classloader.</p>
<p>Some of you would be wondering if Ant itself should be doing a change
where it sets the “right” thread context classloader before invoking the
tasks. It wouldn’t be right for Ant to be doing such a change -
depending on what the custom task does, there could be different answers
to what is the “right” thread context classloader to use and for what
duration. Answers to either of those questions are task specific and as
such should be handled/implemented in the (custom) tasks.</p>Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-14984339493950987442021-05-16T11:17:00.001+05:302021-05-16T11:17:14.313+05:30Special characters in proxy configuration of docker daemon and systemd<p> <br />This post is about some of the struggles I've had while dealing with configuring HTTP(s) proxy for docker daemon process. I note it here for myself as well as others who might run into this issue in future.<br /><br />People familiar with Docker will know that it has a process (called docker daemon) which is responsible for handling requests from a docker client - like the docker CLI or language specific libraries like Python's docker package. This docker daemon process is responsible for handling these requests (for example for a docker image pull) and serving those requests. In that interaction, the docker daemon will communicate with docker registries either hosted internally or available over the Internet. If your system(s) where you have the docker daemon running have a proxy installed, then you will have to configure your docker daemon process to use those proxies.<br /><br />The Docker documentation has a section which explains how to do that <a href="https://docs.docker.com/config/daemon/systemd/#httphttps-proxy">https://docs.docker.com/config/daemon/systemd/#httphttps-proxy</a>. It's pretty straightforward as you see it there. You just configure the HTTP_PROXY and HTTPS_PROXY environment variables to point to the proxy URL.<br /><br />Now imagine your proxy requires a username/password authentication. Configuring this detail too is pretty straightforward - you configure the HTTP_PROXY and HTTPS_PROXY environment variable just like before, but also include the username and password in the URL. For example, if your proxy host was 192.168.10.12 and the user name was "john" and password was "doe", you would configure the environment variable as follows:<br /><br />Environment="HTTP_PROXY=http://john:doe@192.168.10.12:80"<br /><br />in that configuration file noted in the Docker documentation.<br /><br />Things are fine and straightforward so far. However, it gets interesting when the user name (or password) has a special character involved. For example, imagine the username is a Windows style user name where you specify the domain and the user name separated by a "\" (backslash) character. So imagine "john" being in the "dev" domain, so the username for authentication is "dev\john". Using this value literally as follows will not work:<br /><br />Environment="HTTP_PROXY=http://dev\john:doe@192.168.10.12:80"<br /><br />The value provided in HTTP_PROXY is used by docker daemon process and it expects it to be URL encoded. What that means is characters like the "\" (backslash) need to be handled specifically and are expected to be URL encoded. So the URL encoded version of that character is %5C. One would expect that setting that environment variable to include this encoded value would work. So:<br /><br />Environment="HTTP_PROXY=http://dev%5Cjohn:doe@192.168.10.12:80"<br /><br />But no - docker daemon's interaction with the docker registries, which is one of the places where the proxy gets used, kept failing. It wasn't clear why this was failing, however, looking at the logs that get generated in /var/log/messages, this message stood out:<br /><br />Jan 1 04:00:12 localhost systemd[1]: /etc/systemd/system/docker.service.d/http-proxy.conf:2: Failed to resolve unit specifiers in HTTP_PROXY=http://dev%5Cjohn:doe@192.168.10.12:80, ignoring: Invalid slot<br /><br />So clearly the value was being picked up but was being considered invalid and ignored. Thus leading to issues while dealing with the proxy on that system. It wasn't clear why it was considering that value invalid. After all, we had already URL encoded that special character.<br /><br />It took a bit of time before I could spot a hint in that log message. If you look at that log message closely, you will notice that the log message is being logged by "systemd" not by the docker daemon. This is a sign that "systemd" is the one which is considering this value invalid. So how's systemd involved in this? In context of this issue, systemd is the process which manages "services" on your operating system. The docker daemon is just another such service. The file(s) we have been using to configure the HTTP_PROXY environment variable are infact configuration files that systemd parses and manages for the individual services. So clearly, systemd doesn't like this specified value for the HTTP_PROXY environment variable.<br /><br />Reading through the systemd documentation, it became clear why it was having a problem with this value. Turns out for systemd configuration files (like the one we have here), % happens to be a special character and represents something called as a "specifier". So clearly, as noted by that warn message, it's trying to use %5 as a specifier and fails to understand what specifier it is. So we need to add another layer of escaping (although for a different tool - this time systemd) and we have to escape the % character to tell systemd not to interpret it as a specifier. To do that we use the % character, so it now becomes %%5C (as noted in <a href="https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers">https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers</a> %% means use % literal).<br /><br />So that now means, the final value for our HTTP_PROXY environment variable, as configured in the systemd service's configuration file is:<br /><br />Environment="HTTP_PROXY=http://dev%%5Cjohn:doe@192.168.10.12:80"<br /><br />(notice the use of %%)<br /><br />Once this was done and the docker daemon restarted, things started working fine and the docker daemon was able to interact with the docker registries.<br /><br />It's always tricky to get tools/libraries working when special characters are involved. As seen here, it gets even more trickier when multiple tools are involved in using the same value and each one has a different set of special characters.<br /><br />I hope this post helps those who run into similar issues with docker daemon or systemd configurations in general.</p>Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-49162323263940553482021-05-16T08:54:00.001+05:302021-05-16T09:41:14.060+05:30Apache Ant 1.10.10 released - Better test result summary from junitlauncher task<p>Apache Ant 1.10.10 got released around a month back. Among the usual bug fixes, we added a new enhancement for the "junitlauncher" task.<br /><br />For those of you who haven't used or know about "junitlauncher" task, it's a new task we introduced a few years back to allow projects using Ant, to be able to use the new JUnit5 testing framework. The previous (and still supported) "junit" task is meant to be used only if you want to continue using just JUnit4. If you plan to use JUnit5 (which also supports JUnit4 style testcases), then you will have to use the "junitlauncher" task.<br /><br />This "junitlauncher" task has been around for a few years now and some users have reported that its "printSummary" feature isn't of much use. People familiar with the "junit" task will know that when a test gets run, the task prints an instantaneous summary like:<br /><br />org.myapp.foo.bar.SimpleTest<br />Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 sec<br /><br />This is useful to see a quick summary of the tests being run.<br /><br />The "junitlauncher" has a "printSummary" attribute which until Ant 1.10.10 version used to print a summary <b>after all the tests had been executed</b>. Furthermore, the printed summary was a summary that the JUnit5 framework generates by default, something like:<br /><br />[junitlauncher] <br />[junitlauncher] Test run finished after 5103 ms<br />[junitlauncher] [ 2 containers found ]<br />[junitlauncher] [ 0 containers skipped ]<br />[junitlauncher] [ 2 containers started ]<br />[junitlauncher] [ 0 containers aborted ]<br />[junitlauncher] [ 2 containers successful ]<br />[junitlauncher] [ 0 containers failed ]<br />[junitlauncher] [ 1 tests found ]<br />[junitlauncher] [ 0 tests skipped ]<br />[junitlauncher] [ 1 tests started ]<br />[junitlauncher] [ 0 tests aborted ]<br />[junitlauncher] [ 1 tests successful ]<br />[junitlauncher] [ 0 tests failed ]<br /><br />As you can see, summary of this form isn't really useful. So some of the Ant users requested (<a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=64836">https://bz.apache.org/bugzilla/show_bug.cgi?id=64836</a>) this to be improved to provide a summary which resembled what we have with the "junit" task.<br /><br />This Ant 1.10.10 release now consists that enhancement. When you use "printSummary=true" on the "junitlauncher" task, it will now print a more useful and immediate summary like the "junit" task does:</p><p></p><p>Running org.myapp.foo.bar.SimpleTest<br />Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 sec<br /><br /><br />As usual, the release is available for download at the Ant downloads page <a href="https://ant.apache.org/bindownload.cgi">https://ant.apache.org/bindownload.cgi</a>. Please give this a try and if you have any suggestion or feedback on this release, please get in touch with us on our mailing lists <a href="https://ant.apache.org/mail.html">https://ant.apache.org/mail.html</a> or our issue tracker <a href="https://ant.apache.org/bugs.html">https://ant.apache.org/bugs.html</a>.</p><p> </p>Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-33129331296623796252019-10-26T10:09:00.000+05:302019-10-26T10:09:36.994+05:30Apache Ivy 2.5.0 released<div dir="ltr" style="text-align: left;" trbidi="on">
This week, we released 2.5.0 version of <a href="https://ant.apache.org/ivy/">Apache Ivy</a>. Apache Ivy is a build dependency manager that is integrated with the Apache Ant build tool. The download is available as usual at <a href="https://ant.apache.org/ivy/download.cgi">https://ant.apache.org/ivy/download.cgi</a>.<br /><br />This 2.5.0 version comes after a long gap in releases of Ivy. 2.4.0 was released way back on December 26 2014. After that, the project has seen slowness in development activities. However, with help from the some community members, especially <a href="https://github.com/hibnico">Nicolas Lalevée</a>, back in around 2017, we had some bug fixes and enhancements done. On April 19 2018, we released 2.5.0-rc1. We called it a "rc1" because it was a long time since we had done a project release and wanted users to be aware that there might be some unexpected issues.<br /><br />2.5.0-rc1 saw some community members using this version and reporting back some bugs that they ran into. We have been able to fix them during this past year and it was now finally time to release it as 2.5.0. We expect the Ivy community to start using this version in favour of older releases and report back any issues that they run into either at <a href="https://issues.apache.org/jira/browse/IVY">https://issues.apache.org/jira/browse/IVY</a> or in our Ivy user mailing list <a href="https://ant.apache.org/mail.html">https://ant.apache.org/mail.html</a><br />
<br />
Users migrating from previous versions of Ivy are recommended to use a fresh/clean Ivy local cache to avoid certain issues with cached Ivy metadata that might have been introduced in a previous version (2.5.0-rc1) of Ivy. <br /><br />The complete list of changes (since 2.4.0) that are part of this release is available at <a href="https://ant.apache.org/ivy/history/2.5.0/release-notes.html">https://ant.apache.org/ivy/history/2.5.0/release-notes.html</a>.<br /><br />Going forward, the goal is to fix any bugs that are reported and introduce certain enhancements that will help improve the usage of the tool.<br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-35318268870940712352019-09-06T17:59:00.001+05:302019-09-06T17:59:29.288+05:30Ant 1.10.7 released - Ability to include/exclude JUnit 5 "tags" during test execution<div dir="ltr" style="text-align: left;" trbidi="on">
1.10.7 version of Ant has just been released yesterday. This release consists mostly bug fixes and some minor enhancements. The downloads are as usual available at <a href="https://ant.apache.org/bindownload.cgi">https://ant.apache.org/bindownload.cgi</a><br /><br />Notable among these bug fixes is a fix to a regression that happened in our 1.10.6 release. In that 1.10.6 release, we accidentally broke compatibility against Java 8. Ant 1.10.x releases are supposed to support Java runtimes starting from Java 8. However, during our previous release, our use of javac compilation attributes caused us to generate a binary which in some cases would run into issues when run against Java 8. This issue has now been fixed in this 1.10.7 release. More details about the regression are available in the bugzilla issue here <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=63457">https://bz.apache.org/bugzilla/show_bug.cgi?id=63457</a>.<br /><br />Among the enhancements that have made it into this newer release, includes an enhancement to the junitlauncher task. The junitlauncher task is meant for running JUnit 5 framework based test cases. In this 1.10.7 release of Ant, thanks to a contribution from Matthias Gutheil (<a href="https://github.com/MatthiasGutheil">https://github.com/MatthiasGutheil</a>), this task now allows you to include or exclude JUnit 5 "tags" from a particular execution of tests. New attributes "includeTags" and "excludeTags" have been introduced to support selecting the relevant tags for execution. The junitlauncher task manual <a href="https://ant.apache.org/manual/Tasks/junitlauncher.html">https://ant.apache.org/manual/Tasks/junitlauncher.html</a> has the complete details.<br /><br />As usual, any suggestions, feedback or questions can be raised in our user mailing list <a href="https://ant.apache.org/mail.html">https://ant.apache.org/mail.html</a>.</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-32948569697621845522019-05-11T17:14:00.000+05:302019-05-11T17:14:31.147+05:30Apache Ant 1.10.6 released - fork mode for junitlauncher and new jmod and link tasks<div dir="ltr" style="text-align: left;" trbidi="on">
Apache Ant 1.10.6 has been released this week. This release contains numerous bug fixes as well as some very exciting new features. The complete release notes is available <a href="https://dist.apache.org/repos/dist/release/ant/RELEASE-NOTES-1.10.6.html">here</a> and the downloads itself are available <a href="https://ant.apache.org/bindownload.cgi">here</a>. In this article, I will go over some of the new features that have made it into this release.<br />
<br />
<h2 style="text-align: left;">
Running JUnit5 tests in a forked JVM, using junitlauncher task</h2>
<br />
A while back, Ant 1.10.x introduced support for JUnit5 tests to be launched using the new "junitlauncher" task. Given the nature of changes between JUnit 4.x and JUnit 5, the amount of support introduced in the new "junitlauncher" task was minimal. Based on user feedback about this task, this task has now been enhanced to support "fork" mode. This was one of the most asked for enhancement, in this task. The "fork" mode support in this task now allows users to configure this task to launch the tests in a forked JVM instead of running these tests within the same JVM as the one, the build is currently running in. Fork mode allows much more control over how these tests execute (things like setting up additional JVM arguments just for these tests or even system properties). The complete details of how to use fork mode in this task, is available in the <a href="https://ant.apache.org/manual/Tasks/junitlauncher.html#fork">manual for this task</a>. Here's a very basic minimal example of one such usage:<br />
<br />
<pre><target name="test-basic-fork">
<junitlauncher>
<!-- Imagine test.classpath points to a previously configured path -->
<classpath refid="test.classpath"/>
<test name="org.example.myapp.SampleTest" outputdir="${output.dir}">
<fork dir="${basedir}">
<sysproperty key="myapp-system-property" value="hello world!"/>
</fork>
</test>
</junitlauncher>
</target></pre>
<br />
<br />
The example above, sets up "junitlauncher" task to launch a test class named "org.example.myapp.SampleTest" in a forked JVM. The "fork" element in the example above is configured to setup a Java system property named "myapp-system-property" with a value of "hello world!". When the test executes, this Java system property will be made available to this test or any other class being executed in that forked JVM. More advanced ability of the "fork" element is explained in the manual linked previously.<br />
<br />
<h2 style="text-align: left;">
New jmod and link tasks for Java 9+ tools</h2>
<br />
Java 9 shipped with a <a href="https://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUID-527735CF-44E1-4144-919B-E7D7CC9CDD4D">new modular ecosystem</a>. This also brought in new tools to create and manage the Java modules. In this release of Ant 1.10.6, we introduce new tasks - "jmod" and "link", which can be used to create Java modules and then assemble them to create custom JVM runtime images. More details about these tasks can be found in their manuals <a href="https://ant.apache.org/manual/Tasks/jmod.html">here</a> and <a href="https://ant.apache.org/manual/Tasks/link.html">here</a>. A big thanks to <a href="https://github.com/craigpell">Craig Pell</a> who contributed these valuable tasks. More Java 9+ enhancements are being worked upon in Ant and we plan to make them available in future releases.<br />
<br />
Please do download this new version of Ant and provide us feedback, suggestions in our <a href="https://ant.apache.org/mail.html">user mailing list</a>.</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-35740398392544995892018-08-27T10:47:00.000+05:302018-08-27T10:47:09.158+05:30Java 11 release candidate now available - time to try it out<div dir="ltr" style="text-align: left;" trbidi="on">
The Java language development team has just released a release candidate build for Java 11, last week.<br />
<br />
Java 11 release brings in good number of new features as noted at <a href="http://openjdk.java.net/projects/jdk/11/#Features">http://openjdk.java.net/projects/jdk/11/#Features</a>. Personally, the TLS 1.3 and the HTTP client API are of special interest to me. Given the nature of changes in this version, it's important to try out this release candidate to make sure that these changes don't cause regressions or introduce change in semantics or features that your application or framework relies on. So this is a good time to try out this build and provide your feedback to the team.<br />
<br />
The release can be downloaded from <a href="http://jdk.java.net/11/">http://jdk.java.net/11/</a>. Any issues, feedback and suggestions can be provided by following the process noted in the "Feedback" section on that downloads page.<br />
<br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-81162631370754234892018-07-16T12:27:00.000+05:302018-07-16T12:27:49.772+05:30Apache Ant 1.9.13 and 1.10.5 released - Supports Java 11 single-file source programs<div dir="ltr" style="text-align: left;" trbidi="on">
We just <a href="https://mail-archives.apache.org/mod_mbox/ant-dev/201807.mbox/%3Cedc3bc47-31ce-4f99-018a-8b4f94ddf304%40apache.org%3E">released 1.9.13 and 1.10.5 versions of Apache Ant</a>. As usual, you can download it from the <a href="https://ant.apache.org/bindownload.cgi">Ant project download page</a>.<br />
<br />
Both these versions are mainly bug fix releases. The 1.10.5 version however has a new enhancement to the "java" task. As I <a href="https://jaitechwriteups.blogspot.com/2018/07/java-11-upcoming-features-launch-single.html">blogged previously</a> - Java 11 introduces a new feature where you can execute single-file Java programs without having to explicitly compile them first. Ant 1.10.5 release now supports this feature through a new "sourcefile" attribute in the "java" task. More about it can be found the <a href="https://ant.apache.org/manual/Tasks/java.html">manual</a> of that task. <br />
<br />
A simple usage example of this new feature of the "java" task is as follows:<br />
<pre><code>
<project default="launch-java" name="Java 11 - launch single-file source program">
<target name="launch-java"
description="Simple example of single-file source program execution,
introduced in Java 11">
<!-- Make sure Java 11 version is being used -->
<condition property="java11">
<javaversion atleast="11"/>
</condition>
<fail unless="java11">Java 11 runtime version is necessary to run this example</fail>
<mkdir dir="${basedir}/javasource"/>
<!-- Write out simple Java code into a file -->
<echo file="${basedir}/javasource/HelloWorld.java">
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.BufferedWriter;
public class HelloWorld {
public static void main(String[] args) throws Exception {
System.out.println("Hello world, " + args[0] + "!");
}
}
</echo>
<!-- launch the Java source file, using the "sourcefile" attribute -->
<java sourcefile="${basedir}/javasource/HelloWorld.java" fork="true" failonerror="true" logerror="true">
<arg value="Java 11"/>
</java>
</target>
</project>
</code></pre>
<br />
As you'll notice, the build file uses the "java" task to set the "sourcefile" attribute to point to a Java source file. The rest of the usage details of the "java" task, including passing arguments to the program, continue to remain the same as before.<br />
<br />
When you run "ant" on this build file, you should see the following output:<br />
<pre><code>
[java] Hello world, Java 11!
</code></pre>
Of course, you will need to use a Java 11 binary to run this against. You can get the early accessible Java 11 binary from <a href="http://jdk.java.net/11/">here</a>.<br />
<br />
<br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-68120251699189813642018-07-13T18:30:00.002+05:302018-07-13T19:01:25.661+05:30Java 11 upcoming features - Launch Single-File source programs<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
Java 11 is nearing completion and it's entered the <a href="http://openjdk.java.net/projects/jdk/11/#Schedule">rampdown phase</a>. It almost feels like a few weeks back that Java 9 was released and here we are, within a few months of Java 11 being released. Given the new release process and timelines for Java, this will become a common thing. Whether that's a good thing or not, we'll keep it aside.<br />
<br />
The changes coming in Java 11 are listed <a href="http://openjdk.java.net/projects/jdk/11/#Features">here</a>. These are some nice enhancements and features coming in this release. Two of them that I'm really excited about are:<br />
<br />
- HTTP client (standard) <a href="http://openjdk.java.net/jeps/321">http://openjdk.java.net/jeps/321</a> which will bring in HTTP client APIs as part of the Java language.<br />
- Launch Single-File Source-Code Programs <a href="http://openjdk.java.net/jeps/330">http://openjdk.java.net/jeps/330</a><br />
<br />
In this article, I will go through the "Launch Single-File Source-Code Programs" feature. What this enhancement proposes to accomplish is to make it easy for running Java code which consists of a single file with the "main()" method in it. <br />
<br />
Imagine you have a simple HelloWorld program as follows in a file HelloWorld.java under org/myapp directory:<br />
<br />
<pre><code>
package org.myapp;
public class HelloWorld {
public static void main(String[] args) throws Exception {
System.out.println("Hello World!");
}
}</code></pre>
</div>
<br />
<br />
Right now, without the proposed feature, in order to run this program, the user has to first compile it using javac command:<br />
<br />
<pre><code>
javac org/myapp/HelloWorld.java
</code></pre>
</div>
Once that succesfully compiles, you then run the java command to execute the program:<br />
<br />
<pre><code>
java org.myapp.HelloWorld
</code></pre>
<br />
So it's a 2 step process. It looks trivial even for beginners, but it can still be made simpler not just for beginners but even developers who regularly work with Java.<br />
<br />
Once Java 11 gets released (or if you want to try it now, you can get the early access builds from <a href="http://jdk.java.net/11/">http://jdk.java.net/11/</a>) we can run the above program as follows (as a single command):<br />
<br />
<pre><code>
java org/myapp/HelloWorld.java
</code></pre>
<br />
Notice the difference here:<br />
1. one, we no longer use the javac command to explicitly compile the source<br />
2. The java command is now passed the path to the source file (org/myapp/HelloWorld.java) instead previously where we used to pass it the fully-qualified classname. <br />
<br />
This difference is minor but important, since the java command now "understands" that it now has to internally do whatever it's necessary (like compiling the source) when it's passed a file path whose file name ends with the .java extension. Of course, such a file is expected to contain regular/valid Java code with a top level class exposing the "public static void main(String[])" method.<br />
<br />
Furthermore, just like your regular Java programs you can continue to pass application specific arguments to the program as before. For example, for a calculator program which looks below, in a org/myapp/Calculator.java file:<br />
<br />
<pre><code>
package org.myapp;
public class Calculator {
public static void main(final String[] args) throws Exception {
final int sum = Integer.parseInt(args[0]) + Integer.parseInt(args[1]);
System.out.println(args[0] + " + " + args[1] + " = " + sum);
}
}
</code></pre>
<br />
you can pass the program arguments as follows:<br />
<br />
<pre><code>
java org/myapp/Calculator.java 2 4
</code></pre>
<br />
where 2 and 4 are passed as the program arguments and you would see the output as follows:<br />
<pre><code>
2 + 4 = 6
</code></pre>
This feature also adds support for <a href="https://en.wikipedia.org/wiki/Shebang_(Unix)">"shebang" files</a>, files which are expected to hava valid Java code plus a "shebang". Personally, I'm not too fond of this specific aspect of the feature. However, the good thing is, the <a href="http://mail.openjdk.java.net/pipermail/jdk-dev/2018-May/001220.html">JDK team took feedback from the community</a> and made this additional aspect of a feature, non-intrusive (for tools/commands which already deal with Java source files) and something that some of us can ignore if we don't want to use it. The details of when/how to use the "shebang" files for this feature are explained in the linked <a href="http://openjdk.java.net/jeps/330">JEP-330</a>.<br />
<br />
So far, although Java 11 hasn't been released, I have been using the early access builds and extensively using this feature for some of my regular work which sometimes involves coming up with short programs that help reproduce an issue. I usually don't use IDEs for things like these, so it's been a welcome enhancement to be able to issue a single command against such files and have them executed. <br />
<br />
<br />
<br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-73862082640067147892018-05-14T10:50:00.000+05:302018-05-14T12:05:46.673+05:30Apache Ivy 2.5.0-rc1 released - Now allows timeouts on resolvers<div dir="ltr" style="text-align: left;" trbidi="on">
A few weeks back, we released the 2.5.0-rc1 version of Apache Ivy. Apache Ivy is a dependency management build tool, which usually is a used in combination with Apache Ant. The download is available on the <a href="http://ant.apache.org/ivy/download.cgi">project download page</a><br />
<br />
This release is significant since the last release of Apache Ivy was way back in December 2014. So it's more than 3 years since the last official years. During these past few years, the project development stalled for a while. I use Apache Ivy in some of our projects and have been pretty happy with the tool. It's never a good sign to see one of your heavily used tools to be no longer under development or even have bug fixes. So a year or so back, I decided to contribute some bug fixes to the project. Over time, the project management committee invited me to be part of the team.<br />
<br />
We decided that the first obvious, immediate goal would be to revive the project and do a formal release with bug fixes. This 2.5.0-rc1 is the result of that effort which started almost a year back. A lot of changes have gone into this release and also a good number of enhancements have made it into this release. This release has been a result of contributions from various different members from the community. The complete list of release notes is available <a href="https://ant.apache.org/ivy/history/2.5.0-rc1/release-notes.html">here</a><br />
<br />
We intentionally named this release 2.5.0-rc1 (release candidate) since it's been a while we have done an official release and also given the nature of changes. Please give this release a try and let us know how it goes. Depending on the feedback, we will either release 2.5.0 or 2.5.0-rc2. As usual, some of us from the development team keep an active watch in the ivy user mailing <a href="http://ant.apache.org/ivy/mailing-lists.html">list</a>. So if you have any feedback or questions, please do drop a mail to us, there.<br />
<br />
Now coming to one of the enhancements in this release - there's been more than one. One of the issues I personally had was if the repository, backing a dependency resolver configured for Ivy, had some connectivity issues, the build would just hang. This was due to the inability to specify proper timeouts for communicating with these repositories through the resolver. As of this release, Ivy now allows you to configure timeouts for resolvers. This is done through the use of (the new) timeout-constraints element in your Ivy settings file. More details about it are <a href="https://ant.apache.org/ivy/history/2.5.0-rc1/settings/timeout-constraints.html">here</a>. Imagine you have a url resolver which points to some URL. The URL resolver would typically look something like:<br />
<br />
<pre><code><url name="foo">
<ivy pattern=.../>
<artifact pattern=.../>
<artifact pattern=.../>
</url></code></pre>
<br />
<br />
<br />
Let's now try and configure a connection timeout for this resolver. The first thing you would do is define a named timeout-constraint, like below:<br />
<br />
<pre><code><timeout-constraints>
<timeout-constraint name="timeout-1" connectionTimeout="60000" />
</timeout-constraints></code></pre>
<br />
<br />
The value for the name attribute can be anything of your choice. The value for connectionTimeout attribute is represented as a timeout in milli seconds. In the above example, we configure the "timeout-1" timeout-constraint to be of 1 minute. You can even specify a readTimeout which too is in milli seconds. More about this element can be found in the <a href="https://ant.apache.org/ivy/history/2.5.0-rc1/settings/timeout-constraint.html">documentation</a>.<br />
<br />
As you might notice, we have just defined a timeout-constraint here but haven't yet instructed Ivy to use this constraint for some resolver. We do that in the next step, where we set the "timeoutConstraint" attribute on the URL resolver that we had seen before:<br />
<br />
<br />
<pre><code><url name="foo" timeoutConstraint="timeout-1">
<ivy pattern=.../>
<artifact pattern=.../>
<artifact pattern=.../>
</url></code></pre>
<br />
<br />
Notice that the value of "timeoutConstraint" attribute now points to "timeout-1" which we defined to have a 1 minute connection timeout. With this, when this URL resolver gets chosen by Ivy for dependency resolution, this connection timeout will be enforced and if the connections fails to be established within this timeout, then an exception gets thrown instead of the build hanging forever.<br />
<br />
Although the example uses a URL resolver to setup the timeout constraint, this feature is available for all resolvers that are shipped out of the box by Ivy. So you can even use it with the ibiblio resolver (which communicates with Maven central) too.<br />
<br />
<br />
Like I noted earlier, please do give this release a try and let us know how it goes.<br />
<br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-75924044268686235082018-05-11T20:48:00.002+05:302018-05-11T20:48:49.214+05:30VMWare vijava - The curious case of "incorrect user name or password" exception<div dir="ltr" style="text-align: left;" trbidi="on">
In one of the projects I have been involved in, we use <a href="http://www.yavijava.com/">yavijava</a> (which is a fork of <a href="https://sourceforge.net/p/vijava/">vijava</a>) library to interact with vCenter which hosts our VMs. vCenter exposes various APIs through their webservice endpoints which are invoked through HTTP(s). The yavijava library has necessary hooks which allows developers to use a HTTP client library of their choice on the client side to handle invocations to the vCenter.<br /><br />In our integration, we plugged in the <a href="https://hc.apache.org/httpcomponents-client-ga/">Apache HTTP client library</a>, so that the yavijava invocations internally end up using this HTTP library for interaction. Things mostly worked fine and we were able to invoke the vCenter APIs. I say mostly, because every once in a while we kept seeing exceptions like:<br /><br />InvalidLogin : Cannot complete login due to an incorrect user name or password.<br /><br />This was puzzling since we were absolutely sure that the user name and password we use to interact with the vCenter was correct. Especially since all of the previous calls were going through fine, before we started seeing these exceptions.<br /><br />The exception stacktrace didn't include anything more useful and neither did any other logs. So the only option that I was left with was to go look into the vCenter (server side) event logs to see if I can find something. Luckily, I had access to a setup which had a vSphere client, which I then used to connect to the vCenter. The vSphere client allows you to view the event logs that were generated on the vCenter.<br /><br />Taking a look at the logs, showed something interesting and useful. Every time, we had run into this "incorrect user name or password" exception on the client side, there was a corresponding event log on the vCenter server side at INFO level which stated "user cannot logon since user is already logged on". That event log was a good enough hint to give an idea of what might be happening.<br /><br />Based on that hint, the theory I could form was, somehow for an incoming (login) request, vCenter server side notices something on the request which gives it an impression that the user is already logged in. Given my background with Java EE technologies, the immediate obvious thing that came to mind was that the request was being attached with a "Cookie" which the server side uses to associate requests against a particular session. Since I had access to the client side code which was issuing this login request, I was absolutely sure that the request did not have any explicitly set Cookie header. So that raised the question, who/where the cookie was being associated with the request. The only place that can happen, if it's not part of the request we issued, is within the HTTP client library. Reading up the documentation of Apache HTTP client library confirmed the theory that the HTTP client was automagically associating a (previously generated) Cookie against the request. <br /><br />More specifically, the HTTP client library uses pooled connections. When a request is made, one of the pooled connections (if any) gets used. What was happening in this particular case was that, a previous login would pick up connection C1 and the login would succeed. The response returned from vCenter for that login request would include a Cookie set in the response header. The Apache HTTP client library was then keeping track of this Cookie against the connection that was used. Now when a subsequent login request arrived, if the same pooled connection C1 gets used for this request, then the HTTP client library was attaching the Cookie that it kept track against this connection C1, to this new request. As a result, vCenter server side ends up seeing that the incoming login request has a Cookie associated with it, which says that there's already a logged in session for that request. Hence, that INFO message in the event logs of vCenter. Of course, the error returned isn't that informative and in fact a bit misleading since it says the username/password is incorrect.<br /><br />Now that we know what's going on, the solution was pretty straightforward. Apache HTTP client library allows you to configure Cookie policy management. Since in our case, we wanted to handle setting the Cookie explicitly on the request, we decided to go with the "ignoreCookies" policy which can be configured on the HTTP client. More about this can be found in the <a href="https://hc.apache.org/httpclient-3.x/cookies.html">HTTP client library documentation</a> (see the "Manual Handling of Cookies" section). Once we did this change, we no longer saw this exception anymore.<br /><br /><br />There isn't much information about this issue anywhere that I could find. The closest I could find was this forum thread <a href="https://sourceforge.net/p/vijava/discussion/826592/thread/91550e2a/">https://sourceforge.net/p/vijava/discussion/826592/thread/91550e2a/</a>. It didn't have a conclusive solution, but it does appear that it's the same issue that the user there was running into (almost 7 years back!)<br /><br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-6904737586727848572018-03-28T14:51:00.001+05:302018-03-28T14:51:49.920+05:30Ant 1.10.3 released with JUnit 5 support<div dir="ltr" style="text-align: left;" trbidi="on">
We just <a href="https://www.mail-archive.com/user@ant.apache.org/msg42755.html">released</a> 1.9.11 and 1.10.3 versions of Ant today. The downloads are available on the <a href="https://ant.apache.org/bindownload.cgi">Ant project's download page</a>. Both these releases are mainly bug fix releases, especially the 1.9.11 version. The 1.10.3 release is an important one for a couple of reasons. The previous 1.10.2 release, unintentionally introduced a bunch of changes which caused regressions in various places in Ant tasks. These have now been reverted or fixed in this new 1.10.3 version. <br /><br />In addition to these fixes, this 1.10.3 version of Ant introduces a new <a href="https://ant.apache.org/manual/Tasks/junitlauncher.html">junitlauncher</a> task. A while back, the JUnit team has released <a href="https://junit.org/junit5/">JUnit 5.x version</a>. This version is a major change from previous JUnit 3.x & 4.x versions, both in terms of how tests are written and how they are executed. JUnit 5 introduces a separation between test launching and test identification and execution. What that means is, for build tools like Ant, there's now a clear API exposed by JUnit 5 which is solely meant to deal with how tests are launched. Imagine something along the lines of "launch test execution for classes within this directory". Although Ant's <a href="https://ant.apache.org/manual/Tasks/junit.html">junit</a> task already supported such construct, the way we used to launch those tests was very specific to Ant's own implementation and was getting more and more complex. With the introduction of this new API within the JUnit 5 library, it's much more easier and consistent now to launch these tests.<br /><br />JUnit 5, further introduces the concept of test engines. Test engines are responsible for "identifying" which classes are actually tests and what semantics to apply to those tests. JUnit 5 by default comes with a "vintage" engine which identifies and runs JUnit 4.x style tests and a "jupiter" engine which identifies and runs JUnit 5.x API based tests. <br /><br />The "junitlauncher" task in Ant introduces a way to let the build specify which classes to choose for test launching. The goal of this task is to just launch the test execution and let the JUnit 5 framework identify and run the tests. The current implementation shipped in Ant 1.10.3, is the basic minimal for this task. We plan to add more features as we go along and as we get feedback on it. Especially, this new task doesn't currently support executing these tasks in a separate forked JVM, but we do plan to add that in a subsequent release. <br /><br />The junit task which has been shipped in Ant since long time back, will continue to exist and can be used for executing JUnit 3.x or JUnit 4.x tests. However, for JUnit 5 support, the junitlauncher task is what will be supported in Ant.<br /><br />More details about this new task can be found in the <a href="https://ant.apache.org/manual/Tasks/junitlauncher.html">junitlauncher's task manual</a>. Please give it a try and report any bugs or feedback to our <a href="https://ant.apache.org/mail.html">user mailing list</a>.</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com2tag:blogger.com,1999:blog-30587633.post-82909085297875685092018-02-20T10:15:00.000+05:302018-02-20T11:03:08.505+05:30WildFly 12.0.0.Beta1 tagged and available<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="http://wildfly.org/">WildFly</a> 12.0.0.Beta1 has been tagged and has been (I think) officially released. The announcement happened a few days back in the <a href="http://lists.jboss.org/pipermail/wildfly-dev/2018-February/006354.html">dev mailing list</a> and unlike the previous releases, this time the release binaries seem to be only available in Maven repository and can be obtained from here - <a href="https://repo1.maven.org/maven2/org/wildfly/wildfly-dist/12.0.0.Beta1/">WildFly 12.0.0.Beta1 distribution</a> (the .tar.gz and .zip are the relevant ones). The list of changes for this release can be found in the <a href="https://issues.jboss.org/secure/ReleaseNote.jspa?projectId=12313721&version=12334071">JIRA release notes</a>.<br />
<br />
As you'll notice in the release notes, there's some initial support for EE 8 specs, including Servlet 4.0 among others. Plus there's also numerous bug fixes in this release from the previous 11.0.0.Final version which was released some months back. As usual, please give this version a try and if there are any issues or feedback that you would like to report, please start a discussion in the <a href="https://developer.jboss.org/en/wildfly">WildFly user forum</a> <br />
<br />
If you haven't been following the WildFly dev mailing list, there's also a discussion which outlines the release plans for WildFly going forward. You can find that discussion <a href="http://lists.jboss.org/pipermail/wildfly-dev/2017-December/006250.html">here</a><br />
<br />
Finally, there's been major changes to Java EE processes and committee and even the name, over the past year. If you haven't been following those changes, then you can read through <a href="https://developer.jboss.org/blogs/mark.little">Mark Little's recent blogs</a> including the most recent ones which talk about the <a href="https://developer.jboss.org/blogs/mark.little/2018/02/08/new-java-ee-brand-name">new brand name for Java EE</a> and setting up of the <a href="https://developer.jboss.org/blogs/mark.little/2018/02/08/eenext-working-group">working group</a>.<br />
<br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com1tag:blogger.com,1999:blog-30587633.post-50082480019953527472018-02-07T17:32:00.000+05:302018-02-07T17:43:53.095+05:30Apache Ant new versions (1.9.10 and 1.10.2) released<div dir="ltr" style="text-align: left;" trbidi="on">
This past year has been pretty hectic, so I haven't had a chance to update this blog more often. <br />
<br />
In my limited spare time last year, I started contributing to <a href="https://ant.apache.org/">Apache Ant</a> project. Although Ant probably isn't as widely used as some years back, it still is used in many projects, as the build tool. Some of the products I'm involved in, does use Ant and that motivated me to contribute to some bug fixes in Ant. After a period of time, last year, I was invited to be a committer and a few weeks back, to be part of the Ant project management committee (PMC), which I consider a honour.<br />
<br />
Just today, we released a couple of new versions of Ant - 1.9.10 and 1.10.2. These are essentially bug fix releases but do contain some new enhancements. The complete release notes, for each of these releases, can be found <a href="https://www.apache.org/dist/ant/RELEASE-NOTES-1.9.10.html">here</a> and <a href="https://www.apache.org/dist/ant/RELEASE-NOTES-1.10.2.html">here</a>. <br />
<br />
The downloads are available from the <a href="https://ant.apache.org/bindownload.cgi">project's download page</a> and the full announcement, in the mailing list, can be read <a href="https://www.mail-archive.com/user@ant.apache.org/msg42735.html">here</a><br />
<br />
If you have any issues/suggestions/feedback about the project, feel free to report it in the user mailing list which is listed on <a href="https://ant.apache.org/mail.html">this page</a>.<br />
<br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-62493509174900030222017-10-30T13:14:00.000+05:302017-11-11T13:00:05.830+05:30Kafka with OpenSSL<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<br />
<b>UPDATE: </b>This article has been updated on Nov 11th 2017 with the following details:<br />
<br />
<ul style="text-align: left;">
<li>Updated to note that the issues linked in this article, related to WildFly OpenSSL, have all been fixed and the WildFly OpenSSL master branch now has the version which contains these fixes. The numbers that you see in this article, include those fixes.</li>
<li>Updated to add a <a href="https://jaitechwriteups.blogspot.com/2017/10/kafka-with-openssl.html#java9-perf-numbers">section</a> which lists the producer and consumer numbers when Java 9 runtime is used, for both the SSL engine shipped by JRE as well as the OpenSSL one. </li>
<li>Updated to note that the version of Kafka used is 1.0.0 (which was released recently)</li>
</ul>
<br />
<br />
In one of the <a href="https://macaw.io/" target="_blank">products</a> I'm involved in, we use <a href="https://kafka.apache.org/">Kafka</a> extensively. We have been using Kafka since 0.8.x days. If you follow the Kafka development, you might be aware that they are about to release their 1.0.0 version very soon. Kafka allows you to use SSL for both producing and consuming messages. Both the Kafka broker and the client libraries are configurable to specify the necessary SSL characteristics. Within our own product, we use Java client side libraries for consuming and producing messages. Their Java client side libraries have gone through a phase of API changes a while back in one of their releases. We use their "new" Java client APIs.<br />
<br />
We started experimenting with using SSL for producing and consuming messages in Kafka, more than a year back. Our initial experiments showed that switching to SSL instead of using plaintext had a noticeable impact on performance. Given the way we use Kafka within our product, even some consistent (milli seconds) degradation in latency is almost noticeable. It's a acceptable and a known fact that you do incur certain performance impact when you are using SSL. However, the amount of degradation was to a point that we decided not to switch to SSL for a while. There have been discussions and JIRAs like <a href="https://issues.apache.org/jira/browse/KAFKA-2431">this one</a> where such impact has been tracked. Things have definitely improved since that JIRA (we are on 0.10.x release these days), but we didn't have enough time to get some numbers with SSL enabled within our environment.<br />
<br />
<h2 style="text-align: left;">
A small detour</h2>
With that background, let me take a small detour from Kafka discussions. I also follow <a href="http://wildfly.org/">WildFly</a> and various other projects in its ecosystem. Very recently, WildFly added support for <a href="http://wildfly.org/news/2017/10/06/OpenSSL-Support-In-Wildfly/">using OpenSSL as a SSL provider</a> instead of the one that's shipped as part of the JRE. As part of that support, they use <a href="https://github.com/wildfly/wildfly-openssl/">WildFly OpenSSL</a> project, which provides Java bindings (the implementation of interfaces necessary to use it as a SSLEngine in Java) for OpenSSL. Given that Java has a plugable mechanism for SSL providers and that fact that Kafka allows you to configure such SSL configurations, the WildFly OpenSSL project interested me.<br />
<br />
<h2 style="text-align: left;">
Using Kafka with WildFly OpenSSL</h2>
I vaguely remember reading in some discussions that OpenSSL performs better compared to the SSL provider shipped in Java. So I decided to experiment with using WildFly OpenSSL with Kafka and compare it with the SSL provider shipped in Java. My goals of this experiment were pretty much these:<br />
<ul style="text-align: left;">
<li>Use SSL for producing and consuming messages in Kafka</li>
<li>Compare OpenSSL against the SSL provider shipped in Java</li>
<li>Use the default settings that's shipped in Kafka for this performance testing. In fact, Kafka developers encourage you to use the defaults in performance testing as much as possible.</li>
<li>Use the tools shipped within Kafka for testing this performance. Kafka ships both producer and consumer performance testing tool, which is good enough for what we are after. Using their own tools, rules out any issues that I might end up with in the tool that I write for these tests (I did in fact write one of my own, just for the sake of it, but decided to stick with the ones shipped in Kafka since it pretty much ended up being similar both in terms of code and the output it produced)</li>
</ul>
<div style="text-align: left;">
<br />
I would like to note that it <i>wasn't</i> ever a goal for me, in these experiments to compare plain text and SSL numbers. This experiment is solely to see how different SSL providers are performing.</div>
<h2 style="text-align: left;">
Setting up the system for the tests</h2>
<h3 style="text-align: left;">
</h3>
<h3 style="text-align: left;">
Kafka installation</h3>
<div style="text-align: left;">
I decided to use the latest version of Kafka. The latest released version currently is 1.0.0 and I downloaded it from their <a href="http://kafka.apache.org/downloads">downloads</a> page. Kafka installation is straightforward, you just extract the downloaded archive and can straightaway boot it up and start consuming and producing messages. I won't go into any of the installation details of Kafka since that's out of the scope of this installation. I will go into the configurations that I used as we go along.</div>
<h3 style="text-align: left;">
WildFly OpenSSL installation</h3>
<div style="text-align: left;">
I use MacOS for development and will be using this for my tests. In order to use WildFly OpenSSL, I went ahead and cloned the <a href="https://github.com/wildfly/wildfly-openssl/">github repo</a>. Ran into a build issue, but it was a straightforward fix for which there's now a <a href="https://github.com/wildfly/wildfly-openssl/pull/25">pull request with a fix</a>. I then setup Kafka to use WildFly OpenSSL and started experimenting. This set of experiments was just to make sure that it's usable without impacting any functionality. I did run into an issue which turned out to be an issue in WildFly OpenSSL which is now reported <a href="https://github.com/wildfly/wildfly-openssl/issues/26">here</a>. This issue has now been fixed and pushed to the WildFly OpenSSL upstream repo.<br />
<br />
The README of that project already has the necessary instructions to build it, so I won't get into those details.</div>
<h3 style="text-align: left;">
Java installation</h3>
<div style="text-align: left;">
I use the Oracle JRE 1.8 version for these tests:<br />
<br />
<pre><code>
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)</code></pre>
</div>
<h3 style="text-align: left;">
</h3>
<h3 style="text-align: left;">
OpenSSL installation</h3>
<div style="text-align: left;">
In this experiments I'm going to use 1.1 version of OpenSSL. I installed it through homebrew and it's available at /usr/local/opt/openssl@1.1/bin/openssl. The exact version is:<br />
<br />
<pre><code>
/usr/local/opt/openssl@1.1/bin/openssl
OpenSSL> version
OpenSSL 1.1.0f 25 May 2017
</code>
</pre>
</div>
<h3 style="text-align: left;">
Putting it all together</h3>
<div style="text-align: left;">
<br /></div>
<ul style="text-align: left;">
<li>I built my WildFly OpenSSL libraries and copied over the java/target/wildfly-openssl-java-1.0.3.Final-SNAPSHOT.jar and macosx-x86_64/target/wildfly-openssl-macosx-x86_64-1.0.3.Final-SNAPSHOT.jar into the <kafka-install-dir>/libs/ folder. These are the 2 jars that contain the necessary WildFly OpenSSL support (depending on what OS you are on, you might need a different jar).</kafka-install-dir></li>
<li>Given that I was going to use WildFly OpenSSL in multiple different tools which have their own different "main" classes, I decided to write a extremely basic <a href="https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html">Java agent</a> which would just register WildFly OpenSSL as a provider. I then just pass -javaagent:<path-to-my-javaagent-jar> as a JVM option to each of the tools/scripts I use for these tests. The code in my Java agent is pretty straight forward:</path-to-my-javaagent-jar></li>
</ul>
<div style="text-align: left;">
<pre><code>
public class OpenSSLEnabler {
public static void premain(final String agentArgs) throws Exception {
try {
org.wildfly.openssl.OpenSSLProvider.register();
} catch(Exception e) {
System.err.println("Failed to register WildFly OpenSSL provider");
e.printStackTrace();
}
}
}
</code>
</pre>
</div>
<ul style="text-align: left;">
<li>I setup the following as an environment variable to make sure this Java agent is picked up as well as OpenSSL 1.1 is used for these tests (when I enable OpenSSL as the provider):</li>
</ul>
<div style="text-align: left;">
<br />
export KAFKA_OPTS="-javaagent:/opt/installations/kafka/1.0.0.RC4/kafka_2.12-1.0.0/libs/wildfly-openssl-javaagent-1.0.0-SNAPSHOT.jar -Dorg.wildfly.openssl.path=/usr/local/opt/openssl@1.1/lib/"<br />
<br />
Note: The wildfly-openssl-javaagent-1.0.0-SNAPSHOT.jar is the jar containing the Java agent class that I explained above and the -Dorg.wildfly.openssl.path system property is to ensure that WildFly OpenSSL uses this specific OpenSSL installation (when I enable OpenSSL as the provider).</div>
<h3 style="text-align: left;">
Performance tests details</h3>
<div style="text-align: left;">
The first round of testing will be using the SSL provider shipped in Java. We will use the kafka-producer-perf-test.sh and kafka-consumer-perf-test.sh scripts that are shipped by Kafka itself (they are available in the bin directory of your Kafka installation).<br />
<br />
The second round of testing will be using OpenSSL provider backed by WildFly OpenSSL. In these tests too we will use kafka-producer-perf-test.sh and kafka-consumer-perf-test.sh scripts.</div>
<h4 style="text-align: left;">
Kafka Broker and topics</h4>
<div style="text-align: left;">
In my test I'm going to create 3 topics, each with a replication factor of 1 and with partition count 1. The topics will be called kafka-ssl-perf-test-1k, kafka-ssl-perf-test-10k and kafka-ssl-perf-test-500k:<br />
<br />
./kafka-topics.sh --create --topic kafka-ssl-perf-test-1k --partitions=1 --replication-factor=1 --zookeeper=localhost:2181</div>
<div style="text-align: left;">
<br />
./kafka-topics.sh --create --topic kafka-ssl-perf-test-10k --partitions=1 --replication-factor=1 --zookeeper=localhost:2181</div>
<div style="text-align: left;">
<br />
./kafka-topics.sh --create --topic kafka-ssl-perf-test-500k --partitions=1 --replication-factor=1 --zookeeper=localhost:2181</div>
<h4 style="text-align: left;">
Producer tests</h4>
<div style="text-align: left;">
The producer will run with --record-size of 1024, 10240 and 512000 in 3 separate runs. Each run will generate --num-records 10000 with the respective size. Our usage of Kafka typically generates messages of lesser than 10K, so I decided to not stretch the tests for too large messages. In my test, I will use the kafka-ssl-perf-test-1k topic for 1024 sized messages, kafka-ssl-perf-test-10k for 10240 sized messages and kafka-ssl-perf-test-500k for 512000 sized messages. </div>
<h4 style="text-align: left;">
Consumer tests</h4>
<div style="text-align: left;">
The consumer will be consuming (all) 10000 messages of each of these topics, in 3 separate runs. I used `--new-consumer` option for these tests since that's what we use in our application, through the Java client APIs.</div>
<h3 style="text-align: left;">
Java default SSL run</h3>
<div style="text-align: left;">
As noted, by default, Kafka uses the SSL provider shipped in JRE. So it isn't necessary to configure the provider specifically. However, we will configure a few other configurations to enable SSL itself (by default Kafka uses plain text). So the broker configs that I added/changed are these, in $KAFKA_HOME/config/server.properties:<br />
<br />
listeners=PLAINTEXT://localhost:9092,SSL://localhost:9093<br />
ssl.keystore.location=/opt/kafka-experiments/ssl-certs/keystore.jks<br />
ssl.keystore.password=password<br />
ssl.key.password=password<br />
ssl.truststore.location=/opt/kafka-experiments/trust-certs.jks<br />
ssl.truststore.password=password<br />
ssl.protocol=TLSv1.2<br />
<br />
The rest of the configurations are unchanged and the ones default shipped by Kafka. As you see above, the main configurations are enabling SSL and using 9093 as the port for SSL communication and using TLSv1.2 as the SSL protocol.</div>
<h4 style="text-align: left;">
Start Zookeeper and Kafka broker</h4>
<div style="text-align: left;">
cd <kafka-install-dir>/bin/<br />nohup ./zookeeper-server-start.sh ../config/zookeeper.properties &<br />nohup ./kafka-server-start.sh ../config/server.properties &</kafka-install-dir></div>
<h4 style="text-align: left;">
Run the producer perf test script</h4>
<div style="text-align: left;">
We'll pass the following producer configs (through a kafka-jre-ssl-producer.properties) to these runs:<br />
<br />
bootstrap.servers=localhost:9093<br />
security.protocol=SSL<br />
ssl.protocol=TLSv1.2<br />
ssl.truststore.location=/opt/kafka-experiments/trust-certs.jks<br />
ssl.truststore.password=password<br />
<br />
These configurations just enable SSL (and by default uses the JRE shipped SSL provider) with TLSv1.2 as the protocol on 9093 port.</div>
<div style="text-align: left;">
<br /></div>
<h4 style="text-align: left;">
1024 sized message</h4>
<div style="text-align: left;">
./kafka-producer-perf-test.sh --record-size 1024 --num-records 10000 --topic kafka-ssl-perf-test-1k --producer.config ./kafka-jre-ssl-producer.properties --throughput -1 > producer-jre-ssl-1k.txt</div>
<h4 style="text-align: left;">
10240 sized message</h4>
<div style="text-align: left;">
./kafka-producer-perf-test.sh --record-size 10240 --num-records 10000 --topic kafka-ssl-perf-test-10k --producer.config ./kafka-jre-ssl-producer.properties --throughput -1 > producer-jre-ssl-10k.txt</div>
<h4 style="text-align: left;">
512000 sized message</h4>
<div style="text-align: left;">
./kafka-producer-perf-test.sh --record-size 512000 --num-records 10000 --topic kafka-ssl-perf-test-500k --producer.config ./kafka-jre-ssl-producer.properties --throughput -1 > producer-jre-ssl-500k.txt<br />
<br />
<b>Note:</b> I have the performance numbers in a table, later in this blog.</div>
<h4 style="text-align: left;">
Run the consumer perf test script</h4>
<div style="text-align: left;">
We'll pass the following consumer configs (through a kafka-jre-ssl-consumer.properties) to these runs:<br />
<br />
bootstrap.servers=localhost:9093<br />
security.protocol=SSL<br />
ssl.protocol=TLSv1.2<br />
ssl.truststore.location=/opt/kafka-experiments/trust-certs.jks<br />
ssl.truststore.password=password<br />
<br />
Just like for the producer, these configurations enable SSL and use the default JRE provider with TLSv1.2. We will be consuming of 3 separate topics, each having messages of different sizes that we produced above. Each run uses a different and unique consumer group id.</div>
<h4 style="text-align: left;">
1024 sized message</h4>
<div style="text-align: left;">
./kafka-consumer-perf-test.sh --topic kafka-ssl-perf-test-1k --new-consumer --messages 10000 --broker-list localhost:9093 --consumer.config ./kafka-jre-ssl-consumer.properties --group jre-ssl-1k > consumer-jre-ssl-1k.txt</div>
<h4 style="text-align: left;">
10240 sized message</h4>
<div style="text-align: left;">
./kafka-consumer-perf-test.sh --topic kafka-ssl-perf-test-10k --new-consumer --messages 10000 --broker-list localhost:9093 --consumer.config ./kafka-jre-ssl-consumer.properties --group jre-ssl-10k > consumer-jre-ssl-10k.txt</div>
<h4 style="text-align: left;">
512000 sized message</h4>
<div style="text-align: left;">
./kafka-consumer-perf-test.sh --topic kafka-ssl-perf-test-500k --new-consumer --messages 10000 --broker-list localhost:9093 --consumer.config ./kafka-jre-ssl-consumer.properties --group jre-ssl-500k > consumer-jre-ssl-500k.txt<br />
<br />
Just like the producer numbers, I've noted these consumer numbers in a section later in this blog.</div>
<h3 style="text-align: left;">
WildFly OpenSSL run</h3>
<div style="text-align: left;">
Now that we are done with the producer and consumer runs with default JRE SSL, we'll now reconfigure the Kafka broker to use OpenSSL as the provider. We won't be doing any other configuration changes to the broker configs and the producer, consumer configs we use for testing. To give this run the similar characteristics as that of our previous run, I deleted the Kafka and Zookeeper directories that store the Kafka topics. Essentially, this run is going to be from a clean slate. As noted previously, to enable WildFly OpenSSL, I configured the following environment property:<br />
<br />
export KAFKA_OPTS="-javaagent:/opt/installations/kafka/1.0.0.RC4/kafka_2.12-1.0.0/libs/wildfly-openssl-javaagent-1.0.0-SNAPSHOT.jar -Dorg.wildfly.openssl.path=/usr/local/opt/openssl@1.1/lib/"<br />
<br />
Here's what the relevant broker configs (in server.properties) look like now for OpenSSL:<br />
<br />
listeners=PLAINTEXT://localhost:9092,SSL://localhost:9093<br />
ssl.keystore.location=/opt/kafka-experiments/ssl-certs/keystore.jks<br />
ssl.keystore.password=password<br />
ssl.key.password=password<br />
ssl.truststore.location=/opt/kafka-experiments/trust-certs.jks<br />
ssl.truststore.password=password<br />
ssl.provider=openssl<br />
ssl.protocol=TLSv1.2<br />
<br />
As you'll notice the only additional configuration here is the ssl.provider=openssl.<br />
<br />
We then start zookeeper and the Kafka broker as previously. Remember, we (intentionally) deleted the Kafka directories that held the topics. So we will recreate the necessary topics as we did previously.</div>
<h4 style="text-align: left;">
Run the producer perf test script</h4>
<div style="text-align: left;">
We'll pass the following producer configs (through a kafka-openssl-producer.properties) to these runs:<br />
<br />
bootstrap.servers=localhost:9093<br />
security.protocol=SSL<br />
ssl.protocol=TLSv1.2<br />
ssl.provider=openssl<br />
ssl.truststore.location=/opt/kafka-experiments/trust-certs.jks<br />
ssl.truststore.password=password<br />
<br />
It's the same as what we used in our previous run, except that we use ssl.provider=openssl.</div>
<h4 style="text-align: left;">
1024 sized message</h4>
<div style="text-align: left;">
./kafka-producer-perf-test.sh --record-size 1024 --num-records 10000 --topic kafka-ssl-perf-test-1k --producer.config ./kafka-openssl-producer.properties --throughput -1 > producer-openssl-1k.txt<br />
<br />
<b>Note:</b> You'll see the following log message, which indicates that WildFly OpenSSL is rightly picked up, which then uses the natively installed 1.1.0f version of OpenSSL:<br />
<br />
Oct 29, 2017 8:35:25 PM org.wildfly.openssl.SSL init<br />
INFO: WFOPENSSL0002 OpenSSL Version OpenSSL 1.1.0f 25 May 2017</div>
<h4 style="text-align: left;">
10240 sized message</h4>
<div style="text-align: left;">
./kafka-producer-perf-test.sh --record-size 10240 --num-records 10000 --topic kafka-ssl-perf-test-10k --producer.config ./kafka-openssl-producer.properties --throughput -1 > producer-openssl-10k.txt</div>
<h4 style="text-align: left;">
512000 sized message</h4>
<div style="text-align: left;">
./kafka-producer-perf-test.sh --record-size 512000 --num-records 10000 --topic kafka-ssl-perf-test-500k --producer.config ./kafka-openssl-producer.properties --throughput -1 > producer-openssl-500k.txt</div>
<h4 style="text-align: left;">
Run the consumer perf test script</h4>
<div style="text-align: left;">
We'll pass the following consumer configs (through a kafka-openssl-consumer.properties) to these runs:<br />
<br />
bootstrap.servers=localhost:9093<br />
security.protocol=SSL<br />
ssl.protocol=TLSv1.2<br />
ssl.provider=openssl<br />
ssl.truststore.location=/opt/kafka-experiments/trust-certs.jks<br />
ssl.truststore.password=password<br />
<br />
It's the same as what we used for our consumer run with JRE SSL, except that we set the ssl.provider=openssl in this case.</div>
<h4 style="text-align: left;">
1024 sized message</h4>
<div style="text-align: left;">
./kafka-consumer-perf-test.sh --topic kafka-ssl-perf-test-1k --new-consumer --messages 10000 --broker-list localhost:9093 --consumer.config ./kafka-openssl-consumer.properties --group open-ssl-1k > consumer-openssl-1k.txt<br />
<br />
Just like the producer run with OpenSSL, you should see the following log message which confirms that WildFly OpenSSL was picked up for this run:<br />
<br />
Oct 29, 2017 8:35:25 PM org.wildfly.openssl.SSL init<br />
INFO: WFOPENSSL0002 OpenSSL Version OpenSSL 1.1.0f 25 May 2017</div>
<h4 style="text-align: left;">
10240 sized message</h4>
<div style="text-align: left;">
./kafka-consumer-perf-test.sh --topic kafka-ssl-perf-test-10k --new-consumer --messages 10000 --broker-list localhost:9093 --consumer.config ./kafka-openssl-consumer.properties --group openssl-10k > consumer-openssl-10k.txt</div>
<h4 style="text-align: left;">
512000 sized message</h4>
<div style="text-align: left;">
./kafka-consumer-perf-test.sh --topic kafka-ssl-perf-test-500k --new-consumer --messages 10000 --broker-list localhost:9093 --consumer.config ./kafka-openssl-consumer.properties --group openssl-500k > consumer-openssl-500k.txt</div>
<h3 style="text-align: left;">
Final numbers (Java 8)</h3>
<div style="text-align: left;">
So let's now jump to the numbers, that we captured, from the above runs. The following is producer and consumer numbers for various message sizes that we tried above with JRE SSL and OpenSSL:</div>
<h4 style="text-align: left;">
Producer Stats:</h4>
<br />
<table border-collapse="collapse" border="1px" cellpadding="10px">
<tbody>
<tr align="center">
<td>Producer Stats</td>
<td colspan="2">Message size 1024</td>
<td colspan="2">Message size 10240</td>
<td colspan="2">Message size 512000</td>
</tr>
<tr>
</tr>
<tr align="center">
<td></td>
<td>JRE SSL</td>
<td>OpenSSL</td>
<td>JRE SSL</td>
<td>OpenSSL</td>
<td>JRE SSL</td>
<td>OpenSSL</td>
</tr>
<tr align="right">
<td>Records/sec</td>
<td>10857.76</td>
<td>14306.15</td>
<td>2232.64</td>
<td>2645.50</td>
<td>181.41</td>
<td>430.45</td>
</tr>
<tr align="right">
<td>MB/sec</td>
<td>10.60</td>
<td>13.97</td>
<td>21.80</td>
<td>25.83</td>
<td>88.58</td>
<td>210.19</td>
</tr>
<tr align="right">
<td>Avg. Latency (ms)</td>
<td>337.01</td>
<td>222.05</td>
<td>776.62</td>
<td>659.71</td>
<td>361.02</td>
<td>151.50</td>
</tr>
<tr align="right">
<td>Max. Latency (ms)</td>
<td>568.00</td>
<td>387.0</td>
<td>1050.00</td>
<td>887.00</td>
<td>618.00</td>
<td>282.00</td>
</tr>
<tr align="right">
<td>50th % latency (ms)</td>
<td>351</td>
<td>236</td>
<td>814</td>
<td>690</td>
<td>356</td>
<td>146</td>
</tr>
<tr align="right">
<td>95th % latency (ms)</td>
<td>548</td>
<td>369</td>
<td>933</td>
<td>808</td>
<td>381</td>
<td>183</td>
</tr>
<tr align="right">
<td>99th % latency (ms) </td>
<td>565</td>
<td>384</td>
<td>1016</td>
<td>870</td>
<td>522</td>
<td>235</td>
</tr>
<tr align="right">
<td>99.9th % latency (ms)</td>
<td>568</td>
<td>387</td>
<td>1046</td>
<td>885</td>
<td>561</td>
<td>262</td>
</tr>
</tbody></table>
<div style="text-align: left;">
<br />
<br /></div>
<h4 style="text-align: left;">
Consumer Stats:</h4>
<div style="text-align: left;">
<br />
<table border-collapse="collapse" border="1px" cellpadding="10px">
<tbody>
<tr align="center">
<td>Consumer Stats</td>
<td colspan="2">Message size 1024</td>
<td colspan="2">Message size 10240</td>
<td colspan="2">Message size 512000</td>
</tr>
<tr>
</tr>
<tr align="center">
<td></td>
<td>JRE SSL</td>
<td>OpenSSL</td>
<td>JRE SSL</td>
<td>OpenSSL</td>
<td>JRE SSL</td>
<td>OpenSSL</td>
</tr>
<tr align="right">
<td>Data consumed MB</td>
<td>9.7656</td>
<td>9.7656</td>
<td>97.6563</td>
<td>97.6563</td>
<td>4882.8125</td>
<td>4882.8125</td>
</tr>
<tr align="right">
<td>MB/sec</td>
<td>16.5239</td>
<td>24.5986</td>
<td>50.4423</td>
<td>97.2672</td>
<td>86.8797</td>
<td>250.4263</td>
</tr>
<tr align="right">
<td>Total consumed messages</td>
<td>10000</td>
<td>10000</td>
<td>10000</td>
<td>10000</td>
<td>10000</td>
<td>10000</td>
</tr>
<tr align="right">
<td>Num messages/sec</td>
<td>16920.4738</td>
<td>25188.9169</td>
<td>5165.2893</td>
<td>9960.1594</td>
<td>177.9296</td>
<td>512.8731</td>
</tr>
<tr align="right">
<td>Rebalance time (ms)</td>
<td>29</td>
<td>17</td>
<td>31</td>
<td>16</td>
<td>29</td>
<td>17</td>
</tr>
<tr align="right">
<td>Fetch time (ms)</td>
<td>562</td>
<td>380</td>
<td>1905</td>
<td>988</td>
<td>56173</td>
<td>19481</td>
</tr>
<tr align="right">
<td>Fetch MB/sec</td>
<td>17.3766</td>
<td>25.6990</td>
<td>51.2631</td>
<td>98.8424</td>
<td>86.9245</td>
<td>250.6449</td>
</tr>
<tr align="right">
<td>Fetch messages/sec</td>
<td>17793.5943</td>
<td>26315.7895</td>
<td>5249.3438</td>
<td>10121.4575</td>
<td>178.0215</td>
<td>513.3207</td>
</tr>
</tbody></table>
<br />
<br />
<h4 style="text-align: left;">
Summary (Java 8)</h4>
The above tables show that OpenSSL (backed by WildFly OpenSSL) out-performs the SSL provider shipped in the JRE, in both producer and consumer metrics recorded by the Kafka performance scripts. This by no means is a fine tuned performance testing or any kind of benchmark. The whole goal of this exercise was to see if it was worth the efforts to try and use OpenSSL (backed by WildFly OpenSSL) with Kafka. If the numbers/differences weren't as prominent as they are here, it wouldn't have been worth it. But as you see, the numbers show drastic improvements with WildFly OpenSSL and are promising enough to let us experiment more with OpenSSL.<br />
<br />
<br />
<h3 style="text-align: left;">
Performance when using Java 9</h3>
<br />
I (and few other folks) were curious what kind of numbers we get when this same test was run with Java 9 as the runtime environment. Java 9 has some known performance improvements around SSL (like <a href="https://twitter.com/ijuma/status/905847523897724929">this</a>), so I ran the entire set of tests (producer and consumer with both JRE shipped SSLEngine and WildFly OpenSSL) with Java 9 runtime. Just like for Java 8, I used the out-of-the-box settings for Kafka as well as Java 9 itself. The same set of instructions, noted previously in this article, were followed as for Java 8 to run these tests. The exact Java 9 version that was used is:<br />
<br />
<pre style="text-align: left;"><code>
java version "9.0.1"
Java(TM) SE Runtime Environment (build 9.0.1+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)
</code></pre>
<h4 style="text-align: left;">
Producer Stats (Java 9)</h4>
<table border-collapse="collapse" border="1px" cellpadding="10px">
<tbody>
<tr align="center">
<td>Producer Stats</td>
<td colspan="2">Message size 1024</td>
<td colspan="2">Message size 10240</td>
<td colspan="2">Message size 512000</td>
</tr>
<tr>
</tr>
<tr align="center">
<td></td>
<td>JRE-9 SSL</td>
<td>OpenSSL</td>
<td>JRE-9 SSL</td>
<td>OpenSSL</td>
<td>JRE-9 SSL</td>
<td>OpenSSL</td>
</tr>
<tr align="right">
<td>Records/sec</td>
<td>11481.05</td>
<td>14265.33</td>
<td>2480.77</td>
<td>2760.14</td>
<td>437.34</td>
<td>494.07</td>
</tr>
<tr align="right">
<td>MB/sec</td>
<td>11.21</td>
<td>13.93</td>
<td>24.23</td>
<td>26.95</td>
<td>213.55</td>
<td>241.25</td>
</tr>
<tr align="right">
<td>Avg. Latency (ms)</td>
<td>341.45</td>
<td>227.38</td>
<td>702.48</td>
<td>636.20</td>
<td>148.82</td>
<td>132.03</td>
</tr>
<tr align="right">
<td>Max. Latency (ms)</td>
<td>529.00</td>
<td>403.00</td>
<td>1009.00</td>
<td>854.00</td>
<td>691.00</td>
<td>269.00</td>
</tr>
<tr align="right">
<td>50th % latency (ms)</td>
<td>358</td>
<td>236</td>
<td>709</td>
<td>634</td>
<td>138</td>
<td>122</td>
</tr>
<tr align="right">
<td>95th % latency (ms)</td>
<td>513</td>
<td>389</td>
<td>885</td>
<td>775</td>
<td>198</td>
<td>193</td>
</tr>
<tr align="right">
<td>99th % latency (ms) </td>
<td>526</td>
<td>401</td>
<td>987</td>
<td>834</td>
<td>310</td>
<td>228</td>
</tr>
<tr align="right">
<td>99.9th % latency (ms)</td>
<td>529</td>
<td>402</td>
<td>1007</td>
<td>853</td>
<td>645</td>
<td>249</td>
</tr>
</tbody></table>
<div>
<br /></div>
<br />
<h4 style="text-align: left;">
Consumer Stats (Java 9)</h4>
<table border-collapse="collapse" border="1px" cellpadding="10px">
<tbody>
<tr align="center">
<td>Consumer Stats</td>
<td colspan="2">Message size 1024</td>
<td colspan="2">Message size 10240</td>
<td colspan="2">Message size 512000</td>
</tr>
<tr>
</tr>
<tr align="center">
<td></td>
<td>JRE-9 SSL</td>
<td>OpenSSL</td>
<td>JRE-9 SSL</td>
<td>OpenSSL</td>
<td>JRE-9 SSL</td>
<td>OpenSSL</td>
</tr>
<tr align="right">
<td>Data consumed MB</td>
<td>9.7656</td>
<td>9.7656</td>
<td>97.6563</td>
<td>97.6563</td>
<td>4882.8125</td>
<td>4882.8125</td>
</tr>
<tr align="right">
<td>MB/sec</td>
<td>13.3593</td>
<td>24.1723</td>
<td>66.6141</td>
<td>89.5108</td>
<td>233.0253</td>
<td>247.7076</td>
</tr>
<tr align="right">
<td>Total consumed messages</td>
<td>10000</td>
<td>10000</td>
<td>10000</td>
<td>10000</td>
<td>10000</td>
<td>10000</td>
</tr>
<tr align="right">
<td>Num messages/sec</td>
<td>13679.8906</td>
<td>24752.4752</td>
<td>6821.2824</td>
<td>9165.9028</td>
<td>477.2358</td>
<td>507.3052</td>
</tr>
<tr align="right">
<td>Rebalance time (ms)</td>
<td>30</td>
<td>18</td>
<td>31</td>
<td>18</td>
<td>28</td>
<td>17</td>
</tr>
<tr align="right">
<td>Fetch time (ms)</td>
<td>701</td>
<td>386</td>
<td>1435</td>
<td>1073</td>
<td>20926</td>
<td>19695</td>
</tr>
<tr align="right">
<td>Fetch MB/sec</td>
<td>13.9310</td>
<td>25.2995</td>
<td>68.0531</td>
<td>91.0123</td>
<td>233.3371</td>
<td>247.9214</td>
</tr>
<tr align="right">
<td>Fetch messages/sec</td>
<td>14265.3352</td>
<td>25906.7358</td>
<td>6968.6411</td>
<td>9319.6645</td>
<td>477.8744</td>
<td>507.7431</td>
</tr>
</tbody></table>
<br />
<br />
<h4 style="text-align: left;">
<div id="java9-perf-numbers">
</div>
Summary (Java 9)</h4>
<div>
In the above numbers you'll notice that:</div>
<div>
<ul style="text-align: left;">
<li>Both for producer and consumer, there's a <i><b>drastic improvement in the JRE shipped SSLEngine numbers, in almost all metrics, in Java 9 as compared to its counterpart in Java 8</b></i>. It's especially prominent in messages with higher sizes.</li>
<li>There's not much difference in the numbers for WildFly OpenSSL, in Java 9, as compared to its Java 8 counterpart. In fact, the consumer performance numbers of WildFly OpenSSL in Java 9 have dropped slightly when compared to Java 8. The producer performance in Java 9 with WildFly OpenSSL have however improved slightly when compared to Java 8.</li>
<li>When the numbers of producer and consumer metrics of WildFly OpenSSL with Java 9 runtime are compared with the JRE shipped SSL engine in Java 9, <i><b>WildFly OpenSSL still out-performs the one shipped in JRE</b></i>.</li>
</ul>
</div>
All the configurations, the Java agent code and the output of the runs are available in my github repo <a href="https://github.com/jaikiran/kafka-ssl-perf">here</a></div>
</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com3tag:blogger.com,1999:blog-30587633.post-14406564098915726472014-12-27T11:16:00.001+05:302014-12-27T11:52:14.881+05:30Remote JMX access to WildFly (or JBoss AS7) using JConsole<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
One of the goals of JBoss AS7 was to make it much more secure by default, when compared to previous versions. One of the areas which was directly impacted by this goal was that you could no longer expect the server to expose some service on a port and get access to it without any authentication/authorization. Remember that in previous versions of JBoss AS you could access the JNDI port, the JMX port without any authentication/authorization, as long as those ports were opened for communication remotely. Finer grained authorizations on such ports for communications, in JBoss AS7, allows the server to control who gets to invoke operations over that port.<br />
<br />
Of course, this is not just limited to JBoss AS7 but continues to be the goal in WildFly (which is the rename of JBoss Application Server). In fact, WildFly has gone one step further and now has the feature of "one single port" for all communication.<br />
<br />
<br />
<h2 style="text-align: left;">
JMX communication in JBoss AS7 and WildFly</h2>
<div style="text-align: left;">
<br />
With that background, we'll now focus on JMX communication in JBoss AS7 and WildFly. I'll use WildFly (8.2.0 Final) as a reference for the rest of this article, but the same details apply (with minor changes) to other major versions of JBoss AS7 and WildFly, that have been released till date.<br />
<br />
WildFly server is composed of "subsystems", each of which expose a particular set of functionality. For example, there's the EE subsystem which supports the Java EE feature set. Then there's the Undertow subsystem which supports web/HTTP server functionality. Similarly, there's a JMX subsystem which exposes the JMX feature set on the server. As you all are aware, I'm sure, JMX service is standardly used for monitoring and even managing Java servers and this includes managing the servers remotely. The JMX subsystem in WildFly allows remote access to the JMX service and port 9990 is what is used for that remote JMX communication.</div>
<h2>
JConsole for remote JMX access against JBoss AS7 and WildFly</h2>
<div style="text-align: left;">
<br />
Java (JDK) comes bundled with the JConsole tool which allows connecting to local or remote Java runtimes which expose the JMX service. The tool is easy to use, all you have to do is run the jconsole command it will show up a graphical menu listing any local Java processes and also an option to specify a remote URL to connect to a remote process:<br />
<br />
<pre># Start the JConsole
$JAVA_HOME/bin/jconsole</pre>
<br />
<br />
Let's assume that you have started WildFly standalone server, locally. Now when you start the jconsole, you'll notice that the WildFly Java process is listed in the local running processes to which you can connect to. When you select the WildFly Java instance, you'll be auto connected to it and you'll notice MBeans that are exposed by the server. However, in the context of this article, this "local process" mode in JConsole <i>isn't</i> what we are interested in.<br />
<br />
Let's use the "Remote process" option in that JConsole menu which allows you to specify the remote URL to connect to the Java runtime and username and password to use to connect to that instance. Even though our WildFly server is running locally, we can use this "Remote process" option to try and connect to it. So let's try it out. Before that though, let's consider a the following few points:<br />
<br />
<ol style="text-align: left;">
<li>Remember that the JMX subsystem in WildFly allows remote access on port 9990 </li>
<li>For remote access to JMX, the URL is of the format - service:jmx:[vendor-specific-protocol]://[host]:[port]. The vendor specific protocol is the interesting bit here. In the case of WildFly that vendor-specific-protocol is http-remoting-jmx. </li>
<li><vendor-specific-protocol><host><port>Remember that WildFly is secure by default which means that just because the JMX subsystem exposes 9990 port for remote communication, it doesn't mean it's open for communication to anyone. In order to be allowed to communicate over this port, the caller client is expected to be authenticated and authorized. This is backed by the "ManagementRealm" in WildFly. Users authenticated and authorized against this realm are allowed access to that port.</port></host></vendor-specific-protocol></li>
</ol>
</div>
</div>
<vendor-specific-protocol><host><port><br />Keeping those points in mind, let's first create a user in the Management Realm. This can be done using the add-user command line script (which is present in JBOSS_HOME/bin folder). I won't go into the details of that since there's enough documentation for that. Let's just assume that I created a user named "wflyadmin" with an appropriate password in the Management Realm. To verify that the user has been properly created, in the right realm, let's access the WildFly admin console at the URL http://localhost:9990/console. You'll be asked for username and password for access. Use the same username and password of the newly created user. If the login works, then you are good. If not, then make sure you have done things right while adding the new user (as I said I won't go into the details of adding a new user since it's going to just stretch this article unnecessarily long).<br /><br />So at this point we have created a user named "wflyadmin" belonging to ManagementRealm. We'll be using this same user account for accessing the JMX service on WildFly, through JConsole. So let's now bring up the jconsole as usual:</port></host></vendor-specific-protocol><br />
<vendor-specific-protocol><host><port><br /></port></host></vendor-specific-protocol>
<br />
<pre>$JAVA_HOME/bin/jconsole</pre>
<br />
<br />
On the JConsole menu let's again select the "Remote process" option and use the following URL in the URL text box:<br />
<br />
<pre>service:jmx:http-remoting-jmx://localhost:9990</pre>
<br />
<blockquote class="tr_bq">
Note: For <b>JBoss AS 7.x</b> and <b>JBoss EAP 6.x</b>, the vendor specific protocol is <b>remoting-jmx </b>and the port for communication is <b>9999</b>. So the URL will be service:jmx:remoting-jmx://localhost:9999</blockquote>
<br />
In the username and password textboxes, use the same user/pass that you newly created. Finally, click on Connect. What do you see? It <b>doesn't</b> work! The connection fails. So what went wrong?<br />
<br />
<h2>
<vendor-specific-protocol><host><port>Why isn't the JConsole remote access to WildFly not working?</port></host></vendor-specific-protocol></h2>
<h2>
<vendor-specific-protocol><host><port></port></host></vendor-specific-protocol></h2>
<vendor-specific-protocol><host><port><br />You did all the obvious things necessary to access the WildFly JMX service remotely but you keep seeing that JConsole can't connect to it. What could be the reason? Remember, in one of those points earlier, I noted that the "vendor specific protocol" is an interesting bit? We use http-remoting-jmx and that protocol internally relies on certain WildFly/JBoss specific libraries, primarily for remote communication and authentication and authorization. These libraries are WildFly server specific and hence aren't part of the standard Java runtime environment. When you start jconsole, it uses a standard classpath which just has the relevant libraries that are part of the JDK/JRE. <br /><br />To solve this problem, what you need to do is bring in the WildFly server specific libraries into the classpath of JConsole. Before looking into how to do that, let's see which are the WildFly specific libraries that are needed. All the necessary classes for this to work are part of the jboss-cli-client.jar which is present in JBOSS_HOME/bin/client/ folder. So all we need to do in include this jar in the classpath of the jconsole tool. To do that we use the -J option of jconsole tool which allows passing parameters to the Java runtime of jconsole. The command to do that is:</port></host></vendor-specific-protocol><br />
<pre style="white-space: -moz-pre-wrap; white-space: -o-pre-wrap; white-space: -pre-wrap; white-space: pre-wrap; word-wrap: break-word;">$JAVA_HOME/bin/jconsole -J-Djava.class.path=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/jconsole.jar:/opt/wildfly-8.2.0.Final/bin/client/jboss-cli-client.jar</pre>
<br />
(Note that for Windows the classpath separator is the semi-colon character instead of the colon)<br />
<br />
<blockquote class="tr_bq">
Note, the server specific jar for <b>JBoss AS 7.x</b> and <b>JBoss EAP 6.x</b> is named <b>jboss-client.jar </b>and is present at the same JBOSS_HOME/bin/client directory location.</blockquote>
<br />
So we are passing -Djava.class.path as the parameter to the jconsole Java runtime, using the -J option. Notice that we have specified more than just our server specific jar in that classpath. That's because, using the -Djava.class.path is expected to contain the complete classpath. We are including the jars from the Java JDK lib folder that are necessary for JConsole and also our server specific jar in that classpath.<br />
<br />
Running that command should bring up JConsole as usual and let's go ahead and select the "Remote process" option and specify the same URL as before:<br />
<br />
<pre>service:jmx:http-remoting-jmx://localhost:9990</pre>
<br />
and the same username and password as before and click Connect. This time you should be able to connect and should start seeing the MBeans and others services exposed over JMX.<br />
<br />
<br />
<h2 style="text-align: left;">
<vendor-specific-protocol><host><port>How about providing a script which does this necessary classpath setup?</port></host></vendor-specific-protocol></h2>
<h2>
<vendor-specific-protocol><host><port></port></host></vendor-specific-protocol></h2>
<vendor-specific-protocol><host><port><br />Since it's a common thing to try and use JConsole for remote access against WildFly, it's reasonable to expect to have a script which sets up the classpath (as above) and you could then just use that script. That's why WildFly ships such a script. It's in the JBOSS_HOME/bin folder and is called jconsole.sh (and jconsole.bat for Windows). This is just a wrapper script which internally invokes the jconsole tool present in Java JDK, after setting up the classpath appropriately. All you have to do is run:</port></host></vendor-specific-protocol><br />
<pre>$JBOSS_HOME/bin/jconsole.sh</pre>
<br />
<h2 style="text-align: left;">
<vendor-specific-protocol><host><port>What about using JConsole from a really remote machine, against WildFly?</port></host></vendor-specific-protocol></h2>
<h2>
<vendor-specific-protocol><host><port></port></host></vendor-specific-protocol></h2>
<vendor-specific-protocol><host><port><br />So far we were using the jconsole tool that was present on the same machine as the WildFly instance, which meant that we have filesystem access to the WildFly server specific jars present in the WildFly installation directory on the filesystem. This allowed us to setup the classpath for jconsole to point to the jar on the local filesystem?<br /><br />What if you wanted to run jconsole from a remote machine against a WildFly server which is installed and running on a different machine. In that case, your remote client machine won't be having filesystem access to the WildFly installation directory. So to get jconsole running in such a scenario, you will have to copy over the JBOSS_HOME/bin/jboss-cli-client.jar to your remote client machine, to a directory of your choice and then setup the classpath for jconsole tool as explained earlier and point it to that jar location. That should get you access to JMX services of WildFly from jconsole on a remote machine.</port></host></vendor-specific-protocol><br />
<h2 style="text-align: left;">
<vendor-specific-protocol><host><port> </port></host></vendor-specific-protocol></h2>
<h2 style="text-align: left;">
<vendor-specific-protocol><host><port>More questions? </port></host></vendor-specific-protocol></h2>
<vendor-specific-protocol><host><port>If you still have problems getting this to work or have other questions, please start a discussion in the JBoss community forums here <a href="https://developer.jboss.org/en/wildfly/content">https://developer.jboss.org/en/wildfly/content</a>.</port></host></vendor-specific-protocol>
</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com4tag:blogger.com,1999:blog-30587633.post-72685253796623305092014-12-07T13:06:00.000+05:302014-12-07T13:07:31.996+05:30WildFly 8.2.0.Final release - Quick overview of the changes<div dir="ltr" style="text-align: left;" trbidi="on">
It's been a while since I last wrote on this blog. Although I have had some topics that I wanted to blog about, I just haven't found enough time to do it. I finally decided to write this up today after I saw a mail from one of the JBoss community members, checking up on why there haven't been any updates here lately (thanks for checking, Bhaskar! :)).<br />
<br />
Before I move on to some technical things, a quick personal update - It's now been more than a year now since I changed jobs. I no longer work at Red Hat, JBoss. My (almost) 5 years at JBoss have been very fruitful and I enjoyed being part of the (JBoss AS/WildFly) application server development team. Last year, I decided to move on to something different and the right opportunity came along and I decided to take it up. Some of you know that I've been involved with the JBoss community for longer than the 5 years that I had been employed at Red Hat. I have been a JBoss community member since around 2004/2005, so even though I have moved on from Red Hat, I am still active in the JBoss forums. <br />
<br />
Now that you all know what I've been upto, let's move on to some technical things. <br />
<br />
<h2 style="text-align: left;">
WildFly 8.2.0.Final released!</h2>
<div style="text-align: left;">
<br />
The WildFly team just released the 8.2.0.Final version of WildFly some days back. As usual, it's available for download on the project's download page<a href="http://wildfly.org/downloads/" target="_blank"> http://wildfly.org/downloads/</a>. This is mainly a bug fix (plus some features) release in the 8.x series. I for one, was pleased to see this release happen because it allows the community to receive bug fixes on top of 8.1.0.Final release, which has been tested/used in the community for quite some time now. The WildFly team has indicated that this will be the last release in the 8.x series which sounds reasonable, given that the development team has already moved on to work on the 9.x series. It's never easy to work/maintain more than one major version of the code, especially in the context of bug fixes and backward compatibility.</div>
<h2 style="text-align: left;">
What does WildFly 8.2.0.Final contain?</h2>
<div style="text-align: left;">
<br />
The complete overview of changes in available in this announcement on Jason's blog <a href="http://wildfly.org/news/2014/11/20/WildFly82-Final-Released/">http://wildfly.org/news/2014/11/20/WildFly82-Final-Released/</a>. CDI spec upgrade and improved WebSocket support are the main items in terms of feature set. There's also this note in the release notes:</div>
<blockquote class="tr_bq">
- EJBs in WARs now inherit the WAR security domain</blockquote>
<div style="text-align: left;">
<br />
There was a recent forum thread, where one of the users asked what that really means. Here's some background to that change <a href="https://issues.jboss.org/browse/WFLY-3102">https://issues.jboss.org/browse/WFLY-3102</a>. As noted in that JIRA, this was feature request that was raised in the context of EJBs packaged in .war deployments. Most of you, I guess, will be aware that Java EE spec allows EJBs to be deployed as part of the .war deployment. What this means is that you can place your EJB classes within the .war/WEB-INF/classes or within a jar in .war/WEB-INF/lib. Although, this sounds straightforward for the end users, there are some technical implications to this (given the way Java EE "components" and "modules" are defined and configured within the server ecosystem). One such detail, is the way one configures the EJBs that are part of the .war deployment. Remember that if this EJB was part of a separate EJB module (within a .jar packaging outside of the .war) then one would use the ejb-jar.xml (and the WildFly specific jboss-ejb3.xml) as the deployment descriptors to configure it. This applies to EJBs deployed in a .war deployment too. i.e. one can use those same files for configuring EJBs. Now since these EJBs are part of a .war, the .war itself can/will have a deployment descriptor if its own (the web.xml and jboss-web.xml). <br />
<br />
With that context, consider a case where the you have EJBs within the .war deployment and your .war deployment descriptor (the jboss-web.xml) configures a specific security domain for that deployment. Now remember that the EJBs too can configure a security domain (in jboss-ejb3.xml) and if none is configured and security is enabled on some EJBs, then the default "other" security domain gets used. So let's say your .war deployment, in which the EJBs reside, states that it wants to use "foo-bar" security domain and the EJBs, within that deployment, don't specify any specific security domain. So what should one expect in such scenario? Should the EJBs use the security domain configured at the .war level or should they default to the "other" security domain (since the EJB deployment descriptors don't specify any specific security domain configuration). The previous versions of WildFly had decided to use the default "other" security domain for the EJBs in such a case. Of course, the EJBs could use a jboss-ejb3.xml to set a different security domain, one which matches the jboss-web.xml. So that JIRA which I linked to earlier requested for a better, smarter and a more logical default in such cases. So starting this 8.2.0.Final version of WildFly, if you have a .war containing the EJBs and the EJBs don't define a security domain, then the security domain for any secured EJBs in that deployment *defaults* to the one that's defined at the .war deployment level. If the .war deployment doesn't set any specific security domain, then it ultimately, defaults to the "other" security domain. A good and logical change IMO. This will reduce some of the "surprises" that users have reported with previous version of WildFly, when it came to the security domain usage of EJBs in .war deployments.<br />
<br />
For more about this, you can read the discussion here <a href="https://developer.jboss.org/thread/250375">https://developer.jboss.org/thread/250375</a> and ask any questions you have around this, in that thread.</div>
<h2 style="text-align: left;">
What are the other notable things in WildFly 8.2.0.Final?</h2>
<div style="text-align: left;">
<br />
Although, not specific to 8.2.0.Final, the WildFly release contain a "patch" distribution which you can use if you already are using WildFly 8.1.0.Final and just want to "upgrade" to this new release. WildFly 8 has patch management built in and one can apply this patch on top of an existing 8.1.0.Final version.</div>
<h2 style="text-align: left;">
What's next for WildFly?</h2>
<div style="text-align: left;">
<br />
As noted earlier, the WildFly development team has moved on to the next version of the project. Work is now continuing on 9.x version which already has a Alpha version released. So going forward, from what I have read, the releases will happen in the 9.x series.<br />
<br />
<br /></div>
</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com1tag:blogger.com,1999:blog-30587633.post-57521433740160612752014-01-22T19:29:00.000+05:302014-01-22T19:45:48.134+05:30WildFly 8.0 CR1 release and WildFly 8 book<div dir="ltr" style="text-align: left;" trbidi="on">
I guess by now everyone is aware that the community <a href="http://jaitechwriteups.blogspot.in/2013/06/wildfly-release-and-history-behind-the-release.html" target="_blank">JBoss AS server has been renamed to WildFly</a>. The WildFly team has been busy pushing out <a href="http://wildfly.org/downloads/" target="_blank">releases</a> of the 8.0 series during the past few months. It's been a month now since the <a href="http://wildfly.org/news/2013/12/21/WildFly8-CR1-Released/" target="_blank">8.0 CR1 version of WildFly was released</a>. This is a significant release since the 8.0 CR1 version passes the Java EE7 TCK 100%. The Final version of 8.0 is expected any time soon <a href="http://lists.jboss.org/pipermail/wildfly-dev/2014-January/001458.html">http://lists.jboss.org/pipermail/wildfly-dev/2014-January/001458.html</a>.<br />
<br />
Along with this good news about the WildFly 8.0 series nearing the final version, the other good news is that there's now a <a href="http://www.itbuzzpress.com/ebooks/wildfly-8-book.html" target="_blank">WildFly 8 administration guide</a> available for purchase. The author of the book is Francesco Marchioni, who in the past has authored books on the JBoss AS series.<br />
<br />
<h2 style="text-align: left;">
Brief review of the WildFly 8 book</h2>
<h2 style="text-align: left;">
</h2>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.itbuzzpress.com/ebooks/wildfly-8-book.html" target="_blank"><img alt="http://www.itbuzzpress.com/ebooks/wildfly-8-book.html" border="0" src="http://www.itbuzzpress.com/images/books/wildfly-short.png" /></a></div>
<h2 style="text-align: left;">
</h2>
<div style="text-align: left;">
The <a href="http://www.itbuzzpress.com/ebooks/wildfly-8-book.html" target="_blank">WildFly 8 book</a> by Francesco is aimed at admins and does a good job of covering various administrative configurations for each of the major subsystems that form a part of the WildFly server. The author starts by covering the basics, from installation of the server and goes on to give an overview of the standalone and domain modes of the server. He then goes on to extensively explain each of the major subsystem administration configurations, like the new web subsystem which is backed by <a href="http://undertow.io/" target="_blank">Undertow</a>. There's also chapters on EJB and clustering configurations.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Francesco does a good job of covering the major subsystems and also keep the content concise. I found the book to be a good read from an administrator point of view. There are certain tidbits for developers too, but the book is mostly aimed at admins. If you are looking for some book to give you a quick and extensive overview of the subsystems in WildFly, then this is worth it.</div>
<div style="text-align: left;">
<br /></div>
</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-1638025624155386842013-07-25T17:28:00.000+05:302013-07-25T17:32:51.079+05:30WildFly 8.0.0.Alpha3 released with support for EJB invocations over HTTP<div dir="ltr" style="text-align: left;" trbidi="on">
A week back we released WildFly 8.0.0.Alpha3 version. As usual the download is available on <a href="http://wildfly.org/download/" target="_blank">WildFly downloads page</a>. This release comes within a month of the 8.0.0.Alpha2 release. Keeping up with the goals of WildFly 8, this new release contains additional EE7 support, certain bug fixes and also some WildFly specific features. The entire release notes are available <a href="https://community.jboss.org/wiki/800Alpha3ReleaseNotes" target="_blank">here</a>.<br />
<br />
In this article, I'll provide some details about one of the WildFly features which has made into this release.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://wildfly.org/" target="_blank"><img alt="WildFly logo" border="0" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPjoNVlJEh9qoQMKfwTLyPfkqhptwmDwYv6ivPK-3BrGbBccaP8JVc1Oo6ubZu3j_hLJjbg5rnK6j2mFV_tyd_GToCzjaA9-mRPGBWWP-v7DdJCx3nJcwodg1tuZGsq1NuuaSjSg/s320/wildfly_logo_600px.png" title="WildFly logo" width="320" /></a></div>
<br />
<h2 style="text-align: left;">
WildFly ports</h2>
<div style="text-align: left;">
<br />
Traditionally, WildFly and previously named JBoss AS have opened different ports for different protocols and communication. For example, in the JBoss AS7 and now WildFly 8 series, by default the server opens the http port (which is by default 8080), remoting port (which is backed by JBoss Remoting and by default is 4447) and other such ports for usage by the applications deployed on the server. One of the goals of WildFly 8 (Final) is to have one single port open for all types of communication. This is meant to allow admins a better control of the server (firewall rules for example).</div>
<h2 style="text-align: left;">
HTTP Upgrade support in Undertow</h2>
<div style="text-align: left;">
<br />
As some of you might know by now, the WildFly 8 series now uses <a href="http://undertow.io/" target="_blank">Undertow</a> as its web container. Undertow supports a standard feature called <a href="http://tools.ietf.org/html/rfc2616#section-14.42" target="_blank">HTTP Upgrade</a>. As can be read in that RFC, this feature allows the HTTP protocol to switch to a different protcol based on the presence of a header in the protocol data. This HTTP Upgrade feature acts as the backbone of the proposed "single port for communication" feature in WildFly.</div>
<h2 style="text-align: left;">
EJB invocation over HTTP</h2>
<div style="text-align: left;">
<br />
Now that we have some background on HTTP Upgrade, let get to the details about the new feature that WildFly 8.0.0.Alpha3 introduces. Up until WildFly 8.0.0.Alpha2 (and previously in JBoss AS7 series) a project called JBoss Remoting has been the underlying protocol for remote communication with the server. The communication by default used to happen on the port 4447. Many of you will be familiar with this port, since this is what you used while looking up EJBs from a remote client.<br />
<br />
Starting WildFly 8.0.0.Alpha3 (i.e. this new release), this port is no longer opened by WildFly by default. So how does one invoke EJBs or even use remote-naming (which too used this port) starting this version? The answer is simple, these remote clients will now have to use the HTTP port which by default is port 8080. The rest of the code will remain the same. This HTTP port is managed by the Undertow server which like I said earlier, has support for HTTP Upgrade. Internally, the EJB client API project (which is JBoss specific project dealing with remote EJB invocations) does the necessary plumbing to request Undertow to switch to JBoss "remoting" protocol while communicating on that HTTP port. Undertow then switches the protocol to "remoting" and the rest of the communication transparently happens as if it was the usual invocation on the remoting port.<br />
<br />
<br />
So let's see some code to understand what exactly changes from previous version to the new version, from a remote client point of view. Let's take the example of the jboss-ejb-client.properties that's used to invoke EJBs. Earlier, you probably had:
<br />
<br />
<pre style="background: #FAF7F1; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;">
remote.connections=default
# the server hostname/IP
remote.connection.default.host=10.19.20.12
# the port for communication
remote.connection.default.port=4447
</code></pre>
(and some other properties)
<br />
<br />
Starting this release, the only thing that changes is the port number in that properties, rest of it remains the same. So:
<br />
<br />
<pre style="background: #FAF7F1; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;">
remote.connections=default
# the server hostname/IP
remote.connection.default.host=10.19.20.12
# the port for communication (the HTTP port)
remote.connection.default.port=8080
</code></pre>
<br />
<br />
So that's it from a typical client point of view. <br />
<br />
For other new features and bug fixes, please take a look at the <a href="https://community.jboss.org/wiki/800Alpha3ReleaseNotes" target="_blank">release notes</a>.</div>
<div style="text-align: left;">
<br /></div>
<br />
<br />
<div style="text-align: center;">
[<a href="http://wildfly.org/">WildFly Home</a>] [<a href="https://issues.jboss.org/browse/WFLY">WildFly JIRA</a>] [<a href="https://community.jboss.org/community/wildfly?view=discussions">WildFly User Forum</a>] [<a href="http://wildfly.org/download/">WildFly downloads</a>] [<a href="https://community.jboss.org/thread/224262">WildFly nightly builds</a>]<br />
<br /></div>
<div style="text-align: left;">
<br /></div>
</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com5tag:blogger.com,1999:blog-30587633.post-35118736012252040062013-06-22T20:31:00.000+05:302013-06-22T20:31:10.035+05:30WildFly community members nominated for JBoss Community Recognition Award - voting open<div dir="ltr" style="text-align: left;" trbidi="on">
Every year, JBoss community members are rewarded for their work in the community as part of the <a href="http://www.jboss.org/jbcra" target="_blank">JBoss Community Recognition Awards (JBCRA)</a>. This year we have 2 community members from the <a href="http://www.wildfly.org/" target="_blank">WildFly</a> project (previously known as JBoss Application Server) who have been nominated in 3 different categories.<br /><br /><a href="https://community.jboss.org/people/nickarls" target="_blank">Nicklas Karlsson</a> has been nominated in the Issue/JIRA category and <a href="https://community.jboss.org/people/sfcoy" target="_blank">Stephen Coy</a> has been nominated in 2 categories - Community Leadership and New Features. Please do vote for them here <a href="https://www.jboss.org/jbcra/vote.html">https://www.jboss.org/jbcra/vote.html</a> - it's just one page and takes less than a minute to vote. It's one way of thanking them for the help they have been providing in the community. Remember that these nominees are volunteers and are <b>not</b> Red Hat/JBoss employees so their contributions are that much more valuable.<br /><br />The voting ends on July 26 2013. Don't wait for that date, vote now! :)<br />
<br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-10281796657643262842013-06-03T16:56:00.000+05:302013-06-03T17:33:15.748+05:30WildFly 8.0.0.Alpha1 release and a bit of history<div dir="ltr" style="text-align: left;" trbidi="on">
It's been around 2 weeks now since we released <a href="http://wildfly.org/" target="_blank">WildFly</a> 8.0.0.Alpha1 version. The download is available on the <a href="http://wildfly.org/download/" target="_blank">WildFly downloads page</a>. I'm sure many of you might be wondering what WildFly is and some of you who are aware of what it is, might not be aware that there has been a release. I'll try and answer some of these questions and also add some details about what this release contains.<br />
<br />
<h2 style="text-align: left;">
So what's WildFly?</h2>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://wildfly.org/" target="_blank"><img border="0" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPjoNVlJEh9qoQMKfwTLyPfkqhptwmDwYv6ivPK-3BrGbBccaP8JVc1Oo6ubZu3j_hLJjbg5rnK6j2mFV_tyd_GToCzjaA9-mRPGBWWP-v7DdJCx3nJcwodg1tuZGsq1NuuaSjSg/s320/wildfly_logo_600px.png" width="320" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
WildFly is the new name for the community project which was previously known as JBoss Application Server. Late in 2012, we decided that we had to rename the community project, JBoss Application Server, to something else. As part of that (long drawn out) process, community members were asked to suggest new names and a few selected names were voted to select the new name. Ultimately, <a href="https://community.jboss.org/blogs/mark.little/2013/04/19/and-the-winner-is" target="_blank">WildFly turned out to be the winner</a>.</div>
<h2 style="text-align: left;">
Why did we change the name?</h2>
<div style="text-align: left;">
<br />
JBoss Application Server (both the name and the project) has been a very popular project over the years. Initially when it started off, it was known simply as JBoss. Anytime anyone referred to the name JBoss, people knew that they were talking about the JBoss Application Server community edition. Over the years though, the reference started to get hazy. The community edition JBoss Application Server also has a <a href="http://www.redhat.com/products/jbossenterprisemiddleware/application-platform/" target="_blank">paid and fully supported version known as JBoss Enterprise Application Platform (JBoss EAP)</a>. Notice the "JBoss" name in there? So there's JBoss Application Server community edition and then there's JBoss EAP paid version. It did not stop there! Over the years, various community projects hosted at jboss.org started naming their projects with the name "JBoss" in it. So there was "JBoss ESB", "JBoss Transactions", "JBoss Messaging" and many such projects with the name "JBoss" in it. It's certainly no fault of those projects that they used "JBoss" as part of the name. It did make sense to use that name, since those projects were developed by JBoss community members. By the way, did you just notice the name "JBoss" even means a reference to the JBoss community as a whole?<br />
<br />
So I guess at this point you might have realized where I'm headed with all this historical evidence. Clearly, the name "JBoss" had started to mean much more than just the JBoss Application Server community project. Although it was good thing from a brand point of view, it clearly wasn't too good from various other aspects. We had started seeing too much confusion about what each project/product stood for not just from a name point of view but also a release roadmap point of view. Take for example JBoss Application Server and JBoss EAP - users, typically those who are more busy with their application (rightly so) than trying to understand what each variant of project/product with the name "JBoss" in it meant, were just not sure which one to pick and which release of those had what features in it. Of course, it would take some explanation to help them understand this, but doing this on a regular basis was a clear sign that this isn't the right way forward.<br />
<br />
So slowly during the past few years, there has been a conscious decision not to name new projects with "JBoss" in its name and also to rename some of the existing projects wherever possible. So for example, when "JBoss Messaging" project decided to release a completely new and better version, the project decided to name it "HornetQ". Similarly, JBoss Transactions is now known as Narayana. There are various examples of such renames and new names. Obviously, doing the same for JBoss Application Server would need some time and extra efforts since it was a really huge change for various reasons. But it had to be done ultimately and that's why it's now WildFly.</div>
<h2 style="text-align: left;">
So what happens to the "JBoss" name in JBoss EAP?</h2>
<div style="text-align: left;">
<br />
The rename is only for the JBoss Application Server community edition. The paid version is still named JBoss Enterprise Application Platform (JBoss EAP). Since one of the original intentions of the rename was to clear the confusion between JBoss Application Server community edition and similar named JBoss EAP, the name change only applies to the community edition. So ultimately, over time, when someone refers to WildFly, we clearly know they are talking about the community project and very specifically the application server project.</div>
<h2 style="text-align: left;">
How does WildFly 8.0.0.Alpha1 release relate to the previous JBoss AS7 releases?</h2>
<div style="text-align: left;">
<br />
WildFly 8.0.0.Alpha1 is the continuation of the release cycle of the application server community edition, which was previously known as JBoss AS7. The last release of JBoss AS7 was 7.1.1.Final (way back in March 2012) and WildFly 8.0.0.Alpha1 is now the next release of the same project with the new name.</div>
<h2 style="text-align: left;">
Is WildFly 8.0.0.Alpha1 a release of a new project?</h2>
<div style="text-align: left;">
<br />
I know I already answered a variant of this question earlier, but I wanted to include the answer to this differently worded question too since I wanted it to be very clear that WildFly is just a rename of JBoss Application Server. It is <b>not</b> a new project. So WildFly 8.0.0.Alpha1 release is the continuation of the release cycle of the previously named JBoss Application Server project.</div>
<h2 style="text-align: left;">
What's new in 8.0.0.Alpha1 release?</h2>
<div style="text-align: left;">
<br />
Now that we have addressed what WildFly is and a history around the name change, let's focus on the release itself. Some time back, <a href="https://twitter.com/jtgreene" target="_blank">Jason, the project lead of WildFly</a>, listed down the goals of WildFly 8 release in the 2 dev mailing list threads here:</div>
<div style="text-align: left;">
WildFly 8 roadmap (proposal) - <a href="http://lists.jboss.org/pipermail/jboss-as7-dev/2013-March/007884.html">http://lists.jboss.org/pipermail/jboss-as7-dev/2013-March/007884.html</a></div>
<div style="text-align: left;">
WildFly 8 Schedule - <a href="http://lists.jboss.org/pipermail/wildfly-dev/2013-May/000062.html">http://lists.jboss.org/pipermail/wildfly-dev/2013-May/000062.html</a><br />
<br />
So those are the goals and the schedule for WildFly 8. <br />
<br />
WildFly 8.0.0.Alpha1 is the first milestone towards that. The release contains some of the new Java EE7 features, a new web server implementation named Undertow (as a replacement to JBossWeb web server) and some other new features. Of course, it also contains numerous bug fixes and since the previous release was more than a year back, the number of bug fixes are huge. Jason has summarized the WildFly 8.0.0.Alpha1 release in the dev mailing thread here <a href="http://lists.jboss.org/pipermail/wildfly-dev/2013-May/000139.html">http://lists.jboss.org/pipermail/wildfly-dev/2013-May/000139.html</a>.<br />
<br />
Please <a href="http://wildfly.org/download/" target="_blank">download</a> this new version and give it a try. Like always, any feedback, questions or asking for help is always welcome in our <a href="https://community.jboss.org/community/wildfly?view=discussions" target="_blank">WildFly user forums</a>.</div>
<h2 style="text-align: left;">
What's next for WildFly?</h2>
<div style="text-align: left;">
<br />
Like Jason noted in the <a href="http://lists.jboss.org/pipermail/wildfly-dev/2013-May/000062.html" target="_blank">WildFly 8 release schedule thread</a>, we plan to push out a release almost every other month with the goal of having a 8.0.0.Final version at the end of this year. So, like with all the help that the community provided during AS7 releases:<br />
<br />
Community help for JBoss AS 7.0 release - <a href="https://community.jboss.org/thread/169491">https://community.jboss.org/thread/169491</a><br />
Community help for JBoss AS 7.1 release - <a href="https://community.jboss.org/thread/195430">https://community.jboss.org/thread/195430</a><br />
<br />
please continue to do the same for WildFly releases.<br />
<br />
In the coming weeks/months, we plan to blog more about the WildFly releases and the technologies that the WildFly runtime supports. In fact, Jason has asked in this dev mailing list thread <a href="http://lists.jboss.org/pipermail/wildfly-dev/2013-May/000144.html">http://lists.jboss.org/pipermail/wildfly-dev/2013-May/000144.html</a> whether the community members will be willing to blog too. That's another way of contributing too. So if you have any blogs that you have written or plan to write on WildFly, do let us know about it in that thread.</div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
Those of you who want to try out the nightly builds of WildFly, can get it from our continuous integration job mentioned here <a href="https://community.jboss.org/thread/224262">https://community.jboss.org/thread/224262</a>.</div>
<h2 style="text-align: left;">
By the way, what's that image at the beginning of this article?</h2>
<div style="text-align: left;">
<br />
Thanks for noticing! That's the logo for WildFly which the jboss.org team of artists (yeah, we do have team for that) helped us come up with :) Like it?<br />
<br /></div>
<div style="text-align: center;">
[<a href="http://wildfly.org/">WildFly Home</a>] [<a href="https://issues.jboss.org/browse/WFLY">WildFly JIRA</a>] [<a href="https://community.jboss.org/community/wildfly?view=discussions">WildFly User Forum</a>] [<a href="http://wildfly.org/download/">WildFly downloads</a>] [<a href="https://community.jboss.org/thread/224262">WildFly nightly builds</a>]<br />
<br /></div>
</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com1tag:blogger.com,1999:blog-30587633.post-64889475176808014292013-03-26T15:47:00.000+05:302013-06-10T09:47:35.315+05:30Java EE 7 and EJB 3.2 support in JBoss AS 8<div dir="ltr" style="text-align: left;" trbidi="on">
<blockquote class="tr_bq">
<b>Update</b> <b>(June 10 2013)</b>: JBoss AS is now known as WildFly. This post was written before WildFly 8.0.0.Alpha1 was released. Any references to JBoss AS8 in this article should be considered as a reference to WildFly 8. Read my next article here <a href="http://jaitechwriteups.blogspot.in/2013/06/wildfly-release-and-history-behind-the-release.html" target="_blank">http://jaitechwriteups.blogspot.in/2013/06/wildfly-release-and-history-behind-the-release.html</a> which explains what WildFly is and why JBoss AS was renamed to WildFly.</blockquote>
<br />
<br />
Some of you might be aware that the Public Final Draft version of Java EE 7 spec has been <a href="http://java.net/projects/javaee-spec/downloads" target="_blank">released</a>. Among various other new things, this version of Java EE, brings in EJB 3.2 version of the EJB specification. EJB 3.2 has some new features compared to the EJB 3.1 spec. I'm quoting here the text present in the EJB 3.2 spec summarizing what's new:<br />
<br />
The Enterprise JavaBeans 3.2 architecture extends Enterprise JavaBeans to include the following new functionality and simplifications to the earlier EJB APIs:<br />
<blockquote class="tr_bq">
<div>
<ul style="text-align: left;">
<li>Support for the following features has been made optional in this release and their description is moved to a separate EJB Optional Features document:</li>
<ul>
<li>EJB 2.1 and earlier Entity Bean Component Contract for Container-Managed Persistence</li>
<li>EJB 2.1 and earlier Entity Bean Component Contract for Bean-Managed Persistence</li>
<li>Client View of an EJB 2.1 and earlier Entity Bean</li>
<li>EJB QL: Query Language for Container-Managed Persistence Query Methods</li>
<li>JAX-RPC Based Web Service Endpoints</li>
<li>JAX-RPC Web Service Client View</li>
</ul>
<br />
<li>Added support for local asynchronous session bean invocations and non-persistent EJB Timer Service to EJB 3.2 Lite.</li>
<br />
<li>Removed restriction on obtaining the current class loader; replaced ‘must not’ with ‘should exercise caution’ when using the Java I/O package.</li>
<br />
<li>Added an option for the lifecycle callback interceptor methods of stateful session beans to be executed in a transaction context determined by the lifecycle callback method's transaction attribute.</li>
<br />
<li>Added an option to disable passivation of stateful session beans.</li>
<br />
<li>Extended the TimerService API to query all active timers in the same EJB module.</li>
<br />
<li>Removed restrictions on javax.ejb.Timer and javax.ejb.TimerHandle references to be used only inside a bean.</li>
<br />
<li>Relaxed default rules for designating implemented interfaces for a session bean as local or as remote business interfaces.</li>
<br />
<li>Enhanced the list of standard activation properties.</li>
<br />
<li>Enhanced embeddable EJBContainer by implementing AutoClosable interface.</li>
</ul>
</div>
</blockquote>
<br />
<br />
<br />
As can be seen, some of the changes proposed are minor. But there are some which are useful major changes. We'll have a look at a couple of such changes in this article.<br />
<br />
<h4 style="text-align: left;">
1) New API TimerService.getAllTimers() </h4>
<br />
EJB 3.2 version introduces a new method on the javax.ejb.TimerService interface, named getAllTimers. Previously the TimerService interface had (and still has) a getTimers method. The getTimers method was expected to return the active timers that are applicable for the bean on whose TimerService, the method had been invoked (remember: there's one TimerService per EJB). <br />
<br />
In this new EJB 3.2 version, the newly added getAllTimers() method is expected to return all the active timers that are applicable to *all beans within the same EJB module*. Typically, an EJB module corresponds to a EJB jar, but it could also be a .war deployment if the EJBs are packaged within the .war. This new getAllTimers() method is a convenience API for user applications which need to find all the active timers within the EJB module to which that bean belongs.<br />
<br />
<h4 style="text-align: left;">
2) Ability to disable passivation of stateful beans</h4>
<br />
Those familiar with EJBs will know that the EJB container provides passivation (storing the state of the stateful bean to some secondary store) and activation (loading the saved state of the stateful bean) capability to stateful beans. However, previous EJB versions didn't have a portable way of disabling passivation of stateful beans, if the user application desired to do that. The new EJB 3.2 version introduces a way where the user application can decide whether the stateful bean can be passivated or not. <br />
<br />
By default, the stateful bean is considered to be "passivation capable" (like older versions of EJB). However, if the user wants to disable passivation support for certain stateful bean, then the user has the option to either disable it via annotation or via the ejb-jar.xml deployment descriptor.<br />
<br />
Doing it the annotation way is as simple as setting the passivationCapable attribute on the @javax.ejb.Stateful annotation to false. Something like:<br />
<br />
<pre style="background: #FAF7F1; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> @javax.ejb.Stateful(<b>passivationCapable=false</b>) // the passivationCapable attribute takes a boolean value
public class MyStatefulBean {
....
}
</code></pre>
<br />
Doing it in the ejb-jar.xml is as follows:<br />
<br />
<br />
<pre style="background: #FAF7F1; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<b>xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd"
version="3.2"></b>
<enterprise-beans>
<session>
<ejb-name>foo-bar-bean</ejb-name>
<ejb-class>org.myapp.FooBarStatefulBean</ejb-class>
<session-type>Stateful</session-type>
<b><!-- passivation-capable element takes either a true or a false value -->
<passivation-capable>false</passivation-capable> </b>
</session>
...
</enterprise-beans>
</ejb-jar>
</code></pre>
<br />
<br />
Two important things to note in that ejb-jar.xml are the version=3.2 attribute (along with the http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd schema location) on the ejb-jar root element and the passivation-capable element under the session element.<br />
<br />
So, using either of these approaches will allow you to disable passivation on stateful beans, if you want to do so.<br />
<br />
<h4 style="text-align: left;">
Java EE 7 and EJB 3.2 support in JBoss AS8:</h4>
<br />
JBoss AS8 has been adding support for Java EE 7 since the Public Final Draft version of the spec has been announced. Support for EJB 3.2 is already added and made available. Some other Java EE 7 changes have also made it to the latest JBoss AS 8 builds. To keep track of the Java EE 7 changes in JBoss AS8, keep an eye on this JIRA <a href="https://issues.jboss.org/browse/AS7-6553">https://issues.jboss.org/browse/AS7-6553</a>.<br />
<br />
To use the already implemented features of Java EE 7 in general or EJB 3.2 in particular, you can download the latest nightly build/binary of JBoss AS from <a href="https://community.jboss.org/thread/167590" target="_blank">here</a>. Give it a try and let us know how it goes. For any feedback, questions or if you run into any kind of issues, feel free to open a discussion thread in our user forum <a href="https://community.jboss.org/en/jbossas7?view=discussions" target="_blank">here</a>.<a href="https://community.jboss.org/en/jbossas7?view=discussions" target="_blank"></a><br />
<br />
<br />
<br />
<div style="text-align: center;">
[<a href="http://www.jboss.org/as7">JBoss AS Home</a>] [<a href="https://issues.jboss.org/browse/AS7">JBoss AS JIRA</a>] [<a href="http://community.jboss.org/en/jbossas7?view=discussions">JBoss AS User Forum</a>] [<a href="http://www.jboss.org/jbossas/downloads.html">JBoss AS downloads</a>] [<a href="http://community.jboss.org/thread/167590">JBoss AS nightly builds</a>]<br />
<br /></div>
</div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com7tag:blogger.com,1999:blog-30587633.post-77963841863265398182013-01-27T19:15:00.000+05:302013-01-27T19:15:16.579+05:30Custom error pages for expired conversations involving CDI and JSF<div dir="ltr" style="text-align: left;" trbidi="on">
It's been a while since I last blogged. I keep thinking of blogging something technical but end up getting busy with other things. This last week there was a very interesting discussion at the <a href="http://www.coderanch.com/forums" target="_blank">coderanch forums</a>. It was even more interesting because it involved JBoss :)<br /><br />Developers familiar with Java EE web applications would know that the web application deployment descriptor (web.xml) allows you to specify "error pages" which the container will display when a specific exception (class) or a error code is thrown by the server for a web request. Here's a quick example of how it looks like:<br /><br /><pre nbsp="" style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <web-app>
...
<!-- A custom error page for error code == 500 -->
<error-page>
<error-code>500</error-code>
<location>/my-foo-bar-500-page.html</location>
</error-page>
<!-- A custom error page for exception type org.myapp.foo.bar.MyException -->
<error-page>
<exception-type>org.myapp.foo.bar.MyException</exception-type>
<location>/my-foo-bar-exception-page.html</location>
</error-page>
...
</web-app>
</code></pre>
<br /><br />Simple enough - a couple of custom error pages defined for a specific error code and an exception type respectively. All of this works fine.<br /><br />In current days, more and more programming models and frameworks come into picture while developing web applications. CDI and JSF are some of those. CDI has this concept of scopes (ex: request scope, session scope, application scope, conversation scope). We won't go into the details of what those are and when those are used, but let's consider conversation scope in this blog since that's what the discussion was about in the forum thread that prompted this blog.<br /><br />So CDI allows multiple requests to be part of a "conversation scope". A conversation has a "start" and an "end", both of which can be managed by the application. When the application involves JSF, any conversation (id) gets auto-propagated to the JSF request(s). Apart from an explicit start/end demarcation of conversations, a conversation can also timeout. A request which refers to a conversation which has ended or timed out will run into an exception. <br /><br />So we know have a bit of background on CDI conversation scope. So let's consider a case where the application wants to present a good looking page when the "conversation no longer present" exception is thrown (maybe because of a timeout). We have seen how to write a web.xml for error-page configurations - it would be as simple as:<br /><br /><pre nbsp="" style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <web-app>
...
<!-- A custom error page for exception type org.jboss.weld.context.NonexistentConversationException -->
<error-page>
<exception-type>org.jboss.weld.context.NonexistentConversationException</exception-type>
<location>/my-foo-bar-exception-page.html</location>
</error-page>
...
</web-app>
</code></pre>
<br />Simple enough. The org.jboss.weld.context.NonexistentConversationException is the exception class type which gets thrown when the conversation has timed out (note that we are assuming that the web application is relying on Weld as the CDI spec implementation library). The above configuration works fine. The my-foo-bar-exception-page.html gets displayed when the org.jboss.weld.context.NonexistentConversationException is thrown.<br /><br />BUT, let's now consider that we want to involve JSF in the error page just like the other parts of our application. So let's point the error-page to a URL pattern which maps to the JSF servlet:<br /><br /><pre nbsp="" style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <web-app>
...
<!-- A custom error page for exception type org.jboss.weld.context.NonexistentConversationException -->
<error-page>
<exception-type>org.jboss.weld.context.NonexistentConversationException</exception-type>
<location>/my-foo-bar-exception-page.xhtml</location>
</error-page>
...
</web-app>
</code></pre>
<br />Note that we changed the error page mapping to my-foo-bar-exception-page.xhtml (notice the xhtml extension) from my-foo-bar-exception-page.html. We'll again assume that the .xhtml resources are mapped to the JSF servlet so those requests are considered as JSF requests.<br /><br />With this change to the web.xml, you'll notice that the my-foo-bar-exception-page.xhtml will no longer be displayed in you see a big stacktrace with repeatedly shows org.jboss.weld.context.NonexistentConversationException exception in the stacktrace thus giving an impression that the error-page configuration went wrong.<br /><br />So what did we do wrong? Well, remember that earlier I mentioned that for JSF requests the conversation id gets propagated automatically. That's exactly what's happening here. The server notices the org.jboss.weld.context.NonexistentConversationException exception and then tries to render the error-page which is backed by JSF and since the conversation id gets propagated the server tries to find that non-existent conversation and ends up failing with the same org.jboss.weld.context.NonexistentConversationException and ultimately fails to render the error page. It's like going in circles to render that error page.<br /><br />So how does one get past it? Keeping aside all the technical details, the obvious thing would be to not propagate the non-existent conversation id while rendering the (JSF backed) error page. So that's what we are going to do. CDI 1.1 (and Weld 1.1.2 and later) allows you to explicitly specify that a conversation shouldn't be propagated for a particular request. You can do this by passing along a parameter named "nocid" within that request. With that knowledge, let's now modify our web.xml to do the necessary changes so that our error page gets rendered properly:<br /><br /><br /><pre nbsp="" style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <web-app>
...
<!-- A custom error page for exception type org.jboss.weld.context.NonexistentConversationException.
Notice the "nocid" parameter being passed to make sure that the non-existent conversation id
isn't passed to the error page
-->
<error-page>
<exception-type>org.jboss.weld.context.NonexistentConversationException</exception-type>
<location>/my-foo-bar-exception-page.xhtml?nocid=true</location>
</error-page>
...
</web-app>
</code></pre>
<br />
<br />Notice that we are passing the "nocid" parameter as part of the query string of the error page location. The value for "nocid" parameter really doesn't matter but for the sake of keeping that value logical, we have used the value "true" here. Once this change is done, you'll start noticing that the error page (backed by JSF) now renders correctly!<br /><br />It took a while for us to get to this solution in that forum thread because it looked so simple that it should have "just worked", but it didnt' Here's the <a href="http://www.coderanch.com/t/602931/JBoss/handle-CDI-Conversation-expired-JBoss" target="_blank">forum thread at coderanch</a> that I've been talking about. Credit goes to <a href="http://www.coderanch.com/forums/user/profile/21098" target="_blank">Greg Charles</a> for figuring out how to pass that nocid parameter.<br /><br /><br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com4tag:blogger.com,1999:blog-30587633.post-71305040618545929312012-10-07T21:34:00.000+05:302012-10-07T21:35:29.252+05:30JBoss AS is being renamed<div dir="ltr" style="text-align: left;" trbidi="on">
Those of you who missed this year's JavaOne event and still haven't heard about it, here's some news that all <a href="http://www.jboss.org/jbossas/" target="_blank">JBoss AS</a> followers should be aware of - your favourite application server, JBoss AS, is being renamed.<br />
<br />
JBoss AS or just JBoss, as we have all called it since the 3.x days will now be called something else. The reasons for the rename have been explained in this <a href="http://www.jboss.org/vote/faq.html" target="_blank">"Why rename JBoss AS, FAQ?"</a>. Mark Little has blogged about the this rename in his posts <a href="https://community.jboss.org/blogs/mark.little/2012/10/01/announcing-the-renaming-of-jbossas" target="_blank">here</a> and <a href="https://community.jboss.org/blogs/mark.little/2012/10/06/jbossas-renaming" target="_blank">here</a>. Read through those pages to understand what's being proposed.<br />
<br />
So what's the new name going to be for the JBoss AS project? We don't know yet. In fact, the name will be picked by the community. Everyone is allowed to submit a name of their choice and those names will go through a voting process and one out of those names will be chosen. So if you can think of a name for JBoss AS then go suggest it <a href="http://www.jboss.org/rename.html" target="_blank">here</a> before the 14th of this month. Don't leave it for later, this is your chance to be known as the one who chose the new name!<br />
<br /></div>
Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com0tag:blogger.com,1999:blog-30587633.post-46255217685913256912012-02-17T15:11:00.000+05:302012-02-20T22:36:03.179+05:30JBoss AS 7.1.0.Final "Thunder" released - Java EE 6 Full Profile certified!<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxqE-hzYoRcTsBn86zOl8UN8lddAjW7beuHh8TrGYyKGV0JBLjG_GVxK2e6yCKO9U7lv2K88MX4OxQD8JRkXZPsD9pZ1I9wf58HcVfC05W6N9vlhcCebURGkKx0VY-2El4B-UDgw/s1600/AS7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxqE-hzYoRcTsBn86zOl8UN8lddAjW7beuHh8TrGYyKGV0JBLjG_GVxK2e6yCKO9U7lv2K88MX4OxQD8JRkXZPsD9pZ1I9wf58HcVfC05W6N9vlhcCebURGkKx0VY-2El4B-UDgw/s320/AS7.png" width="320" /></a></div>
<br />
After just about more than a year of development on JBoss AS7, we have now <a href="http://lists.jboss.org/pipermail/jboss-as7-dev/2012-February/005331.html" target="_blank">released 7.1.0.Final "Thunder"</a>! The download is available at the usual place <a href="http://www.jboss.org/jbossas/downloads.html" target="_blank">here</a>. This is a really big achievement for the JBoss AS7 team and we are really proud about this release.<br />
<br />
This release contains numerous bug fixes from 7.1.0.CR1b which was released a few months back. But the biggest news about this release is that <a href="http://www.oracle.com/technetwork/java/javaee/overview/compatibility-jsp-136984.html" target="_blank">JBoss AS 7.1.0.Final is Java EE 6 Full Profile certified</a>! I'm sure a lot of our users will be very happy about this news. AS 7.0.x was Web Profile certified but I have seen in the forums that many of you were waiting for the Full Profile certification to happen. So here's a very good reason to start using JBoss AS7, if you haven't done yet.<br />
<br />
Apart from the Full Profile certification, AS 7.1.0.Final contains a lot of bug fixes and other JIRA issues resolved. The entire release notes can be found <a href="https://community.jboss.org/wiki/AS710FinalReleaseNotes" target="_blank">here</a>.<br />
<br />
Like in some of my previous posts on AS7 releases, in this post I'll explain atleast one new feature of this release. Many of you would know that JBoss AS7 is very different compared to the previous JBoss AS versions, on various counts. One prominent difference is that we no longer have numerous XML files in the distribution, configuring various services. Instead we just have *one* single configuration file which governs the entire server. Furthermore, unlike previous JBoss AS versions, JBoss AS7 (prior to 7.1.0.Final) did not allow *deploying* XML files to configure datasources and JMS queues. However, the community members have been repeatedly asking for this feature and JBoss AS 7.1.0.Final now allows deploying of datasources and JMS queues via application specific XML files (in addition to configuring them centrally in the domain/standalone configuration file). So let's take a quick look at how it's done in 7.1.0.Final.<br />
<h4>
Deploying datasource via -ds.xml files in JBoss AS 7.1.0.Final</h4>
The datasource file is expected to end with the -ds.xml suffix, like in previous JBoss AS releases. You can place the *-ds.xml file in the JBOSS_HOME/standalone/deployments folder or even package it in the application under the META-INF folder of the application. If it's a .war application, then the *-ds.xml is expected to be right under the WEB-INF folder of the .war.<br />
<br />
The *-ds.xml is expected to follow the jboss-as-datasources xsd which looks like <a href="http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd" target="_blank">this</a>. So you have a datasources element under which you can define multiple datasource elements. In this example, we'll try and create a MySQL datasource and deploy it as mysql-ds.xml.<br />
<br />
Before creating the datasource, we first have to install the database driver. AS7 allows you install the database driver either as a deployment or as <a href="https://docs.jboss.org/author/display/MODULES/Home" target="_blank">JBoss Module</a>. For more details on this, see <a href="https://community.jboss.org/wiki/DataSourceConfigurationinAS7#Installing_the_JDBC_Driver" target="_blank">this article</a>. In this post, we'll deploy the driver as a JBoss Module.<br />
<br />
<h4>
Create and install the database driver</h4>
As a first step, we'll require the MySQL driver jar file. I downloaded the driver jar from the MySQL download site <a href="http://dev.mysql.com/downloads/connector/j/" target="_blank">here</a>. The step to create the JBoss Module for this driver involves creating a module.xml which looks like this and is named module.xml:<br />
<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <module xmlns="urn:jboss:module:1.1" name="mysql">
<resources>
<resource-root path="mysql-connector-java-5.1.18-bin.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
</code></pre>
We place the mysql-connector-java-5.1.18-bin.jar and this module.xml file in JBOSS_HOME/modules/mysql/main folder (you'll have to create the mysql/main folder). That completes the JBoss Module creation for the MySQL driver. Now let's install this driver so that it gets registered in the standalone/domain configurations. In this example, we'll be using the standalone server. So let's start the server using:<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> ./standalone.sh
</code></pre>
Once the server is up, let's open the Command Line Interface (CLI) utility which is shipped in AS7. The CLI startup script is in the JBOSS_HOME/bin folder and can be started as follows (more details about the CLI can be found <a href="https://docs.jboss.org/author/display/AS71/Admin+Guide#AdminGuide-CommandLineInterface" target="_blank">here</a>)<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> ./jboss-cli.sh --connect
</code></pre>
Once connected successfully, we'll add the jdbc-driver using the following command:<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> /subsystem=datasources/jdbc-driver=mysql-5-driver:add(driver-name=mysql-5-driver, driver-class-name=com.mysql.jdbc.Driver, driver-module-name=mysql)
</code></pre>
So here we are naming the driver as "mysql-5-driver" (you can name it anything). The driver-module-name points to the "mysql" JBoss Module that we created in previous step. The driver-class-name is the fully qualified classname of the MySQL driver. In this case, it's com.mysql.jdbc.Driver.<br />
<br />
A successful execution of that command will show the output as success:<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> [standalone@localhost:9999 /] /subsystem=datasources/jdbc-driver=mysql-5-driver:add(driver-name=mysql-5-driver, driver-class-name=com.mysql.jdbc.Driver, driver-module-name=mysql)
{"outcome" => "success"}
</code></pre>
The installation will be persisted in the configuration file which was used to start the server. In this case it's the standalone.xml and this is how it looks like after the driver has been installed:<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <subsystem xmlns="urn:jboss:domain:datasources:1.0">
...
<drivers>
...
<driver name="mysql-5-driver" module="mysql">
<driver-class>com.mysql.jdbc.Driver</driver-class>
</driver>
</drivers>
</datasources>
</subsystem>
</code></pre>
We are now done with the driver installation. Now let's move on and create the mysql-ds.xml file.<br />
<br />
<h4>
Create the mysql-ds.xml file</h4>
As previously mentioned, the mysql-ds.xml should follow the <a href="http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd" target="_blank">jboss-as-datasources xsd</a>. Here's how the file looks like in our case:<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> <?xml version="1.0" encoding="UTF-8"?>
<datasources>
<datasource jndi-name="java:jboss/datasources/MySQLDS" enabled="true" use-java-context="true"
pool-name="MySQLDS">
<connection-url>jdbc:mysql://localhost:3306/test</connection-url>
<driver>mysql-5-driver</driver>
<security>
<user-name>foo</user-name>
<password>bar</password>
</security>
</datasource>
</datasources>
</code></pre>
Let's see what that xml file contains. The "jndi-name" is the name to which the datasource will be bound to (you can use a name of your choice. Ideally, it would be good to bind them in java:jboss/datasources/ namespace). The "enabled=true" indicates that the datasource should be enabled after being deployed. The "use-java-context" attribute is used to indicate that the JNDI name should be bound under the java: namespace. The "connection-url" is the URL to be used for connecting to the MySQL database (check MySQL documentation for more details about the connection-url). The "driver" element points to the installed JDBC driver that we created in the previous step. In our example, we named it mysql-5-driver and that's what we use here. Finally, the "security" section contains the username and password information for connecting to the database. Make sure you use the appropriate values for all these configurations. <br />
<br />
So now let's place this mysql-ds.xml in the JBOSS_HOME/standalone/deployments folder and see JBoss AS7 hot deploy it (if the server is already running). The logs will show the following on successful deployment:<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> 14:05:55,829 INFO [org.jboss.as.server.deployment] (MSC service thread 1-3) JBAS015876: Starting deployment of "mysql-ds.xml"
14:05:55,847 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-2) JBAS010400: Bound data source [jboss/datasources/MySQLDS]
</code></pre>
So that's it! We have successfully deployed the MySQL datasource through a -ds.xml file in 7.1.0.Final!<br />
<br />
So <a href="http://www.jboss.org/jbossas/downloads.html" target="_blank">download</a> this new version and start deploying your applications and start using these features. We'll be blogging more about the features in this release, in the upcoming days (after the AS7 developers get some much needed sleep :) ). So keep an eye on the <a href="http://planet.jboss.org/view/all" target="_blank">jboss.org blogs</a>. If you run into any issues with AS7, feel free to visit our <a href="https://community.jboss.org/en/jbossas7?view=discussions" target="_blank">user forum</a> and ask for help.<br />
<br />
<div style="text-align: center;">
[<a href="http://www.jboss.org/as7">AS7 Home</a>] [<a href="https://issues.jboss.org/browse/AS7">AS7 JIRA</a>] [<a href="http://community.jboss.org/en/jbossas7?view=discussions">AS7 User Forum</a>] [<a href="https://docs.jboss.org/author/display/AS71/Documentation">AS7 documentation</a>] [<a href="http://www.jboss.org/jbossas/downloads.html">AS7 downloads</a>] [<a href="http://community.jboss.org/thread/167590">AS7 nightly builds</a>]<br />
<br /></div>
</div>Jaikiranhttp://www.blogger.com/profile/08503182723143814781noreply@blogger.com11