<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>State(Art)</title>
        <description>Jonathan's thoughts on the state of the art in software design.</description>
        <link>https://state-of-the-art.org</link>
        <atom:link href="https://state-of-the-art.org/feed.xml" rel="self" type="application/rss+xml" />
        
        <item>
            <title>Kivakit Manifesto</title>
            <description>
&lt;p&gt;&lt;img src=&quot;https://www.state-of-the-art.org/graphics/kivakit/kivakit-logo-large.png&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;the-kivakit-manifesto--a-new-vision-for-java&quot;&gt;The KivaKit Manifesto — A New Vision for Java&lt;/h1&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.kivakit.org&quot;&gt;KivaKit&lt;/a&gt; project is more than a modular application framework for Java.&lt;/p&gt;

&lt;p&gt;It’s a new way to think about coding in Java.&lt;/p&gt;

&lt;h2 id=&quot;the-mission&quot;&gt;The Mission&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;The mission of KivaKit is to provide a new vision for the development of Java software by providing 
a design system that takes code reuse to a new level.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The primary goal of the KivaKit coding system is to deeply unify Java coding so that units of reuse 
(classes and packages) can be discovered and reused blindly, without the need to understand the most 
common API inconsistencies.&lt;/p&gt;

&lt;h2 id=&quot;reuse&quot;&gt;Reuse&lt;/h2&gt;

&lt;p&gt;Code reuse has improved through various means since the early days of Java. The JDK has improved, 
providing better APIs as well as modular Java. Third party frameworks like Spring, OSGi, JSF and 
Apache Wicket, have provided ways to build and reuse code.&lt;/p&gt;

&lt;p&gt;But the JDK does not have interfaces consistent enough to discover and use blindly. For example, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.net&lt;/code&gt; 
package and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.io&lt;/code&gt; package are both concerned with accessing resources, and they have common integration 
points (streams), they do not have the same look and feel to the developer. Network resources and files don’t 
have the same semantics. The contents of a package are not accessed in the same way as a folder. Similar 
criticisms can be made of aspects of many third-party frameworks.&lt;/p&gt;

&lt;p&gt;What we mean by &lt;em&gt;discoverability&lt;/em&gt; and &lt;em&gt;blind access&lt;/em&gt; here is that many, if not most, aspects of reusable 
units should not have a learning curve. It should be possible for a developer to discover a new class or 
package and know how it is structured and how it should behave without learning too much.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Reusable units should have a common structure and consistent behavior that can be relied on.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This sounds like a lofty goal, but how can it work in practice?&lt;/p&gt;

&lt;h2 id=&quot;kivakit-api-design&quot;&gt;KivaKit API Design&lt;/h2&gt;

&lt;p&gt;KivaKit’s system for designing APIs provides discoverability, common structure, and consistent behavior through:&lt;/p&gt;

&lt;h3 id=&quot;1-interface-composition&quot;&gt;1. Interface Composition&lt;/h3&gt;

&lt;p&gt;KivaKit enables the consistent composition of components and packages. Since objects have the same 
structure they are easier to recognize. They are also more discoverable because they have the same 
recognizable features. KivaKit makes it easy to put objects together in complex ways without abandoning 
the familiarity of the Java &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extends&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implements&lt;/code&gt; keywords. For example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BaseComponent&lt;/code&gt; and 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ComponentMixin&lt;/code&gt; are defined in terms of many small pieces, each with only a few methods at most:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://www.state-of-the-art.org/graphics/interface-composition/interface-composition.png&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Fine-grained interface composition permits more reuse because code accepting interfaces is 
applicable to more objects.&lt;/em&gt;&lt;/p&gt;

  &lt;p&gt;&lt;em&gt;Fine-grained interface composition is less fragile because interfaces are smaller and simpler, 
producing stable contracts that are easy to implement.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;2-mixins&quot;&gt;2. Mixins&lt;/h3&gt;

&lt;p&gt;The common structure of reusable units in KivaKit also provides recognizable behavior in the form of 
inherited and composited features. In KivaKit, objects often provide behavior in two forms. Behavior 
can be inherited by extending a base class or it can he inherited by implementing an interface:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class Alien extends BaseComponent     // Extend abstract class or
class Alien implements ComponentMixin // implement mixin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, both forms of inheritance provide &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alien&lt;/code&gt; with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Component&lt;/code&gt; API (see the diagram above), 
freeing the developer to build and compose objects without regard to the limitations of Java’s inheritance model.&lt;/p&gt;

&lt;h3 id=&quot;3-error-handling&quot;&gt;3. Error Handling&lt;/h3&gt;

&lt;p&gt;Through messaging behavior (see the diagram above), KivaKit provides consistent and flexible error handling. 
Errors are handled in the same way, in every component, and by every piece of code. This means we don’t need 
to make a choice when writing an API. The choice is already made:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;All components in KivaKit obey these error reporting rules:
      &lt;ul&gt;
        &lt;li&gt;Any exceptions caught are converted to broadcast messages&lt;/li&gt;
        &lt;li&gt;Any exceptions thrown must be for flow control of fluent method chains&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;All code handles errors by listening to messages&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;This error handling system is flexible enough that we can choose how we want to handle errors for any 
component at the point of use. Since all KivaKit components report and consume errors in the same way, 
this relieves an important barrier to both design and consumption of components. We no longer need to 
know anything about error handling to build or use a component.&lt;/p&gt;

&lt;h3 id=&quot;4-application-design&quot;&gt;4. Application Design&lt;/h3&gt;

&lt;p&gt;Using consistent error handling and composition, KivaKit provides commonly needed pieces that enable 
quick and easy application and component design. These components cover common needs, including project 
structure, applications, components, settings, object discovery, paths, resources, package access, 
serialization, progress reporting, conversion, validation and so on. KivaKit also unifies key JDK 
functionality with the KivaKit coding model. This allows most Java code to look and feel the same.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://www.state-of-the-art.org/graphics/application-design/application-design.png&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The KivaKit project provides a new way to create objects with common structure and behavior that 
are easy to discover and use.&lt;/p&gt;
</description>
            <pubDate>Tue, 09 Aug 2022 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2022/08/09/kivakit-manifesto.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2022/08/09/kivakit-manifesto.html</guid>
        </item>
        
        <item>
            <title>Status Messaging</title>
            <description>
&lt;p&gt;2022.02.07&lt;/p&gt;

&lt;h3 id=&quot;why-messaging-is-a-better-way-to-report-status--&quot;&gt;Why Messaging is a Better Way to Report Status    &lt;img src=&quot;https://www.state-of-the-art.org/graphics/gears/gears.svg&quot; width=&quot;48&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;In a typical Java program, the status of a method call is typically reported in one of three ways:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The method returns a value containing status information&lt;/li&gt;
  &lt;li&gt;The method throws an exception containing status information&lt;/li&gt;
  &lt;li&gt;The method logs or otherwise stores status information&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One result of this is that every API has different error reporting semantics. 
We have all seen code similar to these examples:&lt;/p&gt;

&lt;h4 id=&quot;status-reporting-via-return-values&quot;&gt;Status Reporting via Return Values&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var sender = new EmailSender();

var result = sender.send(email);
if (result != null)
{
    logger.error(result);
}

if (!sender.send(email))
{
    logger.error(&quot;Could not send&quot;);
}

var error = sender.send(email);
if (error &amp;lt; 0)
{
    logger.error(&quot;Couldn't send email: Error #&quot; + error);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;status-reporting-via-exceptions&quot;&gt;Status Reporting via Exceptions&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var sender = new EmailSender();

try
{
    sender.send(email);
}
catch (SendException e)
{
    logger.error(&quot;Unable to send&quot;, e);
}

try
{
    sender.send(email);
}
catch (SendException e)
{
    throw new EmailException(&quot;Couldn't send email&quot;, e);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://state-of-the-art.org/graphics/broadcaster-listener/broadcaster-listener-96.png&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;An alternative to these common idioms is to report status “out-of-band” by broadcasting messages to interested listeners. This has a few immediate advantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It standardizes error reporting, allowing API users to treat all components in the same way, reducing the learning curve for new APIs&lt;/li&gt;
  &lt;li&gt;It allows return values and exceptions to be used only for control flow&lt;/li&gt;
  &lt;li&gt;It simplifies and clarifies the responsibilities of components by decoupling status reporting from status handling&lt;/li&gt;
  &lt;li&gt;It allows multiple listeners and chains of listeners to handle the same status information in different ways&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://state-of-the-art.org/graphics/link/link-96.png&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;This status reporting model is implemented by the Java Open Source microservices 
framework, &lt;a href=&quot;https://www.kivakit.org&quot;&gt;KivaKit&lt;/a&gt;. In KivaKit, our &lt;em&gt;EmailSender&lt;/em&gt; class would implement &lt;em&gt;Repeater&lt;/em&gt; 
(which is a kind of &lt;em&gt;Broadcaster&lt;/em&gt;) by extending &lt;em&gt;BaseRepeater&lt;/em&gt; or (more likely) 
&lt;em&gt;BaseComponent&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class EmailSender extends BaseRepeater
{
    Connector connector = listenTo(new Connector());
    
    boolean send(Email email)
    {
        if (!connector.connect())
        {
            problem(&quot;Could not send&quot;);
            return false;
        }

            [...]
            
        return true;
    }
}

class Connector extends BaseRepeater
{
    boolean connect()
    {
        if ( [...] )
        {
            problem(&quot;Cannot connect to server&quot;);
        }
    }
}

class Client extends BaseRepeater
{
    EmailSender sender = listenTo(new EmailSender());

    void sendReport()
    {
        sender.send(composeReport());
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here, we can see that the &lt;em&gt;Connector&lt;/em&gt; object created during construction is 
passed to &lt;em&gt;listenTo()&lt;/em&gt;. The &lt;em&gt;listenTo()&lt;/em&gt; method, inherited from &lt;em&gt;BaseRepeater&lt;/em&gt;, 
causes &lt;em&gt;EmailSender&lt;/em&gt; to listen for any messages broadcast by &lt;em&gt;Connector&lt;/em&gt;. Since 
&lt;em&gt;EmailSender&lt;/em&gt; is a &lt;em&gt;Repeater&lt;/em&gt;, it will repeat any messages it receives from 
&lt;em&gt;Connector&lt;/em&gt; to its own listeners in &lt;em&gt;Client&lt;/em&gt;, forming a listener chain:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Connector ==&amp;gt; EmailSender ==&amp;gt; Client ==&amp;gt; [...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: In KivaKit, broadcasting messages does not involve message queueing or 
concurrency. Messages are delivered to listeners synchronously via the method 
Listener.onMessage().&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What’s important here is that &lt;em&gt;Connector&lt;/em&gt; and &lt;em&gt;EmailSender&lt;/em&gt; 
only report problems regarding their own status. If &lt;em&gt;Connector&lt;/em&gt; is unable to 
&lt;em&gt;connect()&lt;/em&gt;, it simply calls &lt;em&gt;problem()&lt;/em&gt; explaining what it couldn’t do. The 
&lt;em&gt;problem()&lt;/em&gt; method then transmits a &lt;em&gt;Problem&lt;/em&gt; message to &lt;em&gt;EmailSender&lt;/em&gt;, and 
&lt;em&gt;EmailSender&lt;/em&gt; in turn transmits it to &lt;em&gt;Client&lt;/em&gt;. In this way, &lt;em&gt;EmailSender&lt;/em&gt; 
indirectly provides “out-of-band” information about &lt;em&gt;Connector&lt;/em&gt;’s status to 
&lt;em&gt;Client&lt;/em&gt;. Of course, &lt;em&gt;EmailSender&lt;/em&gt; also broadcasts its own &lt;em&gt;Problem&lt;/em&gt; message 
if the &lt;em&gt;Connector.connect()&lt;/em&gt; method fails, without needing to worry about 
reporting why the connection failed.&lt;/p&gt;

&lt;p&gt;The flow of control for KivaKit messaging is shown in this UML sequence diagram:&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://state-of-the-art.org/uml/out-of-band.png&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center; font-size: 12px&quot;&gt;KivaKit's &quot;Out-of-Band&quot; Messaging&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Client&lt;/em&gt; calls &lt;em&gt;EmailSender.send()&lt;/em&gt;, which calls &lt;em&gt;Connector.connect()&lt;/em&gt;. During the 
execution of each of these methods, status messages may be transmitted down 
the listener chain (as shown by the orange lines) when a method like &lt;em&gt;problem()&lt;/em&gt;
is called.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://state-of-the-art.org/graphics/ruler/ruler-96.png&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;The rules of listener chains are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Components&lt;/em&gt; are &lt;em&gt;Repeaters&lt;/em&gt; which &lt;em&gt;listenTo()&lt;/em&gt; any components they create to form a listener chain&lt;/li&gt;
  &lt;li&gt;Each component in the chain minds its own business, broadcasting any relevant status messages during method calls&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Listeners&lt;/em&gt; can be added at any point along the chain to capture and process status information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use of EmailSender in Client now looks like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var sender = listenTo(new EmailSender());
if (!sender.send(email))
{
    problem(&quot;Unable to send report: $&quot;, email);
    return false;
}
return true;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://state-of-the-art.org/graphics/compress/compress-96.png&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Because the semantics of KivaKit status reporting are so regular, it’s possible to condense this idiom even further:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;return isTrueOr(sender.send(), &quot;Unable to send report $&quot;, email);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;isTrueOr()&lt;/em&gt; method here is inherited from the &lt;em&gt;LanguageTrait&lt;/em&gt; interface 
via the &lt;em&gt;Component&lt;/em&gt; interface. If the boolean argument to &lt;em&gt;isTrueOr()&lt;/em&gt; is not 
true, it broadcasts the message specified by the remaining arguments as a 
&lt;em&gt;Problem&lt;/em&gt;. It then returns the boolean value. This eliminates a lot of 
boilerplate if/else nesting when checking multiple conditions. Code like 
this (23 lines):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if (isTimeToSend())
{
    if (email != null)
    {
        if (sender.send())
        {
            information(&quot;Email sent.&quot;);
            return true;
        }
        else
        {
            problem(&quot;Unable to send report&quot;);
        }
    }
    else
    {
        problem(&quot;No email to send&quot;);
    }
}
else
{
    problem(&quot;Not time to send yet&quot;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;can be reduced to just this (8 lines):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if (isTrueOr(isTimeToSend(), &quot;Not time to send yet&quot;) &amp;amp;&amp;amp;
    isNonNullOr(email, &quot;No email to send&quot;) &amp;amp;&amp;amp;
    isTrueOr(sender.send(email), &quot;Unable to send report&quot;))
{
    information(&quot;Email sent.&quot;);
    return true;
}
return false;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://state-of-the-art.org/graphics/mirror/mirror-96.png&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h4 id=&quot;a-few-kivakit-listeners-and-repeaters&quot;&gt;A Few KivaKit Listeners and Repeaters&lt;/h4&gt;

&lt;p&gt;KivaKit has hundreds of &lt;em&gt;Listeners&lt;/em&gt; and &lt;em&gt;Repeaters&lt;/em&gt;. This includes all KivaKit 
&lt;em&gt;Components&lt;/em&gt;. To give an idea of the range of &lt;em&gt;Listener&lt;/em&gt; implementations:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Listener&lt;/th&gt;
      &lt;th&gt;Purpose&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;Logger&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Log status messages&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;MutableCount&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Count status messages&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;MessageAlarm&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Trigger an alarm if there are too many problems&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;StatusPanel&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Show status messages in a Swing panel&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;MessageList&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Capture messages in a list&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;ValidationIssues&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Capture problems during validation&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;Converter&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Broadcast conversion errors&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;ThrowingListener&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Throws an exception when a problem is received&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;ConsoleWriter&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Writes status messages directly to the console&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;MicroservletRequest&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Captures microservlet request handling errors&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;Application&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;Terminal listener that logs and counts messages&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://state-of-the-art.org/graphics/footprints/footprints-96.png&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;In this short article we took a look at the advantages of broadcaster/listener 
messaging in status reporting over more typical idioms. We then took a look at 
how KivaKit implements this system. More information on KivaKit messaging is 
available &lt;a href=&quot;https://state-of-the-art.org/2021/07/07/broadcaster.html&quot;&gt;on my blog&lt;/a&gt; 
as well as on &lt;a href=&quot;https://github.com/Telenav/kivakit/blob/master/kivakit-kernel/documentation/messaging.md&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512.png&quot; srcset=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512-2x.png 2x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Questions? Comments? Tweet yours to @OpenKivaKit or post here:&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;https://utteranc.es/client.js&quot; repo=&quot;jonathanlocke/jonathanlocke.github.io&quot; issue-term=&quot;status-messaging&quot; theme=&quot;github-dark&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

</description>
            <pubDate>Mon, 07 Feb 2022 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2022/02/07/status-messaging.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2022/02/07/status-messaging.html</guid>
        </item>
        
        <item>
            <title>Docker Build</title>
            <description>&lt;p&gt;2022.01.28&lt;/p&gt;

&lt;h3 id=&quot;kivakit---docker-build-environment--&quot;&gt;KivaKit - Docker Build Environment    &lt;img src=&quot;https://www.state-of-the-art.org/graphics/gears/gears.svg&quot; width=&quot;48&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://www.kivakit.org&quot;&gt;KivaKit&lt;/a&gt; 1.2.3 provides a Docker build environment that makes it easy to build KivaKit without 
installing software or configuring the build environment.&lt;/p&gt;

&lt;h4 id=&quot;launching-the-build-environment---&quot;&gt;Launching the Build Environment     &lt;img src=&quot;https://www.state-of-the-art.org/graphics/rocket/rocket.svg&quot; width=&quot;32&quot; /&gt;&lt;/h4&gt;

&lt;p&gt;Once Docker has been installed, the &lt;a href=&quot;https://github.com/Telenav/kivakit/blob/develop/documentation/building/docker-build-environment.md&quot;&gt;KivaKit Docker build environment&lt;/a&gt; can be launched with a few simple commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export KIVAKIT_WORKSPACE=~/workspaces/kivakit

mkdir -p $KIVAKIT_WORKSPACE 
cd $KIVAKIT_WORKSPACE
git clone --branch develop https://github.com/Telenav/kivakit.git
bash $KIVAKIT_WORKSPACE/kivakit/setup/setup-repositories.sh

export KIVAKIT_BUILD_IMAGE=1.2.3-snapshot

docker run \
    --volume &quot;$KIVAKIT_WORKSPACE:/host/workspace&quot; \
    --volume &quot;$HOME/.m2:/host/.m2&quot; \
    --volume &quot;$HOME/.kivakit:/host/.kivakit&quot; \
    --interactive --tty &quot;jonathanlocke/kivakit:$KIVAKIT_BUILD_IMAGE&quot; \
    /bin/bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The build environment can build source code in a workspace on the host as well as 
inside Docker, so the first line above specifies the &lt;em&gt;host&lt;/em&gt; workspace. The next four lines clone 
all the required repositories into that workspace. The second &lt;em&gt;export&lt;/em&gt; line then specifies 
the &lt;a href=&quot;https://hub.docker.com/repository/docker/jonathanlocke/kivakit&quot;&gt;KivaKit Docker tag&lt;/a&gt; 
to launch. Finally, the &lt;em&gt;docker run&lt;/em&gt; command launches the build environment.&lt;/p&gt;

&lt;h3 id=&quot;build-scripts--&quot;&gt;Build Scripts    &lt;img src=&quot;https://www.state-of-the-art.org/graphics/command-line/command-line.svg&quot; width=&quot;32&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;Several build scripts are available in the Docker build environment, and they are all 
made available on our shell’s PATH. To build KivaKit, we would use &lt;em&gt;kivakit-build.sh&lt;/em&gt;.
Since this script is on our PATH, we can build KivaKit without changing our current working
directory with &lt;em&gt;cd&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kivakit-build.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can see all available KivaKit scripts by typing kivakit- followed by &lt;strong&gt;TAB&lt;/strong&gt;. Here are some of the more important scripts:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;KivaKit Script&lt;/th&gt;
      &lt;th&gt;Purpose&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;kivakit-version.sh&lt;/td&gt;
      &lt;td&gt;Show KivaKit version&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;kivakit-build.sh&lt;/td&gt;
      &lt;td&gt;Build KivaKit&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;kivakit-build-documentation.sh&lt;/td&gt;
      &lt;td&gt;Build KivaKit documentation&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;kivakit-git-pull.sh&lt;/td&gt;
      &lt;td&gt;Pull changes from GitHub **&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;kivakit-git-checkout.sh [branch]&lt;/td&gt;
      &lt;td&gt;Check out the given branch **&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;kivakit-docker-build-workspace.sh&lt;/td&gt;
      &lt;td&gt;Switch between host and Docker workspaces&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;kivakit-feature-start.sh [branch]&lt;/td&gt;
      &lt;td&gt;Start a git flow feature branch **&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;kivakit-feature-finish.sh [branch]&lt;/td&gt;
      &lt;td&gt;Finish a git flow feature branch **&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;** executes the command in each kivakit repository&lt;/p&gt;

&lt;h3 id=&quot;build-workspaces--&quot;&gt;Build Workspaces    &lt;img src=&quot;https://www.state-of-the-art.org/graphics/folder/folder.svg&quot; width=&quot;32&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;When the Docker build environment starts up, it is set up to build a workspace 
provided inside the container. This baseline build should work nearly all of the time, 
because the build environment is standardized, and the build should have worked at 
the time the Docker image was created. Having a common, standardized
build environment provides us with an easy way to determine if there’s a problem 
in the source code versus a build environment problem. If the Docker workspace builds
successfully, we can be fairly sure that there is nothing wrong with code, even if 
the host workspace build fails.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;kivakit-docker-build-workspace.sh&lt;/em&gt; script allows us to switch between the 
Docker and host workspaces. Initially, the workspace inside the Docker container
is set up to build. If we want to switch to the host workspace, we can issue 
this command (use &lt;strong&gt;TAB&lt;/strong&gt; to complete the long script name):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kivakit-docker-build-workspace.sh host
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Switching to the host workspace will allow us to do an initial build of the code we
cloned into that workspace above. Once the host workspace has been built, KivaKit projects 
can be imported into an IDE like IntelliJ.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But how does workspace switching work?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Notice that the &lt;em&gt;docker run&lt;/em&gt; command has three Docker &lt;em&gt;–volume&lt;/em&gt; mounts. 
The &lt;em&gt;–volume&lt;/em&gt; switch makes a host folder visible inside a Docker container:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;--volume [host-folder]:[docker-folder]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, the &lt;em&gt;docker run&lt;/em&gt; command we issued above makes these three host folders 
available under the &lt;em&gt;/host&lt;/em&gt; folder inside Docker:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Docker Mount Folder&lt;/th&gt;
      &lt;th&gt;Host Folder&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;/host/workspace&lt;/td&gt;
      &lt;td&gt;$KIVAKIT_WORKSPACE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/host/.m2&lt;/td&gt;
      &lt;td&gt;$HOME/.m2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/host/.kivakit&lt;/td&gt;
      &lt;td&gt;$HOME/.kivakit&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;When we start up the Docker build environment, the KIVAKIT_WORKSPACE 
environment variable points to a workspace in the &lt;em&gt;/root&lt;/em&gt; folder inside 
our container, and the symbolic links &lt;em&gt;/root/.m2&lt;/em&gt; and &lt;em&gt;/root/.kivakit&lt;/em&gt; 
point to folders under &lt;em&gt;/root/developer&lt;/em&gt;, also inside our container:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Docker Reference&lt;/th&gt;
      &lt;th&gt;Target Folder&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;KIVAKIT_WORKSPACE&lt;/td&gt;
      &lt;td&gt;/root/workspace&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/root/.m2&lt;/td&gt;
      &lt;td&gt;/root/developer/.m2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/root/.kivakit&lt;/td&gt;
      &lt;td&gt;/root/developer/.kivakit&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;When we switch to the host workspace, the KIVAKIT_WORKSPACE environment 
variable and the symbolic links are switched to point to folders that 
have been mapped into the Docker container from the host (using the 
–volume mount switches, as described above). Now our environment
looks like this:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Docker Reference&lt;/th&gt;
      &lt;th&gt;Target Folder&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;KIVAKIT_WORKSPACE&lt;/td&gt;
      &lt;td&gt;/host/workspace&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/root/.m2&lt;/td&gt;
      &lt;td&gt;/host/.m2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/root/.kivakit&lt;/td&gt;
      &lt;td&gt;/host/.kivakit&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;and, when we execute &lt;em&gt;kivakit-build.sh&lt;/em&gt; in Docker, the host’s workspace
will be built, &lt;em&gt;using our standardized Docker build environment&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://www.state-of-the-art.org/graphics/line/line.svg&quot; width=&quot;300&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;code&quot;&gt;Code&lt;/h4&gt;

&lt;p&gt;The scripts for the KivaKit Docker build environment are here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit/tree/develop/tools/building&quot;&gt;Build Scripts&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit/tree/develop/setup&quot;&gt;Setup Scripts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512.png&quot; srcset=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512-2x.png 2x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Questions? Comments? Tweet yours to @OpenKivaKit or post here:&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;https://utteranc.es/client.js&quot; repo=&quot;jonathanlocke/jonathanlocke.github.io&quot; issue-term=&quot;build-environment&quot; theme=&quot;github-dark&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

</description>
            <pubDate>Fri, 28 Jan 2022 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2022/01/28/docker-build.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2022/01/28/docker-build.html</guid>
        </item>
        
        <item>
            <title>Formatting</title>
            <description>&lt;p&gt;2021.12.25&lt;/p&gt;

&lt;h3 id=&quot;kernel---message-formatting-and-template-expansions--&quot;&gt;Kernel - Message Formatting and Template Expansions    &lt;img src=&quot;https://www.state-of-the-art.org/graphics/nucleus/nucleus.svg&quot; width=&quot;48&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;The module &lt;a href=&quot;https://github.com/Telenav/kivakit/tree/master/kivakit-kernel&quot;&gt;kivakit-kernel&lt;/a&gt; supports a simple variable substitution syntax. This syntax
can be used when formatting messages, or when substituting variables into templates.&lt;/p&gt;

&lt;h4 id=&quot;formatting-a-message&quot;&gt;Formatting a Message&lt;/h4&gt;

&lt;p&gt;Basic message formatting is achieved with the &lt;em&gt;Message.format()&lt;/em&gt; method:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var formatted = Message.format(&quot;Hello my name is $&quot;, name);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The symbol &lt;em&gt;$&lt;/em&gt; is an expansion marker, and the corresponding argument is substituted into the 
formatted string at the marker’s location:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var formatted = format(&quot;argument1 = $, argument2 = $&quot;, argumentOne, argumentTwo);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, &lt;em&gt;argumentOne&lt;/em&gt;’s string value will be substituted for the first &lt;em&gt;$&lt;/em&gt; and &lt;em&gt;argumentTwo&lt;/em&gt;’s string
value will be substituted for the second &lt;em&gt;$&lt;/em&gt;. Both arguments will be converted to string values using 
&lt;em&gt;Strings.toString(Object)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://www.state-of-the-art.org/graphics/string/string.svg&quot; width=&quot;64&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In addition to this basic subsitution syntax, arguments can be formatted in a variety of ways using the syntax &lt;em&gt;${format}&lt;/em&gt;, where &lt;em&gt;format&lt;/em&gt; is one of the following:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Format&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;$$&lt;/td&gt;
      &lt;td&gt;evaluates to a literal ‘$’&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${class}&lt;/td&gt;
      &lt;td&gt;converts a &lt;em&gt;Class&lt;/em&gt; argument to a simple (non-qualified) class name&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${hex}&lt;/td&gt;
      &lt;td&gt;converts a long argument to a hexadecimal value&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${binary}&lt;/td&gt;
      &lt;td&gt;converts a long argument to a binary string&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${integer}&lt;/td&gt;
      &lt;td&gt;converts an integer argument to a non-comma-separated numeric string&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${long}&lt;/td&gt;
      &lt;td&gt;converts a long argument to a non-comma-separated numeric string&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${float}&lt;/td&gt;
      &lt;td&gt;converts a float argument to a string with one digit after the decimal&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${double}&lt;/td&gt;
      &lt;td&gt;converts a double argument to a string with one digit after the decimal&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${debug}&lt;/td&gt;
      &lt;td&gt;converts an argument to a string using &lt;em&gt;DebugString.toDebugString()&lt;/em&gt; if that interface is supported.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${object}&lt;/td&gt;
      &lt;td&gt;uses an &lt;em&gt;ObjectFormatter&lt;/em&gt; to format the argument by reflecting on it&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${flag}&lt;/td&gt;
      &lt;td&gt;converts boolean arguments to ‘enabled’ or ‘disabled’&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${name}&lt;/td&gt;
      &lt;td&gt;converts the argument to the name returned by &lt;em&gt;Named.name()&lt;/em&gt; if the argument is &lt;em&gt;Named&lt;/em&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;${nowrap}&lt;/td&gt;
      &lt;td&gt;signals that the message should not be wrapped&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;format(&quot;The file named '${name}' was read in $&quot;, file, start.elapsedSince());
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The reason for the &lt;em&gt;${long}&lt;/em&gt; and &lt;em&gt;${integer}&lt;/em&gt; formats in the table above is that &lt;em&gt;int&lt;/em&gt;, &lt;em&gt;long&lt;/em&gt; and &lt;em&gt;Count&lt;/em&gt; objects are formatted by default
with comma separators. This code:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Count lines;

    [...]

format(&quot;Processed $ lines.&quot;, lines);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;will produce a string like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Processed 1,457,764 lines.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using &lt;em&gt;${integer}&lt;/em&gt; like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Count lines;

    [...]

format(&quot;Processed ${integer} lines.&quot;, lines);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;produces string this instead:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Processed 1457764 lines.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;broadcasting-a-message&quot;&gt;Broadcasting a Message&lt;/h4&gt;

&lt;p&gt;When &lt;a href=&quot;2021-07-07-broadcaster.md&quot;&gt;broadcasting a message&lt;/a&gt; from a &lt;a href=&quot;2021-08-02-components-and-settings.md&quot;&gt;component&lt;/a&gt;, 
each message broadcasting method (&lt;em&gt;information()&lt;/em&gt;, &lt;em&gt;warning()&lt;/em&gt;, &lt;em&gt;problem()&lt;/em&gt;, etc.) accepts the same parameters as 
&lt;em&gt;Message.format()&lt;/em&gt; and they are handled in the same way:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;information(&quot;Processed $ lines.&quot;, lines);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://www.state-of-the-art.org/graphics/broadcaster-listener/broadcaster-listener.svg&quot; width=&quot;96&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;templates&quot;&gt;Templates&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;VariableMap&lt;/em&gt; and &lt;em&gt;PropertyMap&lt;/em&gt; classes allow for easy template substitutions
using a similar syntax:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var properties = PropertyMap.load(this, file);
properties.put(&quot;home&quot;, &quot;/users/shibo&quot;);
properties.put(&quot;job&quot;, &quot;/var/jobs/job1&quot;);
var expanded = properties.expand(&quot;Home = ${home}, Job = ${job}&quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, the marker &lt;em&gt;${home}&lt;/em&gt; is replaced with the value returned by &lt;em&gt;properties.get(“home”)&lt;/em&gt;,
and &lt;em&gt;${job}&lt;/em&gt; is replaced by &lt;em&gt;properties.get(“job”)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Putting it all together, we can load a &lt;em&gt;.properties&lt;/em&gt; file and a template, and expand
the template like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Resource template;
Resource properties;

    [...]

var expanded = PropertyMap.load(this, properties).expand(template.string());
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The properties file resource &lt;em&gt;properties&lt;/em&gt; is read with &lt;em&gt;load()&lt;/em&gt;, broadcasting any warning or
problem messages to &lt;em&gt;this&lt;/em&gt; object. The property map is then expanded into the template 
read from the resource &lt;em&gt;template&lt;/em&gt; with &lt;em&gt;Resource.string()&lt;/em&gt;. Yes, reading and expanding a 
template in KivaKit is a one-liner.&lt;/p&gt;

&lt;h4 id=&quot;code&quot;&gt;Code&lt;/h4&gt;

&lt;p&gt;The code discussed above is available on GitHub:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit/tree/master/kivakit-kernel&quot;&gt;kivakit-kernel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The KivaKit kernel, is available on &lt;em&gt;Maven Central&lt;/em&gt; at these coordinates:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.telenav.kivakit&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;kivakit-kernel&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.2.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512.png&quot; srcset=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512-2x.png 2x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Questions? Comments? Tweet yours to @OpenKivaKit or post here:&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;https://utteranc.es/client.js&quot; repo=&quot;jonathanlocke/jonathanlocke.github.io&quot; issue-term=&quot;formatting&quot; theme=&quot;github-dark&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

</description>
            <pubDate>Wed, 29 Dec 2021 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2021/12/29/formatting.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2021/12/29/formatting.html</guid>
        </item>
        
        <item>
            <title>Aws Lambda</title>
            <description>&lt;p&gt;2021.12.25&lt;/p&gt;

&lt;h3 id=&quot;kivakit-and-aws-lambda--&quot;&gt;KivaKit and AWS Lambda    &lt;img src=&quot;https://www.state-of-the-art.org/graphics/lambda/lambda.svg&quot; height=&quot;32&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;KivaKit 1.2 adds seamless support for &lt;a href=&quot;https://aws.amazon.com/lambda/&quot;&gt;AWS Lambda&lt;/a&gt;. Lambdas for &lt;a href=&quot;2021-10-01-microservices&quot;&gt;REST and GRPC&lt;/a&gt; 
can be added to a KivaKit Microservice without alteration (which will make this a short article).&lt;/p&gt;

&lt;h4 id=&quot;creating-a-lambda&quot;&gt;Creating a Lambda&lt;/h4&gt;

&lt;p&gt;We have already seen a KivaKit request handler for REST in the &lt;a href=&quot;2021-10-01-microservices.md&quot;&gt;Microservices&lt;/a&gt; article.
We will simply reuse this code as our Lambda request handler. As a reminder the code from that article looks like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@OpenApiIncludeType(description = &quot;Request for divisive action&quot;)
public class DivisionRequest extends BaseMicroservletRequest
{
    @OpenApiIncludeType(description = &quot;Response to a divide request&quot;)
    public class DivisionResponse extends BaseMicroservletResponse
    {
        @Tag(1)
        @Expose
        @OpenApiIncludeMember(description = &quot;The result of dividing&quot;,
                              example = &quot;42&quot;)
        int quotient;

        public DivisionResponse()
        {
            this.quotient = dividend / divisor;
        }

        public String toString()
        {
            return Integer.toString(quotient);
        }
    }

    @Tag(1)
    @Expose
    @OpenApiIncludeMember(description = &quot;The number to be divided&quot;,
                          example = &quot;84&quot;)
    private int dividend;

    @Tag(2)
    @Expose
    @OpenApiIncludeMember(description = &quot;The number to divide the dividend by&quot;,
                          example = &quot;2&quot;)
    private int divisor;

    public DivisionRequest(int dividend, int divisor)
    {
        this.dividend = dividend;
        this.divisor = divisor;
    }

    public DivisionRequest()
    {
    }

    @Override
    @OpenApiRequestHandler(summary = &quot;Divides two numbers&quot;)
    public DivisionResponse onRequest()
    {
        return listenTo(new DivisionResponse());
    }

    @Override
    public Class&amp;lt;DivisionResponse&amp;gt; responseType()
    {
        return DivisionResponse.class;
    }

    @Override
    public Validator validator(ValidationType type)
    {
        return new BaseValidator()
        {
            @Override
            protected void onValidate()
            {
                problemIf(divisor == 0, &quot;Cannot divide by zero&quot;);
            }
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;adding-a-lambda-service&quot;&gt;Adding a Lambda Service&lt;/h4&gt;

&lt;p&gt;In a similar fashion to adding a REST service, a Lambda service is added like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class DivisionMicroservice extends Microservice
{
    [...]

    @Override
    public MicroserviceLambdaService onNewLambdaService()
    {
        return new DivisionLambdaService(this);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;onNewLambdaService()&lt;/em&gt; method returns an instance of &lt;em&gt;DivisionLambdaService&lt;/em&gt;, which extends &lt;em&gt;MicroserviceLambdaService&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class DivisionLambdaService extends MicroserviceLambdaService
{
    [...]

    @Override
    public void onInitialize()
    {
        mount(&quot;division&quot;, &quot;1.0&quot;, DivisionRequest.class);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When the service is initialized, a call to the &lt;em&gt;mount()&lt;/em&gt; method in &lt;em&gt;onInitialize()&lt;/em&gt; is used to associate 
the name of our lambda and its version with the handler &lt;em&gt;DivisionRequest&lt;/em&gt;. Nothing more is required.&lt;/p&gt;

&lt;h4 id=&quot;code&quot;&gt;Code&lt;/h4&gt;

&lt;p&gt;The code discussed above is available on GitHub:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit-extensions/tree/master/kivakit-microservice&quot;&gt;kivakit-microservice&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit-examples/tree/master/kivakit-examples-lambda&quot;&gt;kivakit-examples-lambda&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The KivaKit Microservice API, including support for AWS Lambda, is available on &lt;em&gt;Maven Central&lt;/em&gt; at these coordinates:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.telenav.kivakit&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;kivakit-microservice&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.2.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512.png&quot; srcset=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512-2x.png 2x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Questions? Comments? Tweet yours to @OpenKivaKit or post here:&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;https://utteranc.es/client.js&quot; repo=&quot;jonathanlocke/jonathanlocke.github.io&quot; issue-term=&quot;lambda&quot; theme=&quot;github-dark&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

</description>
            <pubDate>Sat, 25 Dec 2021 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2021/12/25/aws-lambda.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2021/12/25/aws-lambda.html</guid>
        </item>
        
        <item>
            <title>Clustering</title>
            <description>&lt;p&gt;2021.12.22&lt;/p&gt;

&lt;h3 id=&quot;kivakit-clustering--&quot;&gt;KivaKit Clustering   &lt;img src=&quot;https://www.state-of-the-art.org/graphics/graph/graph.svg&quot; width=&quot;40&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;KivaKit provides built-in support for clustering of microservices using &lt;a href=&quot;https://zookeeper.apache.org&quot;&gt;Apache Zookeeper&lt;/a&gt;. It supplies a cluster model
that is updated as members join and leave the cluster, and an implementation of the &lt;a href=&quot;2021-08-02-components-and-settings.md&quot;&gt;&lt;em&gt;SettingsStore&lt;/em&gt;&lt;/a&gt; 
interface that stores settings in Zookeeper.&lt;/p&gt;

&lt;h4 id=&quot;joining-and-leaving-a-kivakit-microservice-cluster&quot;&gt;Joining and Leaving a KivaKit Microservice Cluster&lt;/h4&gt;

&lt;p&gt;To use KivaKit in a cluster, Apache Zookeeper must be running according to the instructions. The default port for Zookeeper is 2181.&lt;/p&gt;

&lt;p&gt;The source code for a clustered microservice should be organized like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;├── deployments
│   └── mycluster
│       ├── ZookeeperConnection.properties
│       └── MyMicroserviceSettings.properties
└── MyMicroservice
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;ZookeeperConnection.properties&lt;/em&gt; file here configures &lt;em&gt;ZookeeperConnection&lt;/em&gt; as specified by &lt;a href=&quot;2021-08-02-components-and-settings.md&quot;&gt;kivakit-configuration&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class       = com.telenav.kivakit.settings.stores.zookeeper.ZookeeperConnection$Settings
ports       = 127.0.0.1:2181
timeout     = 5m
create-mode = PERSISTENT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;Microservice&lt;/em&gt; subclass, &lt;em&gt;MyMicroservice&lt;/em&gt;, is then parameterized on a class that holds information about cluster members.
Each cluster member will have its own instance of this object, describing that particular member. An instance of this object 
is created during initialization by the onNewMember() method:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class MyMicroservice extends Microservice&amp;lt;MyMicroserviceSettings&amp;gt;
{
    [...]
    

    protected MicroserviceClusterMember&amp;lt;MyMicroserviceSettings&amp;gt; onNewMember()
    {
        return new MicroserviceClusterMember&amp;lt;&amp;gt;(require(MyMicroserviceSettings.class));
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, the &lt;em&gt;MicroserviceClusterMember&lt;/em&gt; model returned by this method references an instance of the &lt;em&gt;MyMicroserviceSettings&lt;/em&gt;,
which is created and registered during initialization, typically by a settings file in the deployment like MyMicroserviceSettings:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class    = myapp.MyMicroserviceSettings
port     = 8081
grpcPort = 8082
server   = true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once the &lt;em&gt;MicroserviceClusterMember&lt;/em&gt; model object has been created, it is stored in Zookeeper. Other microservice instances 
in the cluster then receive a notification that a new member has joined through this &lt;em&gt;Microservice&lt;/em&gt; method:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;protected void onJoin(MicroserviceClusterMember&amp;lt;MyMicroserviceSettings&amp;gt; member)
{
    announce(&quot;Joined cluster: $&quot;, member.identifier());
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;     &lt;img src=&quot;https://www.state-of-the-art.org/graphics/footprints/footprints.svg&quot; width=&quot;32&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When a member leaves the cluster, its model object will disappear from Zookeeper, and the remaining cluster members
will be notified with a call to:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;protected void onLeave(MicroserviceClusterMember&amp;lt;MyMicroserviceSettings&amp;gt; member)
{
    announce(&quot;Left cluster: $&quot;, member.identifier());
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;cluster-elections&quot;&gt;Cluster Elections&lt;/h4&gt;

&lt;p&gt;A cluster has an elected &lt;em&gt;leader&lt;/em&gt; at any given time. Each time a member joins or leaves the cluster, an election is held
to determine which member should lead the cluster. The election takes place automatically and the elected member will have 
the first &lt;em&gt;MicroserviceClusterMember.identifier()&lt;/em&gt; value alphabetically. This identifier is currently the DNS name of 
the host and the process number, but is only guaranteed to be unique and is subject to change in the future.&lt;/p&gt;

&lt;p&gt;To determine if a cluster member is the elected leader:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if (member.isLeader())
{
    [...]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;zookeeper-settings-stores--&quot;&gt;Zookeeper Settings Stores   &lt;img src=&quot;https://www.state-of-the-art.org/graphics/disks/disks.svg&quot; width=&quot;40&quot; /&gt;&lt;/h4&gt;

&lt;p&gt;Although some applications may require only the settings object provided by &lt;em&gt;MicroserviceClusterMember&lt;/em&gt;, others
may need to store settings for other components in Zookeeper. This can be accomplished by registering a &lt;em&gt;ZookeeperSettingsStore&lt;/em&gt;
instance in &lt;em&gt;Microservice.onInitialize()&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var store = listenTo(register(new ZookeeperSettingsStore(PERSISTENT)));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Settings can be loaded from this store with&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;registerSettingsIn(store);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and settings can be saved to this store with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;saveSettingsTo(store, settings);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because settings are retrieved in KivaKit using a &lt;em&gt;pull&lt;/em&gt; model, any changes to settings objects will be 
automatically available when the desired object is next retrieved with &lt;em&gt;require(Class)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A typical idiom is to read any existing settings from the store, and if the desired settings object is not present,
save a default value. Other members will then read that value using the same logic:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;registerSettingsIn(store);
if (!hasSettings(MyMicroserviceSettings.class))
{
   store.save(new MyMicroserviceSettings());
   registerSettingsIn(store);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Manually modifying the GSON value in Zookeeper will have the identical effect to saving a value with &lt;em&gt;saveSettingsTo()&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&quot;code&quot;&gt;Code&lt;/h4&gt;

&lt;p&gt;The code discussed above is available on GitHub:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit-extensions/tree/master/kivakit-microservice&quot;&gt;kivakit-microservice&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit-extensions/tree/master/kivakit-settings-stores/zookeeper&quot;&gt;kivakit-settings-stores-zookeeper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The KivaKit Microservice API is available on &lt;em&gt;Maven Central&lt;/em&gt; at these coordinates:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.telenav.kivakit&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;kivakit-microservice&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.2.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The KivaKit Zookeeper settings store API is at these coordinates:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.telenav.kivakit&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;kivakit-settings-stores-zookeeper&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.2.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512.png&quot; srcset=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512-2x.png 2x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Questions? Comments? Tweet yours to @OpenKivaKit or post here:&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;https://utteranc.es/client.js&quot; repo=&quot;jonathanlocke/jonathanlocke.github.io&quot; issue-term=&quot;clustering&quot; theme=&quot;github-dark&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

</description>
            <pubDate>Wed, 22 Dec 2021 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2021/12/22/clustering.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2021/12/22/clustering.html</guid>
        </item>
        
        <item>
            <title>Xml Streaming</title>
            <description>&lt;p&gt;2021.11.12&lt;/p&gt;

&lt;h3 id=&quot;kivakit-xml-streaming--&quot;&gt;KivaKit XML Streaming   &lt;img src=&quot;https://www.state-of-the-art.org/graphics/tag/tag.svg&quot; width=&quot;40&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;Since Java 1.6 in 2006, Java has had a built-in XML streaming API in the package &lt;em&gt;javax.xml.stream&lt;/em&gt;. This API is known as StAX (Streaming API for XML), and it is a very efficient “pull parser”, allowing clients to iterate through the sequence of elements in an XML document. Other approaches to working with XML are event-handling “push parsers”, and full-blown, in-memory DOMs (Document Object Models). Although StAX is convenient and very fast, it can be significantly harder to work with than a DOM, because the hierarchy of the document that’s being streamed is lost. Our code sees just one element at a time.&lt;/p&gt;

&lt;h4 id=&quot;kivakits-new-xml-mini-framework&quot;&gt;KivaKit’s New XML Mini-framework&lt;/h4&gt;

&lt;p&gt;KivaKit 1.1 quietly added a small, but useful mini-framework to the &lt;em&gt;kivakit-extensions&lt;/em&gt; repository called &lt;em&gt;kivakit-data-formats-xml&lt;/em&gt;. The project contains just two simple classes: &lt;em&gt;StaxReader&lt;/em&gt; and &lt;em&gt;StaxPath&lt;/em&gt;. The &lt;em&gt;StaxReader&lt;/em&gt; class adds a layer of convenience to the Java StAX API by making it easy to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Open and close XML streams&lt;/li&gt;
  &lt;li&gt;Get information about the reader’s stream position&lt;/li&gt;
  &lt;li&gt;Advance through XML elements&lt;/li&gt;
  &lt;li&gt;Determine the reader’s hierarchical positioning in the stream&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;moving-through-an-xml-stream&quot;&gt;Moving Through an XML Stream&lt;/h4&gt;

&lt;p&gt;The static &lt;em&gt;StaxReader.open(Resource)&lt;/em&gt; method is used to start reading an XML stream. The method either returns a valid &lt;em&gt;StaxReader&lt;/em&gt; that’s ready to go, or it throws an exception. Since &lt;em&gt;StaxReader&lt;/em&gt; implements &lt;em&gt;Closeable&lt;/em&gt;, it can be used within a &lt;em&gt;try-with-resources&lt;/em&gt; statement:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;try (var reader = StaxReader.read(file))
{
    [...]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Within our &lt;em&gt;try-with-resources&lt;/em&gt; block, we can advance through the stream with these methods:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;hasNext()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;next()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;at()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;nextAttribute()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;nextCharacters()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;nextOpenTag()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;nextCloseTag()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;nextMatching(Matcher)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we reach the end of the stream, &lt;em&gt;hasNext()&lt;/em&gt; will return false. So, processing an XML file looks like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;try (var reader = StaxReader.read(file))
{
    for (; reader.hasNext(); reader.next())
    {
        var element = reader.at();
        
        [...]
        
    }        
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we stream our way through an XML document, a few simple methods can help us to identify what kind of tag the reader is currently &lt;em&gt;at&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;isAtEnd()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;isAtCharacters()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;isAtOpenTag()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;isAtCloseTag()&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;isAtOpenCloseTag()&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;streaming-through-an-xml-hierarchy&quot;&gt;Streaming Through an XML Hierarchy&lt;/h4&gt;

&lt;p&gt;Although the underlying StAX API can only move through a document in sequential order, &lt;em&gt;StaxReader&lt;/em&gt; adds functionality that allows us to determine where we are in the document hierarchy as we move along. Using the hierarchical path to our current position the stream, we can search for specific elements in the nested document structure, and we can process data when we reach those elements.&lt;/p&gt;

&lt;p&gt;Okay. Let’s make this concrete. Here is a simple document:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;a&amp;gt;   &amp;lt;---- The path here is a
    &amp;lt;b&amp;gt;   &amp;lt;---- The path here is a/b
        &amp;lt;c&amp;gt;   &amp;lt;---- The path here is a/b/c
        &amp;lt;/c&amp;gt;
    &amp;lt;/b&amp;gt;
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;StaxPath&lt;/em&gt; class represents hierarchical paths in our XML document. As seen above, the path at &amp;lt;a&amp;gt; is &lt;em&gt;a&lt;/em&gt;. The path at &amp;lt;b&amp;gt; in our document is &lt;em&gt;a/b&lt;/em&gt; and the path at &amp;lt;c&amp;gt; is &lt;em&gt;a/b/c&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As we read elements from the XML stream, &lt;em&gt;StaxReader&lt;/em&gt; tracks the current path using a stack of elements. When the reader encounters an open tag, it pushes the name of the tag onto the end of the current path. When it encounters a close tag, it pops the last element off the end of the path. So, the sequence of steps as &lt;em&gt;StaxReader&lt;/em&gt; streams through our document is:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Step  Element     Action    StaxPath
1.    &amp;lt;a&amp;gt;         push a    a
2.      &amp;lt;b&amp;gt;       push b    a/b
3.        &amp;lt;c&amp;gt;     push c    a/b/c
4.        &amp;lt;/c&amp;gt;    pop       a/b
5.      &amp;lt;/b&amp;gt;      pop       a
6.    &amp;lt;/a&amp;gt;        pop       
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The current &lt;em&gt;StaxPath&lt;/em&gt; for a &lt;em&gt;StaxReader&lt;/em&gt; can be obtained by calling &lt;em&gt;StaxReader.path()&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&quot;finding-elements-in-the-document-hierarchy&quot;&gt;Finding Elements in the Document Hierarchy&lt;/h4&gt;

&lt;p&gt;The following methods test the current path of our &lt;em&gt;StaxReader&lt;/em&gt; reader against a given path. The reader is considered &lt;em&gt;at&lt;/em&gt; a given path if the the reader’s path is equal to the given path. For example, if the reader is at the path a/b/c and the given path is a/b/c, the reader is &lt;em&gt;at&lt;/em&gt; the given path. The reader is &lt;em&gt;inside&lt;/em&gt; the given path if the given path is a prefix of the reader’s current path. For example,
if the reader is at a/b/c/d and the path is a/b/c, then the reader is &lt;em&gt;inside&lt;/em&gt; the given path. Finally, the reader is &lt;em&gt;outside&lt;/em&gt; the given path in the reverse situation, where the reader is at a/b and the path is a/b/c.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;isAt(StaxPath)&lt;/em&gt; - Returns true if the reader is at the given path&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;findNext(StaxPath)&lt;/em&gt; - Advances until the given path or the end of the document is reached&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;isInside(StaxPath)&lt;/em&gt; - Returns true if the reader is &lt;em&gt;inside&lt;/em&gt; the given path&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;isAtOrInside(StaxPath)&lt;/em&gt; - Returns true if the reader is &lt;em&gt;at&lt;/em&gt; or &lt;em&gt;inside&lt;/em&gt; the given path&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;isOutside(StaxPath)&lt;/em&gt; - Returns true if the reader is &lt;em&gt;outside&lt;/em&gt; the given path.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;putting-it-all-together-fiasco&quot;&gt;Putting it All Together: Fiasco&lt;/h4&gt;

&lt;p&gt;And now, the reason for doing all of this. I am working on a build tool for Java projects called &lt;a href=&quot;https://github.com/Telenav/fiasco/tree/develop&quot;&gt;Fiasco&lt;/a&gt; (named for Stanislaw Lem’s 1986 science fiction novel, &lt;a href=&quot;https://en.wikipedia.org/wiki/Fiasco_(novel)&quot;&gt;Fiasko&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Fiasco is in the design stages still. When it is completed, it will be  a pure-Java build tool with these design goals, and non-goals:&lt;/p&gt;

&lt;h5 id=&quot;goals&quot;&gt;Goals&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;Intuitive API&lt;/li&gt;
  &lt;li&gt;Quick learning curve&lt;/li&gt;
  &lt;li&gt;Easy to understand and debug builds&lt;/li&gt;
  &lt;li&gt;Modular design&lt;/li&gt;
  &lt;li&gt;Easy to create new build tools&lt;/li&gt;
  &lt;li&gt;Reasonably fast&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;non-goals&quot;&gt;Non-Goals&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;Incremental compilation&lt;/li&gt;
  &lt;li&gt;Build security&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;how-fiasco-reads-pom-files-with-staxreader&quot;&gt;How Fiasco Reads POM Files with StaxReader&lt;/h5&gt;

&lt;p&gt;To build a Java project, Fiasco needs to access artifacts in Maven repositories, like &lt;em&gt;Maven Central&lt;/em&gt;. To be able to do this, it is necessary to parse Maven pom.xml files, and since Fiasco will be parsing a &lt;em&gt;lot&lt;/em&gt; of these files, it is desirable to do it fairly efficiently. The &lt;a href=&quot;https://github.com/Telenav/fiasco/blob/feature/fiasco-resolver/src/main/java/com/telenav/fiasco/internal/building/dependencies/pom/PomReader.java&quot;&gt;&lt;em&gt;PomReader&lt;/em&gt;&lt;/a&gt; class demonstrates how &lt;em&gt;StaxReader&lt;/em&gt; can be used to parse a complex, hierarchical XML file like a Maven POM file.
The relevant details are found in the method &lt;em&gt;read(MavenRepository, Resource)&lt;/em&gt;, which opens a &lt;em&gt;pom.xml&lt;/em&gt; resource, parses it and returns a &lt;em&gt;Pom&lt;/em&gt; model:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class PomReader extends BaseComponent
{
    StaxPath PROPERTIES_PATH = StaxPath.parseXmlPath(&quot;project/properties&quot;);
    StaxPath DEPENDENCY_PATH = StaxPath.parseXmlPath(&quot;project/dependencies/dependency&quot;);

    [...]
    
    Pom read(MavenRepository repository, Resource resource)
    {
        [...]
        
        try (var reader = StaxReader.open(resource))
        {
            var pom = new Pom(resource);

            for (reader.next(); reader.hasNext(); reader.next())
            {
                [...]
                
                if (reader.isAt(PROPERTIES_PATH))
                {
                    pom.properties = readProperties(reader);
                }

                if (reader.isAt(DEPENDENCY_PATH))
                {
                    pom.dependencies.add(readDependency(reader));
                }
                
                [...]
             }
         }
         
     [...]        

 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The code here that opens our &lt;em&gt;pom.xml&lt;/em&gt; resource and moves through the elements of the XML document is essentially the same as we saw earlier. Within the &lt;em&gt;for&lt;/em&gt; loop, is where we deal with the POM hierarchy. The &lt;em&gt;StaxReader.isAt(StaxPath)&lt;/em&gt; method is used to determine when the reader lands on the open tag for the given path. When PROPERTIES_PATH (project/properties) is reached, we call a method that reads the properties nested within the &amp;lt;properties&amp;gt; open tag (see &lt;em&gt;readProperties(StaxReader)&lt;/em&gt; for the gory details). For each DEPENDENCY_PATH (project/dependencies/dependency) we reach (there may be many of them), we read the &amp;lt;dependency&amp;gt; with logic similar to this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Dependency readDependency(StaxReader reader)
{
    MavenArtifactGroup artifactGroup = null;
    String artifactIdentifier = null;
    String version = null;
    var scope = DEPENDENCY_PATH;

    // Skip past the &amp;lt;dependency&amp;gt; open tag we landed on,
    reader.next();

    // and while we're not outside the &amp;lt;dependency&amp;gt; tag scope,
    for (; !reader.isOutside(scope); reader.next())
    {
        // populate any group id,
        if (reader.isAt(scope.withChild(&quot;groupId&quot;)))
        {
            artifactGroup = MavenArtifactGroup.parse(this, reader.enclosedText());
        }

        // any artifact id,
        if (reader.isAt(scope.withChild(&quot;artifactId&quot;)))
        {
            artifactIdentifier = reader.enclosedText();
        }

        // and any version.
        if (reader.isAt(scope.withChild(&quot;version&quot;)))
        {
            version = reader.enclosedText();
        }
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, there we have it. It is true that our code here is not as succinct as it would be with a DOM model. However, we can parse POM files well enough with &lt;em&gt;StaxReader&lt;/em&gt;, and we save the time and memory required by a full, in-memory DOM model.&lt;/p&gt;

&lt;h4 id=&quot;code&quot;&gt;Code&lt;/h4&gt;

&lt;p&gt;The code discussed above is available on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit-extensions/tree/0b0389677d3a82cb0378cf9cb5bd8f67852daeda/kivakit-data/formats/xml&quot;&gt;kivakit-data-formats-xml&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/Telenav/fiasco/tree/develop&quot;&gt;Fiasco (GitHub)&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/Telenav/kivakit-extensions/blob/0b0389677d3a82cb0378cf9cb5bd8f67852daeda/kivakit-data/formats/xml/src/main/java/com/telenav/kivakit/data/formats/xml/stax/StaxReader.java&quot;&gt;PomReader.java&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The KivaKit XML API is available on &lt;em&gt;Maven Central&lt;/em&gt; at these coordinates:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.telenav.kivakit&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;kivakit-data-formats-xml&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${kivakit.version}&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512.png&quot; srcset=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512-2x.png 2x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Questions? Comments? Tweet yours to @OpenKivaKit or post here:&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;https://utteranc.es/client.js&quot; repo=&quot;jonathanlocke/jonathanlocke.github.io&quot; issue-term=&quot;xml-streaming&quot; theme=&quot;github-dark&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

</description>
            <pubDate>Fri, 12 Nov 2021 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2021/11/12/xml-streaming.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2021/11/12/xml-streaming.html</guid>
        </item>
        
        <item>
            <title>Microservices</title>
            <description>&lt;p&gt;2021.10.14&lt;/p&gt;

&lt;h3 id=&quot;kivakit-microservices--&quot;&gt;KivaKit Microservices   &lt;img src=&quot;https://state-of-the-art.org/graphics/gears/gears-32.png&quot; srcset=&quot;https://state-of-the-art.org/graphics/gears/gears-32-2x.png 2x&quot; style=&quot;vertical-align:baseline&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;KivaKit is designed to make coding microservices faster and easier. In this blog post, we will examine the &lt;a href=&quot;https://github.com/Telenav/kivakit-extensions/tree/develop/kivakit-microservice&quot;&gt;&lt;em&gt;kivakit-microservice&lt;/em&gt;&lt;/a&gt; module. As of this date, this module is only available for early access via SNAPSHOT builds and by &lt;a href=&quot;https://github.com/Telenav/kivakit/blob/develop/documentation/overview/setup.md&quot;&gt;building KivaKit&lt;/a&gt;. The final release of KivaKit 1.1 will include this module and should happen by the end of October, 2021.&lt;/p&gt;

&lt;h4 id=&quot;what-does-it-do&quot;&gt;What does it do?&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;kivakit-microservice&lt;/em&gt; mini-framework makes it easy to implement REST-ful GET, POST and DELETE request handlers, and to &lt;em&gt;mount&lt;/em&gt; those handlers on specific paths. It also provides transparent support for GRPC using the same request handlers. Most of the usual plumbing for a REST microservice is taken care of, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Configuration and startup of Jetty web server&lt;/li&gt;
  &lt;li&gt;Handling GET, POST and DELETE requests&lt;/li&gt;
  &lt;li&gt;Serialization of JSON objects with Json&lt;/li&gt;
  &lt;li&gt;Error handling with KivaKit &lt;a href=&quot;2021-07-07-broadcaster.md&quot;&gt;messaging&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Generating an OpenAPI specification&lt;/li&gt;
  &lt;li&gt;Viewing the OpenAPI specification with Swagger&lt;/li&gt;
  &lt;li&gt;Starting an Apache Wicket web application&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;microservices&quot;&gt;Microservices&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;DivisionMicroservice&lt;/em&gt; class below is a &lt;em&gt;Microservice&lt;/em&gt; that performs arithmetic division (in the slowest and most expensive way imaginable). The &lt;em&gt;Microservice&lt;/em&gt; superclass provides automatic configuration and startup of Jetty server:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class DivisionMicroservice extends Microservice
{
    public static void main(final String[] arguments)
    {
        new DivisionMicroservice().run(arguments);
    }

    @Override
    public MicroserviceMetadata metadata()
    {
        return new MicroserviceMetadata()
                .withName(&quot;division-microservice&quot;)
                .withDescription(&quot;Example microservice for division&quot;)
                .withVersion(Version.parse(&quot;1.0&quot;));
    }

    @Override
    public void onInitialize()
    {
        // Register components here 
    } 
        
    @Override
    public DivisionRestService onNewRestService()
    {
        return new DivisionRestService(this);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, the &lt;em&gt;main(String[] arguments)&lt;/em&gt; method creates an instance of &lt;em&gt;DivisionMicroservice&lt;/em&gt; and starts it running with a call to &lt;em&gt;run(String[])&lt;/em&gt; (the same as with any KivaKit application). The &lt;em&gt;metadata()&lt;/em&gt; method returns information about the service that is included in the REST OpenAPI specification (mounted on &lt;em&gt;/open-api/swagger.json&lt;/em&gt;). The &lt;em&gt;onNewRestService()&lt;/em&gt; factory method creates a REST service for the microservice, and the &lt;em&gt;webApplication()&lt;/em&gt; factory method optionally creates an Apache Wicket web application for configuring the service and viewing its status. Any initialization of the microservice must take place in the &lt;em&gt;onInitialize()&lt;/em&gt; method. This is the best place to &lt;a href=&quot;2021-06-23-service-locator.md&quot;&gt;register components&lt;/a&gt; used throughout the application.&lt;/p&gt;

&lt;p&gt;When the &lt;em&gt;run(String[] arguments)&lt;/em&gt; method is called, Jetty web server is started on the port specified by the &lt;em&gt;MicroserviceSettings&lt;/em&gt; object loaded by the &lt;a href=&quot;2021-09-07-deployment.md&quot;&gt;&lt;em&gt;-deployment&lt;/em&gt; switch&lt;/a&gt;. The &lt;em&gt;-port&lt;/em&gt; command line switch can be used to override this value.&lt;/p&gt;

&lt;p&gt;When the microservice starts, the following resources are available:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Resource Path&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;/&lt;/td&gt;
      &lt;td&gt;Apache Wicket web application&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/&lt;/td&gt;
      &lt;td&gt;KivaKit microservlet REST service&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/assets&lt;/td&gt;
      &lt;td&gt;Static resources&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/docs&lt;/td&gt;
      &lt;td&gt;Swagger OpenAPI documentation&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/open-api/assets&lt;/td&gt;
      &lt;td&gt;OpenAPI resources (.yaml files)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/open-api/swagger.json&lt;/td&gt;
      &lt;td&gt;OpenAPI specification&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/swagger/webapp&lt;/td&gt;
      &lt;td&gt;Swagger web application&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;/swagger/webjar&lt;/td&gt;
      &lt;td&gt;Swagger design resources&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 id=&quot;rest-services&quot;&gt;REST Services&lt;/h4&gt;

&lt;p&gt;A REST service is created by extending the &lt;em&gt;MicroserviceRestService&lt;/em&gt; class:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class DivisionRestService extends MicroserviceRestService
{
    public DivisionRestService(Microservice microservice)
    {
        super(microservice);
    }
    
    @Override
    public void onInitialize()
    {
        mount(&quot;divide&quot;, POST, DivisionRequest.class);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Request handlers must be mounted on specific paths inside the &lt;em&gt;onInitialize()&lt;/em&gt; method (or an error is reported). If the mount path (in this case “divide”) doesn’t begin with a slash (“/”), the path “/api/[major-version].[minor-version]/” is prepended automatically. So, “divide” becomes “/api/1.0/divide” in the code above, where the version &lt;em&gt;1.0&lt;/em&gt; comes from the metadata returned by &lt;em&gt;DivisionMicroservice&lt;/em&gt;. The &lt;em&gt;same path&lt;/em&gt; can be used to mount a single request handler for each HTTP method (GET, POST, DELETE). However, trying to mount two handlers for the same HTTP method on the same path will result in an error.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;gsonFactory()&lt;/em&gt; factory method (not shown above) can optionally provide a factory that creates configured &lt;em&gt;Gson&lt;/em&gt; objects. The &lt;em&gt;Gson&lt;/em&gt; factory should extend the class &lt;em&gt;MicroserviceGsonFactory&lt;/em&gt;. KivaKit will use this factory when serializing and deserializing JSON objects.&lt;/p&gt;

&lt;p&gt;For anyone interested in the gory details, the exact flow of control that occurs when a request is made to a KivaKit microservice, is detailed in the Javadoc for &lt;a href=&quot;https://github.com/Telenav/kivakit-extensions/blob/develop/kivakit-microservice/src/main/java/com/telenav/kivakit/microservice/protocols/rest/MicroserviceRestService.java&quot;&gt;&lt;em&gt;MicroserviceRestService&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;microservlets&quot;&gt;Microservlets&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Microservlets&lt;/em&gt; handle &lt;em&gt;MicroservletRequest&lt;/em&gt;s by producing &lt;em&gt;MicroservletResponse&lt;/em&gt;s. They are mounted on paths in the same way that request handlers are mounted. Although &lt;em&gt;Microservlet&lt;/em&gt; is a public API, so far the only use case is in dispatching requests to request handlers. The &lt;em&gt;MicroservletRestService&lt;/em&gt; class uses an anonymous &lt;em&gt;Microservlet&lt;/em&gt; class to forward requests to &lt;em&gt;MicroservletRequestHandler&lt;/em&gt;s. 
You can see this in &lt;em&gt;MicroserviceRestService&lt;/em&gt; in the method &lt;em&gt;mount(String path, HttpMethod method, Class&amp;lt;MicroservletRequest&amp;gt; requestType)&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&quot;microservlet-request-handlers&quot;&gt;Microservlet Request Handlers&lt;/h4&gt;

&lt;p&gt;Request handlers are mounted on a &lt;em&gt;MicroserviceRestService&lt;/em&gt; with calls to &lt;em&gt;mount(String path, HttpMethod method, Class&amp;lt;MicroserviceRequest&amp;gt; requestType)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Note that the &lt;em&gt;BaseMicroservletRequest&lt;/em&gt; class implements both &lt;em&gt;MicroservletRequest&lt;/em&gt; and &lt;em&gt;MicroservletRequestHandler&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public abstract class BaseMicroservletRequest extends BaseComponent implements
        MicroservletRequest,
        MicroservletRequestHandler
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is crucial in terms of object-oriented design and encapsulation: &lt;em&gt;the request object itself has the data and therefore knows how to produce a response using that data&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;KEY DESIGN PRINCIPLE&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.infoworld.com/article/2073723/why-getter-and-setter-methods-are-evil.html&quot;&gt;&lt;em&gt;Don’t ask for the information you need to do the work; ask the object that has the information to do the work for you.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By employing this principle we avoid getters and setters, and our abstraction does not “leak”.&lt;/p&gt;

&lt;p&gt;Below we see a request handler, &lt;em&gt;DivisionRequest&lt;/em&gt;, that divides two numbers. The request contains a dividend and a divisor. Its &lt;em&gt;onRequest()&lt;/em&gt; method produces the response, which is implemented by the nested class &lt;em&gt;DivisionResponse&lt;/em&gt;. The response has access to the dividend and the divisor in the outer request class. So, it can create the response quotient in its constructor:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public DivisionResponse()
{
    this.quotient = dividend / divisor;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The request and response can also perform self-validation, again following the key design principle above, by overriding the &lt;em&gt;Validatable.validator()&lt;/em&gt; method, as seen below.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note that an OpenAPI specification is generated using information from &lt;em&gt;@OpenApi&lt;/em&gt; annotations&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@OpenApiIncludeType(description = &quot;Request for divisive action&quot;)
public class DivisionRequest extends BaseMicroservletRequest
{
    @OpenApiIncludeType(description = &quot;Response to a divide request&quot;)
    public class DivisionResponse extends BaseMicroservletResponse
    {
        @Tag(1)
        @Expose
        @OpenApiIncludeMember(description = &quot;The result of dividing&quot;,
                              example = &quot;42&quot;)
        int quotient;

        public DivisionResponse()
        {
            this.quotient = dividend / divisor;
        }

        public String toString()
        {
            return Integer.toString(quotient);
        }
    }

    @Tag(1)
    @Expose
    @OpenApiIncludeMember(description = &quot;The number to be divided&quot;,
                          example = &quot;84&quot;)
    private int dividend;

    @Tag(2)
    @Expose
    @OpenApiIncludeMember(description = &quot;The number to divide the dividend by&quot;,
                          example = &quot;2&quot;)
    private int divisor;

    public DivisionRequest(int dividend, int divisor)
    {
        this.dividend = dividend;
        this.divisor = divisor;
    }

    public DivisionRequest()
    {
    }

    @Override
    @OpenApiRequestHandler(summary = &quot;Divides two numbers&quot;)
    public DivisionResponse onRequest()
    {
        return listenTo(new DivisionResponse());
    }

    @Override
    public Class&amp;lt;DivisionResponse&amp;gt; responseType()
    {
        return DivisionResponse.class;
    }

    @Override
    public Validator validator(ValidationType type)
    {
        return new BaseValidator()
        {
            @Override
            protected void onValidate()
            {
                problemIf(divisor == 0, &quot;Cannot divide by zero&quot;);
            }
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can appreciate now how time-tested OO design principles have improved encapsulation, eliminated boilerplate and increased code readability.&lt;/p&gt;

&lt;h4 id=&quot;accessing-kivakit-microservices-in-java&quot;&gt;Accessing KivaKit Microservices in Java&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;kivakit-microservice&lt;/em&gt; module includes &lt;em&gt;MicroserviceClient&lt;/em&gt;, which provides easy access to KivaKit microservices in Java. The client can be used like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class DivisionClient extends Application
{
    public static void main(String[] arguments)
    {
        new DivisionClient().run(arguments);
    }

    @Override
    protected void onRun()
    {
        var client = listenTo(new MicroservletClient(
            new MicroserviceGsonFactory(), 
            Host.local().https(8086), 
            Version.parse(&quot;1.0&quot;));

        var response = client.post(&quot;divide&quot;, 
            DivisionRequest.DivisionResponse.class, 
            new DivisionRequest(9, 3));

        Message.println(AsciiArt.box(&quot;response =&amp;gt; $&quot;, response));
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, we create a &lt;em&gt;MicroservletClient&lt;/em&gt; to access the microservice we built above. We tell it to use the service on port 8086 of the local host. Then we POST a &lt;em&gt;DivisionRequest&lt;/em&gt; to divide 9 by 3 using the client, and we read the response. The response shows that the quotient is 3:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-------------------
|  response =&amp;gt; 3  |
-------------------
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;path-and-query-parameters&quot;&gt;Path and Query Parameters&lt;/h4&gt;

&lt;p&gt;A request handler does not access path and query parameters directly. Instead they are automatically turned into JSON objects. For example, a POST to this URL:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;http://localhost:8086/api/1.0/divide/dividend/9/divisor/3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;does the exact same thing as the POST request in the &lt;em&gt;DivisionClient&lt;/em&gt; code above. The &lt;em&gt;dividend/9/divisor/3&lt;/em&gt; part of the path is turned into a JSON object like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;dividend&quot;: 9,
    &quot;divisor&quot;: 3
}    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The microservlet processes this JSON just as if it had been posted. This feature can come in handy when POST-ing “flat” request objects (objects with no nesting). Note that when path variables or query parameters are provided, the body of the request is ignored.&lt;/p&gt;

&lt;h4 id=&quot;openapi&quot;&gt;OpenAPI&lt;/h4&gt;

&lt;p&gt;The “/docs” root path on the server provides a generated OpenAPI specification via Swagger:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://www.state-of-the-art.org/graphics/swagger/swagger.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The annotations available for OpenAPI are minimal, but effective for simple REST projects:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Annotation&lt;/th&gt;
      &lt;th&gt;Purpose&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;@OpenApiIncludeMember&lt;/td&gt;
      &lt;td&gt;Includes the annotated method or field in the specification&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;@OpenApiExcludeMember&lt;/td&gt;
      &lt;td&gt;Excludes the annotation method or field from the specification&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;@OpenApiIncludeMemberFromSuperType&lt;/td&gt;
      &lt;td&gt;Includes a member from the superclass or superinterface in the specification&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;@OpenApiIncludeType&lt;/td&gt;
      &lt;td&gt;Includes the annotated type in the specification schemas&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;@OpenApiRequestHandler&lt;/td&gt;
      &lt;td&gt;Provides information about a request handling method (&lt;em&gt;onGet()&lt;/em&gt;, &lt;em&gt;onPost()&lt;/em&gt; or &lt;em&gt;onDelete()&lt;/em&gt;)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 id=&quot;grpc&quot;&gt;GRPC&lt;/h4&gt;

&lt;p&gt;Google’s remote procedure call protocol (GRPC) is transparently supported by the &lt;em&gt;kivakit-microservice&lt;/em&gt; mini-framework thanks to the &lt;a href=&quot;https://github.com/protostuff/protostuff&quot;&gt;Protostuff&lt;/a&gt; project. To enable the GRPC protocol (on a separate port specified by the &lt;em&gt;-grpc-port&lt;/em&gt; switch), two changes are required. The first is to create a trivial subclass of &lt;em&gt;MicroserviceGrpcService&lt;/em&gt;. The second is to instantiate this class in &lt;em&gt;onNewGrpcService()&lt;/em&gt;. That’s it. Done.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class DivisionGrpcService extends MicroserviceGrpcService
{
    public DivisionGrpcService(Microservice microservice)
    {
        super(microservice);
    }
}

public class DivisionMicroservice extends Microservice
{
    [...]
        
    @Override
    public DivisionGrpcService onNewGrpcService()
    {
        return new DivisionGrpcService(this);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: The &lt;em&gt;@Tag&lt;/em&gt; annotations in the DivisionRequest and DivisionResponse objects above tell &lt;a href=&quot;https://github.com/protostuff/protostuff&quot;&gt;Protostuff&lt;/a&gt; what order the fields should go into the protocol buffer. This is necessary to allow for schema evolution. See the Protostuff documentation for details.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;code&quot;&gt;Code&lt;/h4&gt;

&lt;p&gt;The code discussed above is a &lt;a href=&quot;https://github.com/Telenav/kivakit-examples/tree/develop/kivakit-examples-microservice&quot;&gt;working example&lt;/a&gt; in the &lt;em&gt;kivakit-examples&lt;/em&gt; repository. It can be instructive to trace through the code in a debugger.&lt;/p&gt;

&lt;p&gt;The KivaKit Microservice API is available for early access in the &lt;em&gt;develop&lt;/em&gt; branch of the &lt;a href=&quot;https://github.com/Telenav/kivakit-extensions/tree/develop/kivakit-microservice&quot;&gt;&lt;em&gt;kivakit-microservice&lt;/em&gt;&lt;/a&gt; module of the &lt;em&gt;kivakit-extensions&lt;/em&gt; repository in &lt;a href=&quot;https://www.kivakit.org&quot;&gt;KivaKit&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.telenav.kivakit&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;kivakit-microservice&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${kivakit.version}&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512.png&quot; srcset=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512-2x.png 2x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Questions? Comments? Tweet yours to @OpenKivaKit or post here:&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;https://utteranc.es/client.js&quot; repo=&quot;jonathanlocke/jonathanlocke.github.io&quot; issue-term=&quot;microservices&quot; theme=&quot;github-dark&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

</description>
            <pubDate>Fri, 01 Oct 2021 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2021/10/01/microservices.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2021/10/01/microservices.html</guid>
        </item>
        
        <item>
            <title>State Watcher</title>
            <description>&lt;p&gt;2021.07.20&lt;/p&gt;

&lt;h3 id=&quot;signaling-and-waiting-for-concurrent-state-changes--&quot;&gt;Signaling and waiting for concurrent state changes   &lt;img src=&quot;https://state-of-the-art.org/graphics/communicate/communicate-32.png&quot; srcset=&quot;https://state-of-the-art.org/graphics/communicate/communicate-32-2x.png 2x&quot; style=&quot;vertical-align:baseline&quot; /&gt;&lt;/h3&gt;

&lt;p&gt;Java’s concurrency library (&lt;em&gt;java.util.concurrent&lt;/em&gt;) provides a mutual-exclusion (mutex) &lt;em&gt;Lock&lt;/em&gt; called &lt;em&gt;ReentrantLock&lt;/em&gt;. This lock maintains a queue of threads that are waiting to &lt;em&gt;own&lt;/em&gt; the lock, allowing access to a protected resource. A thread can be added to the lock’s wait queue by calling &lt;em&gt;lock()&lt;/em&gt;. When the &lt;em&gt;lock()&lt;/em&gt; method returns, the thread will own the lock. Once the thread obtains the lock in this way, it can mutate any shared state protected by the lock, and then it can release its ownership by calling &lt;em&gt;unlock()&lt;/em&gt;, allowing another thread to get its turn at owning the lock and accessing the shared state. Because the lock is reentrant, a thread can call &lt;em&gt;lock()&lt;/em&gt; multiple times, and the lock will only be released to the next waiting thread when all nested calls to &lt;em&gt;lock()&lt;/em&gt; have been undone with calls to &lt;em&gt;unlock()&lt;/em&gt;. The flow of a reentrant thread using a lock looks like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lock() 
    lock() 
        lock() 
        unlock()
    unlock()
unlock()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;KivaKit provides a simple extension of this functionality that reduces boilerplate calls to &lt;em&gt;lock()&lt;/em&gt; and &lt;em&gt;unlock()&lt;/em&gt;, and ensures that all lock calls are balanced by unlock calls:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class Lock extends ReentrantLock
{
    /**
     * Runs the provided code while holding this lock.
     */
    public void whileLocked(Runnable code)
    {
        lock();
        try
        {
            code.run();
        }
        finally
        {
            unlock();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Use of this class looks like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;private Lock lock = new Lock();

[...]

lock.whileLocked(() -&amp;gt; mutateSharedState());
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In addition to mutual exclusion, &lt;em&gt;ReentrantLock&lt;/em&gt; (and in fact, all Java &lt;em&gt;Lock&lt;/em&gt; implementations) provides an easy way for one thread to wait for a signal from another thread. This behavior makes &lt;em&gt;ReentrantLock&lt;/em&gt; a &lt;em&gt;condition lock&lt;/em&gt;, as declared in Java’s &lt;em&gt;Lock&lt;/em&gt; interface:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public interface Lock
{
    void lock();
    void unlock();
    Condition newCondition();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;Condition&lt;/em&gt; implementation returned by &lt;em&gt;newCondition&lt;/em&gt; has methods for threads that own the lock to signal or wait on the condition (similar to Java monitors). A simplification of the &lt;em&gt;Condition&lt;/em&gt; interface looks like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public interface Condition
{
    void await() throws InterruptedException;
    void signal();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;KivaKit uses condition locks to implement &lt;em&gt;StateWatcher&lt;/em&gt;, which provides a way to signal and wait for a particular &lt;em&gt;state&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;enum State
{
    IDLE,     // Initial state where nothing is happening
    WAITING,  // Signal that the foreground thread is waiting
    RUNNING,  // Signal that the background thread is running
    DONE      // Signal that the background thread is done
}

private StateWatcher state = new StateWatcher(State.IDLE);

[...]

new Thread(() -&amp;gt;
{
    state.waitFor(WAITING); 
    state.signal(RUNNING);

    doThings();
    
    state.signal(DONE);
    
}).start();

state.signal(WAITING);
state.waitFor(DONE);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, you might expect that this code has a race condition. It is okay if the thread starts up and reaches &lt;em&gt;waitFor(WAITING)&lt;/em&gt; before the foreground thread reaches &lt;em&gt;signal(WAITING)&lt;/em&gt;. But what if the foreground thread signals that it’s &lt;em&gt;WAITING&lt;/em&gt; and proceeds to wait for &lt;em&gt;DONE&lt;/em&gt; before the background thread even starts? With Java monitors (or &lt;em&gt;Conditions&lt;/em&gt;), the signal would be missed by the background thread. It would then hang forever waiting for a &lt;em&gt;WAITING&lt;/em&gt; signal that will never come. The foreground thread would also hang waiting for a &lt;em&gt;DONE&lt;/em&gt; signal that will never arrive. A classic deadlock scenario.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;StateWatcher&lt;/em&gt; solves this issue by making signaling and waiting &lt;em&gt;stateful&lt;/em&gt; operations. In our race condition case, the foreground thread calls &lt;em&gt;signal(WAITING)&lt;/em&gt;, as before. But the signal isn’t lost. Instead, &lt;em&gt;StateWatcher&lt;/em&gt; records that it is in the &lt;em&gt;WAITING&lt;/em&gt; state before proceeding to wait for &lt;em&gt;DONE&lt;/em&gt;. If the background thread then finishes starting up and it calls &lt;em&gt;waitFor(WAITING)&lt;/em&gt;, the current state retained by &lt;em&gt;StateWatcher&lt;/em&gt; will still be &lt;em&gt;WAITING&lt;/em&gt; and the call will return immediately instead of waiting. Our deadlock is eliminated, and with a minimal amount of code. The state that &lt;em&gt;StateWatcher&lt;/em&gt; keeps to allow this to happen is commonly known as a &lt;em&gt;condition variable&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But how exactly does StateWatcher implement this magic?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;StateWatcher&lt;/em&gt; has a &lt;em&gt;State&lt;/em&gt; value that can be updated, and a (KivaKit) &lt;em&gt;Lock&lt;/em&gt; that it uses to protect this state. It also maintains a list of &lt;em&gt;Waiter&lt;/em&gt;s, each of which has a &lt;em&gt;Condition&lt;/em&gt; to wait on (created from the &lt;em&gt;Lock&lt;/em&gt;) and a &lt;em&gt;Predicate&lt;/em&gt; that it needs to be satisfied.&lt;/p&gt;

&lt;p&gt;When the *waitFor(Predicate&lt;State&gt;)* method is called (if the watcher isn't already in the desired *State*), a new *Waiter* object (see below) is created with the *Predicate* and a *Condition* created from the *Lock*. The *waitFor()* method then adds the *Waiter* to the wait list and *awaits()* future signaling of the condition.&lt;/State&gt;&lt;/p&gt;

&lt;p&gt;When &lt;em&gt;signal(State)&lt;/em&gt; is called, the current state is updated, and each waiter is processed. If a waiter’s predicate is satisfied by the new state, its condition object is signaled, causing the thread awaiting satisfaction of the predicate to be awakened.&lt;/p&gt;

&lt;p&gt;Finally, &lt;em&gt;waitFor(State)&lt;/em&gt; is simply implemented with a method reference to &lt;em&gt;equals()&lt;/em&gt; as a predicate:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;waitFor(desiredState::equals)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A simplified version of &lt;em&gt;StateWatcher&lt;/em&gt; is shown below. The full &lt;em&gt;StateWatcher&lt;/em&gt; class is available in &lt;em&gt;kivakit-kernel&lt;/em&gt; in the &lt;a href=&quot;https://www.kivakit.org&quot;&gt;KivaKit&lt;/a&gt; project.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class StateWatcher&amp;lt;State&amp;gt;
{
    /**
     * A thread that is waiting for its predicate to be satisfied
     */
    private class Waiter
    {
        /** The predicate that must be satisfied */
        Predicate&amp;lt;State&amp;gt; predicate;

        /** The condition to signal and wait on */
        Condition condition;
    }

    /** The re-entrant (KivaKit) lock */
    private Lock lock = new Lock();

    /** The clients waiting for a predicate to be satisfied */
    private List&amp;lt;Waiter&amp;gt; waiters = new ArrayList&amp;lt;&amp;gt;();

    /** The most recently reported state */
    private State current;
    
    public StateWatcher(State current)
    {
        this.current = current;
    }

    /**
     * Signals any waiters if the state they are waiting for has arrived
     */
    public void signal(final State state)
    {
        lock.whileLocked(() -&amp;gt;
        {
            // Update the current state,
            current = state;

            // go through the waiters
            for (var watcher : waiters)
            {
                // and if the reported value satisfies the watcher's predicate,
                if (watcher.predicate.test(state))
                {
                    // signal it to wake up.
                    watcher.condition.signal();
                }
            }
        });
    }

    /**
     * Waits for the given boolean predicate to be satisfied based on changes * to the observed state value
     */
    public WakeState waitFor(Predicate&amp;lt;State&amp;gt; predicate)
    {
        return lock.whileLocked(() -&amp;gt;
        {
            // If the predicate is already satisfied,
            if (predicate.test(current))
            {
                // we're done.
                return COMPLETED;
            }

            // otherwise, add ourselves as a waiter,
            var waiter = new Waiter();
            waiter.predicate = predicate;
            waiter.condition = lock.newCondition();
            waiters.add(waiter);

            try
            {
                // and go to sleep until our condition is satisfied.
                if (waiter.condition.await())
                {
                    return TIMED_OUT;
                }
                else
                {
                    return COMPLETED;
                }
            }
            catch (InterruptedException e)
            {
                return INTERRUPTED;
            }
        });
    }

    /**
     * Wait forever for the desired state
     */
    public WakeState waitFor(State desired)
    {
        return waitFor(desired::equals);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;code&quot;&gt;Code&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;StateWatcher&lt;/em&gt; class is available in the &lt;em&gt;kivakit-kernel&lt;/em&gt; module in &lt;a href=&quot;https://www.kivakit.org&quot;&gt;KivaKit&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.telenav.kivakit&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;kivakit-kernel&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${kivakit.version}&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512.png&quot; srcset=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512-2x.png 2x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Questions? Comments? Tweet yours to @OpenKivaKit or post here:&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;https://utteranc.es/client.js&quot; repo=&quot;jonathanlocke/jonathanlocke.github.io&quot; issue-term=&quot;state-watcher&quot; theme=&quot;github-dark&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

</description>
            <pubDate>Tue, 14 Sep 2021 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2021/09/14/state-watcher.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2021/09/14/state-watcher.html</guid>
        </item>
        
        <item>
            <title>Kivakit Build</title>
            <description>
&lt;p&gt;2021.09.07&lt;/p&gt;

&lt;h3 id=&quot;a-poor-mans-multiple-repository-build-system--&quot;&gt;A poor man’s multiple-repository build system   &lt;img src=&quot;https://state-of-the-art.org/graphics/gears/gears-32.png&quot; srcset=&quot;https://state-of-the-art.org/graphics/gears/gears-32-2x.png 2x&quot; style=&quot;vertical-align:baseline&quot; /&gt;&lt;/h3&gt;

&lt;h4 id=&quot;refactoring-feature-branches-across-multiple-repositories&quot;&gt;Refactoring feature branches across multiple repositories&lt;/h4&gt;

&lt;p&gt;A common use case when working with multiple, dependent repositories is to use &lt;a href=&quot;https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow&quot;&gt;git flow&lt;/a&gt; to create multiple feature branches:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kivakit            [feature/simplify-log-api]
kivakit-extensions [feature/simplify-log-api]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If project(s) in &lt;em&gt;kivakit-extensions&lt;/em&gt; here depend on projects in &lt;em&gt;kivakit&lt;/em&gt;, refactoring code in &lt;em&gt;kivakit&lt;/em&gt; can propagate code changes to &lt;em&gt;kivakit-extensions&lt;/em&gt;. Then both feature branches are modified.&lt;/p&gt;

&lt;p&gt;When we commit and push these feature branches (ideally all at the same time for convenience), it would be nice to know that our continuous integration (CI) build system will build them correctly. There are existing solutions to the problem of repository build order, including the &lt;a href=&quot;https://blog.kie.org/2021/07/cross-repo-pull-requests-build-chain-tool-to-the-rescue.html&quot;&gt;KIE build chain tool&lt;/a&gt;. However, for &lt;a href=&quot;https://www.kivakit.org&quot;&gt;KivaKit&lt;/a&gt;, we decided it was desirable to have a bit more flexibility than &lt;a href=&quot;https://docs.github.com/en/actions&quot;&gt;GitHub Actions&lt;/a&gt; provide with their &lt;em&gt;.yaml&lt;/em&gt; configuration files, so we created a few simple scripts to manage our multi-repository builds. Remember Perl?&lt;/p&gt;

&lt;h4 id=&quot;the-kivakit-build-system&quot;&gt;The KivaKit build system&lt;/h4&gt;

&lt;p&gt;In our poor man’s solution to this problem, each repository has its own &lt;em&gt;.github/scripts/build.pl&lt;/em&gt; file that is invoked from a set of &lt;em&gt;.yaml&lt;/em&gt; workflows. The relevant portion of a workflow &lt;em&gt;.yaml&lt;/em&gt; file is very simple. It passes all the build responsibility off to the Perl script &lt;em&gt;build.pl&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- name: Build
   run: |
     perl ./.github/scripts/build.pl package
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;build.pl&lt;/em&gt; script for a given repository takes a &lt;em&gt;build-type&lt;/em&gt; argument, which can be one of two values:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;package&lt;/em&gt; - build the repository’s projects&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;publish&lt;/em&gt; - build the repository’s projects and publish them to OSSRH&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The build script clones the repository &lt;em&gt;Telenav/cactus-build&lt;/em&gt; into the GitHub Action workspace and includes Perl functions from a shared &lt;em&gt;build-include.pl&lt;/em&gt; file in &lt;em&gt;.github/scripts&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;system(&quot;git clone --branch develop --quiet https://github.com/Telenav/cactus-build.git&quot;);

require &quot;./cactus-build/.github/scripts/build-include.pl&quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The script then uses the provided functions to clone and build any dependent repositories in the proper order, followed by the repository itself:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;my ($build_type) = @ARGV;
my $github = &quot;https://github.com/Telenav&quot;;

clone(&quot;$github/kivakit&quot;, &quot;dependency&quot;);
clone(&quot;$github/kivakit-extensions&quot;, &quot;build&quot;);

build_kivakit(&quot;package&quot;);
build_kivakit_extensions($build_type);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit-extensions/blob/develop/.github/scripts/build.pl&quot;&gt;This script&lt;/a&gt; in &lt;em&gt;kivakit-extensions&lt;/em&gt; clones &lt;em&gt;kivakit&lt;/em&gt; and &lt;em&gt;kivakit-extensions&lt;/em&gt; into the GitHub Actions workspace (the second parameter determines which branch gets checked out). It then builds the project &lt;em&gt;kivakit&lt;/em&gt; before building the dependent project, &lt;em&gt;kivakit-extensions&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;This simple build system was created over a fun (and nostalgic!) weekend with Perl. It is true that this is not the most efficient way to build dependent repositories. And for private repositories, that inefficiency will make GitHub a little richer every day. However, this approach to clone and build all required projects, in order, on every repository build action, is conceptually simple, robust, flexible and easy to debug offline.&lt;/p&gt;

&lt;h4 id=&quot;caveat---out-of-order-pushes&quot;&gt;Caveat - Out of order pushes&lt;/h4&gt;

&lt;p&gt;It is useful to note here that if the &lt;em&gt;kivakit-extensions&lt;/em&gt; build action clones &lt;em&gt;kivakit&lt;/em&gt; before it has been pushed it will build against the wrong branch. Out-of-order pushes are a problem with any build method. Imagine that someone pushes a &lt;em&gt;kivakit-extensions&lt;/em&gt; feature branch and then goes to lunch without pushing the corresponding &lt;em&gt;kivakit&lt;/em&gt; feature branch. Failure is always possible with GitHub CI, because GitHub doesn’t know enough about repositories and branches, and how they relate to each other.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;KivaKit&lt;/em&gt; &lt;em&gt;clone()&lt;/em&gt; function in &lt;em&gt;build-include.pl&lt;/em&gt; makes this issue less likely (assuming you have a high bandwidth Internet connection) by simply delaying for 15 seconds before cloning dependencies. It is no substitute for a proper locking mechanism (which could ensure that cross-repository CI builds would never fail), but in practice it works nearly all the time when all interdependent feature branches are pushed at the same time.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;img src=&quot;https://www.state-of-the-art.org/graphics/line/line.svg&quot; width=&quot;300&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;code&quot;&gt;Code&lt;/h4&gt;

&lt;p&gt;The KivaKit build system is somewhat specific to KivaKit in a few places, but it could easily be modified to work in other situations. Feel free to download it and tailor it to your needs. The Perl code for the &lt;em&gt;kivakit&lt;/em&gt; project’s build is here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/cactus-build/blob/develop/.github/scripts/build-include.pl&quot;&gt;cactus-build/.github/scripts/build-include.pl&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit/tree/develop/.github/scripts&quot;&gt;kivakit/.github/scripts/build.pl&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Telenav/kivakit/tree/develop/.github/workflows&quot;&gt;kivakit/.github/workflows/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The build and workflow files for other KivaKit projects are available in the same location in those projects.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.lexakai.org&quot;&gt;Lexakai&lt;/a&gt; also uses the KivaKit build system.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512.png&quot; srcset=&quot;https://telenav.github.io/telenav-assets/images/separators/horizontal-line-512-2x.png 2x&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Questions? Comments? Tweet yours to @OpenKivaKit or post here:&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;https://utteranc.es/client.js&quot; repo=&quot;jonathanlocke/jonathanlocke.github.io&quot; issue-term=&quot;kivakit-build&quot; theme=&quot;github-dark&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

</description>
            <pubDate>Tue, 07 Sep 2021 00:00:00 +0000</pubDate>
            <link>https://state-of-the-art.org/2021/09/07/kivakit-build.html</link>
            <guid isPermaLink="true">https://state-of-the-art.org/2021/09/07/kivakit-build.html</guid>
        </item>
        
    </channel>
</rss>

