2022-11-04T09:56:09.000Z/categories/jakarta-ee/HexoJFall 2022http://www.ivonet.nl/2022/11/03/jfall-2022/2022-11-03T08:07:00.000Z2022-11-04T09:56:09.000Z<p><img src="/images/2022/jfall-2022/jfall-2022_1.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>An impression of JFall by yours truly.</p>
<a id="more"></a>
<h1 id="keynote"><a href="#keynote" class="headerlink" title="keynote"></a>keynote</h1><p>Sold out!</p>
<p><img src="/images/2022/jfall-2022/jfall-2022_2.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>Packet room!</p>
<p><img src="/images/2022/jfall-2022/jfall-2022.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_3.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>Very nice first keynote speaker by Saby Sengupta about the path to transform.<br>He is a really nice storyteller. He had us going. </p>
<blockquote>
<p>Dutch people, wooden shoes, wooden hat, would not listen</p>
<ul>
<li>Saby</li>
</ul>
</blockquote>
<p><strong>lol</strong></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_4.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>Get the answer to three <strong><strong>why</strong></strong> questions. If the answers stop after the first why. It may not be a good idea. </p>
<p><img src="/images/2022/jfall-2022/jfall-2022_5.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>This great first keynote is followed by the very well known Venkat Subramaniam about <strong>The Art of Simplicity</strong>. </p>
<p><img src="/images/2022/jfall-2022/jfall-2022_6.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_7.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>The question is not <strong>what can we add?</strong> But <strong>What can we remove?</strong></p>
<blockquote>
<p>Simple fails less</p>
<p>Simple is elegant</p>
</blockquote>
<p>All in al a great keynote! Loved it. </p>
<h1 id="Design-Patterns-in-the-light-of-Lambdas"><a href="#Design-Patterns-in-the-light-of-Lambdas" class="headerlink" title="Design Patterns in the light of Lambdas"></a>Design Patterns in the light of Lambdas</h1><p>By <strong>Venkat Subramaniam</strong></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_8.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<blockquote>
<p>The GOF are kind of the grand parents of our industry. The worst thing they have done is write the damn book.<br>— Venkat</p>
</blockquote>
<p>The quote is in the context of that writing down grandmas fantastic recipe does not work as it is based on the skill of grandma and not the exact amount of the ingredients. </p>
<p><img src="/images/2022/jfall-2022/jfall-2022_9.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_19.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_10.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>The cleanup is the responsibility of the Resource class. Much better than asking developers to take care of it. It will be forgotten!</p>
<p>The more powerful a language becomes the less we need to talk about patterns. Patterns become practices we use. We do not need to put in extra effort. </p>
<p>I love his way of presenting, but this is the one of those times - I guess - that he is hampered by his own succes. The talk did not go deep into stuff. During his talk I just about covered 5 not too difficult subjects. I missed his speed and depth.</p>
<p><strong>Still a great talk though.</strong></p>
<h1 id="lunch"><a href="#lunch" class="headerlink" title="lunch"></a>lunch</h1><p>Was actually very nice!</p>
<h1 id="NLJUG-update-keynote"><a href="#NLJUG-update-keynote" class="headerlink" title="NLJUG update keynote"></a>NLJUG update keynote</h1><p><img src="/images/2022/jfall-2022/jfall-2022_11.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>The Java Magazine was mentioned we (as Editors) had to shout for that! </p>
<p>Please contact me (@ivonet) if you have ambitions to either be an author or maybe even as a fellow editor of the magazine. We are searching for a new Editor now. </p>
<p>Then the voting for the Innovation Awards. </p>
<p>I kinda missed the next keynote by ING because I was playing with a rubix cube and I did not really like his talk</p>
<h1 id="jakarta-EE-10-platform"><a href="#jakarta-EE-10-platform" class="headerlink" title="jakarta EE 10 platform"></a>jakarta EE 10 platform</h1><p>by Ivar Grimstad</p>
<p><img src="/images/2022/jfall-2022/jfall-2022_12.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>Ivar talks about the specification of Jakarta EE. </p>
<p><img src="/images/2022/jfall-2022/jfall-2022_13.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_14.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_15.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>To create a <strong>lite</strong> version of CDI it is possible to start doing things at build time and facilitate other tools like GraalVM and Quarkus. </p>
<p><img src="/images/2022/jfall-2022/jfall-2022_16.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>He gives nice demos on how to migrate code to work in de jakarta namespace. </p>
<p>To start your own Jakarta EE application just go to <a href="https://start.jakarta.ee" target="_blank" rel="noopener">start.jakarta.ee</a> en follow the very simple UI instructions </p>
<p>I am very proud to be the creator of that UI. Thanks, Ivar for giving me a shoutout for that during your talk. More cool stuff will follow soon. </p>
<p><img src="/images/2022/jfall-2022/jfall-2022_17.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_20.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p><img src="/images/2022/jfall-2022/jfall-2022_21.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>Be prepared to do some namespace changes when moving from Java EE 8 to Jakarta EE. </p>
<p><img src="/images/2022/jfall-2022/jfall-2022_18.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>All slides <a href="https://www.slideshare.net/ivargrimstad/modern-and-lightweight-cloud-application-development-with-jakarta-ee-10" target="_blank" rel="noopener">here</a></p>
<h1 id="conclusion"><a href="#conclusion" class="headerlink" title="conclusion"></a>conclusion</h1><p>I had a fantastic day. For me, it is mainly about the community and seeing all the people I know in the community. I totally love the vibe of the conference and I think it is one of the best organized venues.</p>
<p>See you at JSpring.</p>
<p>Ivo.</p>
<p><img src="/images/2022/jfall-2022/jfall-2022_1.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>An impression of JFall by yours truly.</p>
Java EE - Jakarta EE Initializrhttp://www.ivonet.nl/2022/05/05/javaee---jakarta-ee-initializr/2022-05-05T14:22:32.000Z2022-05-05T14:23:40.000Z<!-- date: 2019-10-26 00:06:49 -->
<!-- date: 2022-04-15 00:00:41 -->
<p><img src="/images/2019/javaee---jakarta-ee-initializr/javaee---jakarta-ee-initializr.jpg" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>Getting started with Jakarta EE just became even easier!</p>
<h1 id="Get-started"><a href="#Get-started" class="headerlink" title="Get started"></a>Get started</h1><ul>
<li><a href="http://ivo2u.nl/oq" target="_blank" rel="noopener">Java EE /Jakarta EE - Initializr</a></li>
</ul>
<h1 id="Hot-new-Update"><a href="#Hot-new-Update" class="headerlink" title="Hot new Update!"></a>Hot new Update!</h1><p>Moved from the Apache 2 license to the Eclipse Public License v2 for the newest version of the archetype as described below.<br>As a start for a possible collaboration with the Eclipse <a href="https://start.jakarta.ee/" target="_blank" rel="noopener">start</a> project.</p>
<p><em>New Archetype with JakartaEE 9</em></p>
<p><strong>JakartaEE 9 + Payara 5.2022.2 + MicroProfile 4.1 running on Java 17</strong></p>
<ul>
<li>And the docker image is also ready for x86_64 (amd64) AND aarch64 (arm64/v8) architectures!</li>
</ul>
<!-- date: 2019-10-26 00:06:49 -->
<!-- date: 2022-04-15 00:00:41 -->
<p><img src="/images/2019/javaee---jakarta-ee-initializr/javaee---jaka
JakartaEE 8 + Payara 5 + MicroProfile 3 + Docker In about a minutehttp://www.ivonet.nl/2019/10/25/jakartaee-8-+-payara-5-+-microprofile-3-+-docker-in-about-a-minute/2019-10-25T21:40:40.000Z2022-03-19T08:15:24.000Z<h1 id="Thin-Wars-to-the-rescue"><a href="#Thin-Wars-to-the-rescue" class="headerlink" title="Thin Wars to the rescue"></a>Thin Wars to the rescue</h1><p><img src="/images/2019/java-ee-8-+-payara-5-+-microprofile-2.1-+-docker-in-about-a-minute/docker-payara.png" style="width: 50%;height: 50%;display: block;margin: 0 auto;"></p>
<p>It can be really easy to start on your JakartaEE application. It’ll take you about a minute…</p>
<p>In this minute you will get a project with:</p>
<ul>
<li>JakartaEE 8</li>
<li>MicroProfile 3.1</li>
<li>Preconfigured Payara 5 Full server docker container - <a href="https://hub.docker.com/r/ivonet/payara" target="_blank" rel="noopener">ivonet/payara</a></li>
<li>Maven essential setup</li>
<li>Run and build scripts for all of this</li>
</ul>
<a id="more"></a>
<h1 id="The-minute-has-started…"><a href="#The-minute-has-started…" class="headerlink" title="The minute has started…"></a>The minute has started…</h1><p>Enter the code below in a terminal were you want to create your project and press enter</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mvn archetype:generate \</span><br><span class="line"> -DarchetypeGroupId=nl.ivonet \</span><br><span class="line"> -DarchetypeArtifactId=jakartaee8-payara-microprofile-archetype \</span><br><span class="line"> -DarchetypeVersion=1.0 -U</span><br></pre></td></tr></table></figure>
<p>The first time you run this command, it will take just a bit more time as it will<br>download everything needed from the maven central repository.</p>
<p>you will be asked these questions:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Define value for property 'groupId': com.example</span><br><span class="line">Define value for property 'artifactId': helloworld</span><br><span class="line">Define value for property 'version' 1.0-SNAPSHOT: :</span><br><span class="line">Define value for property 'package' com.example: :</span><br><span class="line">Define value for property 'docker-hub-name': example</span><br></pre></td></tr></table></figure>
<p>Just follow the instructions and your project will be created:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> helloworld</span><br><span class="line">./run</span><br></pre></td></tr></table></figure>
<p>This will start the project in a docker container.<br>The docker container will be downloaded the first time and that might take more than the minute depending<br>on the speed of your internet connection.<br>After the first time it will only take seconds.</p>
<p>Now go to <a href="http://localhost:8080/helloworld/rest/example" target="_blank" rel="noopener">http://localhost:8080/<artifactid>/rest/example</artifactid></a> and you will have a working<br>example HelloWorld application.</p>
<p>Done 😄</p>
<h1 id="After-burner"><a href="#After-burner" class="headerlink" title="After burner"></a>After burner</h1><p>Now you can load it into your favorite IDE and start building your own stuff.<br>Don’t forget to read the README.md of the project to learn more about the available commands.</p>
<p>Have fun.</p>
<h1 id="Links"><a href="#Links" class="headerlink" title="Links"></a>Links</h1><ul>
<li><a href="https://mvnrepository.com/artifact/nl.ivonet/jakartaee8-payara-microprofile-archetype" target="_blank" rel="noopener">Maven Central</a></li>
<li><a href="https://github.com/IvoNet/jakartaee8-payara-microprofile-archetype" target="_blank" rel="noopener">Github</a></li>
</ul>
<h1 id="Thin-Wars-to-the-rescue"><a href="#Thin-Wars-to-the-rescue" class="headerlink" title="Thin Wars to the rescue"></a>Thin Wars to the rescue</h1><p><img src="/images/2019/java-ee-8-+-payara-5-+-microprofile-2.1-+-docker-in-about-a-minute/docker-payara.png" style="width: 50%;height: 50%;display: block;margin: 0 auto;"></p>
<p>It can be really easy to start on your JakartaEE application. It’ll take you about a minute…</p>
<p>In this minute you will get a project with:</p>
<ul>
<li>JakartaEE 8</li>
<li>MicroProfile 3.1</li>
<li>Preconfigured Payara 5 Full server docker container - <a href="https://hub.docker.com/r/ivonet/payara" target="_blank" rel="noopener">ivonet/payara</a></li>
<li>Maven essential setup</li>
<li>Run and build scripts for all of this</li>
</ul>
Payara 5 in docker with autodeploy functionhttp://www.ivonet.nl/2019/02/06/payara-5-docker-and-autodeployment/2019-02-06T15:52:29.000Z2022-03-19T08:15:24.000Z<p>I wanted to play around with going back to the roots of java(EE) and wanted to take the docker part a step further.<br>Why not have the platform as a docker image in such a way that when building the project the docker image will take care of the<br>deployment automatically after each build.</p>
<a id="more"></a>
<h1 id="Goal"><a href="#Goal" class="headerlink" title="Goal"></a>Goal</h1><ul>
<li>Building a Java EE application as easy as possible</li>
<li>Have all the cool stuff available from MicroProfile</li>
<li>Stay as close to the core as possible.</li>
</ul>
<h1 id="Prerequisites"><a href="#Prerequisites" class="headerlink" title="Prerequisites"></a>Prerequisites</h1><ul>
<li>Docker installed</li>
<li>Java 8 installed</li>
<li>IDE</li>
<li>A sense of adventure :-)</li>
</ul>
<h1 id="Steps"><a href="#Steps" class="headerlink" title="Steps"></a>Steps</h1><h2 id="Payara-docker-image"><a href="#Payara-docker-image" class="headerlink" title="Payara docker image"></a>Payara docker image</h2><p>I wanted to make a docker image with Payara 5 on it. See <a href="http://ivo2u.nl/ty" target="_blank" rel="noopener">this</a> blog for more information on it.<br>It has to be configurable is such a way that it does not need to be rebuild every time I create an artifact.<br>Assume that the war I create will be deployed on a similar server and that I don’t need to deploy the<br>whole platform every time. So I don’t want to build my docker image every time either<br>when programming and building my application.</p>
<p>So I need:</p>
<ul>
<li>Payara as a docker image -> <code>ivonet/payara:5.184</code></li>
<li>a way to deploy automatically after each maven build</li>
<li>have it exposed to the local machine</li>
</ul>
<p>In the <a href="http://ivo2u.nl/tM" target="_blank" rel="noopener">image</a> a link has been created between <code>/autodeploy</code> and the actual autodeploy diretory in the image (see the <a href="http://ivo2u.nl/tK" target="_blank" rel="noopener">Dockerfile</a> for more information). This is done for<br>convenience and ease of reading. Now you can mount this directory as a volume.</p>
<h2 id="How-to-get-auto-deploy-working"><a href="#How-to-get-auto-deploy-working" class="headerlink" title="How to get auto deploy working?"></a>How to get auto deploy working?</h2><p>In order to do this I have chosen to add a very small part to my maven java project to facilitate the autodeploy feature. </p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span></span><br><span class="line"> ...</span><br><span class="line"> <span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">finalName</span>></span>${artifactId}<span class="tag"></<span class="name">finalName</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> ...</span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.maven.plugins<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>maven-war-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>3.1.0<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">failOnMissingWebXml</span>></span>false<span class="tag"></<span class="name">failOnMissingWebXml</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">warName</span>></span>${project.build.finalName}<span class="tag"></<span class="name">warName</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">outputDirectory</span>></span>artifact<span class="tag"></<span class="name">outputDirectory</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> ...</span><br><span class="line"> <span class="tag"></<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">build</span>></span></span><br><span class="line"> ...</span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure>
<p>When executing <code>mvn package</code> it will build the war file but also copy the final artifact to the<br><code><project>/artifact</code> directory.</p>
<p>When starting the created docker container (from the project directory) we can now make sure<br>that it will mount the <code><project>/artifact</code> directory to the <code>/autodeploy</code> container directory.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --name payara \</span><br><span class="line"> -p 8080:8080 \</span><br><span class="line"> -p 4848:4848 \</span><br><span class="line"> -v $(<span class="built_in">pwd</span>)/artifact:/autodeploy \</span><br><span class="line"> ivonet/payara:5.184</span><br></pre></td></tr></table></figure>
<p>This command will run the Payara 5 Full profile server in daemon mode, with the <code><project>/artifact</code> folder mounted as a folder to<br>its inner <code>/autodeploy</code> directory.</p>
<p>Now if you build your project:</p>
<pre><code class="bash">mvn clean package
</code></pre>
<p>it will build the war in the target folder and the plugin defined in the pom.xml file will make sure that the artifact is copied to the <code><project>/artifact</code> directory<br>The Payara server is monitoring that folder because it has been mounted to its autodeploy directory and it will see<br>a new artifact in the directory. Now it will autodeploy that artifact with the artifact name as the rootContext.</p>
<p>So if you project is called <code>HelloWorld</code> the artifact will be called <code>./artifact/HelloWorld.war</code> and the url for Payara will become<br><code>http://localhost:8080/HelloWorld</code>.</p>
<p>Every time you rebuild the project with the maven commando’s payara will redeploy the artifact as it will recognise that it has changed.<br>Now you can build and test your software without having to build a new image every time while still testing against the final environment.</p>
<p>Pretty cool if I do say so myself 😄</p>
<p>Have fun,</p>
<p>Ivo.</p>
<h1 id="Note"><a href="#Note" class="headerlink" title="Note"></a>Note</h1><p>While creating the image I had started out with a small alpine openjdk 1.8 docker image,<br>but to my dismay it threw this error <code>java.lang.NoClassDefFoundError: sun/security/ssl/SupportedEllipticCurvesExtension</code><br>when I tried to enable the remote Admin console. In the end I got it to work on a CentOs with a java 1.8.0_191 version<br>installed on it.<br>I must say that it was a big surprise for me that this bug was there and I will try again with standard<br>OpenJdk versions at a later date as I also want to migrate to Java 11+ but for now it is what it is 😄</p>
<h1 id="Maven-Archetype"><a href="#Maven-Archetype" class="headerlink" title="Maven Archetype"></a>Maven Archetype</h1><p>This feature is also used in projects generated with this <a href="http://ivo2u.nl/ty" target="_blank" rel="noopener">Maven Archetype</a>.</p>
<p>I wanted to play around with going back to the roots of java(EE) and wanted to take the docker part a step further.<br>Why not have the platform as a docker image in such a way that when building the project the docker image will take care of the<br>deployment automatically after each build.</p>
JavaEE 8 + Payara 5 + Microprofile 2.1 + Docker In about a minutehttp://www.ivonet.nl/2019/02/05/java-ee-8-+-payara-5-+-microprofile-2.1-+-docker-in-about-a-minute/2019-02-05T20:48:03.000Z2022-03-19T08:17:20.000Z<h1 id="Thin-Wars-to-the-rescue"><a href="#Thin-Wars-to-the-rescue" class="headerlink" title="Thin Wars to the rescue"></a>Thin Wars to the rescue</h1><p><img src="/images/2019/java-ee-8-+-payara-5-+-microprofile-2.1-+-docker-in-about-a-minute/docker-payara.png" style="width: 50%;height: 50%;display: block;margin: 0 auto;"></p>
<p>It can be really easy to start on your JavaEE / JakartaEE application. It’ll take you about a minute…</p>
<p>In this minute you will get a project with:</p>
<ul>
<li>JavaEE 8</li>
<li>MicroProfile 2.1</li>
<li>Preconfigured Payara 5 Full server docker container - <a href="https://hub.docker.com/r/ivonet/payara" target="_blank" rel="noopener">ivonet/payara:5.184</a></li>
<li>Maven essential setup</li>
<li>Run and build scripts for all of this</li>
</ul>
<a id="more"></a>
<h1 id="The-minute-has-started…"><a href="#The-minute-has-started…" class="headerlink" title="The minute has started…"></a>The minute has started…</h1><p>Enter the code below in a terminal were you want to create your project and press enter</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mvn archetype:generate \</span><br><span class="line"> -DarchetypeGroupId=nl.ivonet \</span><br><span class="line"> -DarchetypeArtifactId=jakartaee8-payara-microprofile-archetype \</span><br><span class="line"> -DarchetypeVersion=1.0 -U</span><br></pre></td></tr></table></figure>
<p>The first time you run this command, it will take just a bit more time as it will<br>download everything needed from the maven central repository.</p>
<p>you will be asked these questions:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Define value for property 'groupId': com.example</span><br><span class="line">Define value for property 'artifactId': helloworld</span><br><span class="line">Define value for property 'version' 1.0-SNAPSHOT: :</span><br><span class="line">Define value for property 'package' com.example: :</span><br><span class="line">Define value for property 'docker-hub-name': example</span><br></pre></td></tr></table></figure>
<p>Just follow the instructions and your project will be created:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> helloworld</span><br><span class="line">./run</span><br></pre></td></tr></table></figure>
<p>This will start the project in a docker container.<br>The docker container will be downloaded the first time and that might take more than the minute depending<br>on the speed of your internet connection.<br>After the first time it will only take seconds.</p>
<p>Now go to <a href="http://localhost:8080/helloworld/rest/example" target="_blank" rel="noopener">http://localhost:8080/<artifactid>/rest/example</artifactid></a> and you will have a working<br>example HelloWorld application.</p>
<p>Done 😄</p>
<h1 id="After-burner"><a href="#After-burner" class="headerlink" title="After burner"></a>After burner</h1><p>Now you can load it into your favorite IDE and start building your own stuff.<br>Don’t forget to read the README.md of the project to learn more about the available commands.</p>
<p>Have fun.</p>
<h1 id="Links"><a href="#Links" class="headerlink" title="Links"></a>Links</h1><ul>
<li><a href="https://mvnrepository.com/artifact/nl.ivonet/jakartaee8-payara-microprofile-archetype" target="_blank" rel="noopener">Maven Central</a></li>
<li><a href="https://github.com/IvoNet/jakartaee8-payara-microprofile-archetype" target="_blank" rel="noopener">Github</a></li>
</ul>
<h1 id="Thin-Wars-to-the-rescue"><a href="#Thin-Wars-to-the-rescue" class="headerlink" title="Thin Wars to the rescue"></a>Thin Wars to the rescue</h1><p><img src="/images/2019/java-ee-8-+-payara-5-+-microprofile-2.1-+-docker-in-about-a-minute/docker-payara.png" style="width: 50%;height: 50%;display: block;margin: 0 auto;"></p>
<p>It can be really easy to start on your JavaEE / JakartaEE application. It’ll take you about a minute…</p>
<p>In this minute you will get a project with:</p>
<ul>
<li>JavaEE 8</li>
<li>MicroProfile 2.1</li>
<li>Preconfigured Payara 5 Full server docker container - <a href="https://hub.docker.com/r/ivonet/payara" target="_blank" rel="noopener">ivonet/payara:5.184</a></li>
<li>Maven essential setup</li>
<li>Run and build scripts for all of this</li>
</ul>
Migrate From Java 6 To Java 8http://www.ivonet.nl/2018/06/20/migrate-from-java-6-to-java-8/2018-06-20T20:15:00.000Z2019-02-12T21:25:30.000Z<p><img src="/images/2018/migrate-from-java-6-to-java-8/migration.png" style="width: 50%;height: 50%;display: block;margin: 0 auto;"></p>
<p>Java 1.6 is almost at the end of the extended support period and will therefore be end of life soon.</p>
<blockquote>
<p>In April 2014 Oracle extended the support lifetime for Java SE 6. End of Premier Support on Dec 2015, and End of Extended Support on Dec 2018.<br>– <a href="http://www.oracle.com/technetwork/java/javase/eol-135779.html" target="_blank" rel="noopener">Oracle</a></p>
</blockquote>
<p>This article will try to give pointers to make a transition to Java 8 go smoothly.<br>What to expect and what to be alert for.<br>I will also try to explain why migration to java 9 or 10 is not advisable at the time writing this article.</p>
<a id="more"></a>
<h1 id="Migration"><a href="#Migration" class="headerlink" title="Migration"></a>Migration</h1><p>As java 1.6 (or java 6) is amost EOL (End Of Life) it becomes more and more important to migrate to a newer version.<br>At the time of writing this article Java 10 is the newest official release. Een though that is a fact it is not advisable<br>to migrate to that version, as Java 10 is not a so called LTS (Long Term Support) version.<br>As soon as a new version is available support for version 10 will stop. Java has started on a half year release cycle,<br>so support for version 10 wil stop in September this year.</p>
<p>Java 8 is an LTS version and also the version currently used by almost the whole world. It also is the closest to<br>Java 6 in architecture. It will also have Premium support until March 2022 and extended support until March 2025.<br>So the safest bet for now. </p>
<p>Java 11 will be an LTS release, but migration to that version will probably have more impact than can now be safely be impacted.</p>
<h1 id="Java-8-language-changes"><a href="#Java-8-language-changes" class="headerlink" title="Java 8 language changes"></a>Java 8 language changes</h1><ul>
<li>From Imperative to Functional<ul>
<li>Modern constructs other newer languages use</li>
<li>Enhance code readability</li>
<li>Strip out boilerplate code</li>
</ul>
</li>
<li>From Sequential to Parallel<ul>
<li>execute code in parallel without extra effort</li>
<li>divide problems into smaller pieces, solving these simultaneously and combining the results</li>
<li>aggregate operations</li>
</ul>
</li>
</ul>
<h2 id="Major-new-Features-Changes"><a href="#Major-new-Features-Changes" class="headerlink" title="Major new Features / Changes"></a>Major new Features / Changes</h2><ul>
<li>Virtual extension methods (interface evolution is now possible)</li>
<li>Lambdas</li>
<li>Method reference</li>
<li>Streams</li>
<li>Collections </li>
<li>DateTime API</li>
<li>Functional Interfaces</li>
</ul>
<p>There are more features but the goal of this article is migration and not a comprehensive feature list</p>
<h2 id="Compatibility-guide"><a href="#Compatibility-guide" class="headerlink" title="Compatibility guide"></a>Compatibility guide</h2><p>If you want to know the nitty-gritty of all the differences and the compatibility between the versions you can<br>look <a href="http://www.oracle.com/technetwork/java/javase/8-compatibility-guide-2156366.html" target="_blank" rel="noopener">here</a></p>
<h2 id="Migration-1"><a href="#Migration-1" class="headerlink" title="Migration"></a>Migration</h2><p>If you want to just have your code work on Java 8 as soon as possible with as little change as possible that is possible,<br>because of the backwards compatibility, but when maintaining it is very advisable to refactor to the new features.<br>But first you need to have your code migrated… </p>
<p>If you do want to migrate to java 10 you can find some guidelines <a href="https://docs.oracle.com/javase/10/migrate/toc.htm#JSMIG-GUID-7744EF96-5899-4FB2-B34E-86D49B2E89B6" target="_blank" rel="noopener">here</a></p>
<h1 id="Plan-of-action"><a href="#Plan-of-action" class="headerlink" title="Plan of action"></a>Plan of action</h1><h2 id="Compile"><a href="#Compile" class="headerlink" title="Compile"></a>Compile</h2><p>On a developer machine install Java 8 and try to compile (and unit test) the code against the newer Java version and see what happends.<br>Odds are that if you have no compile errors your code will function fine without any other changes.</p>
<blockquote>
<p>Java SE 8 is strongly compatible with previous versions of the Java platform.<br>Almost all existing programs should run on Java SE 8 without modification.<br>However, there are some minor potential incompatibilities in the<br>JRE and JDK that involve rare circumstances and “corner cases”<br>that are documented here for completeness.<br>– <a href="http://www.oracle.com/technetwork/java/javase/8-compatibility-guide-2156366.html#A999198" target="_blank" rel="noopener">oracle</a> </p>
</blockquote>
<p>If you follow the link in the quote you can read more about these corner cases if they occur.</p>
<p>So if your application does nothing really weird chances are very good that all code will run fine on java 8.</p>
<p>You might also need to upgrade tools like maven and configure the test environment to work with Java 8, but this is often one<br>of the easiest tests.</p>
<p>Of course there is also chance your code won’t compile even thought great care is taken to make versions backwards<br>compatible. Version 9 is the first version breaking this tradition. In the case of not compiling code you will probably get<br>stacktrace(s) giving you hints… Trouble shooting starts at this point :-)</p>
<p>Some of the more notable incompatibilities are found in the <code>sun.*</code> packages. These packages should have been “private”<br>packages for a long time so if you use these you might run into trouble.</p>
<h2 id="SonarQube-PMD-Checkstyle"><a href="#SonarQube-PMD-Checkstyle" class="headerlink" title="SonarQube / PMD / Checkstyle"></a>SonarQube / PMD / Checkstyle</h2><p>If your code compiles you might want to run it though the newest version of SonarQube and look at the results carefully.<br>This is a great way to learn about new features and pitfalls when migrating. It should be noted that this works best if your code<br>was “clean” when still running under java 1.6. If your code has never been statically tested before by tools like SonarQube, you<br>might not want to look at what is found in either version 😂. You might not like what you see…</p>
<p>You can read more on this subject <a href="http://ivo2u.nl/5E" target="_blank" rel="noopener">here</a></p>
<h2 id="Deploy-your-application"><a href="#Deploy-your-application" class="headerlink" title="Deploy your application"></a>Deploy your application</h2><p>During deployment you might find other issues, like version incompatibility between e.g. application server and newly compiled<br>java application.</p>
<p>During the migration process you need to know what the middleware like Websphere, Tomcat, Glassfish, Wildfly, Payara,<br>JBoss and the like your application is running on and if they need to upgrade as well to stay compatible with the new version of java.</p>
<p>If all works fine and regression tests have not found anything, you have successfully done a migration. </p>
<p>Finished though you are not!</p>
<h1 id="Migration-done-now-lets-migrate"><a href="#Migration-done-now-lets-migrate" class="headerlink" title="Migration done now lets migrate"></a>Migration done now lets migrate</h1><p>Just because the base migration was successful does not mean that all the work is done. Now the real work begins.<br>Writing to the new features of the language and migrating to the new features. Luckily it does not have to be done all at once.</p>
<p>Every time a piece of code needs to change because of a request for change you might want to use the boy-scout<br>rule (leave the ground you play on cleaner than you found it). Cleaning a small piece of code by introducing Java 8 features.</p>
<h2 id="Using-Java-8-features"><a href="#Using-Java-8-features" class="headerlink" title="Using Java 8 features"></a>Using Java 8 features</h2><h3 id="Lambdas"><a href="#Lambdas" class="headerlink" title="Lambdas"></a>Lambdas</h3><p>Lambdas enable the programmer to eliminate a lot of boilerplate code and make code much more readable. This article will<br>not explain how Lambdas are to be used.</p>
<ul>
<li>Streams and filters</li>
</ul>
<p><code>java.util.Stream</code> provides a pipeline with filters with intermediate (map, filter, sorted, etc.) or terminal (forEach,<br>sum, reduce, findFirst, etc) steps.</p>
<ul>
<li>Identify for loops and replace them with the Stream <code>forEach</code>. This notation makes it possible to introduce concurrency<br>and focuses on the how not what should be done.</li>
</ul>
<p>e.g. old versus new style</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">oldCountByZip</span><span class="params">(<span class="keyword">final</span> String zip)</span> </span>{</span><br><span class="line"> <span class="keyword">long</span> count = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">final</span> Person person : persons) {</span><br><span class="line"> <span class="keyword">if</span> (person.getZip().equals(zip)) {</span><br><span class="line"> count++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> count;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">newCountByZip</span><span class="params">(<span class="keyword">final</span> String zip)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> persons</span><br><span class="line"> .stream()</span><br><span class="line"> .parallel()</span><br><span class="line"> .map(Person::getZip)</span><br><span class="line"> .filter(s -> s.equals(zip))</span><br><span class="line"> .count();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ul>
<li>This is just a basic example but does demonstrate that you can map the the object you wanted by method reference<br>(the <code>Person::getZip</code> notation) and introduce concurrency (<code>.parallell()</code>) and filter on what you wanted and then count.<br>The beauty of this notation is that you can explain it easily to a non technical person without really having to explain<br>what but only the how.</li>
<li>The more you start using the new notation the more you will get used to it and start to love it, unless you were already used<br>to these features in another language, then it might still seem quite verbose 😄.</li>
</ul>
<h3 id="DateTime-API"><a href="#DateTime-API" class="headerlink" title="DateTime API"></a>DateTime API</h3><p>The Date and Time API has had a major overhaul in Java 8 and makes e.g. Jodatime not necessary anymore as it is really good.<br>You might want to consider migration to the new API as it is the standard and you might be able to eliminate some converters.</p>
<h1 id="Listen-to-your-IDE"><a href="#Listen-to-your-IDE" class="headerlink" title="Listen to your IDE"></a>Listen to your IDE</h1><p>Your IDE will be a lot of help to you during migration. If you use one of the better once (e.g. IntelliJ) it will tell you,<br>when you can refactor to lambdas or method reference. Just listen and utilize 😂 and live long and prosper 🖖.<br>Some stuff like the diamond <code><></code> notation can be easily refactored over all classes by good IDE’s.<br>Just run an inspection on your code and see what happens…</p>
<h1 id="Tests-are-your-friends"><a href="#Tests-are-your-friends" class="headerlink" title="Tests are your friends"></a>Tests are your friends</h1><p>If you have lots of good unit tests before migration you will gain confidence much easier than when you don’t have them.</p>
<p>Test are your friends!</p>
<h1 id="More"><a href="#More" class="headerlink" title="More"></a>More</h1><p>Of course there is a lot more to think of during a migration like:</p>
<ul>
<li>Education of your employees<ul>
<li>Only some of the new features are mentioned in this article.</li>
<li>are they already aware or not?</li>
</ul>
</li>
<li>Middleware -> is the middleware up to par?</li>
<li>Hardware -> most hardware capable of running java 6 can also run java 8, but is it enough?</li>
<li>OS Upgrades -> sometimes an OS upgrade is necessary in order to install java 8 (e.g. RedHat)</li>
<li>Oh did I mention that tests are your friends?</li>
</ul>
<h1 id="Discussion"><a href="#Discussion" class="headerlink" title="Discussion"></a>Discussion</h1><p>If you have comments of more tips please let me know in the comments below…</p>
<p><img src="/images/2018/migrate-from-java-6-to-java-8/migration.png" style="width: 50%;height: 50%;display: block;margin: 0 auto;"></p>
<p>Java 1.6 is almost at the end of the extended support period and will therefore be end of life soon.</p>
<blockquote>
<p>In April 2014 Oracle extended the support lifetime for Java SE 6. End of Premier Support on Dec 2015, and End of Extended Support on Dec 2018.<br>– <a href="http://www.oracle.com/technetwork/java/javase/eol-135779.html" target="_blank" rel="noopener">Oracle</a></p>
</blockquote>
<p>This article will try to give pointers to make a transition to Java 8 go smoothly.<br>What to expect and what to be alert for.<br>I will also try to explain why migration to java 9 or 10 is not advisable at the time writing this article.</p>
SonarQube Just Do It!http://www.ivonet.nl/2018/01/20/sonarqube-just-do-it/2018-01-20T20:44:00.000Z2020-05-14T07:56:12.000Z<p><img src="/images/2018/sonarqube-just-do-it/docker_maven_sonarqube.png" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<h1 id="Code-transparency-…-Yes-please…"><a href="#Code-transparency-…-Yes-please…" class="headerlink" title="Code transparency … Yes please…"></a>Code transparency … Yes please…</h1><p>Recently I gave a small seminar for my current client about Clean Code and Craftsmanship. The group I was talking to<br>consisted of developers of all levels from junior to senior. </p>
<p>To my complete consternation, when I started talking about tools like PMD / CheckStyle and SonarQube, I found out that<br><em>none</em> of them had ever heard of these tools. Not even the Senior developers. </p>
<p>Well this is bad and needs to be fixed!<br><a id="more"></a></p>
<p>This article will give a short explanation about what SonarQube is.<br>It is also a quick guide on how to start working with it.<br>This will be done with the use of docker because I want to :-) </p>
<p>Prerequisites:</p>
<ul>
<li>docker(-compose)</li>
<li>maven</li>
<li>java</li>
</ul>
<h1 id="What-is-SonarQube"><a href="#What-is-SonarQube" class="headerlink" title="What is SonarQube?"></a>What is SonarQube?</h1><p>This is what SonarQube has to say about it.</p>
<blockquote>
<p><em><em>Continues Inspection</em></em><br>SonarQube provides the capability to not only show health of an application but also to highlight issues newly<br>introduced. With a Quality Gate in place, you can fix the leak and therefore improve code quality systematically.</p>
</blockquote>
<h2 id="How"><a href="#How" class="headerlink" title="How?"></a>How?</h2><p>SonarQube will analyse your code by analysing it statically. Without knowing the inner workings of your application it will<br>“look” at your code and search for code constructions that are known to be fragile or just wrong. After the scan<br>it will generate a report in the form of a browseable website. All issues are explained and you are probably also provided<br>a possible solution for it.</p>
<p>Example:</p>
<p>Noncompliant code: “for” loop increment clauses should modify the loops’ counters</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < <span class="number">10</span>; j++) { <span class="comment">// Noncompliant</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> i++; </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Lots of these language constructions can be tested statically and at the point of this writing there are 423 checks done.</p>
<p><img src="/images/sonarqube-just-do-it.md_1.png" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<h2 id="Use-it-yourself"><a href="#Use-it-yourself" class="headerlink" title="Use it yourself"></a>Use it yourself</h2><p>With docker it is very easy to start your own SonarQube service:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --rm --name sonarqube -p 9000:9000 -p 9092:9092 sonarqube:alpine</span><br></pre></td></tr></table></figure>
<p>The command provided above will erase all history when stopped, but for learning purposes and demo’s that is fine.<br>Farther below I will give some more permanent solutions for local use and some hints for enterprise use.</p>
<p>now go to your maven project and run:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mvn sonar:sonar -Dsonar.host.url=http://localhost:9000</span><br></pre></td></tr></table></figure>
<p>If maven the tells you that the build was successful, you can go look on <a href="http://localhost:9000" target="_blank" rel="noopener">localhost:9000</a> and<br>be amazed at how good or bad your code is. </p>
<h1 id="Take-time"><a href="#Take-time" class="headerlink" title="Take time"></a>Take time</h1><p>If you are willing to take the time to really look into the found issues (yes even the ‘info’ ones) and willing to<br>go and fix these issues, you are on the way to becoming a better developer.</p>
<h2 id="Positive-effect-on-a-team"><a href="#Positive-effect-on-a-team" class="headerlink" title="Positive effect on a team"></a>Positive effect on a team</h2><p>The beauty of using a tool like Sonar is that it will also keep history when configured correctly and therefore provide<br>you with a way of monitoring improvement. If you see improvements and also demonstrate this during sprint reviews, you<br>will start to notice a marked positive effect on your team. Team members will be more proud of the code they are writing<br>and become better as a group. Reviews will start to take code quality into account.</p>
<h2 id="Quality-Gate"><a href="#Quality-Gate" class="headerlink" title="Quality Gate"></a>Quality Gate</h2><p>When you have a level of quality reached where you are comfortable you don’t want to loose it. This is the moment you<br>can introduce the use of a quality gate. This is a level of quality you can define for your project and if the code does<br>not meet the requirements set by the Quality Gate the build will fail. So that is the moment that Code quality might<br>fail the build. A very powerful thing and one that raises the maturity level of the team significantly.</p>
<h1 id="More-advanced-examples"><a href="#More-advanced-examples" class="headerlink" title="More advanced examples"></a>More advanced examples</h1><h2 id="Local-with-database"><a href="#Local-with-database" class="headerlink" title="Local with database"></a>Local with database</h2><p>If you are done with the above provided commands and you want a more permanent solution for your local projects but don’t<br>want to have to create a complete pipeline just for your hobby projects…</p>
<p>We need a database image and the sonar image.</p>
<p>Here the <code>docker-compose.yml</code> file containing the two images and their connections</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">"3"</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line"><span class="attr"> sonarqube:</span></span><br><span class="line"><span class="attr"> image:</span> <span class="string">sonarqube</span></span><br><span class="line"><span class="attr"> ports:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">"9000:9000"</span></span><br><span class="line"><span class="attr"> networks:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">sonarnet</span></span><br><span class="line"><span class="attr"> environment:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">SONARQUBE_JDBC_URL=jdbc:postgresql://database:5432/sonar</span></span><br><span class="line"><span class="attr"> volumes:</span></span><br><span class="line"><span class="attr"> - sonarqube_conf:</span><span class="string">/opt/sonarqube/conf</span></span><br><span class="line"><span class="attr"> - sonarqube_data:</span><span class="string">/opt/sonarqube/data</span></span><br><span class="line"><span class="attr"> - sonarqube_extensions:</span><span class="string">/opt/sonarqube/extensions</span></span><br><span class="line"><span class="attr"> - sonarqube_bundled-plugins:</span><span class="string">/opt/sonarqube/lib/bundled-plugins</span></span><br><span class="line"></span><br><span class="line"><span class="attr"> database:</span></span><br><span class="line"><span class="attr"> image:</span> <span class="string">postgres</span></span><br><span class="line"><span class="attr"> networks:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">sonarnet</span></span><br><span class="line"><span class="attr"> environment:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">POSTGRES_USER=sonar</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">POSTGRES_PASSWORD=sonar</span></span><br><span class="line"><span class="attr"> volumes:</span></span><br><span class="line"><span class="attr"> - postgresql:</span><span class="string">/var/lib/postgresql</span></span><br><span class="line"> <span class="comment"># This needs explicit mapping due to https://github.com/docker-library/postgres/blob/4e48e3228a30763913ece952c611e5e9b95c8759/Dockerfile.template#L52</span></span><br><span class="line"><span class="attr"> - postgresql_data:</span><span class="string">/var/lib/postgresql/data</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line"><span class="attr"> sonarnet:</span></span><br><span class="line"><span class="attr"> driver:</span> <span class="string">bridge</span></span><br><span class="line"></span><br><span class="line"><span class="attr">volumes:</span></span><br><span class="line"><span class="attr"> sonarqube_conf:</span></span><br><span class="line"><span class="attr"> sonarqube_data:</span></span><br><span class="line"><span class="attr"> sonarqube_extensions:</span></span><br><span class="line"><span class="attr"> sonarqube_bundled-plugins:</span></span><br><span class="line"><span class="attr"> postgresql:</span></span><br><span class="line"><span class="attr"> postgresql_data:</span></span><br></pre></td></tr></table></figure>
<p>This image creates volumes for all stuff needed to be saved.</p>
<p>Lets start it up. </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up -d</span><br></pre></td></tr></table></figure>
<p>You can leave of the <code>-d</code> if you want to see what’s happening. It will start in the foreground and not in ‘detached’ mode.</p>
<p>Now if you stop the containers it will preserve the state of your database in the volumes defined.</p>
<p>To stop the containers go back to your <code>docker-compose.yml</code> file and do:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose down</span><br></pre></td></tr></table></figure>
<p>And if you want to loose all your data (volumes) too:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose down -v</span><br></pre></td></tr></table></figure>
<h2 id="Pipeline"><a href="#Pipeline" class="headerlink" title="Pipeline"></a>Pipeline</h2><p>If you use tools like Jenkins to control your pipeline it is very useful to add SonarQube as part of the pipeline setup.<br>If you do not have control over the pipeline environment, you should ask the Ops guys to install Sonar for you. If you do have<br>control over the pipeline, it is a very good idea to make it part of it. It will make code quality something as part of your<br>daily life. Jenkins has good integration for tools like sonar and configuring it is not the obstacle it might seem.</p>
<h2 id="Just-maven"><a href="#Just-maven" class="headerlink" title="Just maven"></a>Just maven</h2><p>You don’t have to do anything to have sonar working for maven. It is one of the default plugins (it is that important yes!) and always available<br>for all projects. You just have to tell it where sonar ‘lives’ and this can be done through the command line (see above).<br>If you want to just be able to do <code>mvn sonar:sonar</code> you can tell maven where sonar lives by editing the <code>$HOME/.m2/settings.xml</code> file<br>by adding the following piece of code to it:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">profiles</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">profile</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>sonar<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">properties</span>></span></span><br><span class="line"> <span class="comment"><!--<sonar.jdbc.url>jdbc:postres://localhost:3306/sonar</sonar.jdbc.url>--></span></span><br><span class="line"> <span class="comment"><!--<sonar.jdbc.driver>com.mysql.jdbc.Driver</sonar.jdbc.driver>--></span></span><br><span class="line"> <span class="comment"><!--<sonar.jdbc.username>sonar</sonar.jdbc.username>--></span></span><br><span class="line"> <span class="comment"><!--<sonar.jdbc.password>xxxxx</sonar.jdbc.password>--></span></span><br><span class="line"> <span class="comment"><!-- SERVER ON A REMOTE HOST --></span></span><br><span class="line"> <span class="tag"><<span class="name">sonar.host.url</span>></span>http://localhost:9000<span class="tag"></<span class="name">sonar.host.url</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">properties</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">profile</span>></span></span><br><span class="line"><span class="tag"></<span class="name">profiles</span>></span></span><br><span class="line"><span class="tag"><<span class="name">activeProfiles</span>></span></span><br><span class="line"><span class="tag"><<span class="name">activeProfile</span>></span>sonar<span class="tag"></<span class="name">activeProfile</span>></span></span><br><span class="line"><span class="tag"></<span class="name">activeProfiles</span>></span></span><br></pre></td></tr></table></figure>
<p>some lines have been commented out. This is because in the form I provided above (docker-compose.yml) you don’t need to tell maven<br>where the database is because it already knows. If you choose to install a database native on your machine and sonar to (without docker)<br>you can enable these lines and adjust them to conform to your needed settings.</p>
<h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>Not doing these kinds of code checks as a developer is robbing you of a learning experience and the opportunity of an extra<br>review. The static code checker does not get tired or is under pressure. It will just check your code and help you become<br>better and your code too.</p>
<p>So SonarQube … Just do it! </p>
<p><img src="/images/2018/sonarqube-just-do-it/docker_maven_sonarqube.png" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<h1 id="Code-transparency-…-Yes-please…"><a href="#Code-transparency-…-Yes-please…" class="headerlink" title="Code transparency … Yes please…"></a>Code transparency … Yes please…</h1><p>Recently I gave a small seminar for my current client about Clean Code and Craftsmanship. The group I was talking to<br>consisted of developers of all levels from junior to senior. </p>
<p>To my complete consternation, when I started talking about tools like PMD / CheckStyle and SonarQube, I found out that<br><em>none</em> of them had ever heard of these tools. Not even the Senior developers. </p>
<p>Well this is bad and needs to be fixed!<br>
Java EE: Heavyweight or Lightweight--Mythbustershttp://www.ivonet.nl/2017/10/04/CON5578__java-ee-heavyweight-or-lightweight--mythbusters/2017-10-04T06:27:00.000Z2019-06-01T12:35:01.000Z<h1 id="Session-abstract"><a href="#Session-abstract" class="headerlink" title="Session abstract"></a>Session abstract</h1><p>How fast is a deployment? What is the minimum size of a Java EE thin WAR? What are the RAM requirements of application servers? What is the out-of-the-box performance? How many transactions per second are achievable? What is the performance penalty of EJB/CDI/JPA and so on? What is the overhead of a transaction? Is Java EE lightweight enough to run in clouds? How big (in terms of disk size) are application servers? This session asks as many heretical questions about Java EE & Co. as possible. Come to answer them together, with plain numbers and code. Heretical questions are highly welcome!<br><a id="more"></a></p>
<h2 id="Speaker-s"><a href="#Speaker-s" class="headerlink" title="Speaker(s)"></a>Speaker(s)</h2><table>
<thead>
<tr>
<th style="text-align:left">Name</th>
<th style="text-align:left">Title</th>
<th style="text-align:left">Company</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Adam Bien</td>
<td style="text-align:left">Consultant / Contractor</td>
<td style="text-align:left">Adam Bien</td>
</tr>
</tbody>
</table>
<h2 id="Session-Info"><a href="#Session-Info" class="headerlink" title="Session Info"></a>Session Info</h2><table>
<thead>
<tr>
<th style="text-align:left">Experience</th>
<th style="text-align:left">Session type</th>
<th style="text-align:left">Track</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Intermediate</td>
<td style="text-align:left">Conference Session</td>
<td style="text-align:left">Java, Cloud, and Server-Side Development</td>
</tr>
</tbody>
</table>
<h1 id="My-Notes"><a href="#My-Notes" class="headerlink" title="My Notes"></a>My Notes</h1><p><img src="/images/2017/OOW17/CON5578__java-ee-heavyweight-or-lightweight--mythbusters.jpg" style="width:50%;height:50%;"></p>
<p><img src="/images/2017/OOW17/CON5578__java-ee-heavyweight-or-lightweight--mythbusters_1.jpg" style="width:50%;height:50%;"><br><img src="/images/2017/OOW17/CON5578__java-ee-heavyweight-or-lightweight--mythbusters_2.jpg" style="width:50%;height:50%;"></p>
<p><img src="/images/2017/OOW17/CON5578__java-ee-heavyweight-or-lightweight--mythbusters_3.jpg" style="width:50%;height:50%;"></p>
<h1 id="Live-demos"><a href="#Live-demos" class="headerlink" title="Live demos"></a>Live demos</h1><p>Al live demoes with the goal to see</p>
<ul>
<li>simple socket server (3 lines of java) took about 7 Mb</li>
<li>Wildfly full profile took about 35 Mb</li>
<li>Websphere liberty full took about 40 Mb</li>
</ul>
<p>So trying to save money 💰 by reducing memory usage is totally useless. You will probably save about 600Mb in a project with 20 Microservices. The memory costs is almost nothing compared to the days / weeks of work on tuning this or making your own smaller server. </p>
<p>Premature optimization is the root of all evil. </p>
<p>By using application servers you get full monitoring for free. </p>
<p><img src="/images/2017/OOW17/CON5578__java-ee-heavyweight-or-lightweight--mythbusters_4.jpg" style="width:50%;height:50%;"></p>
<ul>
<li>Payara micro<br><img src="/images/2017/OOW17/CON5578__java-ee-heavyweight-or-lightweight--mythbusters_5.jpg" style="width:50%;height:50%;"></li>
</ul>
<p>Is only 10 megs smallet the the full version. The sane goes for Wildfly swarm. </p>
<p>So the while small thing looks like a political thing. </p>
<h1 id="docker"><a href="#docker" class="headerlink" title="docker"></a>docker</h1><p>Use the base image of a full profile and only add your own stuff to it. Push the base image to the cloud once and nexe iterations only push the few Kb of the new build and not the whole server again and again. </p>
<ul>
<li>docker history image_here</li>
</ul>
<h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>Very convincing story for just using Java EE. </p>
<p>👍👍</p>
<h1 id="Session-abstract"><a href="#Session-abstract" class="headerlink" title="Session abstract"></a>Session abstract</h1><p>How fast is a deployment? What is the minimum size of a Java EE thin WAR? What are the RAM requirements of application servers? What is the out-of-the-box performance? How many transactions per second are achievable? What is the performance penalty of EJB/CDI/JPA and so on? What is the overhead of a transaction? Is Java EE lightweight enough to run in clouds? How big (in terms of disk size) are application servers? This session asks as many heretical questions about Java EE & Co. as possible. Come to answer them together, with plain numbers and code. Heretical questions are highly welcome!<br>
Baking a Java EE 8 Micro Pihttp://www.ivonet.nl/2017/10/02/TUT2112__baking-a-java-ee-8-micro-pi/2017-10-02T07:18:00.000Z2019-02-12T21:25:10.000Z<h1 id="Session-abstract"><a href="#Session-abstract" class="headerlink" title="Session abstract"></a>Session abstract</h1><p>Microservices are already a popular architecture for new applications, particularly with the modern need for applications to be cloud-native and light enough for the Internet of Things. One of the key challenges of breaking up monoliths into microservices is orchestration. This tutorial looks at some of the brand-new features and APIs in Java EE 8 that can help and presents an interactive Raspberry Pi-based demo that shows how easily messaging can be made cloud-ready with JCA connectors.<br><a id="more"></a></p>
<h2 id="Speaker-s"><a href="#Speaker-s" class="headerlink" title="Speaker(s)"></a>Speaker(s)</h2><table>
<thead>
<tr>
<th style="text-align:left">Name</th>
<th style="text-align:left">Title</th>
<th style="text-align:left">Company</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Ondrej Mihalyi</td>
<td style="text-align:left">Service engineer</td>
<td style="text-align:left">Payara Services</td>
</tr>
<tr>
<td style="text-align:left">Mike Croft</td>
<td style="text-align:left">Java Consultant</td>
<td style="text-align:left">Payara Services Ltd</td>
</tr>
</tbody>
</table>
<h2 id="Session-Info"><a href="#Session-Info" class="headerlink" title="Session Info"></a>Session Info</h2><table>
<thead>
<tr>
<th style="text-align:left">Experience</th>
<th style="text-align:left">Session type</th>
<th style="text-align:left">Track</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Introductory</td>
<td style="text-align:left">Tutorial</td>
<td style="text-align:left">Java, Cloud, and Server-Side Development</td>
</tr>
</tbody>
</table>
<h1 id="My-Notes"><a href="#My-Notes" class="headerlink" title="My Notes"></a>My Notes</h1><p>So my first talk of the day and of JavaOne. I’m curious. It’s a small crowd here. But hidden gems are sometimes found. Something is going wrong. No screen and stuff am about to walk out. Will give it 5 more minutes.<br>He is started but de demo heavyness has been cancelled I think because of connection problems. </p>
<p><img src="/images/2017/OOW17/TUT2112__baking-a-java-ee-8-micro-pi.jpg" style="width:50%;height:50%;"></p>
<h2 id="How-lightweight-is-java-EE-really"><a href="#How-lightweight-is-java-EE-really" class="headerlink" title="How lightweight is java EE, really?"></a>How lightweight is java EE, really?</h2><h3 id="Recent-history…"><a href="#Recent-history…" class="headerlink" title="Recent history…"></a>Recent history…</h3><ul>
<li>2013<ul>
<li>docker was a baby</li>
<li>Wildfly was still JBoss AS (no swarm)</li>
<li>before spring boot</li>
<li>no websphere liberty profile</li>
</ul>
</li>
<li>2017<ul>
<li>docker is now the dominant container format</li>
<li>WildFly have fully product-ized Swarm</li>
<li>Spring boot have now been making jars not wars for a few years now </li>
<li>IBM released Open Liberty </li>
<li>Payara entered the fray and released Payara Micro</li>
<li>Eclipse MicroProfile is established and progressing</li>
</ul>
</li>
</ul>
<h2 id="What’s-in-java-EE-today"><a href="#What’s-in-java-EE-today" class="headerlink" title="What’s in java EE today?"></a>What’s in java EE today?</h2><p><img src="/images/2017/OOW17/TUT2112__baking-a-java-ee-8-micro-pi_2.jpg" style="width:50%;height:50%;"></p>
<ul>
<li>jax-rs now has a reactive profile</li>
</ul>
<h3 id="what-is-Payara-Micro"><a href="#what-is-Payara-Micro" class="headerlink" title="what is Payara Micro"></a>what is Payara Micro</h3><p><img src="/images/2017/OOW17/TUT2112__baking-a-java-ee-8-micro-pi_3.jpg" style="width:50%;height:50%;"></p>
<p><img src="/images/2017/OOW17/TUT2112__baking-a-java-ee-8-micro-pi_4.jpg" style="width:50%;height:50%;"></p>
<h2 id="What-could-be-in-Java-EE-EE4J-In-the-future"><a href="#What-could-be-in-Java-EE-EE4J-In-the-future" class="headerlink" title="What could be in Java EE EE4J??? In the future?"></a>What could be in Java EE EE4J??? In the future?</h2><h1 id="demo"><a href="#demo" class="headerlink" title="demo"></a>demo</h1><p><img src="/images/2017/OOW17/TUT2112__baking-a-java-ee-8-micro-pi_6.jpg" style="width:50%;height:50%;"></p>
<p>But no demo DAMN<br>👎</p>
<h1 id="Session-abstract"><a href="#Session-abstract" class="headerlink" title="Session abstract"></a>Session abstract</h1><p>Microservices are already a popular architecture for new applications, particularly with the modern need for applications to be cloud-native and light enough for the Internet of Things. One of the key challenges of breaking up monoliths into microservices is orchestration. This tutorial looks at some of the brand-new features and APIs in Java EE 8 that can help and presents an interactive Raspberry Pi-based demo that shows how easily messaging can be made cloud-ready with JCA connectors.<br>
How To Have Multiple Versions Of Java On Your macOshttp://www.ivonet.nl/2017/09/27/how-to-have-multiple-versions-of-java-on-your-macos/2017-09-27T07:20:00.000Z2019-02-12T21:25:10.000Z<h1 id="Challenge"><a href="#Challenge" class="headerlink" title="Challenge"></a>Challenge</h1><p>You want to have multiple versions of Java available on your Mac…</p>
<a id="more"></a>
<h1 id="Prerequisites"><a href="#Prerequisites" class="headerlink" title="Prerequisites"></a>Prerequisites</h1><ul>
<li><a href="https://brew.sh/" target="_blank" rel="noopener">brew</a> installed </li>
<li><code>~/bin</code> folder on your path</li>
</ul>
<h1 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h1><ul>
<li><code>brew install jenv</code> to install JEnv</li>
<li>Add versions tap room to brew: <code>brew tap caskroom/versions</code></li>
<li>Install your java versions, e.g.:<ul>
<li><code>brew cask install java</code></li>
<li><code>brew cask install java7</code></li>
<li><code>brew cask install java8</code></li>
</ul>
</li>
<li>Add a file called <code>mvn</code> to your <code>~/bin</code> folder with the following content</li>
</ul>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"><span class="built_in">export</span> JAVA_HOME=$(jenv javahome)</span><br><span class="line">/usr/<span class="built_in">local</span>/bin/mvn <span class="string">"<span class="variable">$@</span>"</span></span><br></pre></td></tr></table></figure>
<ul>
<li>You can now switch between java versions with the <a href="http://www.jenv.be/" target="_blank" rel="noopener">jenv</a> command</li>
<li>Do not forget to create a new terminal session for all this to take effect (just stop and start your terminal)</li>
</ul>
<h1 id="Challenge"><a href="#Challenge" class="headerlink" title="Challenge"></a>Challenge</h1><p>You want to have multiple versions of Java available on your Mac…</p>
How To @Inject Property File Properties With CDIhttp://www.ivonet.nl/2016/03/08/how-to-inject-property-file-properties-with-cdi/2016-03-08T20:34:00.000Z2019-02-12T21:25:10.000Z<p>Also published on <a href="https://dzone.com/articles/how-to-inject-property-file-properties-with-cdi" target="_blank" rel="noopener">DZone</a></p>
<h1 id="Challenge"><a href="#Challenge" class="headerlink" title="Challenge"></a>Challenge</h1><p>You use CDI for your Java application and want to use a Property file for some needed configuration, but don’t know how to do this …<br><a id="more"></a></p>
<h1 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h1><p>Create producers and an annotation to direct it.</p>
<h2 id="Annotation"><a href="#Annotation" class="headerlink" title="Annotation"></a>Annotation</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> nl.ivonet.service.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.enterprise.util.Nonbinding;</span><br><span class="line"><span class="keyword">import</span> javax.inject.Qualifier;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Retention;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> java.lang.annotation.ElementType.FIELD;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> java.lang.annotation.ElementType.METHOD;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> java.lang.annotation.ElementType.PARAMETER;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> java.lang.annotation.ElementType.TYPE;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> java.lang.annotation.RetentionPolicy.RUNTIME;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Represents an property key to be injected</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Qualifier</span></span><br><span class="line"><span class="meta">@Retention</span>(RUNTIME)</span><br><span class="line"><span class="meta">@Target</span>({TYPE, METHOD, FIELD, PARAMETER})</span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> Property {</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Key to search for in the property files.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> a string.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Nonbinding</span> <span class="function">String <span class="title">value</span><span class="params">()</span> <span class="keyword">default</span> ""</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Is the key a mandatory key.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> true as default but false if set</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Nonbinding</span> <span class="function"><span class="keyword">boolean</span> <span class="title">required</span><span class="params">()</span> <span class="keyword">default</span> <span class="keyword">true</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Producer"><a href="#Producer" class="headerlink" title="Producer"></a>Producer</h2><p>The examples provided here enable parsing of Strings, Booleans and Integers but you can of course add producers as needed.<br>Note that the getKey method firsts looks if the @Property annotation has a value and if so it will take that as the key for the property file, but if you don’t provide a value it will take the annotated field name as the key.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> nl.ivonet.service.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.annotation.PostConstruct;</span><br><span class="line"><span class="keyword">import</span> javax.enterprise.inject.Produces;</span><br><span class="line"><span class="keyword">import</span> javax.enterprise.inject.spi.InjectionPoint;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.util.Properties;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PropertyProducer</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Properties properties;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Property</span></span><br><span class="line"> <span class="meta">@Produces</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">produceString</span><span class="params">(<span class="keyword">final</span> InjectionPoint ip)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.properties.getProperty(getKey(ip));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Property</span></span><br><span class="line"> <span class="meta">@Produces</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">produceInt</span><span class="params">(<span class="keyword">final</span> InjectionPoint ip)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> Integer.valueOf(<span class="keyword">this</span>.properties.getProperty(getKey(ip)));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Property</span></span><br><span class="line"> <span class="meta">@Produces</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">produceBoolean</span><span class="params">(<span class="keyword">final</span> InjectionPoint ip)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> Boolean.valueOf(<span class="keyword">this</span>.properties.getProperty(getKey(ip)));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> String <span class="title">getKey</span><span class="params">(<span class="keyword">final</span> InjectionPoint ip)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (ip.getAnnotated()</span><br><span class="line"> .isAnnotationPresent(Property.class) && </span><br><span class="line"> !ip.getAnnotated()</span><br><span class="line"> .getAnnotation(Property.class)</span><br><span class="line"> value().isEmpty()) ? ip.getAnnotated()</span><br><span class="line"> .getAnnotation(Property.class)</span><br><span class="line"> .value() </span><br><span class="line"> : ip.getMember()</span><br><span class="line"> .getName();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@PostConstruct</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.properties = <span class="keyword">new</span> Properties();</span><br><span class="line"> <span class="keyword">final</span> InputStream stream = PropertyProducer.class</span><br><span class="line"> .getResourceAsStream(<span class="string">"/application.properties"</span>);</span><br><span class="line"> <span class="keyword">if</span> (stream == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"No properties!!!"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">this</span>.properties.load(stream);</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> IOException e) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"Configuration could not be loaded!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Usage"><a href="#Usage" class="headerlink" title="Usage"></a>Usage</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Inject</span></span><br><span class="line"><span class="meta">@Property</span></span><br><span class="line"><span class="keyword">private</span> String rootFolder;</span><br></pre></td></tr></table></figure>
<p>or</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Inject</span></span><br><span class="line"><span class="meta">@Property</span>(<span class="string">"root.folder.key.here"</span>)</span><br><span class="line"><span class="keyword">private</span> String rootFolder;</span><br></pre></td></tr></table></figure>
<h2 id="application-properties"><a href="#application-properties" class="headerlink" title="application.properties"></a>application.properties</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">rootFolder=/helloWorldFolder</span><br><span class="line">root.folder.key.here=/another/folder/name</span><br><span class="line">elasticsearchUrl=http://localhost:9200</span><br></pre></td></tr></table></figure>
<h1 id="Extra-consideration"><a href="#Extra-consideration" class="headerlink" title="Extra consideration"></a>Extra consideration</h1><p>Note that when using this method for injecting Strings and stuff it might get difficult to write Unit tests as Mocking frameworks cannot Mock final classes (e.g. String).<br>If you get to this problem you might want to look at <a href="https://www.hardcoder.nl/2016/03/08/field-injection-when-mocking-frameworks-fail/" target="_blank" rel="noopener">FieldInjection</a> article</p>
<p>Also published on <a href="https://dzone.com/articles/how-to-inject-property-file-properties-with-cdi" target="_blank" rel="noopener">DZone</a></p>
<h1 id="Challenge"><a href="#Challenge" class="headerlink" title="Challenge"></a>Challenge</h1><p>You use CDI for your Java application and want to use a Property file for some needed configuration, but don’t know how to do this …<br>
Field Injection When Mocking Frameworks Failhttp://www.ivonet.nl/2016/03/08/field-injection-when-mocking-frameworks-fail/2016-03-08T20:05:00.000Z2019-02-12T21:25:30.000Z<p>Also published on <a href="https://dzone.com/articles/field-injection-when-mocking-frameworks-fail" target="_blank" rel="noopener">DZone</a></p>
<h1 id="Challenge"><a href="#Challenge" class="headerlink" title="Challenge"></a>Challenge</h1><p>You use Dependency Injection (CDI) in your application and you want to unit test your Java classes without making it an integration test by using Weld of Arquillian. You use a Mocking framework like Mockito or EasyMock but still have trouble getting all your dependencies injected into the class because one or the injections is a String type or another final class.<br><a id="more"></a></p>
<blockquote>
<p>org.mockito.exceptions.base.MockitoException: Cannot mock/spy class java.lang.String Mockito cannot mock/spy following: - final classes - anonymous classes - primitive types You don’t want to change your code to make it more testable and you don’t want to add accessors to do this. Now you have trouble creating JUnit tests…</p>
</blockquote>
<h1 id="Solution"><a href="#Solution" class="headerlink" title="Solution "></a>Solution <!-- more --></h1><p>Create your own small injection utility method: </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">injectField</span><span class="params">(<span class="keyword">final</span> Object injectable, </span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">final</span> String fieldname, </span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">final</span> Object value)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">final</span> java.lang.reflect.Field field = injectable.getClass()</span><br><span class="line"> .getDeclaredField(fieldname);</span><br><span class="line"> <span class="keyword">final</span> <span class="keyword">boolean</span> origionalValue = field.isAccessible();</span><br><span class="line"> field.setAccessible(<span class="keyword">true</span>);</span><br><span class="line"> field.set(injectable, value);</span><br><span class="line"> field.setAccessible(origionalValue);</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> NoSuchFieldException | IllegalAccessException e) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(e.getMessage(), e);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p> So if you have a class like this you want to test: </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> nl.ivonet.service.directory;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> nl.ivonet.service.config.Property;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.inject.Inject;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.DirectoryStream;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Files;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Path;</span><br><span class="line"><span class="keyword">import</span> java.util.Locale;</span><br><span class="line"><span class="keyword">import</span> java.util.stream.Stream;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ExtensionFilter</span> <span class="keyword">implements</span> <span class="title">DirectoryStream</span>.<span class="title">Filter</span><<span class="title">Path</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String DELIMETER = <span class="string">":"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Property</span></span><br><span class="line"> <span class="meta">@Inject</span></span><br><span class="line"> <span class="keyword">private</span> String filterExtensions;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">accept</span><span class="params">(<span class="keyword">final</span> Path entry)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">return</span> Files.isRegularFile(entry) && isAcceptable(entry);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">isAcceptable</span><span class="params">(<span class="keyword">final</span> Path entry)</span> </span>{</span><br><span class="line"> <span class="keyword">final</span> String[] split = <span class="keyword">this</span>.filterExtensions.toLowerCase(Locale.US)</span><br><span class="line"> .split(DELIMETER);</span><br><span class="line"> <span class="keyword">return</span> Stream.of(split)</span><br><span class="line"> .anyMatch(extension -> entry.getFileName()</span><br><span class="line"> .toString()</span><br><span class="line"> .toLowerCase(Locale.US)</span><br><span class="line"> .endsWith(extension));</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p> You can test it like this: </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> nl.ivonet.service.directory;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.junit.Before;</span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.nio.file.Path;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Paths;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> nl.ivonet.helper.Utils.injectField;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> org.junit.Assert.assertTrue;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ExtensionFilterTest</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> ExtensionFilter filter;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Before</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setUp</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="keyword">this</span>.filter = <span class="keyword">new</span> ExtensionFilter();</span><br><span class="line"> injectField(<span class="keyword">this</span>.filter, <span class="string">"filterExtensions"</span>, <span class="string">".epub:.kepub"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testEpub</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="keyword">final</span> Path entry = Paths.get(<span class="string">"src/test/resources/books/test.epub"</span>);</span><br><span class="line"> assertTrue(<span class="keyword">this</span>.filter.accept(entry.toAbsolutePath()));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p> For other Injectables you can still use Mockito or your Mocking framework of choice but for final stuff you can do this. Fun and easy.</p>
<p>Also published on <a href="https://dzone.com/articles/field-injection-when-mocking-frameworks-fail" target="_blank" rel="noopener">DZone</a></p>
<h1 id="Challenge"><a href="#Challenge" class="headerlink" title="Challenge"></a>Challenge</h1><p>You use Dependency Injection (CDI) in your application and you want to unit test your Java classes without making it an integration test by using Weld of Arquillian. You use a Mocking framework like Mockito or EasyMock but still have trouble getting all your dependencies injected into the class because one or the injections is a String type or another final class.<br>
PostgreSQL with Glassfish http://www.ivonet.nl/2015/05/23/PostgreSQL-with-Glassfish/2015-05-23T11:43:00.000Z2019-02-12T21:25:30.000Z<p>How to setup JDBC connection to a Postgres datasource in Glassfish</p>
<a id="more"></a>
<h2 id="Prerequisites"><a href="#Prerequisites" class="headerlink" title="Prerequisites"></a>Prerequisites</h2><ul>
<li>PostgreSQL & phppgadmin</li>
<li>Java 8</li>
<li>Glassfish 4.1</li>
</ul>
<h2 id="First-create-a-connection-pool"><a href="#First-create-a-connection-pool" class="headerlink" title="First create a connection pool"></a>First create a connection pool</h2><ul>
<li>Download a <a href="http://jdbc.postgresql.org/download.html" target="_blank" rel="noopener">Postgres JDBC driver</a> (I got the <code>JDBC41 Postgresql Driver, Version 9.3-1102</code> driver)</li>
<li>Copy the downloaded jar to the <strong>[glassfish install folder]/glassfish/domains/[your domain]/lib</strong> folder</li>
<li>Restart GlassFish</li>
<li>Open the GlassFish admin pannel (e.g. <a href="http://localhost:4848" target="_blank" rel="noopener">http://localhost:4848</a>)</li>
<li>Goto to Resources -> JDBC -> JDBC Connection Pool</li>
</ul>
<p><img src="/images/2015/glassfish-jdbc.png" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<ul>
<li>Press the <code>New...</code> button</li>
<li>Give the pool a name</li>
<li>Resource Type to <code>javax.sql.ConnectionPoolDataSource</code> </li>
<li>Database Driver Vendor to <code>Postgresql</code></li>
<li>Press Next</li>
<li>Fill properties<ul>
<li>User</li>
<li>DatabaseName</li>
<li>ServerName (localhost??)</li>
<li>PortNumber (5432 for standard postgres)</li>
</ul>
</li>
<li>Remove all other properties by selecting them and pressing <code>Delete properties</code> button.</li>
<li>Finish</li>
</ul>
<h2 id="Test-the-connection-pool"><a href="#Test-the-connection-pool" class="headerlink" title="Test the connection pool"></a>Test the connection pool</h2><ul>
<li>Select the newly created pool</li>
<li>Press Ping button in General Tab to check the connection. </li>
<li>Fix possible errors in property values if ping is not successful</li>
</ul>
<h2 id="Create-JDBC-Resource-in-Glassfish"><a href="#Create-JDBC-Resource-in-Glassfish" class="headerlink" title="Create JDBC Resource in Glassfish"></a>Create JDBC Resource in Glassfish</h2><ul>
<li>Open the GlassFish admin pannel (e.g. <a href="http://localhost:4848" target="_blank" rel="noopener">http://localhost:4848</a>)</li>
<li>Goto to Resources -> JDBC -> JDBC Connection</li>
<li>Press New button. </li>
<li>Enter JNDI Name like <code>jdbc/thedatabase-name</code></li>
<li>Choose the created connection pool pool</li>
<li>Save changes. </li>
</ul>
<h2 id="asadmin-command-line"><a href="#asadmin-command-line" class="headerlink" title="asadmin command-line"></a>asadmin command-line</h2><p>You can also do all of the above from the commandline:</p>
<p>Creating the ConnectionPool…<br><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">asadmin create-jdbc-connection-pool --datasourceclassname org.postgresql.ds.PGConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property portNumber=5432:password=PASSWORD:user=USER:serverName=localhost:databaseName=DB_NAME_HERE CONNECTION_POOLNAME_HERE</span><br></pre></td></tr></table></figure></p>
<p>Creating the DataSource:<br><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">asadmin create-jdbc-resource --connectionpoolid CONNECTION_POOLNAME_HERE jdbc/JNDI_NAME_HERE</span><br></pre></td></tr></table></figure></p>
<p>Don’t forget to replace the UPPERCASE words and note the corresponding names!</p>
<h3 id="No-Questions-Asked"><a href="#No-Questions-Asked" class="headerlink" title="No Questions Asked"></a>No Questions Asked</h3><p>You can make your scripts run smoothly by adding a passwordfile and –user to the command</p>
<p>Create a file called <code>pwd.txt</code> containing (some of) these options:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">AS_ADMIN_PASSWORD=value</span><br><span class="line">AS_ADMIN_ADMINPASSWORD=value</span><br><span class="line">AS_ADMIN_USERPASSWORD=value</span><br><span class="line">AS_ADMIN_MASTERPASSWORD=value</span><br></pre></td></tr></table></figure>
<p>For me the first option was enough but I guess it would depend on your setup. Just try it out.</p>
<p>Now the commands would look like this:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">asadmin --user USERNAME --passwordfile ./pwd.txt create-jdbc-connection-pool --datasourceclassname org.postgresql.ds.PGConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property portNumber=5432:password=PASSWORD:user=USER:serverName=localhost:databaseName=DB_NAME_HERE CONNECTION_POOLNAME_HERE</span><br><span class="line"></span><br><span class="line">asadmin --user USERNAME --passwordfile ./pwd.txt create-jdbc-resource --connectionpoolid CONNECTION_POOLNAME_HERE jdbc/JNDI_NAME_HERE</span><br></pre></td></tr></table></figure>
<h2 id="Concusion"><a href="#Concusion" class="headerlink" title="Concusion"></a>Concusion</h2><p>Now we can refer to the database from <code>persistence.xml</code> in our application.</p>
<p>How to setup JDBC connection to a Postgres datasource in Glassfish</p>
Reading a File the java 8 wayhttp://www.ivonet.nl/2015/05/23/Java8ReadFile/2015-05-23T11:43:00.000Z2019-02-12T21:25:30.000Z<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Files;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Paths;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> String data = <span class="keyword">new</span> String(Files.readAllBytes(Paths.get(<span class="string">"foo.txt"</span>)));</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class=
How to get Keycloak working with Dockerhttp://www.ivonet.nl/2015/05/23/Keycloak-Docker/2015-05-23T11:43:00.000Z2019-02-12T21:25:30.000Z<p>NOTE: This article might be being revised continuously because of new insights.</p>
<p>This blog describes how I created a couple of Docker images to demonstrate <a href="http://ivo2u.nl/WK" target="_blank" rel="noopener">Keycloak</a>.<br>Important in this blog is that the whole process will be described. I attended a couple of keycloak sessions during Javaone this year and during these sessions the illusion was created that adding Keycloak as the security provider for your application is very easy and almost non-invasive for your code.<br>What they did not tell you that configuring a server that could use keycloak was not as trivial.<br>This blog will also expose a java web application with rest end-points to show how the auth works.</p>
<p>This blog will tell all :-)<br><a id="more"></a></p>
<p><strong>NOTES</strong>: </p>
<ul>
<li>I will use usernames and passwords in this document as this is a demo blog. Be sure to change the relevant stuff if you want to use it for realzlike :-) I will not say so again.</li>
<li>This demo has done on a Mac and the commands will reflect that. You might have to do some translating if you are on another OS. Sorry will not be fixed</li>
</ul>
<h2 id="The-wanted-setup"><a href="#The-wanted-setup" class="headerlink" title="The wanted setup"></a>The wanted setup</h2><p>The whole idea is to setup <a href="http://ivo2u.nl/WK" target="_blank" rel="noopener">Keycloak</a> as a separate server as a kind of “Security as a service” solution.</p>
<p>This is the setup I choose:</p>
<ul>
<li>Get a docker data volume for my database values</li>
<li><a href="http://ivo2u.nl/WL" target="_blank" rel="noopener">jboss/keycloak-postgres</a> docker image to serve as the keycloak security server / service</li>
<li>Tune a postgress docker image to serve as db for the keycloak server</li>
<li><a href="http://ivo2u.nl/WG" target="_blank" rel="noopener">jboss/wildfly</a> docker image as the base for the application server. This images will be adjusted to enable keycloak as security provider.</li>
<li>put it all behind an apache proxy in a production environment.</li>
</ul>
<h2 id="Get-a-keycloak-authentication-server-up-and-running"><a href="#Get-a-keycloak-authentication-server-up-and-running" class="headerlink" title="Get a keycloak authentication server up and running"></a>Get a keycloak authentication server up and running</h2><p>Time to maybe read more <a href="http://ivo2u.nl/W3" target="_blank" rel="noopener">here</a> about what the following commands mean.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Data volume</span></span><br><span class="line">docker run --name ivonet-postgres-data -v /var/lib/postgresql/data busybox <span class="literal">true</span></span><br><span class="line"><span class="comment"># Postgres coupled to the datavolume</span></span><br><span class="line">docker run --name ivonet-keycloak-postgres --volumes-from ivonet-postgres-data -p 15432:5432 -e POSTGRES_DATABASE=keycloak -e POSTGRES_USER=keycloak -e POSTGRES_PASSWORD=keycloak -e POSTGRES_ROOT_PASSWORD=s3cr3t -d postgres</span><br><span class="line"><span class="comment"># Keycloak server image linking to the postgres image</span></span><br><span class="line">docker run --name ivonet-keycloak --link ivonet-keycloak-postgres:postgres -p 10000:8080 -e POSTGRES_DATABASE=keycloak -e POSTGRES_USER=keycloak -e POSTGRES_PASSWORD=keycloak jboss/keycloak-postgres</span><br></pre></td></tr></table></figure>
<p>If you are not interested in accessing the ivonet-postgres-data with external tools, then you can eliminate the -p parameter from the ivonet-keycloak-postgres command.<br>As you might have noticed I gave the external port 15432. I did this because on my production environment I already have a native postgres running and am migrating slowly. </p>
<p>So now we have a setup that might work :-)<br>lets try it out and enter the following in the terminal:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">open http://$(docker-machine ip default):10000/auth</span><br></pre></td></tr></table></figure>
<p>You should now see something like this:</p>
<p><img src="Keycloak-Docker.png" alt="Keycloak-Docker.png"></p>
<p>Play around.</p>
<p>NOTE: the default username and password is admin and admin.</p>
<h2 id="Tune-wildfly"><a href="#Tune-wildfly" class="headerlink" title="Tune wildfly"></a>Tune wildfly</h2><p>So now we have a keycloak auth server up and running. it is time to get another instance of wildfly and make it keycloak enabled. This is the part not mentioned in the sessions I followed and what stumped me in the beginning. On my local machene I mostly use Glassfish as my EE development environment and I could not get the sample apps to work… After a couple of hours I started thinking for real :-) and doing some reading and it actually made sense that it didn’t work. I was so focuessed on the demo I saw that I didn’t realize that glassfish != wildfly and that something might have to be done to get stuff working.</p>
<p>Wel as you may have guessed you actually do need something else. Wildfly is the obvious choise because jboss is the major contributor to keycloak. You need an adaptor installed on the server, because you want the EE container to recognize keycloak as a security provider.</p>
<p>JBoss provides a docker <a href="http://ivo2u.nl/Wr" target="_blank" rel="noopener">image</a> for that to but as of the time of this writing it was in wildfly 9.0.1.Final and on keycloak 1.5.0.Final and the most current versions are 9.0.2.Final for wildfly and 1.6.1.Final for keycloak so I upgraded from the latest default wildfly image.</p>
<p>The power of docker is to make adjustments gradually and modularly and so I did that too…</p>
<ul>
<li>first upgraded to wildfly with the admin console enabled</li>
</ul>
<p>Dockerfile:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">FROM jboss/wildfly</span><br><span class="line">RUN /opt/jboss/wildfly/bin/add-user.sh ivonet s3cr3t --silent</span><br><span class="line">CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0"]</span><br></pre></td></tr></table></figure>
<ul>
<li>now build it: <code>docker build --tag ivonet/wildfly-admin .</code></li>
<li>I also pushed it to de docker repository because I intent to reuse it for development purposes</li>
</ul>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker login</span><br><span class="line">docker push ivonet/wildfly-admin</span><br></pre></td></tr></table></figure>
<ul>
<li>add to this admin enabled wildfly by adding the keycloak adapter</li>
</ul>
<p>See this <a href="http://ivo2u.nl/W1" target="_blank" rel="noopener">Dockerfile</a> for the one I used to build my own version of Wilfly with the keycloak adapter installed.</p>
<ul>
<li>build it: <code>docker build --tag ivonet/wildfly-admin-keycloak-adapter .</code></li>
<li>push it to the repo for reuse: </li>
</ul>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker login</span><br><span class="line">docker push ivonet/wildfly-admin-keycloak-adapter</span><br></pre></td></tr></table></figure>
<ul>
<li>As you can see this images is extended from ivonet/wildfly-admin that was just created.</li>
<li>it sets an environment variable for the keycloak version</li>
<li>it changes the workdir</li>
<li>it fetches (curl) the correct adapter from internet and un-tars’ it</li>
<li>changes workdir again</li>
<li>changes the standalone.xml file at the appropriate points in the file with the sed command to activate the security provider module/adapter</li>
<li>expose the standard port and the admin console port</li>
</ul>
<p>This Dockerfile is of course the product of some trial and error I had to find out if the install was correct. This part will not be explained here, but if you want more input on this subject, drop me a line.</p>
<p>This image is again a base for more because now it is time to write an app and deploy it.</p>
<h1 id="Screencast"><a href="#Screencast" class="headerlink" title="Screencast"></a>Screencast</h1><p>I’ve made a screencast with a basic talk about Keycloak explaining a lot of the above text.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/89xja-k50_U" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<h1 id="Production-environment"><a href="#Production-environment" class="headerlink" title="Production environment"></a>Production environment</h1><p>Well I found out very soon that all of the above was great but didn’t work very wel in production.<br>My production environment is an Ubuntu Linux distribution and I access all my sites through Apache2 VirtualHost configurations. Apache is my front proxy and directs all based on servername resolves and ports.</p>
<p>When trying to put my keycloak docker construction as described above behind an Apache ProxyPass construction it all went to pieces. As we are talking about a security solution it seems kinda important to do all through https. So I went to <a href="http://ivo2u.nl/5z" target="_blank" rel="noopener">letsencrypt</a> and got myself a certificate and proxypassed my content to the inner docker endpoint. The trouble was that when talking secure (https) I got all kinds of error messages about “Mixed content” and stuff was blocked by the browser(s). Solving this was way more hassle than I expected and took my about two evenings of googling and reading to fix.</p>
<p>First I had to create a custom <a href="http://ivo2u.nl/5R" target="_blank" rel="noopener">Dockerfile</a> based on the jboss/keycloak-postgres image to change a few settings in the standalone.xml of that distribution. These settings can be found in the documentation but are not easy to find.<br>and replace the current image with my own</p>
<p>On build machine:<br><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker build --tag ivonet/keycloak-postgres .</span><br><span class="line">docker login</span><br><span class="line">docker push ivonet/keycloak-postgres</span><br></pre></td></tr></table></figure></p>
<p>On server:<br><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker stop ivonet-keycloak</span><br><span class="line">docker rm ivonet-keycloak</span><br><span class="line">docker run --name ivonet-keycloak --link ivonet-keycloak-postgres:postgres -p 10000:8080 -e POSTGRES_DATABASE=keycloak -e POSTGRES_USER=keycloak -e POSTGRES_PASSWORD=keycloak ivonet/keycloak-postgres</span><br></pre></td></tr></table></figure></p>
<p>Notice that now I get the ivonet/keycloak-postgres and not the jboss/keycloak-postgres.</p>
<p>Then I had to make changes to the Apache config:</p>
<figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"><VirtualHost *:80></span></span><br><span class="line"> <span class="attribute"><span class="nomarkup">ServerName</span></span> security.sample.com</span><br><span class="line"></span><br><span class="line"> <span class="section"><Location /></span></span><br><span class="line"> <span class="attribute">RedirectPermanent</span> / https://security.sample.com/auth/admin</span><br><span class="line"> <span class="section"></Locatio></span><span class="attribute">n</span></span><br><span class="line"><span class="section"></VirtualHost></span></span><br><span class="line"><span class="section"><VirtualHost *:443></span></span><br><span class="line"> <span class="attribute"><span class="nomarkup">ServerName</span></span> security.ivonet.it</span><br><span class="line"></span><br><span class="line"> <span class="attribute">SSLEngine</span> <span class="literal">on</span></span><br><span class="line"> <span class="attribute">SSLProtocol</span> <span class="literal">all</span> -SSLv2</span><br><span class="line"> <span class="attribute">SSLCipherSuite</span> <span class="literal">ALL</span>:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Please look at letsencrypt.org for more info on this part of the config.</span></span><br><span class="line"> <span class="attribute">SSLCertificateFile</span> /etc/letsencrypt/live/security.sample.com/cert.pem</span><br><span class="line"> <span class="attribute">SSLCertificateKeyFile</span> /etc/letsencrypt/live/security.sample.com/privkey.pem</span><br><span class="line"> <span class="attribute">SSLCertificateChainFile</span> /etc/letsencrypt/live/security.sample.com/chain.pem</span><br><span class="line"></span><br><span class="line"> <span class="attribute">ProxyRequests</span> <span class="literal">Off</span></span><br><span class="line"> <span class="attribute">ProxyPass</span> / http://172.17.0.1:11000/</span><br><span class="line"> <span class="attribute">ProxyPassReverse</span> / http://172.17.0.1:11000/</span><br><span class="line"> <span class="attribute">ProxyPreserveHost</span> <span class="literal">On</span></span><br><span class="line"></span><br><span class="line"> <span class="attribute">RequestHeader</span> set X-Forwarded-For <span class="string">"https"</span></span><br><span class="line"> <span class="attribute">RequestHeader</span> set X-Forwarded-Proto <span class="string">"https"</span></span><br><span class="line"></span><br><span class="line"> <span class="section"><Location /></span></span><br><span class="line"> <span class="attribute"><span class="nomarkup">Order</span></span> deny,allow</span><br><span class="line"> <span class="attribute"><span class="nomarkup">Allow</span></span> from <span class="literal">all</span></span><br><span class="line"> <span class="attribute">SSLRequireSSL</span></span><br><span class="line"> <span class="section"></Location></span></span><br><span class="line"></span><br><span class="line"> <span class="attribute">LogLevel</span> info</span><br><span class="line"> <span class="attribute">ErrorLog</span> /var/log/apache2/security-error.log</span><br><span class="line"> <span class="attribute">CustomLog</span> /var/log/apache2/security-access.log combined</span><br><span class="line"><span class="section"></VirtualHost></span></span><br></pre></td></tr></table></figure>
<p>Now I have no mixed content messages anymore and a certificate that is not self signed. Great stuff.<br>Hopefully I’m ready for the next step.</p>
<h1 id="Realm-backup"><a href="#Realm-backup" class="headerlink" title="Realm backup"></a>Realm backup</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># make sure that the ivonet-keycloak-postgres image is started!</span></span><br><span class="line">docker start ivonet-keycloak-postgres</span><br><span class="line">docker run --name ivonet-keycloak-backup -it --rm -v $(<span class="built_in">pwd</span>):/backup --link ivonet-keycloak-postgres:postgres -p 10001:8080 -e POSTGRES_DATABASE=keycloak -e POSTGRES_USER=keycloak -e POSTGRES_PASSWORD=keycloak jboss/keycloak-postgres /opt/jboss/keycloak/bin/standalone.sh -Dkeycloak.migration.action=<span class="built_in">export</span> -Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.realmName=IvoNet -Dkeycloak.migration.file=/backup/keycloak-realm-IvoNet-$(date +<span class="string">"%Y-%m-%d"</span>).json</span><br></pre></td></tr></table></figure>
<p>This command is quite involved and will do:</p>
<ul>
<li>run the jboss/keycloak-postgres image </li>
<li>naming it ivonet-keycloak-backup but will be removed after quit</li>
<li>map the current host folder to the image folder /backup</li>
<li>link ivonet-keycloak-postgres to the postgres image</li>
<li>start keycloak with a couple of keycloak specific parameters telling it to extract the realmName=IvoNet to a singleFile </li>
</ul>
<p>The extraction will take place and after that the server is still running. You can quit it by pressing <code>ctrl-c</code>.</p>
<p>Now you will see a file in the current folder named something like: <code>keycloak-realm-IvoNet-2015-11-12.json</code></p>
<p>This is a file you can import as a ream in Keycloak.</p>
<p>Now you can even make it more efficient:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># make sure that the ivonet-keycloak-postgres image is started!</span></span><br><span class="line">docker start ivonet-keycloak-postgres</span><br><span class="line">docker run --name ivonet-keycloak-backup -v $(<span class="built_in">pwd</span>):/backup --link ivonet-keycloak-postgres:postgres -p 10001:8080 -e POSTGRES_DATABASE=keycloak -e POSTGRES_USER=keycloak -e POSTGRES_PASSWORD=keycloak ivonet/keycloak-postgres /opt/jboss/keycloak/bin/standalone.sh -Dkeycloak.migration.action=<span class="built_in">export</span> -Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.realmName=IvoNet -Dkeycloak.migration.file=/backup/keycloak-realm-IvoNet-$(date +<span class="string">"%Y-%m-%d"</span>).json</span><br><span class="line">docker stop ivonet-keycloak-backup</span><br></pre></td></tr></table></figure>
<p>Next time you can just run:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker run ivonet-keycloak-backup</span><br><span class="line">sleep 25</span><br><span class="line">docker stop ivonet-keycloak-backup</span><br></pre></td></tr></table></figure>
<p>and it will create the the json file at the location you ran the command. Now I think that you can change these commands to suit your needs. e.g. when you always want to backup to a specific host location you can replace $(pwd) with a local folder.</p>
<h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>Configuring Keycloak for production based on docker and all was not as easy as I was made to believe. I learned a lot though and that’s why I love doing this stuff so much.<br>Hope you get stuff working a but faster than I did with the help provided here.</p>
<p>Have fun.</p>
<p>NOTE: This article might be being revised continuously because of new insights.</p>
<p>This blog describes how I created a couple of Docker images to demonstrate <a href="http://ivo2u.nl/WK" target="_blank" rel="noopener">Keycloak</a>.<br>Important in this blog is that the whole process will be described. I attended a couple of keycloak sessions during Javaone this year and during these sessions the illusion was created that adding Keycloak as the security provider for your application is very easy and almost non-invasive for your code.<br>What they did not tell you that configuring a server that could use keycloak was not as trivial.<br>This blog will also expose a java web application with rest end-points to show how the auth works.</p>
<p>This blog will tell all :-)<br>
Java Maven AngularJS seed projecthttp://www.ivonet.nl/2015/04/23/java-angularjs-seed/2015-04-23T11:43:00.000Z2019-02-12T21:25:30.000Z<h1 id="Journey"><a href="#Journey" class="headerlink" title="Journey"></a>Journey</h1><p>In this article I’ll try to find the answer to a couple of basic questions like:</p>
<ul>
<li>Is there a marriage possible between AngularJS, Java and Maven? </li>
<li>Can it be done? </li>
<li>Should it be done? </li>
<li>Must it be done?</li>
</ul>
<p>Here I’ll describe the whole process of making a Java Maven AngularJS seed project.<br>This process will include the mistakes I make and the lessons learned.<br>The whole goal is to create a setup that can be build by a Java developer, with no specific front-end skills.</p>
<h2 id="Goals"><a href="#Goals" class="headerlink" title="Goals"></a>Goals</h2><ul>
<li>Maven as the build tool</li>
<li>Java EE 7 as the back-end language</li>
<li>CDI</li>
<li>AngularJS as the frond-end framework</li>
<li>Frond-end testing must also be done during the maven build</li>
<li>Bower as the web package manager.</li>
<li>Use Git as version control</li>
<li>Bootstrap als css standard</li>
<li>Javascript in src/main/javascript</li>
<li>Minifying javascript</li>
<li>Jasmine as javascript unit test tool integrated with maven</li>
</ul>
<h2 id="Prerequisites"><a href="#Prerequisites" class="headerlink" title="Prerequisites"></a>Prerequisites</h2><ul>
<li>Firefox or Chrome</li>
<li><a href="https://www.npmjs.org" target="_blank" rel="noopener">npm</a></li>
<li><a href="http://nodejs.org" target="_blank" rel="noopener">nodejs</a></li>
<li><a href="http://www.oracle.com/technetwork/java/javaee/downloads/index.html" target="_blank" rel="noopener">JDK</a></li>
<li><a href="http://www.jetbrains.com/" target="_blank" rel="noopener">IDE</a></li>
<li><a href="http://bower.io" target="_blank" rel="noopener">bower</a></li>
<li><a href="http://phantomjs.org" target="_blank" rel="noopener">PhantomJs</a> or <code>brew install phantomjs</code></li>
<li><a href="https://glassfish.java.net/download.html" target="_blank" rel="noopener">Application Server</a> or <code>brew install glassfish</code></li>
</ul>
<p>The project is hosted <a href="https://github.com/IvoNet/java-angularjs-seed" target="_blank" rel="noopener">here</a></p>
<h2 id="Basic-maven-project"><a href="#Basic-maven-project" class="headerlink" title="Basic maven project"></a>Basic maven project</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mvn archetype:generate -DgroupId=nl.ivonet -DartifactId=java-angularjs-seed -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=<span class="literal">false</span></span><br></pre></td></tr></table></figure>
<p>After generating I got this:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">./pom.xml</span><br><span class="line">./src</span><br><span class="line">./src/main</span><br><span class="line">./src/main/resources</span><br><span class="line">./src/main/webapp</span><br><span class="line">./src/main/webapp/index.jsp</span><br><span class="line">./src/main/webapp/WEB-INF</span><br><span class="line">./src/main/webapp/WEB-INF/web.xml</span><br></pre></td></tr></table></figure>
<p>Now we start configuring it.</p>
<p>First create test space and remove unnecessary files:</p>
<p>Open a terminal in the root of the project. (from now on all commands are assumed to be executed from the root of the project)</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p src/main/java</span><br><span class="line">mkdir -p src/<span class="built_in">test</span>/java</span><br><span class="line">mkdir -p src/<span class="built_in">test</span>/javascript/unit</span><br><span class="line">mkdir -p src/<span class="built_in">test</span>/javascript/e2e</span><br><span class="line">mkdir -p src/<span class="built_in">test</span>/resources</span><br><span class="line">rm -f ./src/main/webapp/WEB-INF/web.xml</span><br><span class="line">rm -f ./src/main/webapp/index.jsp</span><br><span class="line">mkdir -p ./src/main/webapp/css</span><br><span class="line">touch ./src/main/webapp/css/specific.css</span><br><span class="line">mkdir -p ./src/main/webapp/js</span><br><span class="line">touch ./src/main/webapp/js/app.js</span><br><span class="line">touch ./src/main/webapp/js/controllers.js</span><br><span class="line">touch ./src/main/webapp/js/routes.js</span><br><span class="line">touch ./src/main/webapp/js/services.js</span><br><span class="line">touch ./src/main/webapp/js/filters.js</span><br><span class="line">touch ./src/main/webapp/js/services.js</span><br><span class="line">mkdir -p ./src/main/webapp/vendor</span><br><span class="line">mkdir -p ./src/main/webapp/partials</span><br><span class="line">mkdir -p ./src/main/webapp/img</span><br><span class="line">touch README.md</span><br><span class="line">touch .bowerrc</span><br></pre></td></tr></table></figure>
<h2 id="Initialize-npm"><a href="#Initialize-npm" class="headerlink" title="Initialize npm"></a>Initialize npm</h2><p>As I want to use npm so I want to initialize it.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm init</span><br></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">This utility will walk you through creating a package.json file.</span><br><span class="line">It only covers the most common items, and tries to guess sane defaults.</span><br><span class="line"></span><br><span class="line">See `npm <span class="built_in">help</span> json` <span class="keyword">for</span> definitive documentation on these fields</span><br><span class="line">and exactly what they <span class="keyword">do</span>.</span><br><span class="line"></span><br><span class="line">Use `npm install <pkg> --save` afterwards to install a package and</span><br><span class="line">save it as a dependency <span class="keyword">in</span> the package.json file.</span><br><span class="line"></span><br><span class="line">Press ^C at any time to quit.</span><br><span class="line">name: (java-angularjs-seed)</span><br><span class="line">version: (0.0.0)</span><br><span class="line">description: A starter project <span class="keyword">for</span> AngularJS combined with java and maven</span><br><span class="line">entry point: (index.js)</span><br><span class="line"><span class="built_in">test</span> <span class="built_in">command</span>: karma start <span class="built_in">test</span>/resources/karma.conf.js</span><br><span class="line">git repository: https://github.com/ivonet/java-angular-seed</span><br><span class="line">keywords:</span><br><span class="line">author: Ivo Woltring</span><br><span class="line">license: (ISC) Apache 2.0</span><br><span class="line">About to write to /Users/ivonet/dev/ordina/LabTime/java-angularjs-seed/package.json:</span><br><span class="line"></span><br><span class="line">{</span><br><span class="line"> <span class="string">"name"</span>: <span class="string">"java-angularjs-seed"</span>,</span><br><span class="line"> <span class="string">"version"</span>: <span class="string">"0.0.0"</span>,</span><br><span class="line"> <span class="string">"description"</span>: <span class="string">"A starter project for AngularJS combined with java and maven"</span>,</span><br><span class="line"> <span class="string">"main"</span>: <span class="string">"index.js"</span>,</span><br><span class="line"> <span class="string">"scripts"</span>: {</span><br><span class="line"> <span class="string">"test"</span>: <span class="string">"karma start test/resources/karma.conf.js"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="string">"repository"</span>: {</span><br><span class="line"> <span class="string">"type"</span>: <span class="string">"git"</span>,</span><br><span class="line"> <span class="string">"url"</span>: <span class="string">"https://github.com/ivonet/java-angular-seed"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="string">"author"</span>: <span class="string">"Ivo Woltring"</span>,</span><br><span class="line"> <span class="string">"license"</span>: <span class="string">"Apache 2.0"</span>,</span><br><span class="line"> <span class="string">"bugs"</span>: {</span><br><span class="line"> <span class="string">"url"</span>: <span class="string">"https://github.com/ivonet/java-angular-seed/issues"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="string">"homepage"</span>: <span class="string">"https://github.com/ivonet/java-angular-seed"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Is this ok? (yes)</span><br></pre></td></tr></table></figure>
<p>adjust the <code>./package.json</code> file. It needs a bit more tweaking:</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"java-angular-seed"</span>,</span><br><span class="line"> <span class="attr">"private"</span>: <span class="literal">true</span>,</span><br><span class="line"> <span class="attr">"version"</span>: <span class="string">"0.0.0"</span>,</span><br><span class="line"> <span class="attr">"description"</span>: <span class="string">"A starter project for AngularJS combined with java and maven"</span>,</span><br><span class="line"> <span class="attr">"repository"</span>: <span class="string">"https://github.com/ivonet/java-angular-seed"</span>,</span><br><span class="line"> <span class="attr">"license"</span>: <span class="string">"Apache 2.0"</span>,</span><br><span class="line"> <span class="attr">"devDependencies"</span>: {</span><br><span class="line"> <span class="attr">"bower"</span>: <span class="string">"^1.3.1"</span>,</span><br><span class="line"> <span class="attr">"http-server"</span>: <span class="string">"^0.6.1"</span>,</span><br><span class="line"> <span class="attr">"karma"</span>: <span class="string">"~0.12"</span>,</span><br><span class="line"> <span class="attr">"karma-chrome-launcher"</span>: <span class="string">"^0.1.4"</span>,</span><br><span class="line"> <span class="attr">"karma-firefox-launcher"</span>: <span class="string">"^0.1.3"</span>,</span><br><span class="line"> <span class="attr">"karma-jasmine"</span>: <span class="string">"^0.1.5"</span>,</span><br><span class="line"> <span class="attr">"karma-junit-reporter"</span>: <span class="string">"^0.2.2"</span>,</span><br><span class="line"> <span class="attr">"protractor"</span>: <span class="string">"~0.20.1"</span>,</span><br><span class="line"> <span class="attr">"shelljs"</span>: <span class="string">"^0.2.6"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"scripts"</span>: {</span><br><span class="line"> <span class="attr">"postinstall"</span>: <span class="string">"bower install"</span>,</span><br><span class="line"> <span class="attr">"prestart"</span>: <span class="string">"npm install"</span>,</span><br><span class="line"> <span class="attr">"start"</span>: <span class="string">"http-server src/main/webapp -a localhost -p 8000"</span>,</span><br><span class="line"> <span class="attr">"pretest"</span>: <span class="string">"npm install"</span>,</span><br><span class="line"> <span class="attr">"test"</span>: <span class="string">"karma start src/test/javascript/karma.conf.js"</span>,</span><br><span class="line"> <span class="attr">"test-single-run"</span>: <span class="string">"karma start src/test/javascript/karma.conf.js --single-run"</span>,</span><br><span class="line"> <span class="attr">"preupdate-webdriver"</span>: <span class="string">"npm install"</span>,</span><br><span class="line"> <span class="attr">"update-webdriver"</span>: <span class="string">"webdriver-manager update"</span>,</span><br><span class="line"> <span class="attr">"preprotractor"</span>: <span class="string">"npm run update-webdriver"</span>,</span><br><span class="line"> <span class="attr">"protractor"</span>: <span class="string">"protractor src/test/javascript/protractor-conf.js"</span>,</span><br><span class="line"> <span class="attr">"update-index-async"</span>: <span class="string">"node -e \"require('shelljs/global'); sed('-i', /\\/\\/@@NG_LOADER_START@@[\\s\\S]*\\/\\/@@NG_LOADER_END@@/, '//@@NG_LOADER_START@@\\n' + cat('src/main/webapp/vendor/angular-loader/angular-loader.min.js') + '\\n//@@NG_LOADER_END@@', 'src/main/webapp/index.html');\""</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Add-Bower"><a href="#Add-Bower" class="headerlink" title="Add Bower"></a>Add Bower</h2><p>I want to use <a href="http://bower.io" target="_blank" rel="noopener">bower</a> as the the web package manager. </p>
<p>The default place bower will install its dependencies is <code>./bower-components</code> but as I want them to conform to the maven structure I will add a directive to the <code>.bowerrc</code> file we just created.<br>Information hiding dictates that I won’t tell users that I manage stuff with bower.</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"directory"</span>: <span class="string">"src/main/webapp/vendor"</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>This will tell bower to copy the downloaded packages to that place.</p>
<h2 id="Add-dependencies-by-hand"><a href="#Add-dependencies-by-hand" class="headerlink" title="Add dependencies (by hand)"></a>Add dependencies (by hand)</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">bower install angular<span class="comment">#1.3.0-beta.14</span></span><br><span class="line">bower install angular-route<span class="comment">#1.3.0-beta.14</span></span><br><span class="line">bower install angular-animate<span class="comment">#1.3.0-beta.14</span></span><br><span class="line">bower install angular-mocks<span class="comment">#1.3.0-beta.14</span></span><br><span class="line">bower install angular-loader<span class="comment">#1.3.0-beta.14</span></span><br><span class="line">bower install bootstrap</span><br></pre></td></tr></table></figure>
<p>This should be enough for a first basic setup. You might want to change the versions.</p>
<p>Because I want to have an easy setup I want to eliminate all these manual steps so now I want to have a config file that helps me to do this automagically :-).<br>The following command will help create a setup script for bower.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bower init</span><br></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">[?] name: java-angularjs-seed</span><br><span class="line">[?] version: 0.0.0</span><br><span class="line">[?] description: A java / maven / angularjs seed project</span><br><span class="line">[?] main file: src/main/webapp/index.html</span><br><span class="line">[?] what types of modules does this package expose?</span><br><span class="line">[?] keywords: java,maven,angularjs,seed</span><br><span class="line">[?] authors: IvoNet <webmaster@ivonet.nl></span><br><span class="line">[?] license: Apache 2.0</span><br><span class="line">[?] homepage: http://ivonet.nl</span><br><span class="line">[?] <span class="built_in">set</span> currently installed components as dependencies? Yes</span><br><span class="line">[?] add commonly ignored files to ignore list? Yes</span><br><span class="line">[?] would you like to mark this package as private <span class="built_in">which</span> prevents it from being accidentally pub[?] would you like to mark this package as private <span class="built_in">which</span> prevents it from being accidentally published to the registry? Yes</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">[?] Looks good? (Y/n) Y</span><br></pre></td></tr></table></figure>
<p>The resulting <code>./bower.json</code> file should look something like:</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"java-angularjs-seed"</span>,</span><br><span class="line"> <span class="attr">"version"</span>: <span class="string">"0.0.0"</span>,</span><br><span class="line"> <span class="attr">"authors"</span>: [</span><br><span class="line"> <span class="string">"IvoNet <webmaster@ivonet.nl>"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"description"</span>: <span class="string">"A java / maven / angularjs seed project"</span>,</span><br><span class="line"> <span class="attr">"keywords"</span>: [</span><br><span class="line"> <span class="string">"java"</span>,</span><br><span class="line"> <span class="string">"maven"</span>,</span><br><span class="line"> <span class="string">"angularjs"</span>,</span><br><span class="line"> <span class="string">"seed"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"license"</span>: <span class="string">"Apache 2.0"</span>,</span><br><span class="line"> <span class="attr">"homepage"</span>: <span class="string">"http://ivonet.nl"</span>,</span><br><span class="line"> <span class="attr">"private"</span>: <span class="literal">true</span>,</span><br><span class="line"> <span class="attr">"ignore"</span>: [</span><br><span class="line"> <span class="string">"**/.*"</span>,</span><br><span class="line"> <span class="string">"node_modules"</span>,</span><br><span class="line"> <span class="string">"bower_components"</span>,</span><br><span class="line"> <span class="string">"src/main/webapp/vendor"</span>,</span><br><span class="line"> <span class="string">"test"</span>,</span><br><span class="line"> <span class="string">"tests"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"dependencies"</span>: {</span><br><span class="line"> <span class="attr">"angular"</span>: <span class="string">"1.3.0-beta.14"</span>,</span><br><span class="line"> <span class="attr">"angular-loader"</span>: <span class="string">"1.3.0-beta.14"</span>,</span><br><span class="line"> <span class="attr">"angular-mocks"</span>: <span class="string">"1.3.0-beta.14"</span>,</span><br><span class="line"> <span class="attr">"angular-route"</span>: <span class="string">"1.3.0-beta.14"</span>,</span><br><span class="line"> <span class="attr">"bootstrap"</span>: <span class="string">"3.2.0"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"main"</span>: <span class="string">"src/main/webapp/index.html"</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Now that I have this config file I should be able to add the dependencies with a command.<br>But first to test it We need to remove the manually added dependencies :-)</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rm -rf ./src/main/webapp/vendor</span><br></pre></td></tr></table></figure>
<p>Now to test the try out the setup:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install</span><br></pre></td></tr></table></figure>
<p>It should recreate it all again :-)</p>
<p>It will also add a folder <code>node_modules</code> to the project.<br>These folders should be excluded from version control, but that will be done later</p>
<h2 id="Add-Karma"><a href="#Add-Karma" class="headerlink" title="Add Karma"></a>Add Karma</h2><p>I want to use <a href="http://karma-runner.github.io" target="_blank" rel="noopener">Karma</a> as the testrunner for javascript.<br>Create the <code>./src/test/javascript/karma.conf.js</code> containing:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span>(<span class="params">config</span>)</span>{</span><br><span class="line"> config.set({</span><br><span class="line"></span><br><span class="line"> basePath : <span class="string">'../../../'</span>,</span><br><span class="line"></span><br><span class="line"> files : [</span><br><span class="line"> <span class="string">'src/main/webapp/vendor/angular**/**.min.js'</span>,</span><br><span class="line"> <span class="string">'src/main/webapp/vendor/angular-mocks/angular-mocks.js'</span>,</span><br><span class="line"> <span class="string">'src/main/webapp/js/**/*.js'</span>,</span><br><span class="line"> <span class="string">'src/test/javascript/unit/**/*.js'</span></span><br><span class="line"> ],</span><br><span class="line"></span><br><span class="line"> autoWatch : <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> frameworks: [<span class="string">'jasmine'</span>],</span><br><span class="line"></span><br><span class="line"> browsers : [<span class="string">'Chrome'</span>],</span><br><span class="line"></span><br><span class="line"> plugins : [</span><br><span class="line"> <span class="string">'karma-chrome-launcher'</span>,</span><br><span class="line"> <span class="string">'karma-firefox-launcher'</span>,</span><br><span class="line"> <span class="string">'karma-jasmine'</span>,</span><br><span class="line"> <span class="string">'karma-junit-reporter'</span></span><br><span class="line"> ],</span><br><span class="line"></span><br><span class="line"> junitReporter : {</span><br><span class="line"> outputFile: <span class="string">'target/test_out/unit.xml'</span>,</span><br><span class="line"> suite: <span class="string">'src/test/javascript/unit'</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> });</span><br><span class="line">};</span><br></pre></td></tr></table></figure>
<p>Now we can run the unit tests by using the command <code>npm test</code></p>
<h2 id="Add-Protractor"><a href="#Add-Protractor" class="headerlink" title="Add Protractor"></a>Add Protractor</h2><p>I want to use <a href="https://github.com/angular/protractor" target="_blank" rel="noopener">protractor</a> as the end-2-end tester.<br>Create the <code>./src/test/javascript/protractor-conf.js</code></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"></span><br><span class="line">exports.config = {</span><br><span class="line"> allScriptsTimeout: <span class="number">11000</span>,</span><br><span class="line"></span><br><span class="line"> specs: [</span><br><span class="line"> <span class="string">'e2e/*.js'</span></span><br><span class="line"> ],</span><br><span class="line"></span><br><span class="line"> capabilities: {</span><br><span class="line"> <span class="string">'browserName'</span>: <span class="string">'chrome'</span></span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> baseUrl: <span class="string">'http://localhost:8000/'</span>,</span><br><span class="line"></span><br><span class="line"> framework: <span class="string">'jasmine'</span>,</span><br><span class="line"></span><br><span class="line"> jasmineNodeOpts: {</span><br><span class="line"> defaultTimeoutInterval: <span class="number">30000</span></span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure>
<p>Now we can run the integration tests by using the command <code>npm run protractor</code></p>
<h2 id="Add-html"><a href="#Add-html" class="headerlink" title="Add html"></a>Add html</h2><p><strong>index.html</strong>:</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!doctype html></span></span><br><span class="line"><span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span> <span class="attr">data-ng-app</span>=<span class="string">"app"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>Seed App<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"vendor/bootstrap/dist/css/bootstrap.min.css"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"css/specific.css"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">ng-view</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"vendor/angular/angular.min.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"vendor/angular-route/angular-route.min.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"js/app.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"js/controllers.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"js/filters.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"js/routes.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"js/services.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure>
<p><strong>partials/home.html</strong>:</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">p</span>></span>{{title}}<span class="tag"></<span class="name">p</span>></span></span><br></pre></td></tr></table></figure>
<h2 id="Add-hello-world-AngularJs"><a href="#Add-hello-world-AngularJs" class="headerlink" title="Add hello world AngularJs"></a>Add hello world AngularJs</h2><p><strong>js/apps.js</strong>:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> app = angular.module(<span class="string">'app'</span>, [</span><br><span class="line"> <span class="string">'ngRoute'</span>,</span><br><span class="line"> <span class="string">'controllers'</span></span><br><span class="line">]);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">app.config([<span class="string">'$routeProvider'</span>,</span><br><span class="line"> <span class="function"><span class="keyword">function</span> (<span class="params">$routeProvider</span>) </span>{</span><br><span class="line"> $routeProvider</span><br><span class="line"> .when(<span class="string">'/'</span>, {</span><br><span class="line"> templateUrl: <span class="string">'partials/home.html'</span>,</span><br><span class="line"> controller: <span class="string">'HomeController'</span></span><br><span class="line"> })</span><br><span class="line"> .otherwise({</span><br><span class="line"> redirectTo: <span class="string">'/'</span></span><br><span class="line"> });</span><br><span class="line"> }]);</span><br></pre></td></tr></table></figure>
<p><strong>js/controlers.js</strong>:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> controllers = angular.module(<span class="string">"controllers"</span>, []);</span><br><span class="line"></span><br><span class="line">controllers.controller(<span class="string">"HomeController"</span>, [<span class="string">'$scope'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">$scope</span>) </span>{</span><br><span class="line"> $scope.title = <span class="string">'Hello world!'</span>;</span><br><span class="line">}]);</span><br></pre></td></tr></table></figure>
<h2 id="Add-Jasmine-tests"><a href="#Add-Jasmine-tests" class="headerlink" title="Add Jasmine tests"></a>Add Jasmine tests</h2><p><strong>src/test/javascript/unit/controllersSpec.js</strong>:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* jasmine specs for controllers go here */</span></span><br><span class="line">describe(<span class="string">'Controller tests'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"></span><br><span class="line"> describe(<span class="string">'HomeController'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> scope, ctrl;</span><br><span class="line"></span><br><span class="line"> beforeEach(<span class="built_in">module</span>(<span class="string">'app'</span>));</span><br><span class="line"> beforeEach(inject(<span class="function"><span class="keyword">function</span> (<span class="params">$rootScope, $controller</span>) </span>{</span><br><span class="line"> scope = $rootScope.$<span class="keyword">new</span>();</span><br><span class="line"> ctrl = $controller(<span class="string">'HomeController'</span>, {<span class="attr">$scope</span>: scope});</span><br><span class="line"> }));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> it(<span class="string">'should contain hello world'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> expect(scope.title).toBe(<span class="string">'Hello world!'</span>);</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<h2 id="Add-end-2-end-tests"><a href="#Add-end-2-end-tests" class="headerlink" title="Add end-2-end tests"></a>Add end-2-end tests</h2><p><strong>src/test/javascript/e2e/scenarios.js</strong>:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */</span></span><br><span class="line"></span><br><span class="line">describe(<span class="string">'App integration tests'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> beforeEach(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> browser.get(<span class="string">'/index.html'</span>);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> it(<span class="string">'should redirect index.html to index.html#/'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> browser.getLocationAbsUrl().then(<span class="function"><span class="keyword">function</span> (<span class="params">url</span>) </span>{</span><br><span class="line"> expect(url.split(<span class="string">'#'</span>)[<span class="number">1</span>]).toBe(<span class="string">'/'</span>);</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<h2 id="Test-basic-setup"><a href="#Test-basic-setup" class="headerlink" title="Test basic setup"></a>Test basic setup</h2><p>For this we need two terminal windows opened in the root of the project</p>
<p>In one of the terminals start the test server<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm start</span><br></pre></td></tr></table></figure></p>
<p>Go <a href="http://localhost:8000/" target="_blank" rel="noopener">here</a> in a browser. You should see “Hello world!”</p>
<p>In the other terminal try out:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run progractor</span><br></pre></td></tr></table></figure>
<p>This should result in an executed e2e test with no errors.</p>
<p>Try out:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm <span class="built_in">test</span></span><br></pre></td></tr></table></figure>
<p>This should result in a working unit test and it should keep on monitoring for test changes.<br>If you change the test in controllersSpec.js to a wrong text you should see this almost immediately in the terminal window.</p>
<h2 id="Add-Java-EE-7"><a href="#Add-Java-EE-7" class="headerlink" title="Add Java EE 7"></a>Add Java EE 7</h2><p>I want to be able to use the EE 7 stack.</p>
<p>Adjust the pom.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">modelVersion</span>></span>4.0.0<span class="tag"></<span class="name">modelVersion</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>nl.ivonet<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>java-angularjs-seed<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">packaging</span>></span>war<span class="tag"></<span class="name">packaging</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>java-angularjs-seed Maven Webapp<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">url</span>></span>http://ivonet.nl<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">properties</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifact.name</span>></span>app<span class="tag"></<span class="name">artifact.name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">endorsed.dir</span>></span>${project.build.directory}/endorsed<span class="tag"></<span class="name">endorsed.dir</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">project.build.sourceEncoding</span>></span>UTF-8<span class="tag"></<span class="name">project.build.sourceEncoding</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">properties</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>junit<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>junit<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>4.11<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.mockito<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>mockito-all<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.9.5<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>javax<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>javaee-api<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>7.0<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>provided<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">finalName</span>></span>${artifact.name}<span class="tag"></<span class="name">finalName</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.maven.plugins<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>maven-compiler-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>3.1<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">source</span>></span>1.8<span class="tag"></<span class="name">source</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">target</span>></span>1.8<span class="tag"></<span class="name">target</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">compilerArguments</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">endorseddirs</span>></span>${endorsed.dir}<span class="tag"></<span class="name">endorseddirs</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">compilerArguments</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.maven.plugins<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>maven-war-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.4<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">failOnMissingWebXml</span>></span>false<span class="tag"></<span class="name">failOnMissingWebXml</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.maven.plugins<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>maven-dependency-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.6<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">phase</span>></span>validate<span class="tag"></<span class="name">phase</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goal</span>></span>copy<span class="tag"></<span class="name">goal</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">outputDirectory</span>></span>${endorsed.dir}<span class="tag"></<span class="name">outputDirectory</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">silent</span>></span>true<span class="tag"></<span class="name">silent</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactItems</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactItem</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>javax<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>javaee-endorsed-api<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>7.0<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">type</span>></span>jar<span class="tag"></<span class="name">type</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">artifactItem</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">artifactItems</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">build</span>></span></span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure>
<h2 id="CDI"><a href="#CDI" class="headerlink" title="CDI"></a>CDI</h2><p>Now we want to have CDI so we need ths file <code>./src/main/webapp/WEB-INF/beans.xml</code>:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><?xml version="1.0" encoding="UTF-8"?></span><br><span class="line"><span class="tag"><<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://xmlns.jcp.org/xml/ns/javaee"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">bean-discovery-mode</span>=<span class="string">"annotated"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">beans</span>></span></span><br></pre></td></tr></table></figure>
<p>We now have a basic maven project that can be build by the standard maven commands.</p>
<h2 id="Intermezzo"><a href="#Intermezzo" class="headerlink" title="Intermezzo"></a>Intermezzo</h2><p>So now I have a working project that can contain java and angular with all its functionality. The trouble is there is no integration yet, no version control and no maven build that does it all.</p>
<p>I don’t even know if it can be done with currently available tools.</p>
<p>Goals met:</p>
<ul>
<li>AngularJS as the frond-end framework</li>
<li>Bower as the web package manager.</li>
</ul>
<p>Goals partially met:</p>
<ul>
<li>Maven as the build tool, but no javascript tests yet</li>
<li>Java EE 7 as the back-end language, but no example yet</li>
<li>CDI, but no example yet</li>
<li>bootstrap</li>
<li>Javascript unit testing</li>
</ul>
<p>Goals to be met:</p>
<ul>
<li>Maven as the build tool</li>
<li>Java EE 7 as the back-end language - with example</li>
<li>Frond-end testing must also be able done during the maven build</li>
<li>Use Git as version control</li>
<li>Maven integration for javascript testing</li>
<li>Maven for minifying javascript</li>
<li>Javascript jslint</li>
<li>Javascript as resource</li>
</ul>
<h2 id="Add-Version-Controll"><a href="#Add-Version-Controll" class="headerlink" title="Add Version Controll"></a>Add Version Controll</h2><p>I use Git for this.</p>
<p>add a <code>.gitignore</code> file to the root of the project containing:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">.idea/</span><br><span class="line">.DS_Store</span><br><span class="line">node_modules/</span><br></pre></td></tr></table></figure>
<p>add a <code>.gitignore</code> file to the src/main/webapp of the project containing:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vendor/</span><br></pre></td></tr></table></figure>
<p>now create the git repository:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git init</span><br><span class="line">git add .</span><br><span class="line">git commit -m <span class="string">"initial import"</span></span><br></pre></td></tr></table></figure>
<h2 id="Add-Java-example"><a href="#Add-Java-example" class="headerlink" title="Add Java example"></a>Add Java example</h2><p>In order to get make it possible to create restful services we need a root context for these services. As I want to talk json I also define a json provider.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> nl.ivonet.application;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> nl.ivonet.controler.HomeControler;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.ws.rs.ApplicationPath;</span><br><span class="line"><span class="keyword">import</span> javax.ws.rs.core.Application;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Basic JAX-RS application.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Ivo Woltring</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@ApplicationPath</span>(<span class="string">"service"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SeedApplication</span> <span class="keyword">extends</span> <span class="title">Application</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Set<Class<?>> getClasses() {</span><br><span class="line"> <span class="keyword">final</span> Set<Class<?>> resources = <span class="keyword">new</span> java.util.HashSet<>();</span><br><span class="line"> <span class="comment">// following code can be used to customize Jersey 2.0 JSON provider:</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">final</span> Class jsonProvider = Class.forName(<span class="string">"org.glassfish.jersey.jackson.JacksonFeature"</span>);</span><br><span class="line"> <span class="comment">// Class jsonProvider = Class.forName("org.glassfish.jersey.moxy.json.MoxyJsonFeature");</span></span><br><span class="line"> <span class="comment">// Class jsonProvider = Class.forName("org.glassfish.jersey.jettison.JettisonFeature");</span></span><br><span class="line"> resources.add(jsonProvider);</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> ClassNotFoundException ex) {</span><br><span class="line"> java.util.logging.Logger.getLogger(getClass().getName())</span><br><span class="line"> .log(java.util.logging.Level.SEVERE, <span class="keyword">null</span>, ex);</span><br><span class="line"> }</span><br><span class="line"> addRestResourceClasses(resources);</span><br><span class="line"> <span class="keyword">return</span> resources;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Add your own resources here.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">addRestResourceClasses</span><span class="params">(<span class="keyword">final</span> Set<Class<?>> resources)</span> </span>{</span><br><span class="line"> resources.add(HomeControler.class);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Now for a Hello world service…</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> nl.ivonet.controler;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> nl.ivonet.model.Hello;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.enterprise.context.RequestScoped;</span><br><span class="line"><span class="keyword">import</span> javax.ws.rs.GET;</span><br><span class="line"><span class="keyword">import</span> javax.ws.rs.Path;</span><br><span class="line"><span class="keyword">import</span> javax.ws.rs.Produces;</span><br><span class="line"><span class="keyword">import</span> javax.ws.rs.core.MediaType;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Hello world man.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Ivo Woltring</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Path</span>(<span class="string">"/home"</span>)</span><br><span class="line"><span class="meta">@RequestScoped</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HomeControler</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GET</span></span><br><span class="line"> <span class="meta">@Produces</span>(MediaType.APPLICATION_JSON)</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Hello <span class="title">get</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Hello(<span class="string">"world"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Change the <code>HomeController.js</code></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> controllers = angular.module(<span class="string">"controllers"</span>, []);</span><br><span class="line"></span><br><span class="line">controllers.controller(<span class="string">"HomeController"</span>, [<span class="string">'$scope'</span>, <span class="string">'$http'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">$scope, $http</span>) </span>{</span><br><span class="line"> $scope.debug = <span class="literal">true</span>;</span><br><span class="line"> $scope.title = <span class="string">'Hello '</span>;</span><br><span class="line"></span><br><span class="line"> $http.get(<span class="string">"service/home"</span>).success(<span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>{</span><br><span class="line"> $scope.data = data;</span><br><span class="line"> $scope.title += $scope.data.message;</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> $scope.toggleDebug = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> $scope.debug = !$scope.debug;</span><br><span class="line"> };</span><br><span class="line">}]);</span><br></pre></td></tr></table></figure>
<p>And the <code>home.html</code></p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">p</span>></span>{{title}}<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">pre</span> <span class="attr">data-ng-model</span>=<span class="string">"debug"</span> <span class="attr">data-ng-show</span>=<span class="string">"debug"</span>></span>{{ data | json }}<span class="tag"></<span class="name">pre</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure>
<p>For this all to work we need a Java EE Container and Node.js just won’t do :-)<br>I work with Glassfish for my test environment and deployed it.</p>
<p>And now we get:</p>
<p><img src="/images/2015/seed/Hello_World.png" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<h2 id="Refactoring…"><a href="#Refactoring…" class="headerlink" title="Refactoring…"></a>Refactoring…</h2><p>I stared a bit at the code and concluded that I’m not happy with the current state of affairs. Right now I have my javascript code in the src/main/webapp/js folder and it shouldn’t be there. According to maven rulez it should be in <code>src/main/javascript</code> just like java. I also want to have a minified javascript in the artifact and not the origional.</p>
<p>So added the folder and told maven it needed to recognize it as a resource folder.</p>
<p>Add the folling config snippet to the <code><build></code> tag in the pom.xml<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">resources</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">resource</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">directory</span>></span>src/main/javascript<span class="tag"></<span class="name">directory</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filtering</span>></span>true<span class="tag"></<span class="name">filtering</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">resource</span>></span></span><br><span class="line"><span class="tag"></<span class="name">resources</span>></span></span><br></pre></td></tr></table></figure></p>
<p>now I moved all files in the js folder of the webapp to that folder and removed the js folder in webapp.<br>Now I wanted the minifacation to work and the jslint. I used a maven plugin for that. After some trials and errors the following config seems to work the best.</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>net.alchim31.maven<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>yuicompressor-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.1<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>compress-js<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goal</span>></span>jslint<span class="tag"></<span class="name">goal</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goal</span>></span>compress<span class="tag"></<span class="name">goal</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">failOnWarning</span>></span>true<span class="tag"></<span class="name">failOnWarning</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">outputDirectory</span>></span>target/app/js/<span class="tag"></<span class="name">outputDirectory</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">nosuffix</span>></span>true<span class="tag"></<span class="name">nosuffix</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">excludes</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">exclude</span>></span>vendor/**<span class="tag"></<span class="name">exclude</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">exclude</span>></span>**/*min.css<span class="tag"></<span class="name">exclude</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">exclude</span>></span>**/*min.js<span class="tag"></<span class="name">exclude</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">excludes</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"><span class="tag"></<span class="name">plugin</span>></span></span><br></pre></td></tr></table></figure>
<p>and a small change to the <code>karma.conf.js</code>. Change <code>src/main/webapp/js/**/*.js</code> to <code>src/main/javascript/**/*.js</code>. now the <code>npm test</code> should work again.</p>
<p>The <code>mvn clean package</code> command failed because my app.js didn’t get through the jslint step and that is just what I wanted. Fixed it and voila.</p>
<p>The code until now is checked in.</p>
<h2 id="Intermezzo-1"><a href="#Intermezzo-1" class="headerlink" title="Intermezzo"></a>Intermezzo</h2><p>Goals met:</p>
<ul>
<li>AngularJS as the frond-end framework</li>
<li>Bower as the web package manager.</li>
<li>Javascript jslint</li>
<li>Javascript as resource</li>
<li>Javascript testing with Karma / Jasmine</li>
<li>Maven for minifying javascript</li>
<li>Maven as the build tool</li>
<li>Java EE 7 as the back-end language</li>
<li>bootstrap</li>
<li>CDI</li>
<li>Use Git as version control</li>
</ul>
<p>Goals to be met:</p>
<ul>
<li>Frond-end testing must also be able done during the maven build</li>
<li>Maven integration for javascript testing</li>
</ul>
<p>So I guess that my main goal now is to get jasmine working with maven…</p>
<h2 id="Add-jasmine-maven-plugin"><a href="#Add-jasmine-maven-plugin" class="headerlink" title="Add jasmine maven plugin"></a>Add jasmine maven plugin</h2><p>At first I removed all jasmine pom stuff to start from scratch. Then I added the most basic jasmine config to it.<br>But that didn’t work at all. Which was actually logical but I had to do some reading to understand that :-). I had to tell (in the correct order) what the plugin already needs to know before it can test my personal javascript code. At this time this means that I have to tell it to load JQuery and Angular and the Angular mocks. That seemed to do a bit more but now it didn’t find any *Spec.js files and I had to tell the plugin where to find that and the sources.<br>This seemed to work but I got terrible stacktraces. After some <a href="https://github.com/searls/jasmine-maven-plugin/issues/178" target="_blank" rel="noopener">research</a> I found out that it had nothing to do with my configuration but with htmlunit, which is used by default by the plugin. So I had to install phantomjs and configure it as the driver.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install phantomjs</span><br></pre></td></tr></table></figure>
<p>Or install it according to the <a href="http://phantomjs.org/download.html" target="_blank" rel="noopener">these</a> instructions.</p>
<p>The plugin configuration below finally worked.</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.github.searls<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>jasmine-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.3.1.5<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goal</span>></span>test<span class="tag"></<span class="name">goal</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goal</span>></span>bdd<span class="tag"></<span class="name">goal</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">webDriverClassName</span>></span>org.openqa.selenium.phantomjs.PhantomJSDriver<span class="tag"></<span class="name">webDriverClassName</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">preloadSources</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">source</span>></span>${vendor.loc}/jquery/dist/jquery.js<span class="tag"></<span class="name">source</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">source</span>></span>${vendor.loc}/angular/angular.min.js<span class="tag"></<span class="name">source</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">source</span>></span>${vendor.loc}/angular-route/angular-route.min.js<span class="tag"></<span class="name">source</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">source</span>></span>${vendor.loc}/angular-mocks/angular-mocks.js<span class="tag"></<span class="name">source</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">preloadSources</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">jsSrcDir</span>></span>src/main/javascript<span class="tag"></<span class="name">jsSrcDir</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">jsTestSrcDir</span>></span>src/test/javascript/unit<span class="tag"></<span class="name">jsTestSrcDir</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">specIncludes</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">include</span>></span>*Spec.js<span class="tag"></<span class="name">include</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">specIncludes</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"><span class="tag"></<span class="name">plugin</span>></span></span><br></pre></td></tr></table></figure>
<h2 id="Add-bower-to-maven"><a href="#Add-bower-to-maven" class="headerlink" title="Add bower to maven"></a>Add bower to maven</h2><p>As I want to have the integration as complete as possible I want to have the initial <code>bower install</code> also part of maven. Again some research and for me the maven-exec-plugin seems a good solution:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.codehaus.mojo<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>exec-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.3.2<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">phase</span>></span>generate-sources<span class="tag"></<span class="name">phase</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goal</span>></span>exec<span class="tag"></<span class="name">goal</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">executable</span>></span>bower<span class="tag"></<span class="name">executable</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">arguments</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">argument</span>></span>install<span class="tag"></<span class="name">argument</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">arguments</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">workingDirectory</span>></span>${basedir}<span class="tag"></<span class="name">workingDirectory</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br></pre></td></tr></table></figure>
<p>Now during the generate-source phase it will run bower and put all the javascript dependencies into src/main/webapp/vendor because that has been configured in .bowerrc and bower.json. Good stuff :-)</p>
<h2 id="Clean"><a href="#Clean" class="headerlink" title="Clean"></a>Clean</h2><p>As the vendor folder in webapp is not part of our version control and cleanup is also part of the fun I added the maven clean plugin with a bit of configuration.</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>maven-clean-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.5<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filesets</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">fileset</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">directory</span>></span>src/main/webapp/vendor<span class="tag"></<span class="name">directory</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">fileset</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">fileset</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">directory</span>></span>node_modules<span class="tag"></<span class="name">directory</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">fileset</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">filesets</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"><span class="tag"></<span class="name">plugin</span>></span></span><br></pre></td></tr></table></figure>
<h2 id="Removed-protractor"><a href="#Removed-protractor" class="headerlink" title="Removed protractor"></a>Removed protractor</h2><p>As I tend to use Fitnesse and Selenium (in comination) to do my end-to-end testing I decided to remove protractor from the project. I want to test against the real server with all stuff working before running e2e tests. </p>
<p>I had to refactor some stuff like the path to the javascript unit tests as I moved the other scripts to <code>src/test/javascript</code> and removing references to protractor.</p>
<h2 id="Conclusion-for-now"><a href="#Conclusion-for-now" class="headerlink" title="Conclusion (for now :-))"></a>Conclusion (for now :-))</h2><p>I committed the whole seed project to <a href="https://github.com/IvoNet/java-angularjs-seed" target="_blank" rel="noopener">github</a> and except for the end to end tests it all seems to work. I don’t mind about that because I tend to use Fitnesse for these kinds of tests so I can test against the real server.</p>
<p>It is a learning process and to say that I’m completely happy with the configuration is to lie. </p>
<p>In this version of the seed project it was all about integration. Integrating the different worlds of front-end and back-end with all it’s tools.</p>
<p>The question remains if that should be the way to go? I don’t know yet. Decoupling these worlds might be better.</p>
<p>I tend to think that these worlds should only meet through services and the front-end and back-end should be build separately. But as I was writing this a colleague of mine told me that he really wanted a setup like this because he wanted the java developers to be able to build the whole project with a simple command like mvn clean install, because it cuts down on the learning curve.</p>
<p>Final conclusion: Who am I to judge?!</p>
<h1 id="Extra’s"><a href="#Extra’s" class="headerlink" title="Extra’s"></a>Extra’s</h1><h2 id="IDE-Configuration"><a href="#IDE-Configuration" class="headerlink" title="IDE Configuration"></a>IDE Configuration</h2><p>I assume IntelliJ because lets be real… There can be only one :-)<br>I also assume that glassfish is already installed.</p>
<p>The first time you check out the project you should run <code>mvn package</code> or <code>mvn exec:exec</code> to get the vendor resources installed.</p>
<p>Now you can deploy to glassfish through the IDE but you will still not have the javascript resources copied to the right place. In order to get this to work you can tell IntelliJ to perform a step before every make (see the picture below)</p>
<p>Choose on yuicompressor:compress the right mouse option: <code>Execute Before Make</code>.</p>
<p><img src="/images/2015/seed/java-angularjs-seed-ide.png" style="width:50%;height:50%;display: block;margin: 0 auto;"></p>
<p>Now whenever you press <code>cmd+F9</code> or <code>ctrl+r</code> the compressor plugin will do its thing and update the resources.</p>
<p>Cheerz,</p>
<p>Ivo.</p>
<h1 id="Open-Questions"><a href="#Open-Questions" class="headerlink" title="Open Questions"></a>Open Questions</h1><ul>
<li>Is Yeoman something to look at?</li>
<li>What about grunt? is it better?</li>
<li>Or Gulp?</li>
<li>Should I make the back-end and frond-end separate projects so they can be developed separately? </li>
<li>JHipster?</li>
<li>run with jetty</li>
<li>jslint as part of the config again</li>
<li>webjars</li>
</ul>
<h1 id="Related-topics"><a href="#Related-topics" class="headerlink" title="Related topics"></a>Related topics</h1><ul>
<li>[[Java - AngularJS - maven archetype|/Java/java-angularjs-seed-archetype]]</li>
<li><a href="http://java.dzone.com/articles/java-maven-angularjs-seed" target="_blank" rel="noopener">Java Maven AngularJS seed project on DZone</a></li>
</ul>
<h1 id="Journey"><a href="#Journey" class="headerlink" title="Journey"></a>Journey</h1><p>In this article I’ll try to find the answer to a c