<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Not obvious ]]></title><description><![CDATA[Notes about programming tasks that took too long. By Patrik Duditš. ]]></description><link>https://pdudits.github.io</link><image><url>https://cloud.githubusercontent.com/assets/1588543/21372338/c07f1c2e-c716-11e6-8daa-aa3b35a2d2cf.jpg</url><title>Not obvious </title><link>https://pdudits.github.io</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 30 Nov 2017 15:11:04 GMT</lastBuildDate><atom:link href="https://pdudits.github.io/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Log directly to Logstash from Payara]]></title><description><![CDATA[<div id="preamble">
<div class="sectionbody">
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
Also published on <a href="http://blog.payara.fish/log-directly-to-logstash-from-payara-server">Payara blog</a>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>When running multiple instances of an application server it is quite hard to see correlations between events.
One of the best tools to enable that is <a href="https://www.elastic.co/products">the ELK stack</a> - Elasticsearch for building fulltext index of the log entries, Logstash for managing the inflow the events, and Kibana as a user interface on top of that.</p>
</div>
<div class="paragraph">
<p><a href="https://docs.payara.fish/documentation/core-documentation/logging/payara/json-formatter.html">Solutions for Payara Server exist</a>, that use better parseable log format]which can be then processed by <a href="https://www.elastic.co/products/beats/filebeat">Logstash Filebeat</a> in order to have these log entries processed by a remote Logstash server.</p>
</div>
<div class="paragraph">
<p>In our project, we chose a different path&#8201;&#8212;&#8201;we replaced all logging in the server and our applications with Logback, and make use of the  <a href="https://github.com/logstash/logstash-logback-encoder"><code>logback-logstash-appender</code></a> to push the events directly to Logstash over a TCP socket.
The appender uses LMAX disruptor internally to push the logs, so the processes does not block the application flow.</p>
</div>
<div class="paragraph">
<p>This article will show you how to have this configured for your project as well.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_log_everything_via_logstash">Log everything via Logstash</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In first step, we replace the backend for Payara Server&#8217;s logging with logstash.</p>
</div>
<div class="paragraph">
<p><a href="https://github.com/goodees/goodees">Project goodees</a> was started by me to collect useful small components for Java EE, and Payara Server in particular.
The first released component is <a href="https://github.com/goodees/goodees/tree/master/payara-logback">payara-logback</a>, that includes all libraries properly packaged to use logback as the logging backend in Payara Server and also includes an installation script.</p>
</div>
<div class="paragraph">
<p>Follow <a href="https://github.com/goodees/goodees/blob/master/payara-logback/README.adoc">the instructions there</a> to switch your logging.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_logback_and_logstash_configuration">Logback and logstash configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Our logback configuration looks similar to following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;configuration scan="true"&gt;
    &lt;jmxConfigurator /&gt;
    &lt;shutdownHook/&gt;
    &lt;!-- propagate changes to java.util.logging --&gt; <i class="conum" data-value="1"></i><b>(1)</b>
    &lt;contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"&gt;
        &lt;resetJUL&gt;true&lt;/resetJUL&gt;
    &lt;/contextListener&gt;

    &lt;appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;
        <i class="conum" data-value="2"></i><b>(2)</b>
        &lt;file&gt;${LOG_DIR}/glassfish/${instanceName}/${instanceName}.log&lt;/file&gt;
        &lt;rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"&gt;
            &lt;!-- daily rollover --&gt;
            &lt;fileNamePattern&gt;${LOG_DIR}/glassfish/${instanceName}/${instanceName}.%d{yyyy-MM-dd}.%i.log&lt;/fileNamePattern&gt;
            &lt;timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"&gt;
                &lt;maxFileSize&gt;50MB&lt;/maxFileSize&gt;
            &lt;/timeBasedFileNamingAndTriggeringPolicy&gt;
            &lt;maxHistory&gt;60&lt;/maxHistory&gt;
        &lt;/rollingPolicy&gt;

        &lt;encoder&gt;
            &lt;pattern&gt;[%d{ISO8601}] [%t] [%4p] [%logger]: %m%n&lt;/pattern&gt;
        &lt;/encoder&gt;
    &lt;/appender&gt;

  &lt;appender name="json" class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;<i class="conum" data-value="3"></i><b>(3)</b>
    &lt;file&gt;${LOG_DIR}/glassfish/${isntanceName}/json/${isntanceName}.json&lt;/file&gt;
    &lt;rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"&gt;
      &lt;fileNamePattern&gt;${LOG_DIR}/glassfish/${instanceName}/json/${instanceName}.%d{yyyy-MM-dd}.json.zip&lt;/fileNamePattern&gt;
      &lt;maxHistory&gt;120&lt;/maxHistory&gt;
    &lt;/rollingPolicy&gt;
    &lt;encoder class="net.logstash.logback.encoder.LogstashEncoder"&gt;
      &lt;customFields&gt;{"instance":"${instanceName}","type":"glassfish"}&lt;/customFields&gt;
    &lt;/encoder&gt;
  &lt;/appender&gt;

  &lt;appender name="logstash-socket" class="net.logstash.logback.appender.LogstashTcpSocketAppender"&gt;
    &lt;destination&gt;${LOGSTASH_DEST}&lt;/destination&gt;<i class="conum" data-value="4"></i><b>(4)</b>
    &lt;secondaryConnectionTTL&gt;5 minutes&lt;/secondaryConnectionTTL&gt;
    &lt;encoder class="net.logstash.logback.encoder.LogstashEncoder"&gt;
      &lt;customFields&gt;{"instance":"${instanceName}","type":"glassfish"}&lt;/customFields&gt;
    &lt;/encoder&gt;
  &lt;/appender&gt;

    &lt;root&gt;
        &lt;level value="INFO" /&gt;
        &lt;appender-ref ref="FILE" /&gt;
        &lt;appender-ref ref="json"/&gt;
        &lt;appender-ref ref="logstash-socket"/&gt;
    &lt;/root&gt;
&lt;/configuration&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following points should be noted:</p>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Propagation between <code>slf4j and `java.util.logging</code> is needed</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>We put the logging directory outside of the domain directory, and controlled by an environment variable. <code>instanceName</code> is a JVM argument, that is unique for every instance in our system.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>We keep the JSON formatted logs on disk with greater retention period than our Elasticsearch does. If we need to, we can re-upload those to analyze past events.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Mutliple destinations in form of <code>host:port[,host:port]</code> can be defined for the Logstash socket appender. We keep them in an environment variable.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>We have similar configuration for <code>logback-access.xml</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;configuration scan="true"&gt;
  &lt;jmxConfigurator/&gt;
  &lt;shutdownHook/&gt;
  &lt;!-- always a good activate OnConsoleStatusListener --&gt;
  &lt;statusListener class="ch.qos.logback.core.status.OnErrorConsoleStatusListener" /&gt;

  &lt;appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;
    &lt;file&gt;${LOG_DIR}/glassfish/${instanceName}/${instanceName}.access.log&lt;/file&gt;
    &lt;rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"&gt;
      &lt;fileNamePattern&gt;${LOG_DIR}/glassfish/${instanceName}/${instanceName}.access.%d{yyyy-MM-dd}.log.zip&lt;/fileNamePattern&gt;
      &lt;maxHistory&gt;90&lt;/maxHistory&gt;
    &lt;/rollingPolicy&gt;

    &lt;encoder&gt;
      &lt;pattern&gt;combined&lt;/pattern&gt;
    &lt;/encoder&gt;
  &lt;/appender&gt;
  &lt;appender-ref ref="FILE" /&gt;

  &lt;appender name="json" class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;
    &lt;file&gt;${LOG_DIR}/glassfish/${instanceName}/json/${instanceName}.access.json&lt;/file&gt;
    &lt;rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"&gt;
      &lt;fileNamePattern&gt;${LOG_DIR}/glassfish/${instanceName}/json/${instanceName}.access.%d{yyyy-MM-dd}.json.zip&lt;/fileNamePattern&gt;
      &lt;maxHistory&gt;10&lt;/maxHistory&gt;
    &lt;/rollingPolicy&gt;
    &lt;encoder class="net.logstash.logback.encoder.AccessEventCompositeJsonEncoder"&gt;
      &lt;providers&gt;
         &lt;timestamp/&gt;
         &lt;version/&gt;
         &lt;method/&gt;
         &lt;protocol/&gt;
         &lt;statusCode/&gt;
         &lt;requestedUri/&gt;
         &lt;remoteHost/&gt;
         &lt;hostname/&gt;
         &lt;remoteUser/&gt;
         &lt;contentLength/&gt;
         &lt;elapsedTime/&gt;
         &lt;context/&gt;
         &lt;pattern&gt;&lt;pattern&gt;
           {"instance": "${instanceName}",
            "forwarded_for": "%header{X-Forwarded-For}",
            "server_name": "%v",
            "type": "access"}
         &lt;/pattern&gt;&lt;/pattern&gt;
      &lt;/providers&gt;
    &lt;/encoder&gt;
  &lt;/appender&gt;

  &lt;appender name="logstash-socket" class="net.logstash.logback.appender.LogstashAccessTcpSocketAppender"&gt;
     &lt;destination&gt;${LOGSTASH_DEST}&lt;/destination&gt;
     &lt;secondaryConnectionTTL&gt;5 minutes&lt;/secondaryConnectionTTL&gt;
     &lt;encoder class="net.logstash.logback.encoder.AccessEventCompositeJsonEncoder"&gt;
      &lt;providers&gt;
         &lt;timestamp/&gt;
         &lt;version/&gt;
         &lt;method/&gt;
         &lt;protocol/&gt;
         &lt;statusCode/&gt;
         &lt;requestedUri/&gt;
         &lt;remoteHost/&gt;
         &lt;hostname/&gt;
         &lt;remoteUser/&gt;
         &lt;contentLength/&gt;
         &lt;elapsedTime/&gt;
         &lt;context/&gt;
         &lt;pattern&gt;&lt;pattern&gt;
           {"instance": "${instanceName}",
            "server_name": "%v",
            "forwarded_for": "%header{X-Forwarded-For}",
            "type": "access"}
         &lt;/pattern&gt;&lt;/pattern&gt;
      &lt;/providers&gt;
    &lt;/encoder&gt;
  &lt;/appender&gt;

  &lt;appender-ref ref="logstash-socket" /&gt;
  &lt;appender-ref ref="json" /&gt;
&lt;/configuration&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Finally, the logstash configuration.</p>
</div>
<div class="paragraph">
<p>It is quite a simple, however access log events tend to have field names that are incompatible with recent versions of elasticsearch. To work around this problem, they need to be adapted a bit, as shown in the filter below:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ruby" data-lang="ruby">input {
  tcp {
    port =&gt; 1065
    codec =&gt; json_lines
  }
}

filter {
  if [type] == "access" {
     mutate {
        rename =&gt; {
          "@fields.HOSTNAME" =&gt; "HOSTNAME"
          "@fields.content_length" =&gt; "content_length"
          "@fields.elapsed_time" =&gt; "elapsed_time"
          "@fields.method" =&gt; "method"
          "@fields.protocol" =&gt; "protocol"
          "@fields.remote_host" =&gt; "remote_host"
          "@fields.remote_user" =&gt; "remote_user"
          "@fields.requested_uri" =&gt; "requested_uri"
          "@fields.status_code" =&gt; "status_code"
        }
     }
     if [forwarded_for] != "-" {
        mutate {
          rename =&gt; {
             "forwarded_for" =&gt; "remote_host"
          }
        }
     }
     mutate {
       remove_field =&gt; ["forwarded_for"]
     }
   }
}

output {
  elasticsearch  {
    hosts =&gt; #....
  }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_adapt_your_application">Adapt your application</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Your application also needs small tuning now to prevent various class incompatibility errors.
Both <code>slf4j-api</code>, and <code>logback-classic</code> should now be <em>provided</em> dependencies of your application.
In other words, they should <strong>not</strong> be included in your <em>.war</em> or <em>.ear</em> build.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_downsides">Downsides</h2>
<div class="sectionbody">
<div class="paragraph">
<p>It is important to note that <code>asadmin set-log-levels</code> no longer works, as logback is the one filtering the levels.
You will need a different way of controlling log levels with this kind of configuration.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_give_feedback">Give feedback</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Let us know how this setup works for you in comments on <a href="http://blog.payara.fish/log-directly-to-logstash-from-payara-server">Payara blog</a>.
You&#8217;re also invited to share your projects' <a href="https://github.com/goodees/goodees">goodees</a>!</p>
</div>
</div>
</div>]]></description><link>https://pdudits.github.io/2017/11/30/Log-directly-to-Logstash-from-Payara.html</link><guid isPermaLink="true">https://pdudits.github.io/2017/11/30/Log-directly-to-Logstash-from-Payara.html</guid><dc:creator><![CDATA[Patrik Duditš]]></dc:creator></item><item><title><![CDATA[Semi-automatic Jenkins upgrade on Windows]]></title><description><![CDATA[<div class="paragraph">
<p>Jenkins offers nice auto-update functionality, where it will download new version, schedules a restart and updates.
But what to do when it is unable to download the version?</p>
</div>
<div class="paragraph">
<p>In our company there is this really annoying proxy antivirus scanner, that likes to inspect all <code>jar</code> and <code>war</code> files for viruses, so things like Wildfly or Netbeans take hours to download.
That&#8217;s really bad new when one wants to update Jenkins, as it will time out after minute or two.</p>
</div>
<div class="paragraph">
<p>The usual approach I take for plugins that fail to download, is that I download them manually (e. g. by replacing <code>http</code> with <code>https</code> in the mirror link, then the antivirus is bypassed ;)) and upload them into Jenkins.
This doesn&#8217;t work for the main <code>war</code> file, of course.</p>
</div>
<div class="paragraph">
<p>Should I&#8217;ve been running on Linux, I would just download the file, and overwrite existing file.
I&#8217;m on Windows and the process have the file locked.
I would really like just to trigger this logic for upgrading the file at startup.</p>
</div>
<div class="paragraph">
<p>To find out how that works I looked into Jenkins' <a href="https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java">WindowsLifecycleService</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">    /**
     * On Windows, jenkins.war is locked, so we place a new version under a special name,
     * which is picked up by the service wrapper upon restart.
     */
    @Override
    public void rewriteHudsonWar(File by) throws IOException {
        File dest = getHudsonWar();
        // this should be impossible given the canRewriteHudsonWar method,
        // but let's be defensive
        if(dest==null)  throw new IOException("jenkins.war location is not known.");

        // backing up the old jenkins.war before its lost due to upgrading
        // unless we are trying to rewrite jenkins.war by a backup itself
        File bak = new File(dest.getPath() + ".bak");
        if (!by.equals(bak))
            FileUtils.copyFile(dest, bak);

        String baseName = dest.getName();
        baseName = baseName.substring(0,baseName.indexOf('.'));

        File baseDir = getBaseDir();
        File copyFiles = new File(baseDir,baseName+".copies");

        try (FileWriter w = new FileWriter(copyFiles, true)) {
            w.write(by.getAbsolutePath() + '&gt;' + getHudsonWar().getAbsolutePath() + '\n');
        }
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>So I did the same thing manually:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Downloaded new <code>war</code> file to <code>d:\temp</code></p>
</li>
<li>
<p>Created file jenkins.copies in jenkins' home with content</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>d:/temp/jenkins.war&gt;d:/jenkins/jenkins.war</code></pre>
</div>
</div>
<div class="paragraph">
<p>I saved it with UNIX line endings and verified, that there is indeed just single <code>\n</code> at the end (service will fail to start if that is not the case).</p>
</div>
</li>
<li>
<p>Had jenkins restart once it is idle</p>
</li>
<li>
<p><strong>DONE</strong>. Jenkins did update just as if it had downloaded the file itself.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>I kept the <code>.copies</code> file handy for future updates. I will just put new version in <code>temp</code> and copy the <code>.copies</code> file over.</p>
</div>]]></description><link>https://pdudits.github.io/2017/09/07/Semi-automatic-Jenkins-upgrade-on-Windows.html</link><guid isPermaLink="true">https://pdudits.github.io/2017/09/07/Semi-automatic-Jenkins-upgrade-on-Windows.html</guid><category><![CDATA[Jenkins]]></category><category><![CDATA[Windows]]></category><dc:creator><![CDATA[Patrik Duditš]]></dc:creator><pubDate>Thu, 07 Sep 2017 00:00:00 GMT</pubDate></item><item><title><![CDATA[Your Java EE App on Kubernetes]]></title><description><![CDATA[<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>In <a href="https://pdudits.github.io/2017/05/23/Running-Payara-in-Kubernetes.html">previous  post</a> we managed to run Payara on Kubernetes.
This is of course bit dull without applications deployed.
Next we will create an actual aplication, that will deploy with official Payara container.
We will use the full profile Payara, just to demonstrate, that microservices can be built using standard distribution.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s see what we will need to have our app in Kubernetes as well:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>.war Maven project</p>
</li>
<li>
<p>Fabric8 Maven plugin</p>
</li>
<li>
<p>Docker for Windows / Docker tools</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_installing_docker_tooling">Installing Docker tooling</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Given my hobby environment (Windows 10 Home), I cannot use the current Docker for Windows installation&#8201;&#8212;&#8201;remember, there&#8217;s no HyperV in Home edition.
We need to install <a href="https://www.docker.com/products/docker-toolbox">Docker Toolbox</a>, its retired ancestor.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_sidecar_approach">Sidecar approach</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I assume you don&#8217;t upgrade your application server as often as you upgrade your applications.
But when you do upgrade your server, you shouldn&#8217;t need to rebuild all of your applications. At least I wouldn&#8217;t like to do that.</p>
</div>
<div class="paragraph">
<p>Kubernetes gives you solution to that, called <a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/#understanding-pods">Sidecar containers</a>.
Instead of running single image, you put multiple images together, and they can speak to each other via localhost, or share directories.</p>
</div>
<div class="paragraph">
<p>So we will take <a href="http://blog.payara.fish/payara-docker-images-162-release-update">Official Payara Docker Image</a>, mount its autodeploy directory, and for our app we will build an image based on busybox, that will just copy our .war file to that folder.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/Kubernetes%20sidecar.png" alt="Kubernetes%20sidecar.png">
</div>
</div>
<div class="paragraph">
<p>The app-sidecar will be based on busybox, adding just 1MB of binaries to our app package.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_creating_docker_images_with_maven">Creating Docker images with Maven</h2>
<div class="sectionbody">
<div class="paragraph">
<p>One doesn&#8217;t need to leave its trusted tools for this fancy new tech!
Everything you need to do concerning Docker images and Kubernetes you can achieve with <a href="https://maven.fabric8.io/">Fabric8 Maven Plugin</a>.
Fabric8 is entire CI/CD pipeline for Kubernetes, and I will surely look into it in next posts&#8201;&#8212;&#8201;first, I need to understand what am I doing before I let magical tools do that for me ;).</p>
</div>
<div class="paragraph">
<p>The goal <code>build</code> of Fabric8 plugin constructs the Docker image based on <a href="https://maven.fabric8.io/#image-configuration">image configuration</a>.
So this is what the interesting parts of <a href="https://github.com/pdudits/k8se9s/blob/master/payara-sidecar/pom.xml"><code>pom.xml</code></a> look like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&lt;plugin&gt;
    &lt;groupId&gt;io.fabric8&lt;/groupId&gt;
    &lt;artifactId&gt;fabric8-maven-plugin&lt;/artifactId&gt;
    &lt;version&gt;3.4.1&lt;/version&gt;
    &lt;configuration&gt;
        &lt;images&gt;
            &lt;image&gt;
                &lt;name&gt;pdudits/%a:%l&lt;/name&gt; <i class="conum" data-value="1"></i><b>(1)</b>
                &lt;alias&gt;app-sidecar&lt;/alias&gt; <i class="conum" data-value="2"></i><b>(2)</b>
                &lt;build&gt;
                    &lt;from&gt;busybox:1&lt;/from&gt; <i class="conum" data-value="3"></i><b>(3)</b>
                    &lt;assembly&gt;             <i class="conum" data-value="4"></i><b>(4)</b>
                        &lt;descriptorRef&gt;artifact&lt;/descriptorRef&gt;
                    &lt;/assembly&gt;
                &lt;/build&gt;
            &lt;/image&gt;
        &lt;/images&gt;
    &lt;/configuration&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;fabric8-default&lt;/id&gt;
            &lt;goals&gt;
                &lt;goal&gt;resource&lt;/goal&gt;
                &lt;goal&gt;build&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;</pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The name of docker image. <code>%a</code> stands for artifactId, <code>%l</code> stands for release verson or <code>latest</code> for snapshot</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>we can use this alias for defining kuberenetes resources later</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Our base image</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>The <a href="https://maven.apache.org/plugins/maven-assembly-plugin/descriptor-refs.html">Maven Assembly Descriptor Name</a>, describing what should be copied into the image (inside directory <code>/maven</code> by default).</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To actually run the build you need to have Docker environment configured, as the plugin will call out to Docker.
Minikube has this nice feature, that it will <a href="https://kubernetes.io/docs/getting-started-guides/minikube/#reusing-the-docker-daemon">reuse Docker daemon</a> from within minikube VM.
You therefore doesn&#8217;t need to run another VM, just make sure to follow instructions of <code>minikube docker-env</code> before invoking maven:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>d:\src\k8se9s\payara-sidecar&gt;minikube docker-env
SET DOCKER_TLS_VERIFY=1
SET DOCKER_HOST=tcp://192.168.99.100:2376
SET DOCKER_CERT_PATH=d:\src\kubernetes\.minikube\certs
SET DOCKER_API_VERSION=1.23
REM Run this command to configure your shell:
REM @FOR /f "tokens=*" %i IN ('minikube docker-env') DO @%i

d:\src\k8se9s\payara-sidecar&gt;@FOR /f "tokens=*" %i IN ('minikube docker-env') DO @%i</pre>
</div>
</div>
<div class="paragraph">
<p>That also means, that whatever you build is immediately available for deployment into your Kubernetes cluster.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_kubernetes_resource_descriptors_with_maven">Kubernetes Resource Descriptors with Maven</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>fabric8:resource</code> will take YAML files that serve as templates for resource descriptors, add some useful labels to them, and attaches them as build results.</p>
</div>
<div class="paragraph">
<p>For our sidecar we will create a <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">Deployment</a>.
It is a declaration of what Pod should look like with added features like replication&#8201;&#8212;&#8201;more than one instances of same pod&#8201;&#8212;&#8201;and rolling upgrade. Especially the rolling upgrade is interesting for us. When you upgrade your app, a new Pod will be created, and when it starts successfully, the trafic will be directed to it, and after that the old pod is stopped.</p>
</div>
<div class="paragraph">
<p>So let&#8217;s see the file:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-yaml" data-lang="yaml">spec:
  replicas: 1
  template:
    metadata:
      labels:
        run: payara
    spec:
      volumes:
      - name: apps                    <i class="conum" data-value="1"></i><b>(1)</b>
        emptyDir: {}
      initContainers:
      - alias: app-sidecar            <i class="conum" data-value="2"></i><b>(2)</b>
        volumeMounts:
        - name: apps                  <i class="conum" data-value="3"></i><b>(3)</b>
          mountPath: /apps
        command: ["sh","-c", "cp -a /maven/*.war /apps"] <i class="conum" data-value="4"></i><b>(4)</b>
      containers:
      - image: payara/server-full:171 <i class="conum" data-value="5"></i><b>(5)</b>
        name: payara
        command: ["bin/asadmin", "start-domain", "-v"]
        ports:                        <i class="conum" data-value="6"></i><b>(6)</b>
        - containerPort: 8080
          name: http
        - containerPort: 4848
          name: admin
        volumeMounts:
        - name: apps                  <i class="conum" data-value="7"></i><b>(7)</b>
          mountPath: /opt/payara41/glassfish/domains/domain1/autodeploy</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>That&#8217;s the directory shared between Docker images</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>We refer to the image via alias from <code>pom.xml</code></td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>The shared volume is accessible via /apps for container app-sidecar</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>We copy the files. Every container need to have running process, otherwise it is marked as crashed. Therefore we just hang, waiting for input from the void.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Payara is the other container in the pod</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>Yes that&#8217;s the old version, you&#8217;ll soon find out why&#8230;&#8203;</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>And the files we copied into /apps Payara sees in its autodeploy directory.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Another resource desciptor we&#8217;ll add will describe a <a href="https://kubernetes.io/docs/concepts/services-networking/service/">service</a>.
This will give a set of pods that offer same service a common, load balanced IP address inside the cluster, and may expose it to outside world.</p>
</div>
<div class="paragraph">
<p>In our minikube, it will expose the port of the VM. In the cloud it will integrate with provider&#8217;s load balancers.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-yaml" data-lang="yaml">spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    run: payara
  type: NodePort</code></pre>
</div>
</div>
<div class="paragraph">
<p>The service exposes port 8080 (the http port) as port 8080 of the service API.
The calls will be directed to pods, that have label <code>run</code> equal to <code>payara</code>.
And to expose it to outside world, we will use a port of the node Kubernetes runs on&#8201;&#8212;&#8201;the minikube VM in our case.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_deploying_to_the_cluster">Deploying to the cluster</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Now that we have run our <code>mvn clean install</code>, we&#8217;ll have our docker image pushed, and our resources created.</p>
</div>
<div class="paragraph">
<p>Next we&#8217;ll deploy with <code>mvn fabric8:deploy</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre>[INFO] &lt;&lt;&lt; fabric8-maven-plugin:3.4.1:deploy (default-cli) &lt; install @ payara-sidecar &lt;&lt;&lt;
[INFO]
[INFO] --- fabric8-maven-plugin:3.4.1:deploy (default-cli) @ payara-sidecar ---
[INFO] F8: Using Kubernetes at https://192.168.99.100:8443/ in namespace default with manifest d:\src\k8se9s\payara-sidecar\target\classes\META-INF\fabric8\kubernetes.yml
[INFO] Using namespace: default
[INFO] Updating a Service from kubernetes.yml
[INFO] Updated Service: \payara-sidecar\target\fabric8\applyJson\default\service-payara-sidecar.json
[INFO] Updating Deployment from kubernetes.yml
[INFO] Updated Deployment: \payara-sidecar\target\fabric8\applyJson\default\deployment-payara.json
[INFO] F8: HINT: Use the command `kubectl get pods -w` to watch your pods start up</pre>
</div>
</div>
<div class="paragraph">
<p>Here we are!</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://user-images.githubusercontent.com/1588543/27405216-fca5ba9c-56d0-11e7-9ed1-d77db9216400.png" alt="27405216 fca5ba9c 56d0 11e7 9ed1 d77db9216400.png">
</div>
</div>
<div class="paragraph">
<p>Our .war that were deploying to Payara now deploys to docker container with payara server inside Kubernetes!</p>
</div>
<div class="listingblock">
<div class="content">
<pre>minikube service payara-sidecar</pre>
</div>
</div>
<div class="paragraph">
<p>Will open browser with the app. You need to add <code>/payara-sidecar</code> to the path.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_p_s">P. S.</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Look what this does:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt;kubectl set image deployment/payara payara=payara/server-full:172
deployment "payara" image updated</pre>
</div>
</div>
<div class="imageblock">
<div class="content">
<img src="https://user-images.githubusercontent.com/1588543/27405642-aaa048aa-56d2-11e7-9df9-350547abcdca.png" alt="27405642 aaa048aa 56d2 11e7 9df9 350547abcdca.png">
</div>
</div>
<div class="paragraph">
<p>New pod was started with newer version of application server, and after it started, the old one was removed.</p>
</div>
</div>
</div>]]></description><link>https://pdudits.github.io/2017/06/22/Your-Java-EE-App-on-Kubernetes.html</link><guid isPermaLink="true">https://pdudits.github.io/2017/06/22/Your-Java-EE-App-on-Kubernetes.html</guid><category><![CDATA[Payara]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Patrik Duditš]]></dc:creator><pubDate>Thu, 22 Jun 2017 00:00:00 GMT</pubDate></item><item><title><![CDATA[Running Payara in Kubernetes]]></title><description><![CDATA[<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>In the first part of hopefully longer series I will focus at the tasks one should do to get plain server&#8201;&#8212;&#8201;without the app, but a Java EE full profile one&#8201;&#8212;&#8201;up and running in Kubernetes cluster.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_installing_the_tools">Installing the tools</h2>
<div class="sectionbody">
<div class="paragraph">
<p>For this series I will be using my Windows 10 Home notebook. Particulary important consequence of that is, that Hyper-V <a href="https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v#check-requirements">is not availble</a>. I will therefore use VirtualBox.</p>
</div>
<div class="sect2">
<h3 id="_step_1_install_virtualbox">Step 1: Install VirtualBox</h3>
<div class="paragraph">
<p>There&#8217;s not much to be said to this one, just head over to <a href="https://www.virtualbox.org/wiki/Downloads">VirtualBox download page</a>, download and install.</p>
</div>
</div>
<div class="sect2">
<h3 id="_step_2_install_kubernetes">Step 2: Install Kubernetes</h3>
<div class="paragraph">
<p>Kubernetes is a tool for (virtual machine) clusters. However, you can run it all in single virtual machine on your computer! To achieve that you&#8217;ll need:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/kubernetes/minikube#user-content-quickstart">minikube</a>: the management tool for the vm.
Download <a href="https://storage.googleapis.com/minikube/releases/latest/minikube-windows-amd64.exe">minikube-windows-amd64.exe</a>, put it in a dedicated folder for your kubernetes tools, and rename it to minikube.exe</p>
</li>
<li>
<p><a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-binary-via-curl">kubectl</a>: CLI tool for interacting with Kubernetes. They have fancy bash&#160;&amp;&#160;curl script for downloading the current release, I&#8217;m pretty sure it&#8217;s almost of no use for you, the Windows guy. Here&#8217;s bit of PowerShell instead:</p>
<div class="listingblock">
<div class="content">
<pre>$(
  $base = "https://storage.googleapis.com/kubernetes-release/release";
  $ver = iwr "$base/stable.txt" | % { $_.Content.Trim() };
  "$base/$ver"
) | % {
  iwr "$_/bin/windows/amd64/kubectl.exe" -OutFile kubectl.exe
}</pre>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_create_and_run_the_cluster">Create and run the cluster</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We&#8217;re just few commands away from running the cluster now.</p>
</div>
<div class="sect2">
<h3 id="_step_3_prepare_environment_vars">Step 3: Prepare Environment vars</h3>
<div class="paragraph">
<p>On typical home machine, you don&#8217;t need to set any variables. However, on "enterprise" one you might consider:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>:: We will download some ISOs now
SET https_proxy=http://proxy.company.local:8080
:: Into directory %MINIKUBE_HOME%\.minikube, defaults to %HOMEPATH%.
:: Also a vm disk image gets created there
:: it also fails if you're not running minikube on your HOMEDRIVE
SET MINIKUBE_HOME=d:\src\kubernetes</pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_step_4_create_cluster">Step 4: Create cluster</h3>
<div class="listingblock">
<div class="content">
<pre>d:\src\kubernetes&gt;minikube start --vm-driver=virtualbox
Starting local Kubernetes v1.6.0 cluster...
Starting VM...
Downloading Minikube ISO
 89.51 MB / 89.51 MB [==============================================] 100.00% 0s
SSH-ing files into VM...
Setting up certs...
Starting cluster components...
Connecting to cluster...
Setting up kubeconfig...
Kubectl is now configured to use the cluster.</pre>
</div>
</div>
<div class="paragraph">
<p>You can see virtual machine <em>minikube</em> running in VirtualBox now. Let&#8217;s check, that it indeed works:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>d:\src\kubernetes&gt;kubectl cluster-info
Kubernetes master is running at https://192.168.99.100:8443

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

d:\src\kubernetes&gt;minikube dashboard
Opening kubernetes dashboard in default browser...</pre>
</div>
</div>
<div class="imageblock">
<div class="content">
<img src="https://cloud.githubusercontent.com/assets/1588543/26376434/c2301036-400c-11e7-8a3f-7c1a249a8624.png" alt="c2301036 400c 11e7 8a3f 7c1a249a8624.png">
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_deploy_payara">Deploy Payara</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_step_5_create_deployment">Step 5: Create deployment</h3>
<div class="paragraph">
<p>Bare deployment of Payara inside cluster can be achieved with</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt; kubectl run payara --image=payara/server-full --port=8080 --replicas 1
deployment "payara" created</pre>
</div>
</div>
<div class="paragraph">
<p>This starts download of a docker image and creates a <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">Deployment</a>
and a <a href="https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/">Replica Set</a>, that in turn contains single <a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/">Pod</a>, that exposes standard HTTP port. It will take a while, since the docker image needs to be downloaded. You can monitor the progress like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt; kubectl get events
LASTSEEN   FIRSTSEEN   COUNT     NAME                      KIND         SUBOBJECT                 TYPE      REASON              SOURCE                  MESSAGE
6m         6m          1         payara-4223602339-vr5w5   Pod                                    Normal    Scheduled           default-scheduler       Successfully assigned payara-4223602339-vr5w5 to minikube
6m         6m          1         payara-4223602339-vr5w5   Pod          spec.containers{payara}   Normal    Pulling             kubelet, minikube       pulling image "payara/server-full"
6m         6m          1         payara-4223602339         ReplicaSet                             Normal    SuccessfulCreate    replicaset-controller   Created pod: payara-4223602339-vr5w5
6m         6m          1         payara                    Deployment                             Normal    ScalingReplicaSet   deployment-controller   Scaled up replica set payara-4223602339 to 1</pre>
</div>
</div>
<div class="paragraph">
<p>Alternatively you can use <code>minikube dashboard</code> for more interactive view.</p>
</div>
</div>
<div class="sect2">
<h3 id="_step_6_expose_http_port">Step 6: Expose HTTP port</h3>
<div class="paragraph">
<p>After the replica set is running, you yet need to make it accessible from within container inside minikube VM to your host:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt; kubectl expose deployment payara --port=80 --type=NodePort
service "payara" exposed
&gt; minikube service payara
Opening kubernetes service default/payara in default browser...</pre>
</div>
</div>
<div class="imageblock">
<div class="content">
<img src="https://cloud.githubusercontent.com/assets/1588543/26421598/e607bc24-40c6-11e7-80b7-a4ea7b632e3a.png" alt="e607bc24 40c6 11e7 80b7 a4ea7b632e3a.png">
</div>
</div>
<div class="paragraph">
<p>Six steps are already enough for a nice evening spent at your computer, in next part of the series we&#8217;ll try to <a href="http://imgur.com/gallery/RadSf">draw the rest of the owl</a>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Deploying the app into server, ideally without every build result being 800MB</p>
</li>
<li>
<p>Improving logging</p>
</li>
<li>
<p>Customizing your domain</p>
</li>
<li>
<p>&#8230;&#8203;</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Stay tuned!
</p>
</div>
</div>
</div>
</div>]]></description><link>https://pdudits.github.io/2017/05/23/Running-Payara-in-Kubernetes.html</link><guid isPermaLink="true">https://pdudits.github.io/2017/05/23/Running-Payara-in-Kubernetes.html</guid><category><![CDATA[Payara]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Patrik Duditš]]></dc:creator><pubDate>Tue, 23 May 2017 00:00:00 GMT</pubDate></item><item><title><![CDATA[Setting up Angular2 CLI with Maven in enterprise network]]></title><description><![CDATA[<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Working with Angular2 CLI is easy - you just wait for npm to download the Internet and afterwards and then <code>ng</code> will take care of all your tooling setup.</p>
</div>
<div class="paragraph">
<p>Not so much if at your workplace you&#8217;re running Windows, your network has NTLM-based firewall and your project is actually Java-based one built with Maven.</p>
</div>
<div class="paragraph">
<p>Even if the proxy for NPM can be configured via <code>npm set</code> or <code>http_proxy</code> environment variable, npm does not support <code>no_proxy</code> clause, so the things
would start failing if you want to consume your own packages.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_needed_infrastructure">Needed infrastructure</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Instead, we will use <a href="https://www.sonatype.com/download-oss-sonatype">Nexus 3</a>. We will install it on a server, that has reasonable access to Internet (e. g. no auth, or service user autorization to proxy), and it will do the proxying for all things NodeJS and NPM we need.</p>
</div>
<div class="paragraph">
<p>For running NPM as part of our Maven build, we&#8217;ll use <a href="https://github.com/eirslett/frontend-maven-plugin">Frontend Maven Plugin</a>. It will take care of installing node, npm and project dependencies for us, and also for our CI build.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_maven_module_structure">Maven module structure</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We will lay out our modules in following way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>parent (pom)
\_ app-backend (war module)
\_ app-frontend (war module)
    \_ node (js project)</pre>
</div>
</div>
<div class="paragraph">
<p>Module <code>app-frontend</code> will invoke npm build in directory <code>app-frontend/node</code>. I tried to be Maven compatible here at first, but it wasn&#8217;t really helping when trying to open the JS project in the IDE. Maven will then pack the result of npm into a <code>.war</code> file.</p>
</div>
<div class="paragraph">
<p>In case you want to deploy single artifact, <code>app-backend</code> may depend on <code>app-frontend</code> and the build result will be then copied to backend <code>.war</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_setting_up_proxies_in_nexus">Setting up proxies in Nexus</h2>
<div class="sectionbody">
<div class="paragraph">
<p>After you install nexus and verify that it is able to download artifacts you will need following repositories.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<colgroup>
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Repo Name</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Remote path</th>
<th class="tableblock halign-left valign-top">Note</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">npm</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">npm (Proxy)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://registry.npmjs.org" class="bare">https://registry.npmjs.org</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">We actually use group, along with our release repository, but this is minimal setup needed</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">node-dist</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">raw (Proxy)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://nodejs.org/dist/" class="bare">https://nodejs.org/dist/</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For downloading node binaries</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">node-sass</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">raw (Proxy)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/sass/node-sass/releases/download/" class="bare">https://github.com/sass/node-sass/releases/download/</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">node-sass binaries</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">node-zopfli</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">raw (Proxy)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://node-zopfli.s3.amazonaws.com" class="bare">https://node-zopfli.s3.amazonaws.com</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">node-zopfli binaries</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Generally you only need the first two. The other two are dependencies of angular-cli that either need to be build or downloaded as binaries.</p>
</div>
<div class="paragraph">
<p>We had quite some problems when there was reverse proxy in front of Nexus. Or, actually npm did have problems.
So for now we are speaking to nexus3 directly.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_frontend_pom">Frontend POM</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>pom.xml</code> of <code>app-frontend</code> is different from your usual pom.</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>It doesn&#8217;t compile any java or run surefire</p>
</li>
<li>
<p>It will also clean <code>node/node_modules</code> in clean phase</p>
</li>
<li>
<p>It will download node binaries and npm installation from nexus</p>
</li>
<li>
<p>It will run npm install</p>
</li>
<li>
<p>It will run npm run build to invoke build of the project</p>
</li>
<li>
<p>It will package the result of the build into a <code>.war</code> file</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  &lt;parent&gt;
    &lt;groupId&gt;com.example&lt;/groupId&gt;
    &lt;artifactId&gt;parent&lt;/artifactId&gt;
    &lt;version&gt;1.0.0-SNAPSHOT&lt;/version&gt;
  &lt;/parent&gt;

  &lt;artifactId&gt;app-frontend&lt;/artifactId&gt;
  &lt;packaging&gt;war&lt;/packaging&gt;

  &lt;name&gt;app-frontend&lt;/name&gt;

  &lt;properties&gt;
    &lt;!-- (1) this is NOT a java project, therefore we do not compile anything --&gt;
    &lt;maven.main.skip&gt;true&lt;/maven.main.skip&gt;
    &lt;maven.test.skip&gt;true&lt;/maven.test.skip&gt;
    &lt;!-- this is our Nexus3 installations. No reverse proxy in front --&gt;
    &lt;url.nexus&gt;http://nexus.server:8088/nexus3&lt;/url.nexus&gt;
    &lt;!-- proxy of https://nodejs.org/dist --&gt;
    &lt;node.repository&gt;${url.nexus}/repository/node-dist/&lt;/node.repository&gt;
    &lt;!-- proxy of NPM registry --&gt;
    &lt;npm.registry&gt;${url.nexus}/repository/npm/&lt;/npm.registry&gt;
    &lt;!-- location of npm installation within npm registry --&gt;
    &lt;npm.repository&gt;${npm.registry}npm/-/&lt;/npm.repository&gt;
  &lt;/properties&gt;

  &lt;dependencies /&gt;

  &lt;build&gt;
    &lt;plugins&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-clean-plugin&lt;/artifactId&gt;
        &lt;version&gt;3.0.0&lt;/version&gt;
        &lt;configuration&gt;
          &lt;filesets&gt;
            &lt;fileset&gt;
              &lt;!-- (2) during clean phase also clean node_modules of js project --&gt;
              &lt;directory&gt;node/node_modules&lt;/directory&gt;
            &lt;/fileset&gt;
          &lt;/filesets&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;com.github.eirslett&lt;/groupId&gt;
        &lt;artifactId&gt;frontend-maven-plugin&lt;/artifactId&gt;
        &lt;version&gt;1.2&lt;/version&gt;
        &lt;configuration&gt;
          &lt;npmVersion&gt;3.10.8&lt;/npmVersion&gt;
          &lt;nodeVersion&gt;v6.9.1&lt;/nodeVersion&gt;
          &lt;workingDirectory&gt;node&lt;/workingDirectory&gt;
          &lt;!-- node executable and npm gets installed under target/ --&gt;
          &lt;installDirectory&gt;target&lt;/installDirectory&gt;
          &lt;npmDownloadRoot&gt;${npm.repository}&lt;/npmDownloadRoot&gt;
          &lt;nodeDownloadRoot&gt;${node.repository}&lt;/nodeDownloadRoot&gt;
          &lt;npmRegistryURL&gt;${npm.registry}&lt;/npmRegistryURL&gt;
          &lt;npmInheritsProxyConfigFromMaven&gt;false&lt;/npmInheritsProxyConfigFromMaven&gt;
        &lt;/configuration&gt;
        &lt;executions&gt;
          &lt;execution&gt;
            &lt;!-- (3) First, install node and npm --&gt;
            &lt;id&gt;install node and npm&lt;/id&gt;
            &lt;goals&gt;
              &lt;goal&gt;install-node-and-npm&lt;/goal&gt;
            &lt;/goals&gt;
            &lt;phase&gt;generate-resources&lt;/phase&gt;
          &lt;/execution&gt;
          &lt;execution&gt;
            &lt;!-- (4) And then run npm install --&gt;
            &lt;id&gt;npm&lt;/id&gt;
            &lt;goals&gt;
              &lt;goal&gt;npm&lt;/goal&gt;
            &lt;/goals&gt;
            &lt;phase&gt;generate-resources&lt;/phase&gt;
            &lt;configuration&gt;
              &lt;!-- The extra arguments specify paths to proxied binaries --&gt;
              &lt;arguments&gt;install --sass-binary-site=${url.nexus}/repository/node-sass/
                       --zopfli_binary_host_mirror=${url.nexus}/repository/node-zopfli&lt;/arguments&gt;
            &lt;/configuration&gt;
          &lt;/execution&gt;
          &lt;execution&gt;
            &lt;!-- (5) And finally do npm run build. We do ng build --aot --prod there --&gt;
            &lt;id&gt;build&lt;/id&gt;
            &lt;goals&gt;
              &lt;goal&gt;npm&lt;/goal&gt;
            &lt;/goals&gt;
            &lt;phase&gt;prepare-package&lt;/phase&gt;
            &lt;configuration&gt;
              &lt;arguments&gt;run build&lt;/arguments&gt;
            &lt;/configuration&gt;
          &lt;/execution&gt;
        &lt;/executions&gt;
      &lt;/plugin&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;
        &lt;version&gt;2.6&lt;/version&gt;
        &lt;configuration&gt;
          &lt;webResources&gt;
            &lt;!-- (6) Put the build results and all the assets into the war --&gt;
            &lt;resource&gt;
              &lt;directory&gt;node/dist&lt;/directory&gt;
            &lt;/resource&gt;
            &lt;resource&gt;
              &lt;directory&gt;node/assets&lt;/directory&gt;
            &lt;/resource&gt;
          &lt;/webResources&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
    &lt;/plugins&gt;
  &lt;/build&gt;

&lt;/project&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_tool_wrappers">Tool wrappers</h2>
<div class="sectionbody">
<div class="paragraph">
<p>After we have <code>mvn clean install</code> passing and building our frontend, we might want to ensure, that developers will also use the same version of node and npm that our CI does. Since we&#8217;re on Windows, we&#8217;ll set up two cute wrappers in directory <code>app-frontend/node</code>:</p>
</div>
<div class="listingblock">
<div class="title">npm.cmd</div>
<div class="content">
<pre class="highlight"><code>@echo off
set dir=%~dp0
set node_dir=%dir%\..\target\node
IF NOT EXIST "%node_dir%\node.exe" (
    rem Invoke maven to install the tools
	cd ..
	call mvn frontend:install-node-and-npm
	cd %dir%
)

%node_dir%\node.exe %node_dir%\node_modules\npm\bin\npm-cli.js %*</code></pre>
</div>
</div>
<div class="paragraph">
<p>This ensures that when we invoke npm in project directory the version that Maven will use is used. It also automatically downloads it when not present!</p>
</div>
<div class="listingblock">
<div class="title">ng.cmd</div>
<div class="content">
<pre class="highlight"><code>@echo off
set dir=%~dp0
REM installing angular-cli
set acli_dir=%dir%node_modules\angular-cli\bin
IF NOT EXIST "%acli_dir%\ng" (
   cd ..
   call mvn generate-resources
   cd %dir%
)
set node_dir=%dir%\..\target\node
call %node_dir%\node.exe %acli_dir%\ng %*</code></pre>
</div>
</div>
<div class="paragraph">
<p>We do the same for <code>ng</code>. We cannot just run <code>node_modules\.bin\ng</code> as that would invoke with our system&#8217;s node. It is probably much easier to <code>set PATH=..\target\node;node_modules\.bin;%PATH%</code> but you cannot be sure enough with lazy people.</p>
</div>
<div class="paragraph">
<p>For the less lazy we provide following file they should execute when they start a new terminal for the project:</p>
</div>
<div class="listingblock">
<div class="title">initenv.cmd</div>
<div class="content">
<pre class="highlight"><code>set HTTP_PROXY=
set HTTPS_PROXY=
set PATH=node_modules\.bin;..\target\node;%PATH%</code></pre>
</div>
</div>
</div>
</div>]]></description><link>https://pdudits.github.io/2016/11/16/Setting-up-Angular2-CLI-with-Maven-in-enterprise-network.html</link><guid isPermaLink="true">https://pdudits.github.io/2016/11/16/Setting-up-Angular2-CLI-with-Maven-in-enterprise-network.html</guid><category><![CDATA[Maven]]></category><category><![CDATA[Angular]]></category><category><![CDATA[Windows]]></category><dc:creator><![CDATA[Patrik Duditš]]></dc:creator><pubDate>Wed, 16 Nov 2016 00:00:00 GMT</pubDate></item><item><title><![CDATA[Java EE 7 Training resources]]></title><description><![CDATA[<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>I&#8217;ve done a training with two-day Java EE overview. This is annotated browser history of the things I showed.</p>
</div>
<div class="paragraph">
<p>At the training we followed book <a href="http://www.apress.com/9781430246268">Beginning Java EE 7</a> from <a href="https://antoniogoncalves.org/">Antonio Goncalves</a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="the-code">The code</h3>
<div class="paragraph">
<p>We followed <a href="https://github.com/agoncal/agoncal-book-javaee7">code samples
from the book</a> troughout the training.</p>
</div>
</div>
<div class="sect2">
<h3 id="other-general-resources">Other general resources</h3>
<div class="paragraph">
<p><a href="http://docs.oracle.com/javaee/7/api/index.html">Java EE 7 javadoc</a> lists
all of the relevant APIs defined by Java EE spec.</p>
</div>
<div class="paragraph">
<p>Adam Bien’s book <a href="http://realworldpatterns.com/">Real World Java EE
Patterns – Rethinking Best Practices</a> will help you put EJB and CDI in
practice.</p>
</div>
<div class="paragraph">
<p><a href="https://github.com/javaee-samples/javaee7-samples">Java EE 7 samples</a>
demonstrates Java EE 7 features in Arquillian-based tests.</p>
</div>
<div class="paragraph">
<p><a href="http://arquillian.org/">Arquillian</a> helps testing parts of your Java EE
applications within container - be it just Weld, embedded Payara or
remote standalone servers.</p>
</div>
</div>
<div class="sect2">
<h3 id="cdi">CDI</h3>
<div class="paragraph">
<p>Read <a href="http://docs.jboss.org/weld/reference/latest/en-US/html/">Weld
Reference Documentation</a> for in-depth details about all CDI features.</p>
</div>
<div class="paragraph">
<p><a href="https://deltaspike.apache.org/">Apache Deltaspike</a> is collection of CDI
extensions covering various infrastructure aspects of your application.</p>
</div>
</div>
<div class="sect2">
<h3 id="jpa">JPA</h3>
<div class="paragraph">
<p>For in-depth look into JPA, design of the entities and trade-offs of the
features, read <a href="http://www.apress.com/9781430219569">Pro JPA 2</a> by Mike
Keith and Merrick Schincariol.</p>
</div>
<div class="paragraph">
<p>Another great source of JPA knowledge is <a href="https://vladmihalcea.com/">Vlad
Mihalcea</a>.</p>
</div>
<div class="paragraph">
<p>Instead of Criteria API, consider using
<a href="http://www.querydsl.com/">QueryDSL</a>.</p>
</div>
<div class="paragraph">
<p>For managing of database schema I recommend
<a href="https://flywaydb.org/">FlyWay</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="security">Security</h3>
<div class="paragraph">
<p>Ultimate source on JAAS and JASPIC is
<a href="http://arjan-tijms.omnifaces.org/">Arjan Tijms</a> (and also for JSF and
OmniFaces).</p>
</div>
</div>
<div class="sect2">
<h3 id="transactions">Transactions</h3>
<div class="paragraph">
<p>To understand cases, where distributed transactions are not a good
choice, read
<a href="http://www.enterpriseintegrationpatterns.com/docs/IEEE_Software_Design_2PC.pdf">Your
Coffee Shop Doesn’t<br>
Use Two-Phase Commit</a> by Gregor Hohpe.</p>
</div>
<div class="paragraph">
<p>Also good source for understanding distributed systems, that usually
reach outside scope of Java EE, look at
<a href="http://book.mixu.net/distsys/single-page.html">Distributed Systems for
Fun and Profit</a> by Mikito Takada.</p>
</div>
</div>
<div class="sect2">
<h3 id="messaging">Messaging</h3>
<div class="paragraph">
<p>Even though Java Serialization is very comfortable, for high performance
systems consider <a href="https://github.com/eishay/jvm-serializers/wiki">other
serialization libraries</a> that might give you smaller payloads, less CPU
usage, and better interface evolution options.</p>
</div>
<div class="paragraph">
<p>For building business processes based on message passing you may want to
read
<a href="https://books.google.sk/books/about/Enterprise_Integration_Patterns.html?id=qqB7nrrna_sC&amp;source=kp_cover&amp;redir_esc=y">Enterprise
Integration Patterns</a> by Gregor Hohpe (yes, the one of the coffee shop
article).</p>
</div>
</div>
<div class="sect2">
<h3 id="rest">REST</h3>
<div class="paragraph">
<p>The origin of the term is in
<a href="https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation.pdf">Roy
Fieldings’ disertation</a>, where it says it’s not just about HTTP, but
also <a href="http://olivergierke.de/2016/04/benefits-of-hypermedia/">about
hypermedia</a>.</p>
</div>
<div class="paragraph">
<p>Serialization frameworks from above may also be a good option for
message exchange over REST.</p>
</div>
</div>
<div class="sect2">
<h3 id="jsf">JSF</h3>
<div class="paragraph">
<p>I think no JSF app can survive without
<a href="http://www.primefaces.org/">PrimeFaces</a> and
<a href="http://showcase.omnifaces.org/">OmniFaces</a>. And the
<a href="https://www.amazon.com/dp/1908689293">book explaining OmniFaces and
therefore JSF</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="application-servers">Application Servers</h3>
<div class="ulist">
<ul>
<li>
<p><a href="http://www.payara.fish/">Payara</a> - maintained fork of deceased platform
reference implementation <a href="https://glassfish.java.net/">Glassfish</a>. See
also <a href="http://docs.oracle.com/cd/E26576_01/index.htm">Glassfish
Documentation</a> and
<a href="https://payara.gitbooks.io/payara-server/content">Payara Documentation</a></p>
</li>
<li>
<p><a href="http://wildfly.org/">Wildfly</a> - open source variant of
<a href="http://developers.redhat.com/products/eap/download/">JBoss EAP 7</a>. See
also
<a href="https://docs.jboss.org/author/display/WFLY10/Developer+Guide">Development
guide</a> for server specifics.</p>
</li>
<li>
<p><a href="http://tomee.apache.org/apache-tomee.html">TomEE</a> Java EE <em>6</em>
application server built on top of Tomcat from Tomcat maintainers</p>
</li>
<li>
<p><a href="https://developer.ibm.com/wasdev/websphere-liberty/">WebShpere Liberty</a>
free version of WebShere with heap limit 2GB (total over all instances)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><a href="http://www.oracle.com/technetwork/java/javaee/overview/compatibility-jsp-136984.html">Full
listing of certified servers</a></p>
</div>
</div>
<div class="sect2">
<h3 id="standards-specifications">Standards’ specifications</h3>
<div class="paragraph">
<p>All Java EE specifications are governed by <a href="http://jcp.org">Java Comunity
Process</a> as Java Speficication Requests (JSRs). The list of Java EE 7
JSR with links to spec downloads is available
<a href="http://www.oracle.com/technetwork/java/javaee/tech/index-jsp-142185.html">at
Oracle’s site</a></p>
</div>
</div>
<div class="sect2">
<h3 id="misc">Misc</h3>
<div class="paragraph">
<p>At heart of every server there is bytecode manipulation library like
<a href="http://asm.ow2.org/">ASM</a>. Other good use cases are writing tests, that
verify correctness of the code (e. g. security check is invoked in every
method).</p>
</div>
</div>]]></description><link>https://pdudits.github.io/2016/08/26/Java-EE-7-Training-resources.html</link><guid isPermaLink="true">https://pdudits.github.io/2016/08/26/Java-EE-7-Training-resources.html</guid><category><![CDATA[Java EE]]></category><dc:creator><![CDATA[Patrik Duditš]]></dc:creator><pubDate>Fri, 26 Aug 2016 00:00:00 GMT</pubDate></item><item><title><![CDATA[400 Bad Request when using Glassfish REST API]]></title><description><![CDATA[<div class="paragraph">
<p>When you try to automate your Glassfish administration duties with its REST API using POST or DELETE methods, and all you get is HTTP response 400 and zero content, you forgot to read <a href="http://docs.oracle.com/cd/E26576_01/doc.312/e24928/general-administration.htm#GSADG00708">this:</a></p>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>REST requests that add, update, or delete objects must specify the <code>X-Requested-By</code> header with the value <code>GlassFish REST HTML interface</code>.</p>
</div>
</blockquote>
</div>
<div class="paragraph">
<p>It is intended to prevent CSRF attacks as noted in <a href="http://blogs.steeplesoft.com/2012/03/glassfish-3-1-2-and-rest-security/">Jason&#8217;s Lee post</a>.</p>
</div>]]></description><link>https://pdudits.github.io/2012/05/23/400-Bad-Request-when-using-Glassfish-REST-API.html</link><guid isPermaLink="true">https://pdudits.github.io/2012/05/23/400-Bad-Request-when-using-Glassfish-REST-API.html</guid><category><![CDATA[Glassfish]]></category><dc:creator><![CDATA[Patrik Duditš]]></dc:creator><pubDate>Wed, 23 May 2012 00:00:00 GMT</pubDate></item><item><title><![CDATA[Enabling SOAP message signing for EJB webservice client in Glassfish]]></title><description><![CDATA[<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Today&#8217;s solution is for following scenario: An EJB uses a web service client, and needs to sign its request with a trusted certificate. We are running Glassfish 3.1.1. Its documentation is <a href="http://docs.oracle.com/cd/E18930_01/html/821-2418/beaca.html#gbjxw">pretty straighforward</a> about specifying default client provider, which will cause all webservice calls to be signed. But we cannot do that, because other web service we&#8217;re calling cannot handle digitally signed SOAP messages. Documentation only mentions <a href="http://docs.oracle.com/cd/E18930_01/html/821-2418/beaca.html#beacg">web service endpoint configuration</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_here_s_what_to_do">Here&#8217;s what to do</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Add following to your <code>glassfish-ejb-jar.xml</code>:</p>
</div>
<div class="paragraph">
<p>[source,xml</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE glassfish-ejb-jar PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 EJB 3.1//EN"
  "http://glassfish.org/dtds/glassfish-ejb-jar_3_1-1.dtd"&gt;
&lt;glassfish-ejb-jar&gt;
    &lt;enterprise-beans&gt;
        &lt;ejb&gt;
            &lt;ejb-name&gt;EjbThatSignsSoapRequests&lt;/ejb-name&gt;
            &lt;service-ref&gt;
                &lt;!-- you might need explicit @WebService(name="service") on that field,
                     even if the field is named service --&gt;
                &lt;service-ref-name&gt;service&lt;/service-ref-name&gt;
                &lt;port-info&gt;
                    &lt;!-- This is the vital part - specify port of web service --&gt;
                    &lt;wsdl-port&gt;
                        &lt;namespaceURI&gt;urn:webservice:namespace-from-wsdl&lt;/namespaceURI&gt;
                        &lt;localpart&gt;WebServicePortName&lt;/localpart&gt;
                    &lt;/wsdl-port&gt;
                    &lt;message-security-binding
                        auth-layer="SOAP" provider-id="ClientProvider"/&gt;
                &lt;/port-info&gt;
            &lt;/service-ref&gt;
       &lt;/ejb&gt;
   &lt;/enterprise-beans&gt;
&lt;/glassfish-ejb-jar&gt;</pre>
</div>
</div>
<div class="paragraph">
<p>Then, configure your client e. g. via admin gui at path <strong>Configurations &gt; server-config &gt; Security &gt; Message Security &gt; SOAP &gt; Tab Providers &gt; Client Provider</strong>.</p>
</div>
</div>
</div>]]></description><link>https://pdudits.github.io/2012/04/20/Enabling-SOAP-message-signing-for-EJB-webservice-client-in-Glassfish.html</link><guid isPermaLink="true">https://pdudits.github.io/2012/04/20/Enabling-SOAP-message-signing-for-EJB-webservice-client-in-Glassfish.html</guid><category><![CDATA[Glassfish]]></category><category><![CDATA[JAX-WS]]></category><dc:creator><![CDATA[Patrik Duditš]]></dc:creator><pubDate>Fri, 20 Apr 2012 00:00:00 GMT</pubDate></item></channel></rss>