<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.2">Jekyll</generator><link href="https://paspaola.it/feed.xml" rel="self" type="application/atom+xml" /><link href="https://paspaola.it/" rel="alternate" type="text/html" /><updated>2023-12-04T12:01:34+01:00</updated><id>https://paspaola.it/feed.xml</id><title type="html">paspaola.it</title><subtitle>A simple blog about my dev life.</subtitle><author><name>Pasquale Paola</name></author><entry><title type="html">A Kafka streaming application with Quarkus</title><link href="https://paspaola.it/2023/05/21/QuarkusStreamingApp.html" rel="alternate" type="text/html" title="A Kafka streaming application with Quarkus" /><published>2023-05-21T18:43:00+02:00</published><updated>2023-05-21T18:43:00+02:00</updated><id>https://paspaola.it/2023/05/21/QuarkusStreamingApp</id><content type="html" xml:base="https://paspaola.it/2023/05/21/QuarkusStreamingApp.html"><![CDATA[<p><img style="display: block;  margin-left: auto;  margin-right: auto;" src="/assets/images/quarkus_logo_kafka.png" alt="" width="600px" /></p>

<p>The Kafka streaming application platform is becoming <em>“de facto”</em> the modern approach to the ETL (Extract, transform and load) world. Probably you already read a lot about “What is Kafka”, “What is a topic” and “What is a partition”, but i want to discuss with you “What is a streaming application”, this is the aim of this article, I hope I’ll achieve the goal.
<!--more-->
The book <em>“Kafka streams in Action”</em> defines the stream processing as <em>“working with data as it’s arriving in your system”</em> or more refined <em>“stream processing is the ability to work with an infinite stream of data with continuous computation, as it flows, with no need to collect or store the data
to act on it”</em>. Usually, we use a stream processing application when we have a lot of data (BigData) and the need to quickly respond to or report on incoming data.</p>

<p>Before continuing, the complete example described here, it’s published on Github at <a href="https://github.com/paspao/quarkus-streaming-app">https://github.com/paspao/quarkus-streaming-app</a>, it doesn’t contain the streaming app only, but a complete deployment scenarios:</p>

<ul>
  <li>1 Zookeeper instance</li>
  <li>3 Kafka instances</li>
  <li>1 Kafdrop instance (easy way to give a look inside the Kafka topic/instance etc)</li>
  <li>1 Streaming app (described in this article)</li>
</ul>

<p>Through Kafdrop you can verify the content the Kafka topics.</p>

<hr />

<p>Now, let’s suppose that all the data are already present inside Kafka topics, i tried to draw them in the below picture:</p>

<p><img style="display: block;  margin-left: auto;  margin-right: auto;" src="/assets/images/allTogether.svg" alt="" width="800px" /></p>

<p>So i have created four simple entities (each one is a Kafka topic representation): Person, DriverLicense, Sim, Fee. The data architecture is pretty simple: a person could have some driver licenses, a person could have sim cards and last but not least a person pays the fees unfortunately.
I marked with red color the <em>key</em> of the topics and the entire row is the kafka message or the <em>payload</em>.</p>

<p>Obviously, the table representation is a simplification, we have to keep in mind that each row in the table could be more than one message, like in the picture below:</p>

<p><img style="display: block;  margin-left: auto;  margin-right: auto;" src="/assets/images/3dRow.svg" alt="" width="800px" /></p>

<p>We could have multiple <em>versions</em> of the same row/message, why?</p>

<p><img style="display: block;  margin-left: auto;  margin-right: auto;" src="/assets/images/hiddenValues.svg" alt="" width="800px" /></p>

<p>Kafka acts like a <em>commit log</em> which is a record of transactions. In a database context, it’s used to keep track of what’s happening, and it helps with disaster recovery, it represents the bearing structure of all RDBMS. We can define that a <em>commit log</em> is an immutable, ordered record of events.</p>

<p>Well, Kafka stores two hidden values for each row: an <em>offset</em> and a <em>timestamp</em>. With the <em>offset</em> field you can univocal identify a row in a partition. The choice to manage these two <em>hidden</em> values is due to manage the <em>time</em>: indeed Kafka gives us the option to process the messages in a specific time window.
For example we could decide to process the messages that we received in the year 2009, ignoring all the messages that we have received before or after that year, <em>ignoring</em> it is what allow us to achieve high speed, in fact this is one of the secrets for realtime processing (<em>streaming</em>) sponsored/achieved by Kafka.</p>

<p>Now come back to the example. My first goal is to join two simple topic that are <em>Person</em> and <em>DriverLicense</em> because i want to discover how many person already had a driver license, so let’s start to join these two topics. 
From a data perspective to join two topics they have to respect the <em>co-partitioning</em> requirements that are:</p>

<ul>
  <li>The input records for the join must have the same key (or key schema)</li>
  <li>The input records must have the same number of partitions on both sides</li>
  <li>Both sides of the join must have the same partitioning strategy (usually we use the default one offered by the Kafka client, practically ignoring the ability to choose a different one)</li>
</ul>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="code"><pre><span class="kd">public</span> <span class="nc">Topology</span> <span class="nf">appJoinPersonAndDriverLicense</span><span class="o">()</span> <span class="o">{</span>

    <span class="kd">final</span> <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Person</span><span class="o">&gt;</span> <span class="n">personStream</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">stream</span><span class="o">(</span><span class="no">PERSON</span><span class="o">,</span>
            <span class="nc">Consumed</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getPersonSerde</span><span class="o">()));</span>
    <span class="kd">final</span> <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">DriverLicense</span><span class="o">&gt;</span> <span class="n">driverLicenseStream</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">stream</span><span class="o">(</span><span class="no">DRIVERLICENSE</span><span class="o">,</span>
            <span class="nc">Consumed</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getDriverLicenseSerde</span><span class="o">()));</span>

    <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Person</span><span class="o">&gt;</span> <span class="n">peekStream</span> <span class="o">=</span> <span class="n">personStream</span><span class="o">.</span><span class="na">peek</span><span class="o">(</span><span class="n">loggingForEach</span><span class="o">);</span>

    <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">PersonDriverLicense</span><span class="o">&gt;</span> <span class="n">joined</span> <span class="o">=</span> <span class="n">peekStream</span><span class="o">.</span><span class="na">join</span><span class="o">(</span><span class="n">driverLicenseStream</span><span class="o">,</span>
            <span class="o">(</span><span class="n">person</span><span class="o">,</span> <span class="n">license</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nc">PersonDriverLicense</span><span class="o">(</span><span class="n">person</span><span class="o">,</span> <span class="n">license</span><span class="o">),</span>
            <span class="nc">JoinWindows</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="nc">Duration</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">5</span><span class="o">,</span> <span class="nc">ChronoUnit</span><span class="o">.</span><span class="na">MINUTES</span><span class="o">)),</span> <span class="nc">StreamJoined</span><span class="o">.</span><span class="na">with</span><span class="o">(</span>
                    <span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="cm">/* key */</span>
                    <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getPersonSerde</span><span class="o">(),</span>   <span class="cm">/* left value */</span>
                    <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getDriverLicenseSerde</span><span class="o">()</span>  <span class="cm">/* right value */</span>
            <span class="o">));</span>

    <span class="n">joined</span><span class="o">.</span><span class="na">to</span><span class="o">(</span><span class="no">ALL</span><span class="o">,</span> <span class="nc">Produced</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getPersonDriverLicenseSerde</span><span class="o">()));</span>

    <span class="nc">Topology</span> <span class="n">build</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">build</span><span class="o">();</span>
    <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="n">build</span><span class="o">.</span><span class="na">describe</span><span class="o">().</span><span class="na">toString</span><span class="o">());</span>
    <span class="k">return</span> <span class="n">build</span><span class="o">;</span>
<span class="o">}</span>

<span class="kd">final</span> <span class="nc">ForeachAction</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Person</span><span class="o">&gt;</span> <span class="n">loggingForEach</span> <span class="o">=</span> <span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="n">person</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">person</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span>
            <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Key: {}, Value: {}"</span><span class="o">,</span> <span class="n">key</span><span class="o">,</span> <span class="n">person</span><span class="o">);</span>
<span class="o">};</span>
</pre></td></tr></tbody></table></code></pre></figure>

<p>In this code snippet you don’t find the configuration, this is not our focus, here the focus is the streaming (you can find the details in the repo anyway): at lines 3 and 5 we defined two streams one for the <em>Person</em> topic and one for the <em>DriverLicense</em> topic, then just a <em>peek</em> operation to log the <em>stream person</em> and later the <em>join</em> operation at lines 10-16 between Person and DriverLicense. Be careful, I used a <em>peekStream</em> and not the <em>personStream</em> at line 10 because I wanted to add a new node in order to log the flow (I’m building a <em>topology…</em>), we need something to see this topology, so at line 21 I printed out the stream/topology in the console log, it’s a logical description:</p>

<figure class="highlight"><pre><code class="language-properties" data-lang="properties"><span class="py">Topologies</span><span class="p">:</span>
<span class="py">Sub-topology</span><span class="p">:</span> <span class="s">0</span>
<span class="py">Source</span><span class="p">:</span> <span class="s">KSTREAM-SOURCE-0000000000 (topics: [person])</span>
<span class="err">--&gt;</span> <span class="err">KSTREAM-PEEK-0000000002</span>
<span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-PEEK-0000000002 (stores: [])</span>
<span class="err">--&gt;</span> <span class="err">KSTREAM-WINDOWED-0000000003</span>
<span class="err">&lt;--</span> <span class="err">KSTREAM-SOURCE-0000000000</span>
<span class="py">Source</span><span class="p">:</span> <span class="s">KSTREAM-SOURCE-0000000001 (topics: [driverlicense])</span>
<span class="err">--&gt;</span> <span class="err">KSTREAM-WINDOWED-0000000004</span>
<span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-WINDOWED-0000000003 (stores: [KSTREAM-JOINTHIS-0000000005-store])</span>
<span class="err">--&gt;</span> <span class="err">KSTREAM-JOINTHIS-0000000005</span>
<span class="err">&lt;--</span> <span class="err">KSTREAM-PEEK-0000000002</span>
<span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-WINDOWED-0000000004 (stores: [KSTREAM-JOINOTHER-0000000006-store])</span>
<span class="err">--&gt;</span> <span class="err">KSTREAM-JOINOTHER-0000000006</span>
<span class="err">&lt;--</span> <span class="err">KSTREAM-SOURCE-0000000001</span>
<span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-JOINOTHER-0000000006 (stores: [KSTREAM-JOINTHIS-0000000005-store])</span>
<span class="err">--&gt;</span> <span class="err">KSTREAM-MERGE-0000000007</span>
<span class="err">&lt;--</span> <span class="err">KSTREAM-WINDOWED-0000000004</span>
<span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-JOINTHIS-0000000005 (stores: [KSTREAM-JOINOTHER-0000000006-store])</span>
<span class="err">--&gt;</span> <span class="err">KSTREAM-MERGE-0000000007</span>
<span class="err">&lt;--</span> <span class="err">KSTREAM-WINDOWED-0000000003</span>
<span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-MERGE-0000000007 (stores: [])</span>
<span class="err">--&gt;</span> <span class="err">KSTREAM-SINK-0000000008</span>
<span class="err">&lt;--</span> <span class="err">KSTREAM-JOINTHIS-0000000005,</span> <span class="err">KSTREAM-JOINOTHER-0000000006</span>
<span class="py">Sink</span><span class="p">:</span> <span class="s">KSTREAM-SINK-0000000008 (topic: alltogether)</span>
<span class="err">&lt;--</span> <span class="err">KSTREAM-MERGE-0000000007</span></code></pre></figure>

<p>We can use this snippet to draw the topology using a tool like <a href="https://zz85.github.io/kafka-streams-viz/">https://zz85.github.io/kafka-streams-viz/</a>, below you can find the result:</p>

<p><img style="display: block;  margin-left: auto;  margin-right: auto;" src="/assets/images/firstTopology.png" alt="" width="600px" /></p>

<p>Well, now we have a graphical representation of our simple topology. It’s more clear to see the topics, the stream and the <em>peek</em> operation we already discussed, but now we can see more clearly what happen during a join operation. At line 12 we used a <em>JoinWindow</em>, the <em>join</em> operation is a stateful transformation, we need a state store to collect all of the records received so far within the defined window boundary. With Kafka we have the ability to consider the time as data, so we don’t want to process all the updates received a for a specific record but only what is changed in the last 5 minutes for example, in this way I will process only few kilobyte of data (in a BigData context we could have topic with Terabyte of data). So, topology wise for each element of the join operation a state store will be created (the two cylinder on the right side of the picture) and a corresponding topic will be created on Kafka as well, these topics are named as <em>store-changelog</em> topics, this to ensure the the foult-talerant capabilities of the Kafka Streams. As described in the Confluent documentation: <em>“These changelog topics are partitioned as well so that each local state store instance, and hence the task accessing the store, has its own dedicated changelog topic partition. Log compaction is enabled on the changelog topics so that old data can be purged safely to prevent the topics from growing indefinitely. If tasks run on a machine that fails and are restarted on another machine, Kafka Streams guarantees to restore their associated state stores to the content before the failure by replaying the corresponding changelog topics prior to resuming the processing on the newly started tasks. As a result, failure handling is completely transparent to the end user.”</em></p>

<p>So, in the final step at line 18 the data will be joined by the key and the result will be stored in the <em>alltogether</em> topic, something like:</p>

<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">{</span><span class="w">
   </span><span class="nl">"person"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"ssn"</span><span class="p">:</span><span class="w"> </span><span class="s2">"789"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Giacchino"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"surname"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Murat"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"sex"</span><span class="p">:</span><span class="w"> </span><span class="s2">"M"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"dateOfBirth"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1981-06-28"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"phoneNumber"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1113245798"</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"driverLicense"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"789"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"CAR"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"licenseNumber"</span><span class="p">:</span><span class="w"> </span><span class="s2">"4213245768"</span><span class="w">
   </span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre></figure>

<p>Well, now let’s try to create a more complex/realistic scenario: let’s try to join topics not <em>co-partitionated</em> or at least not yet, so what we will try to do now is joining the <em>alltogether</em> topic with the <em>fee</em> topic . The result will be a payload with:</p>

<ul>
  <li>Person</li>
  <li>Driver License</li>
  <li>Fee</li>
</ul>

<p>The first part is already implemented (it’s a copy of the previous one) so we can completly ignore the lines 1-20:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
</pre></td><td class="code"><pre><span class="kd">public</span> <span class="nc">Topology</span> <span class="nf">appJoinPersonAndDriverLicenseAndFee</span><span class="o">()</span> <span class="o">{</span>

        <span class="kd">final</span> <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Person</span><span class="o">&gt;</span> <span class="n">personStream</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">stream</span><span class="o">(</span><span class="no">PERSON</span><span class="o">,</span>
                <span class="nc">Consumed</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getPersonSerde</span><span class="o">()));</span>
        <span class="kd">final</span> <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">DriverLicense</span><span class="o">&gt;</span> <span class="n">driverLicenseStream</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">stream</span><span class="o">(</span><span class="no">DRIVERLICENSE</span><span class="o">,</span>
                <span class="nc">Consumed</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getDriverLicenseSerde</span><span class="o">()));</span>


        <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Person</span><span class="o">&gt;</span> <span class="n">peekStream</span> <span class="o">=</span> <span class="n">personStream</span><span class="o">.</span><span class="na">peek</span><span class="o">(</span><span class="n">loggingForEach</span><span class="o">);</span>

        <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">PersonDriverLicense</span><span class="o">&gt;</span> <span class="n">joinedPersonDriverLicense</span> <span class="o">=</span> <span class="n">peekStream</span><span class="o">.</span><span class="na">join</span><span class="o">(</span><span class="n">driverLicenseStream</span><span class="o">,</span>
                <span class="o">(</span><span class="n">person</span><span class="o">,</span> <span class="n">license</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nc">PersonDriverLicense</span><span class="o">(</span><span class="n">person</span><span class="o">,</span> <span class="n">license</span><span class="o">),</span>
                <span class="nc">JoinWindows</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="nc">Duration</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">5</span><span class="o">,</span> <span class="nc">ChronoUnit</span><span class="o">.</span><span class="na">MINUTES</span><span class="o">)),</span> <span class="nc">StreamJoined</span><span class="o">.</span><span class="na">with</span><span class="o">(</span>
                        <span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="cm">/* key */</span>
                        <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getPersonSerde</span><span class="o">(),</span>   <span class="cm">/* left value */</span>
                        <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getDriverLicenseSerde</span><span class="o">()</span>  <span class="cm">/* right value */</span>
                <span class="o">));</span>


        <span class="n">joinedPersonDriverLicense</span><span class="o">.</span><span class="na">to</span><span class="o">(</span><span class="no">ALL</span><span class="o">,</span> <span class="nc">Produced</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getPersonDriverLicenseSerde</span><span class="o">()));</span>
        
        <span class="c1">// End of the first example</span>
        
        <span class="kd">final</span> <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Fee</span><span class="o">&gt;</span> <span class="n">feeStream</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">stream</span><span class="o">(</span><span class="no">FEE</span><span class="o">,</span>
            <span class="nc">Consumed</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getFeeSerde</span><span class="o">()));</span>

        <span class="nc">KeyValueBytesStoreSupplier</span> <span class="n">feeBySsnTableSupplier</span> <span class="o">=</span> <span class="nc">Stores</span><span class="o">.</span><span class="na">persistentKeyValueStore</span><span class="o">(</span><span class="s">"feeBySsnTableSupplier"</span><span class="o">);</span>

        <span class="kd">final</span> <span class="nc">Materialized</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">FeeBySsn</span><span class="o">,</span> <span class="nc">KeyValueStore</span><span class="o">&lt;</span><span class="nc">Bytes</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">materialized</span> <span class="o">=</span>
                <span class="nc">Materialized</span><span class="o">.&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">FeeBySsn</span><span class="o">&gt;</span><span class="n">as</span><span class="o">(</span><span class="n">feeBySsnTableSupplier</span><span class="o">)</span>
                        <span class="o">.</span><span class="na">withKeySerde</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">())</span>
                        <span class="o">.</span><span class="na">withValueSerde</span><span class="o">(</span><span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getFeeBySsnSerde</span><span class="o">());</span>

        <span class="nc">KStream</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">PersonDriverLicenseFee</span><span class="o">&gt;</span> <span class="n">joinedPersonDriverLicenseFee</span> <span class="o">=</span> <span class="n">feeStream</span>
                <span class="o">.</span><span class="na">selectKey</span><span class="o">((</span><span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="n">value</span><span class="o">.</span><span class="na">getSsn</span><span class="o">())</span>
                <span class="o">.</span><span class="na">groupByKey</span><span class="o">(</span><span class="nc">Grouped</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getFeeSerde</span><span class="o">()))</span>
                <span class="o">.</span><span class="na">aggregate</span><span class="o">(()</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nc">FeeBySsn</span><span class="o">(),</span> <span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">,</span> <span class="n">aggregate</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span>
                    <span class="n">aggregate</span><span class="o">.</span><span class="na">setSsn</span><span class="o">(</span><span class="n">key</span><span class="o">);</span>
                    <span class="n">aggregate</span><span class="o">.</span><span class="na">getFeeList</span><span class="o">().</span><span class="na">add</span><span class="o">(</span><span class="n">value</span><span class="o">);</span>
                    <span class="k">return</span> <span class="n">aggregate</span><span class="o">;</span>
                <span class="o">},</span> <span class="n">materialized</span><span class="o">)</span>
                <span class="o">.</span><span class="na">toStream</span><span class="o">()</span>
                <span class="o">.</span><span class="na">join</span><span class="o">(</span><span class="n">joinedPersonDriverLicense</span><span class="o">,</span>
                        <span class="o">(</span><span class="n">feeBySsn</span><span class="o">,</span> <span class="n">personDl</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nc">PersonDriverLicenseFee</span><span class="o">(</span><span class="n">personDl</span><span class="o">.</span><span class="na">getPerson</span><span class="o">(),</span> <span class="n">personDl</span><span class="o">.</span><span class="na">getDriverLicense</span><span class="o">(),</span> <span class="n">feeBySsn</span><span class="o">),</span>
                        <span class="nc">JoinWindows</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="nc">Duration</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">5</span><span class="o">,</span> <span class="nc">ChronoUnit</span><span class="o">.</span><span class="na">MINUTES</span><span class="o">)),</span> <span class="nc">StreamJoined</span><span class="o">.</span><span class="na">with</span><span class="o">(</span>
                                <span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="cm">/* key */</span>
                                <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getFeeBySsnSerde</span><span class="o">(),</span>   <span class="cm">/* left value */</span>
                                <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getPersonDriverLicenseSerde</span><span class="o">()</span>  <span class="cm">/* right value */</span>
                        <span class="o">));</span>
        <span class="n">joinedPersonDriverLicenseFee</span><span class="o">.</span><span class="na">to</span><span class="o">(</span><span class="no">ALL_ENHANCEMENT</span><span class="o">,</span> <span class="nc">Produced</span><span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="nc">Serdes</span><span class="o">.</span><span class="na">String</span><span class="o">(),</span> <span class="nc">FactorySerde</span><span class="o">.</span><span class="na">getPersonDriverLicenseFeeSerde</span><span class="o">()));</span>

        <span class="nc">Topology</span> <span class="n">build</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">build</span><span class="o">();</span>
        <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="n">build</span><span class="o">.</span><span class="na">describe</span><span class="o">().</span><span class="na">toString</span><span class="o">());</span>
        <span class="k">return</span> <span class="n">build</span><span class="o">;</span>
    <span class="o">}</span>

<span class="kd">final</span> <span class="nc">ForeachAction</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Person</span><span class="o">&gt;</span> <span class="n">loggingForEach</span> <span class="o">=</span> <span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="n">person</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">person</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span>
            <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Key: {}, Value: {}"</span><span class="o">,</span> <span class="n">key</span><span class="o">,</span> <span class="n">person</span><span class="o">);</span>
<span class="o">};</span>
</pre></td></tr></tbody></table></code></pre></figure>

<p>At line 24 we defined a new stream for the <em>fee</em> topic, then at lines 27-32 we defined  something of new that is a <em>persistent KeyValue store</em> used to set the <em>serde</em> classes that are used to serialize and deserialize the data.</p>

<p>At line 34 we start to join <em>alltogether</em> topic with <em>fee</em> topic:</p>

<ul>
  <li>we need to “override” the key of the <em>fee</em> topic as i cannot join two topics with different keys, we do it at line 35</li>
  <li>when overriding the key you need to define an aggregation strategy as well, it’s done at lines 37-41.</li>
  <li>now the <em>fee</em> stream is ready to join with <em>alltogether</em> so at lines 42-49 we simply join these two streams defining the serialization and the time window (in our example the time window is just an example)</li>
  <li>last step the joined data are moved to a new topic</li>
</ul>

<p>As usual at line 53 we print out the description of the defined topology:</p>

<figure class="highlight"><pre><code class="language-properties" data-lang="properties"><span class="py">Topologies</span><span class="p">:</span>
   <span class="py">Sub-topology</span><span class="p">:</span> <span class="s">0</span>
    <span class="py">Source</span><span class="p">:</span> <span class="s">KSTREAM-SOURCE-0000000000 (topics: [person])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-PEEK-0000000003</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-PEEK-0000000003 (stores: [])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-WINDOWED-0000000004</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-SOURCE-0000000000</span>
    <span class="py">Source</span><span class="p">:</span> <span class="s">KSTREAM-SOURCE-0000000001 (topics: [driverlicense])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-WINDOWED-0000000005</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-WINDOWED-0000000004 (stores: [KSTREAM-JOINTHIS-0000000006-store])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-JOINTHIS-0000000006</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-PEEK-0000000003</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-WINDOWED-0000000005 (stores: [KSTREAM-JOINOTHER-0000000007-store])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-JOINOTHER-0000000007</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-SOURCE-0000000001</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-JOINOTHER-0000000007 (stores: [KSTREAM-JOINTHIS-0000000006-store])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-MERGE-0000000008</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-WINDOWED-0000000005</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-JOINTHIS-0000000006 (stores: [KSTREAM-JOINOTHER-0000000007-store])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-MERGE-0000000008</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-WINDOWED-0000000004</span>
    <span class="py">Source</span><span class="p">:</span> <span class="s">feeBySsnTableSupplier-repartition-source (topics: [feeBySsnTableSupplier-repartition])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-AGGREGATE-0000000011</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-AGGREGATE-0000000011 (stores: [feeBySsnTableSupplier])</span>
      <span class="err">--&gt;</span> <span class="err">KTABLE-TOSTREAM-0000000015</span>
      <span class="err">&lt;--</span> <span class="err">feeBySsnTableSupplier-repartition-source</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-MERGE-0000000008 (stores: [])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-WINDOWED-0000000017,</span> <span class="err">KSTREAM-SINK-0000000009</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-JOINTHIS-0000000006,</span> <span class="err">KSTREAM-JOINOTHER-0000000007</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KTABLE-TOSTREAM-0000000015 (stores: [])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-WINDOWED-0000000016</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-AGGREGATE-0000000011</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-WINDOWED-0000000016 (stores: [KSTREAM-JOINTHIS-0000000018-store])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-JOINTHIS-0000000018</span>
      <span class="err">&lt;--</span> <span class="err">KTABLE-TOSTREAM-0000000015</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-WINDOWED-0000000017 (stores: [KSTREAM-JOINOTHER-0000000019-store])</span>

      <span class="err">--&gt;</span> <span class="err">KSTREAM-JOINOTHER-0000000019</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-MERGE-0000000008</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-JOINOTHER-0000000019 (stores: [KSTREAM-JOINTHIS-0000000018-store])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-MERGE-0000000020</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-WINDOWED-0000000017</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-JOINTHIS-0000000018 (stores: [KSTREAM-JOINOTHER-0000000019-store])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-MERGE-0000000020</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-WINDOWED-0000000016</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-MERGE-0000000020 (stores: [])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-SINK-0000000021</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-JOINTHIS-0000000018,</span> <span class="err">KSTREAM-JOINOTHER-0000000019</span>
    <span class="py">Sink</span><span class="p">:</span> <span class="s">KSTREAM-SINK-0000000009 (topic: alltogether)</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-MERGE-0000000008</span>
    <span class="py">Sink</span><span class="p">:</span> <span class="s">KSTREAM-SINK-0000000021 (topic: alltogether-enhancement)</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-MERGE-0000000020</span>

  <span class="py">Sub-topology</span><span class="p">:</span> <span class="s">1</span>
    <span class="py">Source</span><span class="p">:</span> <span class="s">KSTREAM-SOURCE-0000000002 (topics: [fee])</span>
      <span class="err">--&gt;</span> <span class="err">KSTREAM-KEY-SELECT-0000000010</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">KSTREAM-KEY-SELECT-0000000010 (stores: [])</span>
      <span class="err">--&gt;</span> <span class="err">feeBySsnTableSupplier-repartition-filter</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-SOURCE-0000000002</span>
    <span class="py">Processor</span><span class="p">:</span> <span class="s">feeBySsnTableSupplier-repartition-filter (stores: [])</span>
      <span class="err">--&gt;</span> <span class="err">feeBySsnTableSupplier-repartition-sink</span>
      <span class="err">&lt;--</span> <span class="err">KSTREAM-KEY-SELECT-0000000010</span>
    <span class="py">Sink</span><span class="p">:</span> <span class="s">feeBySsnTableSupplier-repartition-sink (topic: feeBySsnTableSupplier-repartition)</span>
      <span class="err">&lt;--</span> <span class="err">feeBySsnTableSupplier-repartition-filter</span></code></pre></figure>

<p>It’s really more complex now, below the graphical representation of the snippet above:</p>

<p><img style="display: block;  margin-left: auto;  margin-right: auto;" src="/assets/images/secondTopology3.png" alt="" width="1000px" /></p>

<p>I highlighted with the red line the first topology analyzed in the first section of the article, it’s just represented differently by the graph tool, everything outside the red section was added by the second topology. With the blue section I highlighted the <em>select key/repartition</em> operation needed to respect the co-partition rule. The result of this new join topology is shown below:</p>

<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">{</span><span class="w">
   </span><span class="nl">"person"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"ssn"</span><span class="p">:</span><span class="w"> </span><span class="s2">"456"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Pasquale"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"surname"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Paola"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"sex"</span><span class="p">:</span><span class="w"> </span><span class="s2">"M"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"dateOfBirth"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1981-06-25"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"phoneNumber"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1113245768"</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"driverLicense"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"456"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"MOTORBIKE, CAR"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"licenseNumber"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1213245768"</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"feeBySsn"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"ssn"</span><span class="p">:</span><span class="w"> </span><span class="s2">"456"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"feeList"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
         </span><span class="p">{</span><span class="w">
            </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"456"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"ssn"</span><span class="p">:</span><span class="w"> </span><span class="s2">"456"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"TASI"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="mi">515</span><span class="w">
         </span><span class="p">},</span><span class="w">
         </span><span class="p">{</span><span class="w">
            </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"123"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"ssn"</span><span class="p">:</span><span class="w"> </span><span class="s2">"456"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"IMU"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="mi">512</span><span class="w">
         </span><span class="p">},</span><span class="w">
         </span><span class="p">{</span><span class="w">
            </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"567"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"ssn"</span><span class="p">:</span><span class="w"> </span><span class="s2">"456"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"IMU"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="mi">516</span><span class="w">
         </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
   </span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre></figure>

<p>Thank you a lot for reading and let me know if something it’s not clear.</p>]]></content><author><name>Pasquale Paola</name></author><category term="docker" /><category term="kafka" /><category term="quarkus" /><category term="streaming" /><category term="topology" /><category term="join" /><category term="peek" /><category term="ETL" /><category term="kafdrop" /><summary type="html"><![CDATA[A Kafka streaming applicationt with Quarkus.]]></summary></entry><entry><title type="html">Jenkins Shared Library</title><link href="https://paspaola.it/2020/03/30/JenkinsLibrary.html" rel="alternate" type="text/html" title="Jenkins Shared Library" /><published>2020-03-30T12:43:00+02:00</published><updated>2020-03-30T12:43:00+02:00</updated><id>https://paspaola.it/2020/03/30/JenkinsLibrary</id><content type="html" xml:base="https://paspaola.it/2020/03/30/JenkinsLibrary.html"><![CDATA[<p><img style="display: block;  margin-left: auto;  margin-right: auto;" src="/assets/images/jenkins.png" alt="" width="400px" /></p>

<p>Every body in the IT world know what is the CI and its famous implementation, that is <strong>Jenkins</strong>.<!--more--> In the last years the DevOps engineer can organize 
the continous integration <em>chain</em> as a pipeline introducing a <strong>DSL</strong> (domain specific language) to manage it throught the <em>Jenkinsfile</em>:</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pipeline</span> <span class="o">{</span>
    <span class="n">agent</span> <span class="n">any</span>

    <span class="n">stages</span> <span class="o">{</span>
        <span class="n">stage</span><span class="o">(</span><span class="s1">'Build'</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">steps</span> <span class="o">{</span>
                <span class="n">echo</span> <span class="s1">'Building..'</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="n">stage</span><span class="o">(</span><span class="s1">'Test'</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">steps</span> <span class="o">{</span>
                <span class="n">echo</span> <span class="s1">'Testing..'</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="n">stage</span><span class="o">(</span><span class="s1">'Deploy'</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">steps</span> <span class="o">{</span>
                <span class="n">echo</span> <span class="s1">'Deploying....'</span>
            <span class="o">}</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The following link <a href="https://jenkins.io/doc/book/pipeline/jenkinsfile/">https://jenkins.io/doc/book/pipeline/jenkinsfile/</a> explains what are its syntax and features, but  in this post I want introduce you the <a href="https://jenkins.io/doc/book/pipeline/shared-libraries/">Jenkins Shared Library</a> with a pratical example.</p>

<p>As shown in the previous script, the Jenkinsfile can become extremly unreadeable, to avoid it you can write a library to wrap your jobs. Let’s start from the following pipeline:</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pipeline</span> <span class="o">{</span>
    <span class="n">agent</span> <span class="n">any</span> 
    <span class="n">tools</span> <span class="o">{</span>
        <span class="n">jdk</span> <span class="s1">'jdk11'</span>
    <span class="o">}</span>
    
    <span class="n">stages</span> <span class="o">{</span>
        <span class="n">stage</span><span class="o">(</span><span class="s1">'Checkout'</span><span class="o">)</span> <span class="o">{</span> 
            <span class="n">steps</span> <span class="o">{</span>
                <span class="n">ansiColor</span><span class="o">(</span><span class="s1">'xterm'</span><span class="o">)</span> <span class="o">{</span>
                    <span class="n">checkout</span> <span class="n">scm</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="n">stage</span><span class="o">(</span><span class="s1">'Build'</span><span class="o">)</span> <span class="o">{</span> 
            <span class="n">steps</span> <span class="o">{</span>
                <span class="n">ansiColor</span><span class="o">(</span><span class="s1">'xterm'</span><span class="o">)</span> <span class="o">{</span>
                    <span class="n">withMaven</span><span class="o">(</span><span class="nl">maven:</span><span class="s1">'maven3.6.3'</span><span class="o">){</span>
                        <span class="n">sh</span> <span class="s1">'mvn clean package'</span>
                    <span class="o">}</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
        
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>A simple checkout and build already become unreadble, let’s think what happen if you start adding other stages like quality or deployments steps. To simplify the pipeline you could use a Jenkins Shard library but let’s start from beginning.
In order to execute the previous pipeline you need to install on Jenkins:</p>

<ul>
  <li>JDK11</li>
  <li>Maven</li>
  <li><a href="https://plugins.jenkins.io/pipeline-maven/">Pipeline Maven Integration</a></li>
</ul>

<p>To install JDK11 I installed also <a href="https://plugins.jenkins.io/adoptopenjdk/">AdoptOpenJDK installer</a>, as shown in the image, now Jenkins is able to download the JDK11 from the section <em>Global instrument</em> (I set the label to <em>‘jdk11’</em>)</p>

<figure class="image">
  <img src="/assets/images/jenkins_jdk11.png" alt="" />
  <figcaption><a href="" target="_blank"></a></figcaption>
</figure>

<p>Then I installed Maven 3.6.3 and labelled it with <em>‘maven3.6.3’</em></p>

<figure class="image">
  <img src="/assets/images/jenkins_maven.png" alt="" />
  <figcaption><a href="" target="_blank"></a></figcaption>
</figure>

<p>Now you can execute the previous pipeline…but can we write the previous pipeline in a better way like the following snippet?</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Library</span><span class="o">(</span><span class="s1">'jenkins-lib@1.0.0'</span><span class="o">)</span> <span class="n">_</span>

<span class="n">jenkinslib</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="s2">"test"</span><span class="o">)</span>
    <span class="o">.</span><span class="na">withMavenVersion</span><span class="o">(</span><span class="s2">"maven3.6.3"</span><span class="o">)</span>
    <span class="o">.</span><span class="na">withJdkVersion</span><span class="o">(</span><span class="s2">"jdk11"</span><span class="o">)</span>
    <span class="o">.</span><span class="na">execute</span><span class="o">()</span>
</code></pre></div></div>

<p>Yes we can through the Jenkins Shared library functionality! The first line indicates the library reference: to reference a library you need to install it through the Jenkins global configuration. Usally the library must be located on the SCM repository, I put my library on <a href="https://github.com/paspao/jenkins-lib/">this github repo</a> then I configured it on Jenkins giving the name <em>‘jenkins-lib’</em>, I also enabled the <em>‘Discover tags’</em>.</p>

<figure class="image">
  <img src="/assets/images/jenkins_shdlib.png" alt="" />
  <figcaption><a href="" target="_blank"></a></figcaption>
</figure>

<p>Now I can reference my library in a Jenkinsfile like <strong>@Library(‘jenkins-lib@1.0.0’)</strong> or <em>@Library(‘jenkins-lib@master’)</em> or simply <em>@Library(‘jenkins-lib’)</em> using a specific version through a tag or a branch. After the library notation there is an underscore <strong>_</strong>, it means that we want to include everything into the currente pipiline (otherwise we have to put a sepcific <em>import</em>, but it isn’t our case).</p>

<p>Let’s see the library structure:</p>

<p><img style="display: block;  margin-left: auto;  margin-right: auto;" src="/assets/images/jenkinsStructure.png" alt="" width="300px" /></p>

<p>I defined a directory <strong>vars</strong> required by Jenkins Library structure that contains a groovy script <em>jenkinslib.groovy</em>, in this directory every .groovy file could be referenced by the <em>Jekinsfile</em>. In my example the line <em>jenkinslib(…)</em> it is a reference to <em>jenkinslib.groovy</em> file that contains a special function <em>call(…)</em></p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">org.paspao.sharedlib.JenkinsBuilder</span>

<span class="n">JenkinsBuilder</span> <span class="nf">call</span><span class="o">(</span><span class="kt">def</span> <span class="n">scriptReference</span><span class="o">,</span> <span class="n">String</span> <span class="n">projectName</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="k">new</span> <span class="nf">JenkinsBuilder</span><span class="o">(</span><span class="n">scriptReference</span><span class="o">,</span><span class="n">projectName</span><span class="o">,</span><span class="n">env</span><span class="o">[</span><span class="s1">'BRANCH_NAME'</span><span class="o">])</span>
<span class="o">}</span>

<span class="k">return</span> <span class="k">this</span>
</code></pre></div></div>
<p>In this function I simply create an object <em>JenkinsBuilder</em> with some initialization parameters, but the real news is that I’m moving my pipiline from a functional programming to an Object Oriented Programming giving more readibility to the pipeline code.
The magic is realized using the Closure object that (getting the Groovy definition) <em>is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable</em>.</p>

<p><a href="https://github.com/paspao/jenkins-lib/">GitHub jenkins-lib</a></p>]]></content><author><name>Pasquale Paola</name></author><category term="jenkinsfile" /><category term="jenkins" /><category term="ci" /><category term="cd" /><category term="groovy" /><summary type="html"><![CDATA[How to create a Jenkins Shared Library.]]></summary></entry><entry><title type="html">Microservices architecture: an implementation of Saga pattern</title><link href="https://paspaola.it/2019/09/25/Microservices-architecture-an-implementation-of-Saga-pattern.html" rel="alternate" type="text/html" title="Microservices architecture: an implementation of Saga pattern" /><published>2019-09-25T16:44:00+02:00</published><updated>2019-09-25T16:44:00+02:00</updated><id>https://paspaola.it/2019/09/25/Microservices-architecture-an-implementation-of-Saga-pattern</id><content type="html" xml:base="https://paspaola.it/2019/09/25/Microservices-architecture-an-implementation-of-Saga-pattern.html"><![CDATA[<figure class="image">
  <img src="/assets/images/ketan-rajput-n-g7dgwNZg4-unsplash.jpg" alt="Ketan Rajput" />
  <figcaption><a href="https://unsplash.com/photos/n-g7dgwNZg4" target="_blank">Ketan Rajput</a></figcaption>
</figure>

<p>In the last years the microservices is one of the hot topic right now in the industry, also in a context where it is not needed. Often, the architecture design is wrong, probably it’s more like a micro-monolith service. <!--more-->If you answer “Yes” to one of these basic questions, your architecture is wrong, probably :-D</p>

<ul>
  <li>Have you a single instance of your service?</li>
  <li>Have you a single database (or schema)?</li>
  <li>Is the communication between services syncronous?</li>
  <li>…</li>
</ul>

<p>There are a lot of questions to answer, but in this post I’ll show you a simple microservices architecture comply with pattern, based on the book “<em>Microservices Patterns</em>” by <strong>Chris Richardson</strong>.</p>

<p>The main idea,in my example, is to build a management software for “McPaspao”, my hypothetical fast food :-D. Following, a preliminary domain based analysis:</p>

<ul>
  <li>Orders Mangement</li>
  <li>Kitchen Management</li>
  <li>Delivery Management</li>
</ul>

<p>The <em>Orders Management</em> manages the hamburger order, the <em>Kitchen Mangement</em> manages the kitchen job (eg: cooking hamburger or the fridge management), the <em>Delivery Management</em> manages the deliveries of the hamburgers.
So I need three different services at least, each one with it’s own database, then each service needs to communicate with each others. 
In this scenario other five components are needed:</p>

<ul>
  <li>Orders Database</li>
  <li>Kitchen Database</li>
  <li>Delivery Database</li>
  <li>Messaging Service</li>
  <li>API Gateway</li>
</ul>

<p>In the microservices architecture API Gateway, Messaging Service and Database per Service are common patterns used to solve a lot of problems, for example:</p>

<ul>
  <li><strong>Messaging Service</strong>: Services often collaborate to handle many requests so, they must use an inter-process communication protocol. More specifically an asynchronous messaging system.</li>
  <li><strong>Database per Service</strong>: The service’s database must be part of the implementation to ensure loosly coupling so that it can be developed, deployed and scaled indipendently.</li>
  <li><strong>API Gateway</strong>:  In a microservices architecture there are a lot fo services, protocols, addresses, ports, security policies, redundancy policies, etc the API Gateway pattern tries to solve this problem, it gives to the clients a single entry point managing all the listed aspects and more.</li>
</ul>

<p><img src="/assets/images/McPaspaoArchitecure.png" alt="Architecture" /></p>

<p>This is the big picture of the architecture, the <em>API Gateway</em> is <a href="https://konghq.com/kong">Kong</a>, the <em>Messaging Service</em> <a href="https://kafka.apache.org/">Kafka</a> and the <em>Database per Service</em> <a href="https://www.mongodb.com/">MongoDB</a>.
The project is <a href="https://github.com/paspao/McPaspaoTakeAway">here</a> on Github.</p>

<p>Each Microservice is implemented following the <em>Hexagonal</em> architecture style: the core logic is embedded inside a hexagon, and the edges of the hexagon are considered the input and output. The aim is to layer the objects in a way that isolates your core logic from outside elements: the core logic is at the center of the picture and all the other elements are considered as integration points (DB, API, Messaging). We talk about <em>inbound adapters</em> that handle requests from the outside by invoking the business logic and about <em>outbound adapters</em> that are invoked by the business logic (to invoke external applications). A <em>port</em> defines a set of operations that is how the business logic interacts with what’s outside of it.</p>

<p><img src="/assets/images/Heaxagonal.png" alt="Hexagonal" /></p>

<p>In the picture <em>Controller</em> and <em>Consumer</em> are inbound adapters, <em>Services</em> are inbound port, <em>Messaging interfaces</em> and <em>DB Interfaces</em> are outbound port while <em>DAO</em> and <em>Producer</em> are outbound adapter.</p>

<p>I’ll show the details of a single microservice for an explanation of the internal architecture used, the <em>Delivery Service</em>. It has a single api to monitor the status of a delivery, it defines an <em>inbound port IDeliveryAPI</em>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">IDeliveryApi</span> <span class="o">{</span>
    <span class="nd">@ApiOperation</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="s">"View delivery status"</span><span class="o">,</span> <span class="n">response</span> <span class="o">=</span> <span class="nc">DeliveryDTO</span><span class="o">.</span><span class="na">class</span><span class="o">,</span><span class="n">responseContainer</span> <span class="o">=</span> <span class="s">"list"</span><span class="o">)</span>
    <span class="nd">@RequestMapping</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="s">"status"</span><span class="o">,</span> <span class="n">produces</span> <span class="o">=</span> <span class="nc">MediaType</span><span class="o">.</span><span class="na">APPLICATION_JSON_VALUE</span><span class="o">,</span> <span class="n">method</span> <span class="o">=</span> <span class="nc">RequestMethod</span><span class="o">.</span><span class="na">GET</span><span class="o">)</span>
    <span class="nd">@ResponseBody</span>
    <span class="nc">List</span><span class="o">&lt;</span><span class="nc">DeliveryDTO</span><span class="o">&gt;</span> <span class="nf">status</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The class <em>DeliveryApi</em> is an <em>inbound adapter</em>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@RestController</span>
<span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/delivery/"</span><span class="o">)</span>
<span class="nd">@Api</span><span class="o">(</span><span class="n">tags</span> <span class="o">=</span> <span class="s">"DeliveryServices"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">DeliveryApi</span> <span class="kd">implements</span> <span class="nc">IDeliveryApi</span> <span class="o">{</span>

    <span class="nd">@Autowired</span>
    <span class="kd">private</span> <span class="nc">DeliveryService</span> <span class="n">deliveryService</span><span class="o">;</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">DeliveryDTO</span><span class="o">&gt;</span> <span class="nf">status</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">deliveryService</span><span class="o">.</span><span class="na">getAll</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The class <em>DeliveryService</em> represents the <em>business logic</em>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Service</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">DeliveryService</span> <span class="o">{</span>
    <span class="nd">@Autowired</span>
    <span class="kd">private</span> <span class="nc">DeliveryRepository</span> <span class="n">deliveryRepository</span><span class="o">;</span>

    <span class="nd">@Autowired</span>
    <span class="kd">private</span> <span class="nc">DozerBeanMapper</span> <span class="n">dozerBeanMapper</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">DeliveryDTO</span><span class="o">&gt;</span> <span class="nf">getAll</span><span class="o">()</span>
    <span class="o">{</span>
        <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Delivery</span><span class="o">&gt;</span> <span class="n">deliveryList</span>  <span class="o">=</span><span class="n">deliveryRepository</span><span class="o">.</span><span class="na">findAll</span><span class="o">();</span>
        <span class="nc">List</span><span class="o">&lt;</span><span class="nc">DeliveryDTO</span><span class="o">&gt;</span> <span class="n">res</span><span class="o">=</span><span class="kc">null</span><span class="o">;</span>
        <span class="k">if</span><span class="o">(</span><span class="n">deliveryList</span><span class="o">!=</span><span class="kc">null</span><span class="o">)</span>
        <span class="o">{</span>
            <span class="n">res</span><span class="o">=</span><span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
            <span class="k">for</span><span class="o">(</span><span class="nc">Delivery</span> <span class="nl">delivery:</span><span class="n">deliveryList</span><span class="o">)</span>
            <span class="o">{</span>
                <span class="nc">DeliveryDTO</span> <span class="n">deliveryDTO</span><span class="o">=</span><span class="n">dozerBeanMapper</span><span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="n">delivery</span><span class="o">,</span><span class="nc">DeliveryDTO</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
                <span class="n">res</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">deliveryDTO</span><span class="o">);</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">res</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The interface <em>IDeliveryPublisher</em> is an <em>outbound port</em>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">IDeliveryPublisher</span> <span class="o">{</span>
    <span class="kt">void</span> <span class="nf">sendToOrderCallback</span><span class="o">(</span><span class="nc">OrderDTO</span> <span class="n">orderDTO</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">JsonProcessingException</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The class <em>DeliveryPublisher</em> is an <em>outbound adapter</em>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Service</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">DeliveryPublisher</span> <span class="kd">implements</span> <span class="nc">IDeliveryPublisher</span> <span class="o">{</span>

    <span class="nd">@Autowired</span>
    <span class="kd">private</span> <span class="nc">ObjectMapper</span> <span class="n">objectMapper</span><span class="o">;</span>

    <span class="nd">@Autowired</span>
    <span class="kd">private</span> <span class="nc">KafkaTemplate</span> <span class="n">kafkaTemplate</span><span class="o">;</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">sendToOrderCallback</span><span class="o">(</span><span class="nc">OrderDTO</span> <span class="n">orderDTO</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">JsonProcessingException</span> <span class="o">{</span>
        <span class="n">kafkaTemplate</span><span class="o">.</span><span class="na">send</span><span class="o">(</span><span class="no">TOPIC_ORDER_CALLBACK</span><span class="o">,</span><span class="n">objectMapper</span><span class="o">.</span><span class="na">writeValueAsString</span><span class="o">(</span><span class="n">orderDTO</span><span class="o">));</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Each microservice (in my example) has this style of architcture internally to ensure an high <em>loosly coupling</em> between software layers. But this is only the internally architecture of a single microservice, it’s possible that other microservices uses a <em>Layered</em> architecture style, for example.</p>

<p>Well, a simple use case that involve every microservice is the <em>order management</em>, that is: a browser makes a request for one hamburger, the <em>Order Service</em> receives the order and write it on the database, the order management work is finished but to complete the order it needs to contact the <em>Kitchen Service</em>, so it sends a message on a topic (to ensure an asyncronous inter-process-communiction), the <em>Kitchen Service</em> is listening on this topic, it consumes the message and it processes the order, giving a feedback to the <em>Order Service</em> through another topic. When the <em>Kitchen Service</em> has cooked the hamburger it sends a message to <em>Delivery Service</em>, the <em>Delivery Service</em> processes the message, it delivers the hamburger and it sends a feedback. Every communication between the microservices goes through the message broker, in my example <em>Kafka</em>, I have applied a <em>Choreography Saga pattern</em>, that is:</p>

<blockquote>
  <p>A saga is a sequence of local transactions. Each local transaction updates the database and publishes a message or event to trigger the next local transaction in the saga. If a local transaction fails because it violates a business rule then the saga executes a series of compensating transactions that undo the changes that were made by the preceding local transactions.
There are two ways of coordination sagas:</p>
  <ul>
    <li>Choreography - each local transaction publishes domain events that trigger local transactions in other services</li>
    <li>Orchestration - an orchestrator (object) tells the participants what local transactions to execute</li>
  </ul>

  <p><cite>Chris Richardson</cite></p>
</blockquote>

<p>To see the entire architecture, I use the docker-compose.yml (docker app) listed below:</p>

<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">3.2'</span>
<span class="na">services</span><span class="pi">:</span>

  <span class="na">order-service</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">paspaola/order-service:0.0.1</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">8090:8090</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mongodb-order</span>
      <span class="pi">-</span> <span class="s">kafkabroker</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mcpaspao</span>

  <span class="na">kitchen-service</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">paspaola/kitchen-service:0.0.1</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">8080:8080</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mongodb-kitchen</span>
      <span class="pi">-</span> <span class="s">kafkabroker</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mcpaspao</span>

  <span class="na">delivery-service</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">paspaola/delivery-service:0.0.1</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">8070:8070</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mongodb-delivery</span>
      <span class="pi">-</span> <span class="s">kafkabroker</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mcpaspao</span>

  <span class="na">mongodb-delivery</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">mongo:3.4.22-xenial</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">27017:27017</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mcpaspao</span>

  <span class="na">mongodb-order</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">mongo:3.4.22-xenial</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">27018:27017</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mcpaspao</span>

  <span class="na">mongodb-kitchen</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">mongo:3.4.22-xenial</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">27019:27017</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mcpaspao</span>

  <span class="na">kafkabroker</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">paspaola/kafka-mcpaspao</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">2181:2181</span>
      <span class="pi">-</span> <span class="s">9092:9092</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">KAFKA_ADVERTISED_LISTNERS=${advertised.addr}</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mcpaspao</span>

  <span class="na">kong-mcpaspao</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">paspaola/kong-mcpaspao:0.0.1</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">8000:8000</span>
      <span class="pi">-</span> <span class="s">8443:8443</span>
      <span class="pi">-</span> <span class="s">8001:8001</span>
      <span class="pi">-</span> <span class="s">8444:8444</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mcpaspao</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">delivery-service</span>
      <span class="pi">-</span> <span class="s">kitchen-service</span>
      <span class="pi">-</span> <span class="s">order-service</span>

<span class="na">networks</span><span class="pi">:</span>
  <span class="na">mcpaspao</span><span class="pi">:</span>
</code></pre></div></div>

<p>Like into the big picture above, there are three services and three database, then there is the Kafka broker, a personalized image that already have on borad all the needed topics:</p>

<ul>
  <li>orderservice</li>
  <li>orderservicecallback</li>
  <li>kitchenservice</li>
  <li>deliveryservice</li>
</ul>

<p>In the Kafka container there is also an instance of Zookeeper, needed to start Kafka, you can read how to make it <a href="/2019/09/09/Kafka-in-one-container.html">here</a>.</p>

<p>The last component is the API Gateway, <em>Kong</em>: the classic installation uses a database like <em>Postgresql</em>, but it’s also possible (for development usage) to start Kong in a declarative way, following the simple configuration of Kong <em>kong.yml</em>:</p>

<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">_format_version</span><span class="pi">:</span> <span class="s2">"</span><span class="s">1.1"</span>

<span class="na">services</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">order-service</span>
    <span class="na">url</span><span class="pi">:</span> <span class="s">http://order-service:8090</span>
    <span class="na">routes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">order-service</span>
        <span class="na">paths</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="s">/order-service</span>

  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">kitchen-service</span>
    <span class="na">url</span><span class="pi">:</span> <span class="s">http://kitchen-service:8080</span>
    <span class="na">routes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">kitchen-service</span>
        <span class="na">paths</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="s">/kitchen-service</span>

  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">delivery-service</span>
    <span class="na">url</span><span class="pi">:</span> <span class="s">http://delivery-service:8070</span>
    <span class="na">routes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">delivery-service</span>
        <span class="na">paths</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="s">/delivery-service</span>

<span class="na">plugins</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">request-transformer</span>
    <span class="na">service</span><span class="pi">:</span> <span class="s">kitchen-service</span>
    <span class="na">config</span><span class="pi">:</span>
      <span class="na">add</span><span class="pi">:</span>
        <span class="na">headers</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="s">x-forwarded-prefix:/kitchen-service</span>

  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">request-transformer</span>
    <span class="na">service</span><span class="pi">:</span> <span class="s">order-service</span>
    <span class="na">config</span><span class="pi">:</span>
      <span class="na">add</span><span class="pi">:</span>
        <span class="na">headers</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="s">x-forwarded-prefix:/order-service</span>

  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">request-transformer</span>
    <span class="na">service</span><span class="pi">:</span> <span class="s">delivery-service</span>
    <span class="na">config</span><span class="pi">:</span>
      <span class="na">add</span><span class="pi">:</span>
        <span class="na">headers</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="s">x-forwarded-prefix:/delivery-service</span>
</code></pre></div></div>
<p>In this example I’m using the API Gateway in the simplest way, without any Authentication and Authorization service or Service replica or Service Discovery, etc. to avoid confusing on the main aspect: the implementation of <em>Choreography Saga pattern</em>.</p>

<p>To build the project, you can use <em>maven</em> and then start manually every service, or you can build everything with the multistage Dockerfile (you have to enable the <em>experimental features</em> on Docker 19.x):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker buildx build <span class="nt">--target</span><span class="o">=</span>order-service <span class="nt">-t</span> paspaola/order-service:0.0.1 <span class="nt">--load</span> <span class="nb">.</span> <span class="o">&amp;&amp;</span><span class="se">\</span>
docker buildx build <span class="nt">--target</span><span class="o">=</span>kitchen-service <span class="nt">-t</span> paspaola/kitchen-service:0.0.1 <span class="nt">--load</span> <span class="nb">.</span> <span class="o">&amp;&amp;</span><span class="se">\</span>
docker buildx build <span class="nt">--target</span><span class="o">=</span>delivery-service <span class="nt">-t</span> paspaola/delivery-service:0.0.1 <span class="nt">--load</span> <span class="nb">.</span> <span class="o">&amp;&amp;</span><span class="se">\</span>
docker buildx build <span class="nt">--target</span><span class="o">=</span>kong-mcpaspao <span class="nt">-t</span> paspaola/kong-mcpaspao:0.0.1 <span class="nt">--load</span> <span class="nb">.</span>
</code></pre></div></div>

<p>and then start with command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker app render <span class="nt">-s</span> advertised.addr<span class="o">=</span><span class="s2">"your docker host ip"</span> mcpaspao.dockerapp| docker-compose <span class="nt">-f</span> - up
</code></pre></div></div>

<p>It’s time to test!</p>

<p>You can verify that every microservice is runnig, using the Swagger user interface:</p>

<ul>
  <li>Order Service: <em>http://localhost:8000/kitchen-service/swagger-ui.html</em></li>
  <li>Kitchen Services <em>http://localhost:8000/order-service/swagger-ui.html</em></li>
  <li>Delivery Services <em>http://localhost:8000/delivery-service/swagger-ui.html</em></li>
</ul>

<p><strong>Now I want an hamburger!!!</strong> The kithcen needs some hamburgers, the fridge is empty, so (you have to install <a href="https://stedolan.github.io/jq/">jq</a>):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-X</span> POST <span class="s2">"http://localhost:8000/kitchen-service/kitchen/add?hamburgerType=KOBE&amp;quantity=2"</span> <span class="nt">-H</span> <span class="s2">"accept: application/json"</span>|jq <span class="nt">-C</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
 <span class="se">\</span>
curl <span class="nt">-X</span> GET <span class="s2">"http://localhost:8000/kitchen-service/kitchen/status"</span> <span class="nt">-H</span> <span class="s2">"accept: application/json"</span>|jq <span class="nt">-C</span>
</code></pre></div></div>

<p>I have added two hamburgers, now I make a request for an order with two hamburgers:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">printf</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">--START--</span><span class="se">\n</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
curl <span class="nt">-X</span> POST <span class="s2">"http://localhost:8000/order-service/order/create"</span> <span class="nt">-H</span> <span class="s2">"accept: application/json"</span> <span class="nt">-H</span> <span class="s2">"Content-Type: application/json"</span> <span class="nt">-d</span> <span class="s2">"{ </span><span class="se">\"</span><span class="s2">addressDTO</span><span class="se">\"</span><span class="s2">: { </span><span class="se">\"</span><span class="s2">number</span><span class="se">\"</span><span class="s2">: </span><span class="se">\"</span><span class="s2">string</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">street</span><span class="se">\"</span><span class="s2">: </span><span class="se">\"</span><span class="s2">string</span><span class="se">\"</span><span class="s2"> }, </span><span class="se">\"</span><span class="s2">cookingType</span><span class="se">\"</span><span class="s2">: </span><span class="se">\"</span><span class="s2">BLOOD</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">hamburgerList</span><span class="se">\"</span><span class="s2">: [ { </span><span class="se">\"</span><span class="s2">hamburgerType</span><span class="se">\"</span><span class="s2">: </span><span class="se">\"</span><span class="s2">KOBE</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">quantity</span><span class="se">\"</span><span class="s2">: 2 } ], </span><span class="se">\"</span><span class="s2">price</span><span class="se">\"</span><span class="s2">: 10}"</span> |jq <span class="nt">-C</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">printf</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">---------</span><span class="se">\n</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
 <span class="se">\</span>
curl <span class="nt">-X</span> GET <span class="s2">"http://localhost:8000/order-service/order/view"</span> <span class="nt">-H</span> <span class="s2">"accept: application/json"</span>|jq <span class="nt">-C</span>  <span class="o">&amp;&amp;</span> <span class="nb">sleep </span>5 <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">printf</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">---------</span><span class="se">\n</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
curl <span class="nt">-X</span> GET <span class="s2">"http://localhost:8000/order-service/order/view"</span> <span class="nt">-H</span> <span class="s2">"accept: application/json"</span>|jq <span class="nt">-C</span> <span class="o">&amp;&amp;</span> <span class="nb">sleep </span>5 <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">printf</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">---------</span><span class="se">\n</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
curl <span class="nt">-X</span> GET <span class="s2">"http://localhost:8000/order-service/order/view"</span> <span class="nt">-H</span> <span class="s2">"accept: application/json"</span>|jq <span class="nt">-C</span> <span class="o">&amp;&amp;</span> <span class="nb">sleep </span>5 <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">printf</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">---------</span><span class="se">\n</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
curl <span class="nt">-X</span> GET <span class="s2">"http://localhost:8000/order-service/order/view"</span> <span class="nt">-H</span> <span class="s2">"accept: application/json"</span>|jq <span class="nt">-C</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">printf</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">---------</span><span class="se">\n</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
 <span class="se">\</span>
curl <span class="nt">-X</span> GET <span class="s2">"http://localhost:8000/delivery-service/delivery/status"</span> <span class="nt">-H</span> <span class="s2">"accept: application/json"</span>|jq <span class="nt">-C</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">printf</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">--END--</span><span class="se">\n</span><span class="s2">"</span>
</code></pre></div></div>

<p>In the first step the order goes in <em>WAITING</em> status, then <em>COOKING</em>, <em>PACKAGING</em> and <em>DELIVERED</em> status. If you run again the script, the system doesn’t have enough hamburgers and the next order will be in status <em>WAITING</em> and then <em>ABORTED</em>.</p>

<p>I hope this guide will help you to clarify the power and the complexity of a microservice architecture, this is only a pratical example implemented using simple and basic components, but you can guess when use or not it. Thank you for reading.</p>]]></content><author><name>Pasquale Paola</name></author><category term="docker" /><category term="kafka" /><category term="spring" /><category term="springboot" /><category term="saga" /><category term="choreography" /><category term="microservices" /><category term="hexagonal" /><category term="buildkit" /><category term="multistage" /><summary type="html"><![CDATA[An implementation of Saga pattern and an Hexagonal architecure.]]></summary></entry><entry><title type="html">Multiple processes in one container (like Kafka+Zookeeper)</title><link href="https://paspaola.it/2019/09/09/Kafka-in-one-container.html" rel="alternate" type="text/html" title="Multiple processes in one container (like Kafka+Zookeeper)" /><published>2019-09-09T18:22:19+02:00</published><updated>2019-09-09T18:22:19+02:00</updated><id>https://paspaola.it/2019/09/09/Kafka-in-one-container</id><content type="html" xml:base="https://paspaola.it/2019/09/09/Kafka-in-one-container.html"><![CDATA[<p>Often, I need an instance of Kafka for development purpose - if you develop services in a microservice architecture you know my problem! - but the latest versions of Kafka need an instance of Zookeeper to start.  It’s very frustrating  that you need a docker-compose only to make a test!</p>

<p>In most cases you don’t need a cluster to test your work but only a single broker, so I have created a docker image containing Zookeeper and Kafka (version 2.12-2.3.0) together, the container starts one instance of <strong>supervisor</strong> <a href="http://supervisord.org/">http://supervisord.org/</a> that manage the processes life.
<!--more-->
I’ll show you how to do step by step:</p>

<p>Download a stable version of Kafka from <a href="https://kafka.apache.org/">https://kafka.apache.org/</a>, then:</p>

<div class="language-docker highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="s"> adoptopenjdk/openjdk11-openj9</span>
<span class="k">LABEL</span><span class="s"> maintainer="pasquale.paola@gmail.com" </span>
<span class="k">COPY</span><span class="s"> start.sh /</span>
<span class="k">RUN </span>apt update <span class="o">&amp;&amp;</span> apt <span class="nb">install</span> <span class="nt">-y</span> supervisor <span class="o">&amp;&amp;</span> <span class="nb">chmod </span>a+x /start.sh
<span class="k">ADD</span><span class="s"> kafka_2.12-2.3.0 kafka_2.12-2.3.0</span>
<span class="k">COPY</span><span class="s"> supervisord.conf /etc/supervisor/conf.d/supervisord.conf</span>
<span class="k">EXPOSE</span><span class="s"> 2181 9092</span>
<span class="k">CMD</span><span class="s"> ["/start.sh"]</span>
</code></pre></div></div>

<ul>
  <li>In the first line I want to use <em>adoptopenjdk</em> as base image because it is debian based (I want to use <em>apt</em>) and it has a valid openjdk already installed</li>
  <li>COPY the <em>start.sh</em> file in the root (details below)</li>
  <li>An <em>apt update</em> it’s needed to synchronize the package manager repositories</li>
  <li>Then install supervisor and add a copy of Kafka as is and copy the following <em>supervisor.conf</em> file</li>
</ul>

<p>The <em>start.sh</em> manages the environment variable <em>KAFKA_ADVERTISED_LISTNERS</em> used to configure the Kafka advertise url.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash -e</span>

<span class="k">if</span> <span class="o">[[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$KAFKA_ADVERTISED_LISTNERS</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"ERROR: missing mandatory config: KAFKA_ADVERTISED_LISTNERS"</span>
    <span class="nb">exit </span>1
<span class="k">fi

</span><span class="nb">echo</span> <span class="s2">"advertised.listeners=PLAINTEXT://</span><span class="nv">$KAFKA_ADVERTISED_LISTNERS</span><span class="s2">:9092"</span> <span class="o">&gt;&gt;</span> /kafka_2.12-2.3.0/config/server.properties

<span class="nb">exec</span> <span class="s2">"/usr/bin/supervisord"</span> <span class="s2">"-c"</span> <span class="s2">"/etc/supervisor/conf.d/supervisord.conf"</span>
</code></pre></div></div>

<p>At the end of <em>start.sh</em>, it starts the <em>supervisor daemon</em> with the following configuration:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>supervisord]
<span class="nv">nodaemon</span><span class="o">=</span><span class="nb">true</span>

<span class="o">[</span>program:zookeeper]
<span class="nv">directory</span><span class="o">=</span>/
<span class="nv">user</span><span class="o">=</span>root
<span class="nb">command</span><span class="o">=</span>/kafka_2.12-2.3.0/bin/zookeeper-server-start.sh /kafka_2.12-2.3.0/config/zookeeper.properties
<span class="nv">stdout_logfile</span><span class="o">=</span>/dev/fd/1
<span class="nv">stdout_logfile_maxbytes</span><span class="o">=</span>0
<span class="nv">redirect_stderr</span><span class="o">=</span><span class="nb">true</span>

<span class="o">[</span>program:kafka]
<span class="nv">directory</span><span class="o">=</span>/
<span class="nv">user</span><span class="o">=</span>root
<span class="nb">command</span><span class="o">=</span>/kafka_2.12-2.3.0/bin/kafka-server-start.sh /kafka_2.12-2.3.0/config/server.properties
<span class="nv">stdout_logfile</span><span class="o">=</span>/dev/fd/1
<span class="nv">stdout_logfile_maxbytes</span><span class="o">=</span>0
<span class="nv">redirect_stderr</span><span class="o">=</span><span class="nb">true
</span><span class="nv">starters</span><span class="o">=</span>5

</code></pre></div></div>

<p>Supervisor starts Zookeeper and one Kafka broker: that’s all. 
The container is now running with a valid instance of Zookeeper and Kafka, you can bind the standard ports to interact with Kafka and Zookeeper.</p>

<h2 id="build">Build</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> paspaola/kafka-one-container <span class="nb">.</span>
</code></pre></div></div>

<h2 id="run">Run</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">-it</span> <span class="nt">-p2181</span>:2181 <span class="nt">-p9092</span>:9092 <span class="nt">-e</span> <span class="s2">"KAFKA_ADVERTISED_LISTNERS={your-host-address}"</span> paspaola/kafka-one-container
</code></pre></div></div>

<h2 id="repository">Repository</h2>

<p><a href="https://github.com/paspao/kafka-in-one-container">https://github.com/paspao/kafka-in-one-container</a></p>]]></content><author><name>Pasquale Paola</name></author><category term="docker" /><category term="kafka" /><summary type="html"><![CDATA[An example of Docker container with 2 processes running within, using supervisor.]]></summary></entry><entry><title type="html">Zuul API Gateway with Spring Session (Redis): Authenticate and Route in same request with Apache module Mellon (SAML)</title><link href="https://paspaola.it/2019/06/28/Spring-Zuul-API-Gateway-with-Spring-Session-Redis-Authenticate-and-Route-in-same-Request-with-Mellon-SAML.html" rel="alternate" type="text/html" title="Zuul API Gateway with Spring Session (Redis): Authenticate and Route in same request with Apache module Mellon (SAML)" /><published>2019-06-28T14:32:49+02:00</published><updated>2019-06-28T14:32:49+02:00</updated><id>https://paspaola.it/2019/06/28/Spring-Zuul-API-Gateway-with-Spring-Session-Redis-Authenticate-and-Route-in-same-Request-with-Mellon-SAML</id><content type="html" xml:base="https://paspaola.it/2019/06/28/Spring-Zuul-API-Gateway-with-Spring-Session-Redis-Authenticate-and-Route-in-same-Request-with-Mellon-SAML.html"><![CDATA[<p>My APIGateway (Zuul) is proxied by Apache Httpd and protected by <a href="https://github.com/Uninett/mod_auth_mellon">Mellon module</a> (SAML 2.0). After a successfully authentication on the identity provider, mellon module inject correctly some headers read into the SAML response, but the first request fails with a 403 status code. 
<!--more-->
I’m also using SpringSecurity. To solve the problem I’m using a simple filter added on the security filter chain that ensure the correct creation of SecurityContext:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Component</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">MellonFilter</span> <span class="kd">extends</span> <span class="nc">OncePerRequestFilter</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Logger</span> <span class="n">log</span> <span class="o">=</span> <span class="nc">LoggerFactory</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="nc">MellonFilter</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>


    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">doFilterInternal</span><span class="o">(</span><span class="nc">HttpServletRequest</span> <span class="n">req</span><span class="o">,</span> <span class="nc">HttpServletResponse</span> <span class="n">httpServletResponse</span><span class="o">,</span> <span class="nc">FilterChain</span> <span class="n">filterChain</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">ServletException</span><span class="o">,</span> <span class="nc">IOException</span> <span class="o">{</span>
 
       <span class="nc">String</span> <span class="n">mellonId</span><span class="o">=</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="s">"mellon-nameid"</span><span class="o">);</span>

        <span class="k">if</span><span class="o">(</span><span class="n">mellonId</span><span class="o">==</span><span class="kc">null</span><span class="o">||</span><span class="n">mellonId</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">())</span>
            <span class="o">;</span><span class="c1">//do filterchain</span>
        <span class="k">else</span> <span class="o">{</span>
            
            <span class="nc">UserWithRoles</span> <span class="n">userWithRoles</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">UserWithRoles</span><span class="o">();</span>
            <span class="n">userWithRoles</span><span class="o">.</span><span class="na">setUsername</span><span class="o">(</span><span class="n">mellonId</span><span class="o">);</span>
            <span class="nc">SilUserDetails</span> <span class="n">details</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SilUserDetails</span><span class="o">(</span><span class="n">userWithRoles</span><span class="o">);</span>

            <span class="nc">SilAuthenticationPrincipal</span> <span class="n">silPrincipal</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
            <span class="nc">Collection</span><span class="o">&lt;</span><span class="nc">SimpleGrantedAuthority</span><span class="o">&gt;</span> <span class="n">authorities</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>

            <span class="n">authorities</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="nc">SimpleGrantedAuthority</span><span class="o">(</span><span class="s">"Some roles"</span><span class="o">);</span>

            <span class="n">silPrincipal</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SilAuthenticationPrincipal</span><span class="o">(</span><span class="n">details</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="n">authorities</span><span class="o">);</span>
            <span class="nc">SecurityContextHolder</span><span class="o">.</span><span class="na">clearContext</span><span class="o">();</span>
            <span class="nc">SecurityContextHolder</span><span class="o">.</span><span class="na">getContext</span><span class="o">().</span><span class="na">setAuthentication</span><span class="o">(</span><span class="n">silPrincipal</span><span class="o">);</span>
        <span class="o">}</span>
        <span class="n">filterChain</span><span class="o">.</span><span class="na">doFilter</span><span class="o">(</span><span class="n">req</span><span class="o">,</span><span class="n">httpServletResponse</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="kt">boolean</span> <span class="nf">shouldNotFilter</span><span class="o">(</span><span class="nc">HttpServletRequest</span> <span class="n">request</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">ServletException</span> <span class="o">{</span>
        <span class="k">if</span><span class="o">(</span><span class="nc">SecurityContextHolder</span><span class="o">.</span><span class="na">getContext</span><span class="o">().</span><span class="na">getAuthentication</span><span class="o">()!=</span><span class="kc">null</span><span class="o">&amp;&amp;</span><span class="nc">SecurityContextHolder</span><span class="o">.</span><span class="na">getContext</span><span class="o">().</span><span class="na">getAuthentication</span><span class="o">()</span> <span class="k">instanceof</span> <span class="nc">SilAuthenticationPrincipal</span><span class="o">)</span>
            <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>

    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Then I need a ZuulFilter to save the session (on Redis) and to propagate the actual session id:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ZuulSessionCookieFilter</span> <span class="kd">extends</span> <span class="nc">ZuulFilter</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Logger</span> <span class="n">log</span> <span class="o">=</span> <span class="nc">LoggerFactory</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="nc">ZuulSessionCookieFilter</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>

    <span class="nd">@Autowired</span>
    <span class="kd">private</span> <span class="nc">SessionRepository</span> <span class="n">repository</span><span class="o">;</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="nc">String</span> <span class="nf">filterType</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="nc">FilterConstants</span><span class="o">.</span><span class="na">PRE_TYPE</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">filterOrder</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="mi">0</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">shouldFilter</span><span class="o">()</span> <span class="o">{</span>

        <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="nc">Object</span> <span class="nf">run</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">ZuulException</span> <span class="o">{</span>

        <span class="nc">RequestContext</span> <span class="n">context</span> <span class="o">=</span> <span class="nc">RequestContext</span><span class="o">.</span><span class="na">getCurrentContext</span><span class="o">();</span>

        <span class="nc">HttpSession</span> <span class="n">httpSession</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="na">getRequest</span><span class="o">().</span><span class="na">getSession</span><span class="o">();</span>
        <span class="n">httpSession</span><span class="o">.</span><span class="na">setAttribute</span><span class="o">(</span>
                <span class="nc">HttpSessionSecurityContextRepository</span><span class="o">.</span><span class="na">SPRING_SECURITY_CONTEXT_KEY</span><span class="o">,</span>
                <span class="nc">SecurityContextHolder</span><span class="o">.</span><span class="na">getContext</span><span class="o">()</span>
        <span class="o">);</span>
        <span class="nc">Session</span> <span class="n">session</span> <span class="o">=</span> <span class="n">repository</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">httpSession</span><span class="o">.</span><span class="na">getId</span><span class="o">());</span>
        <span class="n">context</span><span class="o">.</span><span class="na">addZuulRequestHeader</span><span class="o">(</span><span class="s">"cookie"</span><span class="o">,</span> <span class="s">"SESSION="</span> <span class="o">+</span> <span class="n">base64Encode</span><span class="o">(</span><span class="n">httpSession</span><span class="o">.</span><span class="na">getId</span><span class="o">()));</span>
        <span class="n">log</span><span class="o">.</span><span class="na">debug</span><span class="o">(</span><span class="s">"ZuulPreFilter session proxy: {} and {}"</span><span class="o">,</span> <span class="n">session</span><span class="o">.</span><span class="na">getId</span><span class="o">(),</span><span class="n">httpSession</span><span class="o">.</span><span class="na">getId</span><span class="o">());</span>

        <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="nc">String</span> <span class="nf">base64Encode</span><span class="o">(</span><span class="nc">String</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">byte</span><span class="o">[]</span> <span class="n">encodedCookieBytes</span> <span class="o">=</span> <span class="nc">Base64</span><span class="o">.</span><span class="na">getEncoder</span><span class="o">().</span><span class="na">encode</span><span class="o">(</span><span class="n">value</span><span class="o">.</span><span class="na">getBytes</span><span class="o">());</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">String</span><span class="o">(</span><span class="n">encodedCookieBytes</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>I hope this solution will be helpful to everyone.</p>]]></content><author><name>Pasquale Paola</name></author><category term="zuul" /><category term="spring" /><category term="spring boot" /><category term="java" /><category term="mellon" /><category term="saml" /><summary type="html"><![CDATA[My APIGateway (Zuul) is proxied by Apache Httpd and protected by Mellon module (SAML 2.0). After a successfully authentication on the identity provider, mellon module inject correctly some headers read into the SAML response, but the first request fails with a 403 status code.]]></summary></entry><entry><title type="html">A ‘Kiss architecture’: Springboot + Angular</title><link href="https://paspaola.it/2018/11/03/Spring-Boot-Kiss-Architecture.html" rel="alternate" type="text/html" title="A ‘Kiss architecture’: Springboot + Angular" /><published>2018-11-03T13:32:49+01:00</published><updated>2018-11-03T13:32:49+01:00</updated><id>https://paspaola.it/2018/11/03/Spring-Boot-Kiss-Architecture</id><content type="html" xml:base="https://paspaola.it/2018/11/03/Spring-Boot-Kiss-Architecture.html"><![CDATA[<p>Like suggested by wikipedia, KISS is an acronym for “Keep it simple, stupid” as a design principle noted by the U.S. Navy in 1960. The KISS principle states that most systems work best if they are kept simple rather than made complicated; therefore simplicity should be a key goal in design, and that unnecessary complexity should be avoided. The phrase has been associated with aircraft engineer Kelly Johnson.</p>

<p>In my experience, I worked on various types of technologies, having the opportunity to inspect the source code and, in general, the development of an application both from the client side (which can be a SPA or a native App) and from server side. By relying on such experience, I tried to develop a simple architecture that involves the respect of fundamental <strong>PATTERN</strong> in a <strong>CRUD</strong> context. I will try to illustrate the foundations of this architecture, used as a starting point in all my projects.
<!--more-->
Into the design I kept in mind the KISS concept and in this perspective I would provide 5 layers as known as tiers, with a specific accomplishment task:</p>

<ul>
  <li>FRONTEND</li>
  <li>API</li>
  <li>BUSINESS LOGIC</li>
  <li>INTEGRATION</li>
  <li>DAO</li>
</ul>

<p>I use a <em>multi-tier</em> architectural model where the tiers order in the list, is strictly associated to the information flow: from the frontend to get up to the DAO</p>

<p><img src="/assets/images/Ska.png" alt="Architecture" /></p>

<p>The article refers to the project downloadable at the link <a href="https://github.com/paspao/springboot-kiss-architecture">https://github.com/paspao/springboot-kiss-architecture</a></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/paspao/springboot-kiss-architecture
</code></pre></div></div>

<p>The project is managed using <em>maven</em> (i.e. parent and child types); even the frontend, developed in Angular, is included into the <em>maven</em> building phase in order to create a single artifact (further details available in the <strong>FRONTEND</strong> paragraph below).</p>

<p>Trill down each tier, I prefer to use a <em>BottomUp</em> approach. Let’s start with the data.</p>

<h2 id="dao">DAO</h2>

<p>Data Access Object. When I’m talking about CRUD applications in early step I’m talking about data, in SQL, NOSQL, but in any case data to collect and process. This module represents the deepest point. This tier performs the data, it describes the entities and the access logic. Caution: simple data access logic of inserting, modifying, deleting and displaying data, without any binding to other tiers; it’s the deepest tier and also it has no dependencies with any of its brothers, it does not handle specific aspect of the application, such as authorizations, transactions or other: just access to data exclusively, as well.
In a Springboot context I’m performing <strong>Entity</strong> and <em>*Repository</em> paradigms. In detail I show you the <em>@Configuration</em> of the DAO module, central <em>annotation</em> in each Springboot application/module.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Configuration</span>
<span class="nd">@ComponentScan</span><span class="o">(</span><span class="s">"org.ska.dao"</span><span class="o">)</span>
<span class="nd">@EntityScan</span><span class="o">(</span><span class="n">basePackages</span> <span class="o">=</span> <span class="o">{</span><span class="s">"org.ska.dao.entity"</span><span class="o">})</span>
<span class="nd">@EnableJpaRepositories</span><span class="o">(</span><span class="n">basePackages</span> <span class="o">=</span> <span class="o">{</span><span class="s">"org.ska.dao.repository"</span><span class="o">})</span>
<span class="nd">@EnableAutoConfiguration</span>
<span class="nd">@EnableTransactionManagement</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">KissDaoConfiguration</span> <span class="o">{</span>
<span class="o">}</span>
</code></pre></div></div>

<p>So I define where the <em>Components, Entities</em> and <em>Repositories</em> are located. In addition I enable transactions, so anyone using the DAO module will not have to worry about aspects of configuring the DAO module.</p>

<h2 id="integration">INTEGRATION</h2>

<p>The simple CRUD data management is not enough: we probably need to interoperate with other systems that don’t depend on our data, such as JAX-WS or JAX-RS services, or specific printing systems with different protocols, etc. This component includes all these interactions/integrations without a specific binding to the application’s context in order to guarantee you a very high reusability (like the DAO module, also this tier is leaf type).</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Configuration</span>
<span class="nd">@ComponentScan</span><span class="o">(</span><span class="n">basePackages</span> <span class="o">=</span> <span class="o">{</span><span class="s">"org.ska.integration.beans"</span><span class="o">})</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">KissIntegrationConfiguration</span> <span class="o">{</span>

    <span class="nd">@Bean</span>
    <span class="kd">public</span> <span class="nc">GeoApiContext</span> <span class="nf">geocoder</span><span class="o">(){</span>
        <span class="nc">GeoApiContext</span> <span class="n">context</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">GeoApiContext</span><span class="o">.</span><span class="na">Builder</span><span class="o">()</span>
                <span class="o">.</span><span class="na">apiKey</span><span class="o">(</span><span class="s">"Your apikey"</span><span class="o">)</span>
                <span class="o">.</span><span class="na">build</span><span class="o">();</span>
        <span class="k">return</span> <span class="n">context</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Here I report the central point of the module configuration: there is only one reference to the <strong>Service</strong> definition and the instance of a <em>third party</em> service (GeoApiContext).</p>

<h2 id="business-logic">BUSINESS LOGIC</h2>

<p>Later of the identification of the data to be processed, each application has to deal with the logic of interaction between entities defined into the DAO tier. You have to combine user requirements with application logic, break them up and then expose to the upper tiers simple and readable <em>signatures</em>. So this tier lets developers to make some processing without entering into the details of how the database is structured or what integration is underneath.</p>

<p>We find here the definition and usage of <strong>DTO</strong> useful to mask the data stored in the database system or in the various integration beans: why?
There are some reasons: first and foremost it is a form of information hiding for sensitive data (for example password, timestamp or other informations needed for data consistency, but no to the end user). Instead, if the returned data needs to be elaborated (like data combined from multiple sources), DTO helps to structure these data in a suitable way.
Another aspect is the serialization of data: in some context you have to transform the information present in the database, to make it usable to humans. So the developers have to “stain” the <em>Entities</em> with serialization logics, whose purpose should be only to represent the data, for example: the DATE field on the database system may be a number, but we represent it in a printable way, so probably we will use a formatting annotation; that’s a solution! but in this case we will link aspects of serialization to an entity, and in the long run this solution will leads to unusable codes. Harold Abelson said: <em>Programs must be written for people to read , and only incidentally for machines to execute</em>.</p>

<p>The DTOs allow to face the problems listed, creating something like a “buffer”, consequently more <em>loosely coupled</em> and more reusability.</p>

<p>Summing up, the BUSINESS LOGIC communicates with the DAO tier and the INTEGRATION tier, creating a synergy and an interaction between them. Besides, it brings logic and data transformation into DTO, usable by other tiers. Warning: the business logic tier uses DTO defined within and the same applies to the data returned. They <em>NEVER</em> are objects defined in other tiers, so to ensure what we said above and to give the ability to work on data returned.</p>

<p>Another feature of this tier is the transaction management: since it implements business logic it is able to determine whether an operation on the data can be successful or not, therefore defines the “transactionality” of the operation.</p>

<p>Here is the <strong>@Configuration</strong> of the business logic tier:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Configuration</span>
<span class="nd">@ComponentScan</span><span class="o">(</span><span class="n">basePackages</span> <span class="o">=</span> <span class="o">{</span><span class="s">"org.ska.business"</span><span class="o">})</span>
<span class="nd">@Import</span><span class="o">({</span><span class="nc">KissDaoConfiguration</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="nc">KissIntegrationConfiguration</span><span class="o">.</span><span class="na">class</span><span class="o">})</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">KissBusinessConfiguration</span> <span class="o">{</span>
	
	<span class="nd">@Bean</span>
    <span class="kd">public</span> <span class="nc">Mapper</span> <span class="nf">dozerMapper</span><span class="o">(){</span>
        <span class="nc">Mapper</span> <span class="n">dozerBeanMapper</span> <span class="o">=</span>  <span class="nc">DozerBeanMapperBuilder</span><span class="o">.</span><span class="na">buildDefault</span><span class="o">();</span>
	    <span class="k">return</span> <span class="n">dozerBeanMapper</span><span class="o">;</span>
    <span class="o">}</span>

<span class="o">}</span>
</code></pre></div></div>

<p>It is the only module with a direct link to the DAO and INTEGRATION tier, so it will necessarily have to import the configurations in order to use them. Moreover, to speed up the mapping between Entity and DTO it is a good practice to use frameworks born for this, avoiding long and unreadable code blocks of <em>setter</em> and <em>getter</em>; in my example, I use a mapping framework called <strong>Dozer</strong>.</p>

<h2 id="api">API</h2>

<p>In this tier falls the logic of presentation, it represents the entry point of our application, at least from the server point of view. The services like JAX-RS or JAX-WS are defined with the mainly task of presenting the data in XML, JSON or other. It talks only with the BUSINESS LOGIC tier: a service will only call one or more services offered by the Business layer, it will never use the INTEGRATION or DAO tier directly, nor it will use objects defined within them, in order to avoid <em>tightly coupled</em> and <em>spaghetti code</em>.</p>

<p>It deals with the management of authentication and authorization: here it is possible to determine who can perform an operation or not: in the layers below is much more complicated or the informations to determine what role is necessary is not yet known.</p>

<p>The APIs ALWAYS need some documentation: one of the lack of the REST world is the absence of a universal descriptor of these services. A technology that guarantees this aspect is <strong>Swagger</strong> (now OpenAPI): it allows to document the APIs, but the documentation produced can also be reused to generate the client part, therefore not just a descriptive one. For example, in my case the communication layer with the REST services was completely generated by the Swagger description of the services: in the <strong>FRONTEND</strong> module there is the <em>remote-services</em> folder that contains the result of this generation by the tool [https://editor.swagger.io] (https://editor.swagger.io).</p>

<p>In the configuration class of the api tier, I import the business tier’s one and set the generation of the Swagger documentation.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Configuration</span>
<span class="nd">@Import</span><span class="o">(</span><span class="nc">KissBusinessConfiguration</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="nd">@EnableSwagger2</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">KissApiConfiguration</span> <span class="o">{</span>
	
	    <span class="nd">@Autowired</span>
	    <span class="kd">private</span> <span class="nc">Environment</span> <span class="n">env</span><span class="o">;</span>

	    <span class="nd">@Bean</span>
	    <span class="kd">public</span> <span class="nc">Docket</span> <span class="nf">api</span><span class="o">()</span> <span class="o">{</span>
	        <span class="k">return</span> <span class="k">new</span> <span class="nf">Docket</span><span class="o">(</span><span class="nc">DocumentationType</span><span class="o">.</span><span class="na">SWAGGER_2</span><span class="o">)</span>
	                <span class="o">.</span><span class="na">select</span><span class="o">()</span>
	                <span class="o">.</span><span class="na">apis</span><span class="o">(</span><span class="nc">RequestHandlerSelectors</span><span class="o">.</span><span class="na">basePackage</span><span class="o">(</span><span class="s">"org.ska.api.web"</span><span class="o">))</span>
	                <span class="o">.</span><span class="na">paths</span><span class="o">(</span><span class="nc">PathSelectors</span><span class="o">.</span><span class="na">any</span><span class="o">())</span>
	                <span class="o">.</span><span class="na">build</span><span class="o">()</span>
	                <span class="o">.</span><span class="na">apiInfo</span><span class="o">(</span><span class="n">apiInfo</span><span class="o">());</span>
	    <span class="o">}</span>

	    <span class="kd">private</span> <span class="nc">ApiInfo</span> <span class="nf">apiInfo</span><span class="o">()</span> <span class="o">{</span>
	        <span class="k">return</span> <span class="k">new</span> <span class="nf">ApiInfo</span><span class="o">(</span>
	                <span class="s">"Contact management REST API"</span><span class="o">,</span>
	                <span class="s">"API"</span><span class="o">,</span>
	                <span class="n">env</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"info.version"</span><span class="o">),</span>
	                <span class="kc">null</span><span class="o">,</span>
	                <span class="k">new</span> <span class="nf">Contact</span><span class="o">(</span><span class="s">"Pasquale Paola"</span><span class="o">,</span> <span class="s">"https://www.linkedin.com/in/pasqualepaola/"</span><span class="o">,</span> <span class="s">"pasquale.paola@gmail.com"</span><span class="o">),</span>
	                <span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="nc">Collections</span><span class="o">.</span><span class="na">emptyList</span><span class="o">());</span>
	    <span class="o">}</span>
	    
<span class="o">}</span>
</code></pre></div></div>

<h2 id="frontend">FRONTEND</h2>

<p>It represents the Single Page Application: this type of application must be completely separated from the application and the usage of the Rest technology already guarantees this aspect, but it is necessary to pay attention to how the communications with remote services are implemented. Often I have fallen into very bad organization and management of various HTTP clients used to invoke remote services, and I mean the references that are found throughout the application. To solve this problem and to make the SPA strictly separated from everything that represents the communication with remote services, as already mentioned, I use Swagger technology to generate a stub that allows communication with the Rest API. So the developers will use what is produced by Swagger, mainly because it provides a lot of ready to use code, with different usage options, and you no longer need to rewrite it. Also the logic will be implemented elsewhere, because the remote communication section (Stub) will be continuously regenerated and no developer will ever dream to implement its own logic in sources that could be overwritten (I hope).</p>

<p>To ensure that an application written in Angular can be included in the building cycle of a Maven project, I ensure that even the <strong>FRONTEND</strong> becomes a Maven module by adding a <em>pom.xml</em> file. This module will not produce any artifact so the packaging will be <em>pom type</em>, but in this way I can insert it into the maven build and create dependencies with its siblings. To be able to integrate an Angular build in a Maven context, I use a plugin named <em>frontend-maven-plugin</em>: it allows the installation of a <em>Node</em> and <em>Npm</em> instance</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
          <span class="nt">&lt;execution&gt;</span>
            <span class="nt">&lt;id&gt;</span>install node and npm<span class="nt">&lt;/id&gt;</span>
            <span class="nt">&lt;goals&gt;</span>
              <span class="nt">&lt;goal&gt;</span>install-node-and-npm<span class="nt">&lt;/goal&gt;</span>
            <span class="nt">&lt;/goals&gt;</span>
            <span class="nt">&lt;phase&gt;</span>generate-resources<span class="nt">&lt;/phase&gt;</span>
          <span class="nt">&lt;/execution&gt;</span>
          <span class="nt">&lt;execution&gt;</span>
            <span class="nt">&lt;id&gt;</span>npm install<span class="nt">&lt;/id&gt;</span>
            <span class="nt">&lt;goals&gt;</span>
              <span class="nt">&lt;goal&gt;</span>npm<span class="nt">&lt;/goal&gt;</span>
            <span class="nt">&lt;/goals&gt;</span>
            <span class="nt">&lt;configuration&gt;</span>
              <span class="nt">&lt;arguments&gt;</span>install<span class="nt">&lt;/arguments&gt;</span>
            <span class="nt">&lt;/configuration&gt;</span>
          <span class="nt">&lt;/execution&gt;</span>
...
</code></pre></div></div>

<p>and the consequent invocation of the Angular <em>CLI</em> to manage dependencies and builds angular side.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
          <span class="nt">&lt;execution&gt;</span>
            <span class="nt">&lt;id&gt;</span>npm build<span class="nt">&lt;/id&gt;</span>
            <span class="nt">&lt;goals&gt;</span>
              <span class="nt">&lt;goal&gt;</span>npm<span class="nt">&lt;/goal&gt;</span>
            <span class="nt">&lt;/goals&gt;</span>
            <span class="nt">&lt;phase&gt;</span>generate-resources<span class="nt">&lt;/phase&gt;</span>
            <span class="nt">&lt;configuration&gt;</span>
              <span class="nt">&lt;arguments&gt;</span>run build<span class="nt">&lt;/arguments&gt;</span>
            <span class="nt">&lt;/configuration&gt;</span>
          <span class="nt">&lt;/execution&gt;</span>
...
</code></pre></div></div>

<p>When the Npm build task is invoked, the control will be taken from the Angular CLI, as described in <em>package.json</em>:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">...</span><span class="w">
</span><span class="nl">"build"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ng build --prod --progress --build-optimizer --delete-output-path --base-href /kiss/ui/ --output-path dist/resources/static/ui"</span><span class="w">
</span><span class="err">...</span><span class="w">
</span></code></pre></div></div>

<p>The output path is set to <em>dist/resources/static/ui</em>, and the path <em>dist/resources</em> is also configured as <em>resource</em> of the frontend module. Combined with the configuration of the tier API that follows below, it allows to inject the result of the Angular build in the Springboot application. In the output path (of the <em>build</em> command in package.json) there is a special directory <strong>…/static/…</strong>, one of those where Springboot allows to define static contents.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
<span class="nt">&lt;resources&gt;</span>
	<span class="nt">&lt;resource&gt;</span>
		<span class="nt">&lt;directory&gt;</span>../frontend/dist/resources<span class="nt">&lt;/directory&gt;</span>
	<span class="nt">&lt;/resource&gt;</span>
	<span class="nt">&lt;resource&gt;</span>
		<span class="nt">&lt;directory&gt;</span>src/main/resources<span class="nt">&lt;/directory&gt;</span>
		<span class="nt">&lt;filtering&gt;</span>true<span class="nt">&lt;/filtering&gt;</span>
	<span class="nt">&lt;/resource&gt;</span>

<span class="nt">&lt;/resources&gt;</span>
...
</code></pre></div></div>

<h1 id="build">Build</h1>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mvn clean <span class="nb">install</span>
</code></pre></div></div>

<h1 id="run">Run</h1>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>java <span class="nt">-jar</span> api/target/api-0.0.1-SNAPSHOT.jar
</code></pre></div></div>

<p>Got to url <a href="http://localhost:8080/kiss/">http://localhost:8080/kiss/</a></p>

<h1 id="build-docker">Build Docker</h1>

<p>Require BUILDKIT enabled</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">--target</span><span class="o">=</span>kiss-main-service <span class="nt">-t</span> kiss-main-service <span class="nb">.</span>
docker build <span class="nt">--target</span><span class="o">=</span>kiss-httpd <span class="nt">-t</span> kiss-httpd <span class="nb">.</span>
</code></pre></div></div>

<h1 id="run-docker">Run Docker</h1>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-compose up
</code></pre></div></div>]]></content><author><name>Pasquale Paola</name></author><summary type="html"><![CDATA[In my experience, I worked on various types of technologies, having the opportunity to inspect the source code and, in general, the development of an application both from the client side (which can be a SPA or a native App) and from server side. By relying on such experience, I tried to develop a simple architecture that involves the respect of fundamental **PATTERN** in a **CRUD** context. I will try to illustrate the foundations of this architecture, used as a starting point in all my projects.]]></summary></entry></feed>