<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Hüseyin Akdoğan on Medium]]></title>
        <description><![CDATA[Stories by Hüseyin Akdoğan on Medium]]></description>
        <link>https://medium.com/@hakdogan?source=rss-1c6d42742f90------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*v1IUzraBa9bVc2rcr7T8dw.jpeg</url>
            <title>Stories by Hüseyin Akdoğan on Medium</title>
            <link>https://medium.com/@hakdogan?source=rss-1c6d42742f90------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 03 Jun 2026 04:17:24 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@hakdogan/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[DPoP: What It Is, How It Works, and Why Bearer Tokens Aren’t Enough]]></title>
            <link>https://hakdogan.medium.com/dpop-what-it-is-how-it-works-and-why-bearer-tokens-arent-enough-d37bcbbe4493?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/d37bcbbe4493</guid>
            <category><![CDATA[ami]]></category>
            <category><![CDATA[keycloak]]></category>
            <category><![CDATA[quarkus]]></category>
            <category><![CDATA[dpop]]></category>
            <category><![CDATA[bearer-token]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Mon, 09 Mar 2026 08:10:38 GMT</pubDate>
            <atom:updated>2026-03-10T20:25:35.073Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wRvxGXvzN1JXT0tnLFrZtA.png" /></figure><p>DPoP is one of the most exciting developments in the IAM (Identity and Access Management) space in recent years. Yet many backend developers either have not heard of it or are unsure what it actually changes. In this article, I will break down what DPoP is, what problem it solves, and walk through a working implementation with Keycloak and Quarkus.</p><h3>What is DPoP?</h3><p>DPoP (Demonstration of Proof-of-Possession) is an OAuth 2.0 security mechanism defined in <a href="https://datatracker.ietf.org/doc/html/rfc9449">RFC 9449</a>. Its core purpose is simple: cryptographically bind an access token to the client that requested it. This way, even if a token is intercepted, it cannot be used by another client.</p><p>In the traditional Bearer token model, anyone who possesses the token is considered authorized. DPoP changes this model; to use a token, the client must also prove possession of the corresponding private key.</p><h3>The Problem: Bearer Tokens and the “Finders Keepers” Risk</h3><p>Bearer tokens are tokens carried in the HTTP Authorization header and accepted by the server without any additional verification of the presenter. <a href="https://datatracker.ietf.org/doc/html/rfc6750">RFC 6750</a> explicitly states that possession of the token is the sole authorization criterion. This means any party that obtains the token can act as if it were the legitimate client.</p><p>This is not a theoretical risk. Real-world breaches have shown, time and again, that stolen Bearer tokens translate directly into unauthorized access:</p><p>This is not a theoretical risk. Real-world breaches have shown, time and again, that stolen Bearer tokens translate directly into unauthorized access:</p><ul><li><strong>Codecov Supply Chain Attack (2021):</strong> Attackers who infiltrated Codecov’s CI/CD process harvested tokens stored in customers’ environment variables. These tokens potentially granted access to private repositories of hundreds of organizations, including HashiCorp, which confirmed it was affected.</li><li><strong>GitHub OAuth Token Leak (2022):</strong> OAuth tokens belonging to Heroku and Travis CI were stolen, allowing attackers to list private repositories and access repository metadata across dozens of GitHub organizations, including npm.</li><li><strong>Microsoft SAS Token Incident (2023):</strong> Microsoft’s AI research team accidentally shared an overly permissive SAS token in a GitHub repository. This token made it possible to access 38 TB of internal data.</li></ul><p>The common thread across these incidents is that a token was obtained and seamlessly used in a different context by a different actor. What makes this possible is the Bearer token model’s core assumption: <strong>whoever presents the token = the authorized actor.</strong> The model checks who holds the token, not who the token belongs to.</p><h3>How Does DPoP Work?</h3><p>DPoP requires the client to send a <strong>DPoP Proof</strong> JWT with every request. This proof is signed with the client’s private key and contains the following claims:</p><ol><li><strong>htm and htu (HTTP method and URL):</strong> Restricts the proof to a specific endpoint, preventing a proof generated for one resource from being used against another.</li><li><strong>jti (JWT ID):</strong> Each proof carries a unique ID. The server records used jti values and rejects any proof that attempts to reuse one.</li><li><strong>iat (Issued At):</strong> Indicates when the proof was generated, allowing the server to enforce a validity window and reject stale proofs.</li><li><strong>ath (Access Token Hash):</strong> Specifies which access token the proof is associated with.</li></ol><p>The flow works as follows:</p><pre>1. Client generates an asymmetric key pair.<br>2. During the token request, the client sends a DPoP proof JWT whose header contains the public key (JWK).<br>3. The authorization server issues a DPoP-bound access token containing the JWK thumbprint (cnf.jkt).<br>4. When calling a protected resource, the client sends:<br>   - Authorization: DPoP &lt;access_token&gt;<br>   - DPoP: &lt;signed proof JWT&gt;<br>5. The resource server:<br>   - Verifies the proof signature<br>   - Checks that the proof&#39;s public key matches the token&#39;s cnf.jkt<br>   - Validates htm, htu, iat, jti<br>   - Verifies the ath claim binding the proof to the access token</pre><p>With this model, stealing the token alone is not enough. The attacker cannot generate valid proofs without the private key, limiting any potential misuse to an already captured, unused proof within its narrow validity window. Compare this to the Bearer model, where a stolen token grants unrestricted access until it expires. DPoP does not eliminate token theft, but it makes stolen tokens fundamentally harder to exploit.</p><h3>Configuring DPoP in Keycloak</h3><p>For this article, I use Keycloak (v26.5.5) as the identity provider. It is open-source, widely adopted, and provides built-in DPoP support with a straightforward configuration.</p><p>DPoP was introduced as a preview feature in Keycloak 23.0.0 and became <a href="https://www.keycloak.org/2025/10/dpop-support-26-4">officially supported in version 26.4</a>, working out of the box without any additional client configuration. If a client sends a DPoP proof during the token request, Keycloak validates it and includes the key thumbprint in the issued token. No extra setup is needed for this default behavior.</p><p>However, if you want to <strong>enforce</strong> DPoP for a specific client, meaning Bearer tokens will no longer be accepted for that client’s resources, follow these steps:</p><p><strong>Step 1:</strong> In the Keycloak Admin Console, navigate to the relevant realm and select the client from the <strong>Clients</strong> menu.</p><p><strong>Step 2:</strong> In the <strong>Settings</strong> tab, locate the <strong>Capability config</strong> section.</p><p><strong>Step 3:</strong> Enable the <strong>Require DPoP bound tokens</strong> switch.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HckRqvDkaMiB_OGrimDAHg.png" /></figure><p>With this option enabled, the client must include a DPoP proof with every token request. Requests without valid proof will be rejected, and Bearer tokens will not be accepted to access this client’s resources.</p><h3>DPoP in Action with Quarkus</h3><p>To see DPoP in practice, I built a Quarkus application with protected REST endpoints and tested them using a <a href="https://k6.io/">k6</a> script. The full source code is available on <a href="https://github.com/hakdogan/quarkus-dpop-example">GitHub</a>.</p><h3>Project Setup</h3><p>The application uses Quarkus 3.32.2 with the following key extension: <strong>OpenId Connect</strong>. Quarkus provides extensions for OpenID Connect and OAuth 2.0 access token management, focusing on acquiring, refreshing, and propagating tokens.</p><pre>&lt;dependency&gt;<br>    &lt;groupId&gt;io.quarkus&lt;/groupId&gt;<br>    &lt;artifactId&gt;quarkus-oidc&lt;/artifactId&gt;<br>&lt;/dependency&gt;</pre><p>The quarkus.oidc.auth-server-url property specifies the base URL of the OpenID Connect (OIDC) server, which points to the Keycloak instance in this case:</p><pre>quarkus.http.port=8180<br>quarkus.oidc.auth-server-url=http://localhost:8080/realms/master<br>quarkus.oidc.client-id=dpop-demo<br>quarkus.oidc.token.authorization-scheme=dpop</pre><p>The key line here is quarkus.oidc.token.authorization-scheme=dpop. This property tells Quarkus OIDC extension to expect the Authorization: DPoP &lt;token&gt; scheme and to perform the full DPoP proof verification process as defined by <a href="https://datatracker.ietf.org/doc/html/rfc9449">RFC 9449</a>. This includes validating the proof&#39;s signature, htm, htu, ath, and the cnf thumbprint binding between the token and the proof&#39;s public key.</p><h3>Protected Endpoints</h3><p>The application exposes three endpoints under the /api path, all requiring authentication. Each endpoint returns the caller&#39;s name and the token type (Bearer or DPoP) by checking the presence of the cnf claim in the JWT:</p><pre>@Path(&quot;/api&quot;)<br>@Authenticated<br>public class ProtectedResource {<br><br>    private final JsonWebToken jwt;<br><br>    public ProtectedResource(JsonWebToken jwt) {<br>        this.jwt = jwt;<br>    }<br><br>    @GET<br>    @Path(&quot;/user-info&quot;)<br>    @Produces(MediaType.TEXT_PLAIN)<br>    public String getUserInfo() {<br>        return buildResponse();<br>    }<br><br>    @POST<br>    @Path(&quot;/user-info&quot;)<br>    @Produces(MediaType.TEXT_PLAIN)<br>    public String postUserInfo() {<br>        return buildResponse();<br>    }<br><br>    @POST<br>    @Path(&quot;/list-users&quot;)<br>    @Produces(MediaType.TEXT_PLAIN)<br>    public String listUsers() {<br>        return buildResponse();<br>    }<br><br>    private String buildResponse() {<br>        return &quot;Hello, %s! Token type: %s&quot;.formatted(<br>                jwt.getName(),<br>                jwt.containsClaim(&quot;cnf&quot;) ? &quot;DPoP&quot; : &quot;Bearer&quot;<br>        );<br>    }<br>}</pre><p>Having both GET and POST on /user-info plus a separate /list-users endpoint is intentional. These allow us to demonstrate how DPoP proof claims (htm and htu) restrict token usage to a specific HTTP method and URL.</p><h3>Replay Protection with a jti Filter</h3><p>As mentioned above, Quarkus OIDC extension handles the core DPoP verification. However, jti replay protection is not part of that process, since tracking used values requires server-side state, which falls outside the scope of a stateless token validation layer.</p><p>I added a minimal @ServerRequestFilter that records each proof&#39;s jti and rejects any reuse:</p><pre>@Singleton<br>public class DpopJtiFilter {<br><br>    private final Set&lt;String&gt; usedJtis = ConcurrentHashMap.newKeySet();<br><br>    @ServerRequestFilter<br>    public Optional&lt;Response&gt; checkJti(ContainerRequestContext ctx) {<br>        String dpopHeader = ctx.getHeaderString(&quot;DPoP&quot;);<br>        if (dpopHeader == null || dpopHeader.isBlank()) {<br>            return Optional.empty();<br>        }<br><br>        String[] parts = dpopHeader.split(&quot;\\.&quot;);<br>        if (parts.length != 3) {<br>            return Optional.empty();<br>        }<br><br>        try {<br>            String payloadJson = new String(<br>                    Base64.getUrlDecoder().decode(parts[1]));<br>            String jti = extractJti(payloadJson);<br>            if (jti != null &amp;&amp; !usedJtis.add(jti)) {<br>                return Optional.of(Response.status(Response.Status.UNAUTHORIZED)<br>                        .type(MediaType.TEXT_PLAIN)<br>                        .entity(&quot;DPoP proof replay detected: jti &#39;%s&#39; has already been used&quot;<br>                                .formatted(jti))<br>                        .build());<br>            }<br>        } catch (Exception e) {<br>            // Let Quarkus OIDC handle malformed proofs<br>        }<br><br>        return Optional.empty();<br>    }<br><br>    // ...<br>}</pre><p>In this example, I use an in-memory ConcurrentHashMap to keep the demo simple. In a production environment, you would use a distributed store such as Redis or Infinispan to track used jti values across multiple application instances and to apply TTL-based eviction aligned with the proof&#39;s validity window.</p><p>It is worth noting that Keycloak already performs jti replay protection at the <strong>authorization server</strong> level. Internally, its <a href="https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/services/util/DPoPUtil.java#L378">DPoPReplayCheck</a> uses the SingleUseObjectProvider, which is backed by Infinispan&#39;s replicated cache. When a DPoP proof arrives at the token endpoint, Keycloak hashes the jti combined with the request URI using SHA-1 and stores it with a TTL derived from the proof&#39;s iat claim. If the same proof is submitted again, the putIfAbsent call fails and the request is rejected.</p><p>However, this protection only covers requests made to Keycloak itself. Once a DPoP-bound token is issued, the <strong>resource server</strong> is responsible for its own jti tracking. A stolen proof could be replayed against the Quarkus application, and Keycloak would have no visibility into that. This is why I added the jti filter at the resource server level, creating a two-layer defense: <strong>Keycloak guards the token endpoint, and the filter guards the application endpoints.</strong></p><h3>Testing with k6</h3><p>The repository includes a k6 test script (k6/dpop-test.js) that exercises the full DPoP flow. Run it with:</p><pre>k6 run k6/dpop-test.js</pre><blockquote><strong>Security note:</strong> The k6 test script in the repository uses <a href="https://github.com/hakdogan/quarkus-dpop-example/blob/main/k6/dpop-test.js#L68">extractable: true</a> when generating the DPoP key pair. This is fine for k6 since it’s a server-side test runner with no XSS attack surface. In browser-based implementations, you should set this to false so the private key material can never be accessed or exported by JavaScript. The key will still be usable for signing DPoP proofs via crypto.subtle.sign().</blockquote><p>The script performs seven HTTP calls in sequence. The first request obtains a DPoP-bound token from Keycloak, the next three are happy-path requests (one per endpoint), and the final three test failure scenarios. Let’s take a closer look at what happens behind the scenes at both the Keycloak and Quarkus layers:</p><h4>1. Token Request (Keycloak)</h4><p>Before any resource access, the script requests a DPoP-bound access token:</p><ol><li>The script generates an <strong>EC key pair</strong> (P-256) using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API">WebCrypto API</a>.</li><li>It creates a DPoP proof JWT targeting Keycloak’s token endpoint (htm: POST, htu: .../protocol/openid-connect/token), signed with the private key. The public key is embedded in the proof&#39;s jwk header.</li><li>It sends a POST to the token endpoint with the DPoP header and user credentials (grant_type=password).</li><li><strong>Keycloak</strong> validates the DPoP proof (signature, structure, claims), then issues an access token containing a cnf (confirmation) claim with the SHA-256 thumbprint of the client&#39;s public key. This binds the token to that specific key pair. Notice the typ: DPoP and the cnf.jkt field in the issued token:</li></ol><pre>{<br>  &quot;typ&quot;: &quot;DPoP&quot;,<br>  &quot;azp&quot;: &quot;dpop-demo&quot;,<br>  &quot;sub&quot;: &quot;830783f9-ab1b-4c41-9c23-fa6a335de1bc&quot;,<br>  &quot;cnf&quot;: {<br>    &quot;jkt&quot;: &quot;8iU6dz7Uclsxek7kgyreJc8sc2LjZIbFqtUUFpWKZIc&quot;<br>  },<br>  &quot;scope&quot;: &quot;email profile&quot;,<br>  &quot;preferred_username&quot;: &quot;hakdogan&quot;<br>}</pre><h4>2. GET /user-info (Happy Path)</h4><ol><li>The script creates a <strong>fresh DPoP proof</strong> for GET /api/user-info with a new jti, current iat, and an ath computed from the access token&#39;s SHA-256 hash. The proof payload looks like this:</li></ol><pre>{<br>  &quot;jti&quot;: &quot;6f0bf628-309d-489b-9243-38ed169e1d8c&quot;,<br>  &quot;htm&quot;: &quot;GET&quot;,<br>  &quot;htu&quot;: &quot;http://localhost:8180/api/user-info&quot;,<br>  &quot;iat&quot;: 1772897361,<br>  &quot;ath&quot;: &quot;3yFPVhSab16gaSgMAFtZCgm7GXpBMx5t3ZYCeuWqT0w&quot;<br>}</pre><ol><li>It sends GET /api/user-info with Authorization: DPoP &lt;token&gt; and DPoP: &lt;proof&gt;.</li><li><strong>Quarkus jti filter</strong> checks the proof’s jti against the used-jti store. This is a new jti, so the request passes through.</li><li><strong>Quarkus OIDC</strong> <strong>extension</strong> validates the DPoP proof as required by <a href="https://datatracker.ietf.org/doc/html/rfc9449#section-7.1">RFC 9449 (Section 7.1)</a>, which assigns this responsibility to the resource server. It verifies the proof’s signature, confirms htm matches GET, htu matches the request URL, ath matches the token hash, and the cnf thumbprint in the token matches the proof&#39;s public key. All checks pass.</li><li>The endpoint reads the cnf claim from the token, identifies it as a DPoP token, and responds:</li></ol><pre>HTTP 200: Hello, hakdogan! Token type: DPoP</pre><p>The script repeats this same flow for POST /user-info and POST /list-users, each with a fresh proof matching the target method and URL. Both return 200 with the same response.</p><h4>3. GET /user-info (Replay Attack)</h4><ol><li>The script sends the <strong>exact same proof</strong> that was used in the happy path request.</li><li><strong>Quarkus jti filter</strong> checks the jti and finds it already in the used-jti store. The request is rejected before reaching OIDC validation:</li></ol><pre>HTTP 401: DPoP proof replay detected: jti &#39;...&#39; has already been used</pre><blockquote><strong><em>Note:</em></strong><em> The error message above includes the </em><em>jti value for demonstration purposes, making it easy to observe what the filter caught. In a production environment, avoid exposing internal claim values in error responses. A generic </em><em>401 Unauthorized with no body, or a minimal message like </em><em>&quot;invalid DPoP proof&quot;, is sufficient and prevents information leakage.</em></blockquote><h4>4. POST /user-info (Method Mismatch — htm)</h4><ol><li>The script creates a new proof with htm: GET targeting /api/user-info, but sends it as a POST request.</li><li><strong>Quarkus jti filter</strong> passes the request (new jti).</li><li><strong>Quarkus OIDC</strong> <strong>extension</strong> compares the proof’s htm (GET) with the actual request method (POST). They do not match. The request is rejected:</li></ol><pre>HTTP 401</pre><h4>5. POST /list-users (URL Mismatch — htu)</h4><ol><li>The script creates a new proof targeting POST /api/user-info.</li><li>It sends the request to POST /api/list-users instead.</li><li><strong>Quarkus jti filter</strong> passes the request (new jti).</li><li><strong>Quarkus OIDC</strong> <strong>extension</strong> compares the proof’s htu with the actual request URL. They do not match. The request is rejected:</li></ol><pre>HTTP 401</pre><p>All seven checks pass:</p><pre>✓ Token request succeeds<br>✓ GET /user-info returns 200<br>✓ POST /user-info returns 200<br>✓ POST /list-users returns 200<br>✓ Replay attack returns 401<br>✓ htm mismatch returns 401<br>✓ htu mismatch returns 401</pre><p>In contrast, if the same requests were sent as plain Bearer tokens without DPoP proofs, all of them would succeed with 200. The replay, method mismatch, and URL mismatch scenarios would go undetected because there is no proof to validate. <strong>This is exactly the gap that DPoP closes.</strong></p><h3>Conclusion</h3><p>Bearer tokens follow a simple rule: whoever holds the token is authorized. DPoP changes this by binding each token to a cryptographic key pair and requiring a fresh, signed proof on every request. A stolen token alone is no longer sufficient.</p><p>The IAM ecosystem is moving in this direction. Identity providers like Keycloak and frameworks like Quarkus already offer built-in DPoP support, making adoption straightforward. Bearer tokens are not going away, but for access to sensitive resources, adopting DPoP is becoming less of a choice and more of a necessity.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d37bcbbe4493" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to intermediate operations modeler: Stream Gatherers]]></title>
            <link>https://hakdogan.medium.com/introduction-to-intermediate-operations-modeler-stream-gatherers-c9d701b9403f?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/c9d701b9403f</guid>
            <category><![CDATA[stream-gatherers]]></category>
            <category><![CDATA[stream-api]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Wed, 19 Mar 2025 13:22:56 GMT</pubDate>
            <atom:updated>2025-04-02T13:29:53.822Z</atom:updated>
            <content:encoded><![CDATA[<p>Java is a programming language with many language features, specifications, and APIs. Even among experienced Java developers, being aware of all of these is quite rare. If a study were conducted, we might come across Java developers who have never worked with Threads, never used JPA, or never developed custom annotations. However, is there a Java developer who has worked with Java 8 or later but has never used the Stream API? I highly doubt it.</p><p>Gatherers is a powerful extension of the Stream API that introduces support for customized intermediate operations. Initially introduced as a preview feature in JDK 22, it became a standard feature in JDK 24.</p><h3>What are Gatherers?</h3><p>Gatherers were developed to model intermediate operations in the Stream API. Just as a collector models a terminal operation, a gatherer is an object that models an intermediate operation. Gatherers support the characteristics of intermediate operations — they can push any number of elements to the stream they produce, maintain an internal mutable state, interrupt a stream, delay consumption, be chained, and execute in parallel.</p><p>For this reason, as stated in <a href="https://openjdk.org/jeps/485">JEP 485</a></p><blockquote><em>In fact every stream pipeline is, conceptually, equivalent to<br>source.gather(…).gather(…).gather(…).collect(…)</em></blockquote><p>The java.util.stream.Gatherer interface, which models a gatherer, has three type parameters.</p><pre>public interface Gatherer&lt;T, A, R&gt; { … }</pre><p>T represents the input element.<br>A represents the potential mutable state object.<br>R represents the output that will be pushed downstream.</p><p>A gatherer is built upon four key elements:</p><pre>Supplier&lt;A&gt; initializer();<br>Integrator&lt;A, T, R&gt; integrator();<br>BinaryOperator&lt;A&gt; combiner();<br>BiConsumer&lt;A, Downstream&lt;? super R&gt;&gt; finisher();</pre><p>Initializer – A function that produces an instance of the internal intermediate state.<br>Integrator – Integrates a new element into the stream produced by the Gatherer.<br>Combiner – A function that accepts two intermediate states and merges them into one. Supporting parallel execution.<br>Finisher – A function that allows performing a final action at the end of input elements.</p><p>Among these four elements, only the integrator is mandatory because it has the role of integrating a new element into the stream produced by the Gatherer. The other elements may or may not be required, depending on the operation you intend to model, making them optional.</p><h3>Creating a Gatherer</h3><p>Gatherers are created using factory methods, or you can implement the Gatherer interface. Depending on the operation you want to model, you can use the overloaded variants of Gatherer.of and Gatherer.ofSequential.</p><pre>var uppercaseGatherer = Gatherer.&lt;String, String&gt;of((state, element, downstream) <br>-&gt; downstream.push(element.toUpperCase()));</pre><p>The example gatherer above calls toUpperCase on an input element of type String and pushes the result downstream. This gatherer is equivalent to the following map operation.</p><pre>Stream.of(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;, &quot;f&quot;, &quot;g&quot;)<br>   .map(String::toUpperCase)<br>   .forEach(System.out::print);</pre><p>The Stream interface now includes a method called gather(), which accepts a Gatherer parameter. We can use it by passing the gatherer we created.</p><pre>Stream.of(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;, &quot;f&quot;, &quot;g&quot;)<br>    .gather(uppercaseGatherer) <br>    .forEach(System.out::print);</pre><h3>Built-in Gatherers</h3><p>The java.util.stream.Gatherers class is a factory class that contains predefined implementations of the java.util.stream.Gatherer interface, defining five different gatherers.</p><ul><li><a href="https://cr.openjdk.org/~vklang/gatherers/api/java.base/java/util/stream/Gatherers.html#windowFixed(int)">windowFixed</a><br>It is a many-to-many gatherer which groups input elements into lists of a supplied size, emitting the windows downstream when they are full.</li><li><a href="https://cr.openjdk.org/~vklang/gatherers/api/java.base/java/util/stream/Gatherers.html#windowSliding(int)">windowSliding</a><br>It is a many-to-many gatherer which groups input elements into lists of a supplied size. After the first window, each subsequent window is created from a copy of its predecessor by dropping the first element and appending the next element from the input stream.</li><li><a href="https://cr.openjdk.org/~vklang/gatherers/api/java.base/java/util/stream/Gatherers.html#fold(java.util.function.Supplier,java.util.function.BiFunction)">fold</a><br>It is a many-to-one gatherer which constructs an aggregate incrementally and emits that aggregate when no more input elements exist.</li><li><a href="https://cr.openjdk.org/~vklang/gatherers/api/java.base/java/util/stream/Gatherers.html#scan(java.util.function.Supplier,java.util.function.BiFunction)">scan</a><br>It is a one-to-one gatherer which applies a supplied function to the current state and the current element to produce the next element, which it passes downstream.</li><li><a href="https://cr.openjdk.org/~vklang/gatherers/api/java.base/java/util/stream/Gatherers.html#mapConcurrent(int,java.util.function.Function)">mapConcurrent</a><br>It is a one-to-one gatherer which invokes a supplied function for each input element concurrently, up to a supplied limit. The function executes in Virtual Thread.</li></ul><p>All of the above gatherers are stateful. Fold and Scan are very similar to the Stream reduce operation. The key difference is that both can take an input of type T and produce an output of type R, and their identity element is mandatory, not optional.</p><h3>Create your own Gatherer</h3><p>Let’s see how we can write our custom gatherer using a real-world scenario. Imagine you are processing a system’s log stream. Each log entry represents an event, and it is evaluated based on certain rules to determine whether it is anomalous. The rule and scenario are as follows.</p><ul><li><strong>Rule:</strong> An event (log entry) is considered anomalous if it exceeds a certain threshold or contains an error.</li><li><strong>Scenario:</strong> If an error occurs and is immediately followed by several anomalous events (<em>three in a row, e.g</em>), they might be part of a failure chain. However, if a “normal” event appears in between, the chain is broken.</li></ul><p>In this case, we can write a gatherer that processes a log stream and returns only the uninterrupted anomalous events.</p><blockquote><em>INFO, ERROR, ERROR, INFO, WARNING, ERROR, ERROR, ERROR, INFO, DEBUG</em></blockquote><p>Let’s assume that the object in our log stream is structured as follows.</p><pre>class LogWrapper { <br><br>    enum Level{ <br>         INFO, <br>         DEBUG, <br>         WARNING, <br>         ERROR <br>    } <br><br>   private Level level; <br>   private String details;<br>}</pre><p>The object has a level field representing the log level. The details field represents the content of the log entry.</p><p>We need a stateful gatherer because we must retain information about past events to determine whether failures occur consecutively. To achieve this, the internal state of our gatherer can be a List&lt;LogWrapper&gt;</p><pre>static Supplier&lt;List&lt;LogWrapper&gt;&gt; initializer() { <br>   return ArrayList::new; <br>}</pre><p>The object returned by the initializer() corresponds to the second parameter explained earlier in the type parameters of the Gatherer interface.</p><pre>static Integrator&lt;List&lt;LogWrapper&gt;, LogWrapper, String&gt; integrator(final int threshold) { <br><br>    return ((internalState, element, downstream) -&gt; { <br>        if(downstream.isRejecting()){ <br>            return false; <br>        } <br><br>        if(element.getLevel().equals(LogWrapper.Level.ERROR)){ <br>            internalState.add(element); <br>        } else {<br> <br>            if(internalState.size() &gt;= threshold){ <br>                internalState.stream().map(LogWrapper::getDetails).forEach(downstream::push); <br>            } <br>            <br>            internalState.clear(); <br>        } <br><br>        return true; <br>    }); <br>}</pre><p>The integrator will be responsible for integrating elements into the produced stream. The third parameter of the integrator represents the downstream object.</p><p>We check whether more elements are needed by calling the isRejecting(), which determines if the next stage no longer wants to receive elements. If this condition is met, we return false.</p><p>If the integrator returns false, it performs a short-circuit operation similar to intermediate operations like allMatch, anyMatch, and noneMatch in the Stream API, indicating that no more elements will be integrated into the stream.</p><p>If isRejecting() returns false, we check whether the level value of our stream element, LogWrapper, is ERROR. If the level is ERROR, we add the object to our internal state. If the level is not ERROR, we then check the size of our internal state.</p><p>If the size exceeds or is equal to the threshold, we push the LogWrapper objects stored in the internal state downstream. If not, we don’t.</p><blockquote>I want you to pay attention to two things here. Pushing an element downstream or not, as per the business rule, is similar to what filter() does. Accepting an input of type LogWrapper and producing an output of type String is similar to what map() does.</blockquote><p>After that, according to our business rule, we clear the internal state and return true to allow new elements to be integrated into the stream.</p><pre>static BinaryOperator&lt;List&lt;LogWrapper&gt;&gt; combiner() { <br>    return (_, _) -&gt; { <br>        throw new UnsupportedOperationException(&quot;Cannot be parallelized&quot;); <br>    }; <br>}</pre><p>To prevent our gatherer from being used in a parallel stream, we define a combiner, even though it is not strictly required. This is because our gatherer is inherently designed to work as expected only in a sequential stream.</p><pre>static BiConsumer&lt;List&lt;LogWrapper&gt;, Downstream&lt;? super String&gt;&gt; finisher(final int threshold) { <br>    return (state, downstream) -&gt; { <br>        if(!downstream.isRejecting() &amp;&amp; state.size() &gt;= threshold){ <br>            state.stream().map(LogWrapper::getDetails).forEach(downstream::push); <br>        } <br>    }; <br>}</pre><p>Finally, we define a finisher to push any remaining stream elements that have not yet been emitted downstream.</p><p>If isRejecting() returns false and the size of the internal state is greater than or equal to the threshold, we push the LogWrapper objects stored in the internal state downstream.</p><p>When we use this gatherer on data</p><pre>ERROR,   Process ID: 191, event details ...<br>INFO,    Process ID: 216, event details ...<br>DEBUG,   Process ID: 279, event details ...<br>ERROR,   Process ID: 312, event details ...<br>WARNING, Process ID: 340, event details ...<br>ERROR,   Process ID: 367, event details ...<br>ERROR,   Process ID: 389, event details ...<br>INFO,    Process ID: 401, event details ...<br>ERROR,   Process ID: 416, event details ...<br>ERROR,   Process ID: 417, event details ...<br>ERROR,   Process ID: 418, event details ...<br>WARNING, Process ID: 432, event details ...<br>ERROR,   Process ID: 444, event details ...<br>ERROR,   Process ID: 445, event details ...<br>ERROR,   Process ID: 446, event details ...<br>ERROR,   Process ID: 447, event details ...</pre><p>similar to the one above, we get the following result.</p><blockquote><em>Process ID: 416, event details …<br>Process ID: 417, event details …<br>Process ID: 418, event details …<br>Process ID: 444, event details …<br>Process ID: 445, event details …<br>Process ID: 446, event details …<br>Process ID: 447, event details …</em></blockquote><p>The code example is accessible in the <a href="https://github.com/hakdogan/stream-gatherers">GitHub repository</a>.</p><h3>Conclusion</h3><p>Gatherers is a new and powerful API that enhances the Stream API by modeling intermediate operations and allowing the definition of custom intermediate operations. A gatherer supports the features that intermediate operations have, it can push any number of elements to the resulting stream, maintain an internal mutable state, short-circuit a stream, delay consumption, be chained, and execute in parallel.</p><h3>References</h3><ul><li><a href="https://openjdk.org/jeps/485">JEP 485</a></li><li><a href="https://cr.openjdk.org/~vklang/Gatherers.html">cr.openjdk.org</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c9d701b9403f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Basis of Virtual Threads: Continuations]]></title>
            <link>https://hakdogan.medium.com/the-basis-of-virtual-threads-continuations-e54c9d2aec8?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/e54c9d2aec8</guid>
            <category><![CDATA[continuation]]></category>
            <category><![CDATA[concurrency]]></category>
            <category><![CDATA[virtual-threads]]></category>
            <category><![CDATA[threads]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Fri, 28 Apr 2023 13:47:44 GMT</pubDate>
            <atom:updated>2023-04-28T13:47:44.521Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://openjdk.org/projects/loom/">Project Loom</a> has been the focus of attention in the Java community since the day it was announced. Java developers were excited by Loom’s promise that, with virtual threads, they could write highly scalable applications that made utilized the hardware optimally, without changing their habits.</p><p>Virtual threads were first introduced as a preview API in JDK 19, delivered to the second preview round in JDK 20, and are expected to become standard with JDK 21. Until now, you may have read many articles and listened to many presentations about virtual threads.</p><p>So, assuming you are familiar with the basic concepts, I would like to give a brief summary instead of repeating in detail what you’re known in this article and then turn the spotlight on the Continuations that allow the Java platform to achieve a more fine-grained concurrency model.</p><h3>A brief summary</h3><p>With Loom we now have two types of threads: Platform thread and virtual thread. While a platform thread is an instance of java.lang.Thread that’s implemented in the traditional way, as a thin wrapper around an OS thread, a virtual thread is an alternative implementation of java.lang.Thread that’s not tied to a particular OS thread.</p><p>The fact that platform threads are a thin wrapper around OS threads means that each traditional Java thread opens a new native thread on the OS level, thus establishing a one-to-one relationship(<em>1:1 scheduling</em>) with the OS threads.</p><p>By contrast, a virtual thread is mounted to a platform thread(therefore it is called a carrier thread) by the JVM, thus establishing a many-to-one relationship(<em>M:N scheduling</em>) between virtual threads and platform threads.</p><p>A virtual thread can remain mounted to the carrier thread until it encounters a blocking operation, and is unmounted by the JVM when a blocking operation occurs.</p><p>This means that the blocking code running in the virtual thread is not blocking the kernel thread. In this way, many virtual threads can run on the same OS thread. Because they are managed by the JVM instead of OS, the overhead of task-switching of virtual threads is close to zero.</p><blockquote>There are two cases where a blocking operation doesn’t unmount the virtual thread from the carrier thread: 1) When the virtual thread executes a synchronized block or method code. 2) When it calls a native method or a foreign function. In these cases, the virtual thread is pinned to the carrier thread.</blockquote><p>In addition, platform threads carry megabyte-scale chunks of memory to manage the Java call stack, while the memory footprint for virtual threads starts at just a few hundred bytes, and their stack frames are stored in the Java heap rather than in memory allocated by the OS.</p><p>All of these are what make virtual threads cheap. Therefore, a concurrent application can use hundreds of thousands or even millions of virtual threads.</p><h3>Continuations</h3><p>In Project Loom, the word continuation will mean a delimited continuation also sometimes called a coroutine. It can be thought of as sequential code that may suspend or yield execution at some point by itself and can be resumed by a caller.</p><p>I mentioned above that the virtual threads are mounted and unmounted by the JVM, now let’s make this behavior observable.</p><pre>class Task implements Runnable<br>{<br>   private final int taskNumber;<br><br><br>   public Task(int taskNumber) {<br>       this.taskNumber = taskNumber;<br>   }<br><br><br>   @Override<br>   public void run() {<br>       if(taskNumber == 1) {<br>           System.out.println(Thread.currentThread());<br>       }<br>       try {<br>           Thread.sleep(Duration.ofMillis(20));<br>       } catch (InterruptedException e) {<br>           throw new RuntimeException(e);<br>       }<br>       if(taskNumber == 1) {<br>           System.out.println(Thread.currentThread());<br>       }<br>   }<br>}</pre><p>The Task object is seen above responsible for both putting the task to sleep for 20ms and if the variable taskNumber has a value of 1 printing the name of the current thread before and after this operation.</p><pre>var virtualThreads = IntStream.rangeClosed(1, 10)<br>       .mapToObj(taskNumber -&gt;<br>               Thread.ofVirtual().unstarted(new Task(taskNumber)))<br>       .toList();<br><br><br>virtualThreads.forEach(Thread::start);<br>for(Thread t :virtualThreads){<br>   t.join();<br>}</pre><p>When the Task object is passed to virtual threads for execution, we will get an output similar to the following.</p><blockquote>VirtualThread[#21]/runnable@ForkJoinPool-1-worker-1</blockquote><blockquote>VirtualThread[#21]/runnable@ForkJoinPool-1-worker-7</blockquote><p>From the output, we understand that the same virtual thread jumps from one platform thread it was running in at the beginning to another when it comes back from sleeping.</p><p>This is what happens in the mount and unmount process and at the core of this, there is a <a href="https://github.com/openjdk/loom/blob/75a5161d853893dee740bdf458f4461fc449aea1/src/java.base/share/classes/jdk/internal/vm/Continuation.java">Continuation</a> object.</p><pre>// JDK core code<br><br>public Continuation(ContinuationScope scope, Runnable target) {<br>   this.scope = scope;<br>   this.target = target;<br>}</pre><p>When we examine the <a href="https://github.com/openjdk/loom/blob/75a5161d853893dee740bdf458f4461fc449aea1/src/java.base/share/classes/java/lang/VirtualThread.java">VirtualThread</a> class, we see that a virtual thread is implemented as a continuation that is wrapped as a task and scheduled by a java.util.concurrent.Executor.</p><pre>// JDK core code<br><br>private static final ContinuationScope VTHREAD_SCOPE = new ContinuationScope(&quot;VirtualThreads&quot;);<br><br>// scheduler and continuation<br>private final Executor scheduler;<br>private final Continuation cont;<br>private final Runnable runContinuation;<br><br>    … <br><br>VirtualThread(Executor scheduler, String name, int characteristics, Runnable task) {<br>    super(name, characteristics, /*bound*/ false);<br>    Objects.requireNonNull(task);<br><br>    // choose scheduler if not specified<br>    if (scheduler == null) {<br>        Thread parent = Thread.currentThread();<br>        if (parent instanceof VirtualThread vparent) {<br>                scheduler = vparent.scheduler;<br>            } else {<br>                scheduler = DEFAULT_SCHEDULER;<br>            }<br>        }<br><br>        this.scheduler = scheduler;<br>        this.cont = new VThreadContinuation(this, task);<br>        this.runContinuation = this::runContinuation;<br>}<br><br>private static class VThreadContinuation extends Continuation {<br>    VThreadContinuation(VirtualThread vthread, Runnable task) {<br>        super(VTHREAD_SCOPE, () -&gt; vthread.run(task));<br>    }<br><br>    ...        <br>}<br><br>private void runContinuation() {<br>        <br>    ...<br>    <br>    try {<br>        cont.run();<br>    } finally {<br>        if (cont.isDone()) {<br>            afterTerminate(/*executed*/ true);<br>        } else {<br>            afterYield();<br>        }<br>    }<br>}</pre><p>As can you see above, when a virtual thread is created, a continuation object is also created to represent its execution state. This object allows a virtual thread to save its current execution state and later resume from that state, typically on a different thread.</p><p>Let’s look at a pure continuation example for a better grasp.</p><pre>public class ContinuationExample<br>{<br>   public static void main(String[] args) {<br><br><br>       var scope = new ContinuationScope(&quot;MyScope&quot;);<br><br><br>       var continuation = new Continuation(scope, () -&gt; {<br>           System.out.println(&quot;Continuation running&quot;);<br>           Continuation.yield(scope);<br>           System.out.println(&quot;Continuation still running&quot;);<br>       });<br><br><br>       continuation.run();<br>   }<br>}</pre><blockquote>Notice that continuations aren’t exposed as a public API because it is a low-level primitive. They should only be used by library authors to build higher-level APIs such as virtual threads, the builder API to run virtual threads, etc.</blockquote><p>When executing the above example, we will get the following output.</p><blockquote>Continuation running</blockquote><p>When we change the <em>continuation.run();</em> line as below and run the code again, we get a different output.</p><pre>while (!continuation.isDone()){<br>   continuation.run();<br>}</pre><blockquote>Continuation running</blockquote><blockquote>Continuation still running</blockquote><p>As can be seen from the output and mentioned above, a continuation is an object which may suspend or yield execution at some point by itself and, when resumed or invoked, carries out the rest of some computation.</p><p>When a continuation suspends, control is passed outside of the continuation, and when it is resumed, control returns to the last yield point, with the execution context up to the entry point intact.</p><p>That is what happens when a virtual thread was suspended and later resumed. Parking (<em>blocking</em>) virtual thread results in yielding its continuation, and unparking it results in the continuation being resubmitted to the scheduler.</p><blockquote>To provide this behavior, nearly all blocking points in the JDK have been refactored.</blockquote><p>The needed stack frames of the virtual thread are temporarily copied from the heap to the stack of the carrier thread during the process of mounting and they are moved back to the heap during the process of unmounting.</p><p>Thanks to this behavior, the ability to capture, store and resume call stacks that are not part of kernel threads has been added to the JVM.</p><p>Moving the stack frames from the heap to the stack of the carrier thread(<em>i.e to main memory</em>) and vice-versa is the cost of blocking a virtual thread. This cost is pretty cheap compared to the cost of blocking platform threads.</p><p>Because the Java runtime can explicitly control when a virtual thread is suspended and resumed and can schedule other virtual threads to run in the meantime, this structure built on Continuations allows a more fine-grained concurrency model.</p><h3>Conclusion</h3><p>With virtual threads, Project Loom promise that Java developers could write highly scalable applications that made utilize the hardware optimally, without changing their habits.</p><p>This promise is fulfilled by the cheap nature of virtual threads, each associated with carrier threads rather than an OS thread. A virtual thread has a continuation object that represents its execution state.</p><p>Blocking a virtual thread results in yielding its continuation and unparking it results in the continuation being resubmitted to the scheduler. Because the Java runtime can explicitly control when a virtual thread is suspended and resumed, that structure allows a more fine-grained concurrency model for Java.</p><h3>References</h3><ul><li><a href="https://cr.openjdk.org/~rpressler/loom/Loom-Proposal.html">Loom Proposal</a></li><li><a href="https://openjdk.org/jeps/444">JEP 444: Virtual Threads</a></li><li><a href="https://wiki.openjdk.org/display/loom/Main">Loom Wiki</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e54c9d2aec8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[An introduction to Scoped Values in Java]]></title>
            <link>https://hakdogan.medium.com/an-introduction-to-scoped-values-in-java-7b63ff4364a6?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/7b63ff4364a6</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[virtual-threads]]></category>
            <category><![CDATA[structured-concurrency]]></category>
            <category><![CDATA[threadlocal]]></category>
            <category><![CDATA[scoped-values]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Mon, 20 Feb 2023 12:13:24 GMT</pubDate>
            <atom:updated>2023-02-20T12:13:24.398Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/880/1*tT_XBLnYy1_mbxukmN9a-Q.jpeg" /><figcaption><a href="https://umtemple.com/values-matter/">https://umtemple.com/values-matter/</a></figcaption></figure><p>After moving to the six-month release cadence, the Java language has entered a rapid development process.</p><p>While the process introduces many new features, these new features sometimes cause updates to existing APIs and sometimes result in the development of new APIs.</p><p>An example of the second is <a href="https://openjdk.org/jeps/429">Scoped Values</a> which has been included in the JDK since Java 20 as an incubator API.</p><h3>Why were Scoped Values proposed?</h3><p><a href="https://openjdk.org/jeps/425">Virtual threads</a> became a part of JDK as a preview feature in Java 19.</p><p>They are a lightweight implementation of Java threads and promise dramatically reduce the effort of writing, maintaining, and observing high-throughput concurrent applications.</p><p>Virtual threads are cheap by nature. This means that thousands or even millions of virtual threads can be used.</p><p>On the other hand, <a href="https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/lang/ThreadLocal.html">ThreadLocal API</a> has been widely used since Java 1.2 for object sharing between application components without resorting to method arguments.</p><p>At this point, given the aforementioned nature of virtual threads, some problems arise.</p><h3>What is the problem?</h3><p>The ThreadLocal API supports a fully general model of communication that allows any code to mutate the data by calling related methods(<em>eg set(), remove()</em>) at any time, so these variables are mutable.</p><p>In many scenarios, however, Java developers need to work with immutable objects to be passed throughout a process.</p><p>The mentioned communication model of ThreadLocal API isn’t conducive to such transmission, i.e., the simple one-way transmission of immutable data from one application component to another.</p><p>In addition, when a thread-local variable is written via the set() method it is retained for the lifetime of the thread, or until code in the thread calls the remove() method.</p><p>This means that per-thread data is often retained for longer than necessary.</p><p>Hence when using large numbers of threads, or when there is an inheritance relationship between the threads the overhead of thread-local variables may be even higher.</p><p>Considering this described design flaws of thread-local variables, the drawbacks of using them with tens of thousands or even millions of virtual threads are obvious.</p><p>The Scoped Values API proposed to overcome the aforementioned potential problems. They should be preferred to thread-local variables, especially when using large numbers of virtual threads.</p><h3>What are Scoped Values and how to use them?</h3><p>The Scoped Values API allows us to store and share immutable data for a bounded lifetime and only the thread that wrote the data can read it.</p><p>A scoped value is a variable of type ScopedValue and is typically declared as a static final field like a thread-local variable so it can easily be reached from many components.</p><pre>public class PaymentGateway<br>{<br>    public static final ScopedValue&lt;PaymentRequest&gt; PAYMENT_REQUEST = ScopedValue.newInstance();<br>   <br>    //...<br>}</pre><p>Once declared, a scoped value is used as shown below.</p><pre>import static org.jugistanbul.PaymentGateway.PAYMENT_REQUEST;<br><br>public class PaymentProcessor<br>{<br>   public static void createPaymentTask(final PaymentRequest request){<br>       ScopedValue.where(PAYMENT_REQUEST, request)<br>                   .run(() -&gt; PaymentService.getPaidByCreditCard());<br>   }<br>}</pre><p>In the code snippet above, a scoped value and the object to which it is to be bound are passed to the where() method as a key and a value argument.</p><p>The run() call binds the scoped value to the current thread by providing a specific incarnation of it. That makes the scoped value accessible in getPaidByCreditCard() method.</p><p>In this way, notice that the where() and run() methods together provide a one-way sharing of data from one component to another.</p><blockquote>The where() is a method of the <a href="https://download.java.net/java/early_access/loom/docs/api/jdk.incubator.concurrent/jdk/incubator/concurrent/ScopedValue.Carrier.html">Carrier</a> class which is one of the inner classes of ScopedValues. It maps scoped values as keys, to values and returns a new Carrier hence the where() method can be chained.</blockquote><pre>public class PaymentService<br>{<br>   public static void getPaidByCreditCard(){<br>       ValidationService.checkValidity();<br>}</pre><pre>public class ValidationService<br>{<br>   public static void checkValidity(){<br>       PaymentRequest paymentRequest = PaymentGateway.PAYMENT_REQUEST.get();<br>       checkNumber(paymentRequest.cardNumber());<br>   }<br>}</pre><p>The bound scoped value can be read via the value’s get() method during the lifetime of the run() method, the lambda expression, or any method called directly or indirectly from that expression.</p><p>After the run() method finishes, the binding is destroyed or reverts to its previous value when previously bound, in the current thread. That is where the question of “<em>What is the meaning of scoped?</em>” is answered.</p><blockquote>The value’s get() call after destroyed bindings will throw an exception. You can use ScopedValue.isBound() to check if it has a binding for the current thread.</blockquote><p>When a scoped value is written once, then is immutable, which means a caller using a scoped value can reliably pass it as a constant value to its callees in the same thread.</p><p>However, this does not mean that one callee can’t share the same scoped value with a different value with its own callees in the thread. In such cases the ScopedValue API allows a new binding to be established for nested calls, this is called rebinding.</p><p>Let’s say we have a service where we print the payment information after charging the payment.</p><p>We can use the current PaymentRequest instance bound to the current thread for the print process but we don’t want to share sensitive information without masking it such as card number, cardholder name, etc, with the service and any method called directly or indirectly from it. This is where rebinding comes to our help.</p><pre>public class PaymentService<br>{<br>   public static void getPaidByCreditCard(){<br>       ValidationService.checkValidity();<br>       getPaid();<br>       ScopedValue.where(PaymentGateway.PAYMENT_REQUEST, maskedPaymentRequest)<br>       .run(() -&gt; PrintService.printPaymentInfo());<br>   }<br>}</pre><blockquote>The return type of the run() method is void. If the printPaymentInfo() method was returning a value, we can prefer the call() method which calls a value-returned operation to handle the returned value.</blockquote><p>In the above code snippet, the scoped value that was initially bound in createPaymentTask() method, rebinding to a new instance of PaymentRequest in getPaidByCreditCard() method. Hence, during the lifetime of the run method, the accessible object is only this new PaymentRequest instance.</p><p>In short, the Scoped Values API doesn’t allow a method body to change the binding seen by the method itself(<em>it has no method like set()</em>) but allows it to change the binding seen by its callees. This guarantees a bounded lifetime for sharing of the new value.</p><p>As soon as the run() call finishes in the getPaidByCreditCard() method, the binding reverts to its previous value.</p><h3>How to enable cross-thread sharing?</h3><p>Java developers can create their own threads for many reasons. In such a case, if the code running in a child thread needs to access the scoped value how can access it?</p><p>The answer is that use <a href="https://openjdk.org/jeps/428">Structured Concurrency</a> which enables cross-thread sharing.</p><p>Structured Concurrency has been included in the JDK since Java 19 as an incubator API. It treats multiple tasks running in different threads as a single unit of work.</p><p>The principal class of the API is <a href="https://download.java.net/java/early_access/loom/docs/api/jdk.incubator.concurrent/jdk/incubator/concurrent/StructuredTaskScope.html">StructuredTaskScope</a> and scoped values are automatically inherited by all child threads created via it.</p><pre>public static void getPaidByCreditCard() throws InterruptedException, ExecutionException {<br><br>    PaymentRequest request = PaymentGateway.PAYMENT_REQUEST.get();<br><br>    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {<br>        Future&lt;Boolean&gt; validation  = scope.fork(() -&gt; ValidationService.checkValidity());<br>        Future&lt;Boolean&gt; account = scope.fork(() -&gt; UserService.accountChecker());<br>            <br>        scope.join();<br>        scope.throwIfFailed();<br><br>        if(validation.resultNow() &amp;&amp; account.resultNow()){<br>            getPaid();<br>            ScopedValue.where(PaymentGateway.PAYMENT_REQUEST, request.copyOf())<br>                       .run(() -&gt; PrintService.printPaymentInfo());<br>        }<br>    }<br>}</pre><p>The fork() method of StructuredTaskScope starts a new thread to run the given task. In the above code snippet it is called to run the ValidationService.checkValidity() and UserService.accountChecker() methods concurrently, in their own virtual threads.</p><p>StructuredTaskScope.fork() ensures that the binding of the scoped value made in the parent thread code is automatically visible to the child thread. This is an example of scoped value inheritance and it provides enables cross-thread sharing.</p><p>Because, unlike thread-local variables, there is no copying of a parent thread’s scoped value bindings to the child thread, cross-thread sharing occurs with minimal overhead.</p><p>I created a <a href="https://github.com/hakdogan/scoped-values">repository</a> for the scenario discussed in this article, which you can examine.</p><h3>Conclusion</h3><p>The Scoped Values API allows storing and sharing immutable data for a bounded lifetime.</p><p>It is recommended to be used to overcome potential problems that may arise when using thread-local variables, especially with large numbers of virtual threads.</p><p>Scoped Values must be used with Structured Concurrency to enable cross-thread sharing.</p><p>Cross-thread sharing occurs with minimal overhead because no copying of a parent thread’s scoped value bindings to the child thread.</p><p>Note that Scoped Values and Structured Concurrency are still incubator APIs, so they may still be subject to fundamental changes.</p><h3>References</h3><ul><li><a href="https://openjdk.org/jeps/429">Scoped Values</a></li><li><a href="https://openjdk.org/jeps/428">Structured Concurrency</a></li><li><a href="https://openjdk.org/jeps/425">Virtual Threads</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7b63ff4364a6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Serve Azure Storage Resources with Grant Limited Access using SAS?]]></title>
            <link>https://hakdogan.medium.com/how-to-serve-azure-storage-resources-with-grant-limited-access-using-sas-a0dde4fc36bd?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/a0dde4fc36bd</guid>
            <category><![CDATA[azure-storage-blob]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[spring-boot]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Sat, 31 Jul 2021 11:37:55 GMT</pubDate>
            <atom:updated>2021-07-31T11:37:55.455Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*D-VU_bgRsvDlU9uPSJ6ipw.png" /><figcaption><a href="https://mostafaelmasry.com/2020/04/21/copy-files-to-or-from-azure-storage-using-azcopy/">https://mostafaelmasry.com</a></figcaption></figure><p>After the decision to use Azure Cloud Storage for the shared resources at the project I was involved in, by reviewing the SDK, I explored how clients can have limited access to resources. We develop the project with Spring Boot and during my research, I found that the resources are not up-to-date for the current Java SDK and Spring Boot version and the tutorials/examples contain many ceremonies and boilerplates.</p><p>I wrote this article to share my experience and show how to use Azure Storage Blob SDK with more concise and readable code.</p><h3>What is Azure Blob Storage?</h3><p>Azure Blob Storage is Microsoft’s object storage solution that allows you to store a massive amount of unstructured data. Azure Storage Service is a good solution for needs such as streaming video and audio, serving images or documents directly to a browser, etc, as they are accessible using REST APIs.</p><h3>How to Access Blobs and Serve with Spring Boot?</h3><p>Since the target audience of this article is users with the service, I will not talk about some prerequisites such as how to create an Azure Storage account and blob containers, etc. In addition, we usually write the access URLs of the stored resources to the database in production but to avoid complexity, I will not include these steps in my example.</p><p>As a first step, let’s examine the dependencies we will add to our project to configure and manage the Azure Blob service.</p><h3>Dependencies</h3><pre>&lt;dependency&gt;<br>    &lt;groupId&gt;com.azure.spring&lt;/groupId&gt;<br>    &lt;artifactId&gt;azure-spring-boot-starter&lt;/artifactId&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>    &lt;groupId&gt;com.azure.spring&lt;/groupId&gt;<br>    &lt;artifactId&gt;azure-spring-boot-starter-storage&lt;/artifactId&gt;<br>&lt;/dependency&gt;</pre><p><a href="https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/spring/azure-spring-boot-starter">The first artifact</a> is for Spring Boot Starters of Azure services and helps Spring Boot developers to adopt Azure services. It supports Spring Boot 2.1.x, 2.2.x, and 2.3.x.</p><p><a href="https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/spring/azure-spring-boot-starter-storage">The second</a> provides a starter to auto-configure Azure Blob Storage in your Spring project and allows you to interact with Azure Blob Storage using Spring programming model.</p><h3>Configuration</h3><p>The azure-spring-boot-starter-storage dependency requires us to provide values of storage account name and key. In addition to these two values, since we will be using the storage blob resources, we will also provide the endpoint value, which is optional, and connection string value, to be able to inject it at runtime when creating a blob client. You can be found the account key and connection string under Azure Portal ==&gt; Storage Account page ==&gt; Access keys and blob service endpoint URL Azure Portal ==&gt; Storage Account page ==&gt; Endpoints.</p><pre>azure.storage.accountName=${yourAccontName}<br>azure.storage.accountKey=${yourAccontKey}<br>azure.storage.blob-endpoint=${yourAccountBlobEndpoint}<br>azure.storage.connection-string=${yourAccontConnectionString}</pre><h3>Code</h3><p>For the service we will create, we define a default method that returns a BlobClient in the interface that must be implemented by classes that want to access the Storage Account. In order to obtain the client, we need the connection string, the container name, and the name of the resource to be accessed. Let&#39;s explain for readers who are not storage service users. Our blobs are stored in containers, a container can think like a directory on the filesystem holding a set of files.</p><pre>default BlobClient getBlobClient(final String connectionString, final String containerName, final String blobName){<br><br>    return new BlobClientBuilder()<br>            .connectionString(connectionString)<br>            .containerName(containerName)<br>            .blobName(blobName)<br>            .buildClient();<br>}</pre><p>We will call this method in the implementer class for operations such as access and upload to blobs.</p><pre>public String generateAccessUrlWithSAS(final String containerName, final String blobName,<br>               final int amount, final ChronoUnit chronoUnit) {<br>    var blobContainerSasPermission = <br>           new BlobContainerSasPermission().setReadPermission(true);<br>    var builder = <br>           new BlobServiceSasSignatureValues(OffsetDateTime.<em>now</em>()<br>.plus(amount, chronoUnit),<br>            blobContainerSasPermission).setProtocol(SasProtocol.<em>HTTPS_ONLY</em>);<br><br>    var client = getBlobClient(connectionString, containerName, blobName);<br><br>    return client.exists()?String.<em>format</em>(&quot;https://%s.blob.core.windows.net/%s/%s?%s&quot;, client.getAccountName(),<br>            client.getContainerName(), blobName, client.generateSas(builder)):&quot;Resource not found&quot;;<br>}</pre><p>In the generateAccessUrlWithSAS method, we will return access URLs of our resources with the shared access signature(SAS) token to our clients. SAS is a URI that grants restricted access rights to Azure Storage resources. We will distribute that URI to our clients to grant them access to our resources for a specified period of time, with a specified set of permissions. For that, we first configure the BlobContainerSasPermission object. The new BlobContainerSasPermission() initializes a BlobContainerSasPermission object with all fields set to false. We give our clients read permission by setReadPermission(true) on the object.</p><p>Then we configure the BlobServiceSasSignatureValues object with its constructor that accepts two parameters of type OffsetDateTime and BlobContainerSasPermission. The first parameter defines the expiry time for access and the second permissions.</p><p>Notice that the generateAccessUrlWithSAS method has a ChronoUnit type parameter. By passing the ChronoUnit type as the second argument to the plus method of OffsetDateTime, we allowed the user to define declaratively the time specified by the amount parameter in seconds, hours, day, or another type of their choice. We pass the BlobContainerSasPermission object that we just configured as the second argument to theBlobServiceSasSignatureValues object.</p><p>In the final step, we obtain the blob client and return the access URL to be valid for the time defined in the parameters passed to the method if the resource exists, if not, we notify the client that the resource is not found.</p><p>That is all.</p><p>Along with the above method, I have created a <a href="https://github.com/hakdogan/azure-storage-account">repository</a> including the scenario of uploading the specified resource into the storage account, you can examine it.</p><h3>Conclusion</h3><p>Azure Blob Storage is Microsoft’s object storage solution that allows you to store a massive amount of unstructured data. It is a good solution for needs such as streaming video and audio, serving images or documents directly to a browser, etc, as they are accessible using REST APIs. Under the com.azure.storage.blob.sas package, there are suitable objects to generate SAS tokens with more concise and readable coding without boilerplate and to meet the grant limited access need.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a0dde4fc36bd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[HOW TO KEEP ELASTICSEARCH IN SYNC WITH RELATIONAL DATABASES?]]></title>
            <link>https://hakdogan.medium.com/how-to-keep-elasticsearch-in-sync-with-relational-databases-a8c4c2b4c9fe?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/a8c4c2b4c9fe</guid>
            <category><![CDATA[hibernate]]></category>
            <category><![CDATA[full-text-search]]></category>
            <category><![CDATA[elasticsearch]]></category>
            <category><![CDATA[apache-lucene]]></category>
            <category><![CDATA[hibernate-search]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Tue, 08 Dec 2020 12:21:29 GMT</pubDate>
            <atom:updated>2020-12-08T12:23:44.623Z</atom:updated>
            <content:encoded><![CDATA[<h3>How to Keep Elasticsearch in Sync with Relational Databases?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VZrT1vtKC7UVBw7w0zVeBg.jpeg" /><figcaption><a href="https://jazzteam.org/">https://jazzteam.org/</a></figcaption></figure><blockquote>This article was published in <a href="https://www.javaadvent.com/2020/12/how-to-keep-elasticsearch-in-sync-with-relational-databases.html">Java Advent Calendar</a> on December 6, 2020</blockquote><p>Many businesses are looking to take advantage of Elasticsearch’s powerful search capabilities using it in close relationship with existing relational databases. In this context, it’s not rare to use Elasticsearch as a caching layer. At this point, a basic and important need arises which is synchronizing Elasticsearch with the database.</p><p>Roughly, the steps below are followed for synchronization:</p><ul><li>A field is added that contains the update or insertion time to the table that will be kept synchronized with Elasticsearch</li><li>A field is added that contains a boolean for marking record deletion to the table that will be kept synchronized with Elasticsearch</li><li>Both the two fields are used in a query that is periodically executed on the table by a scheduler to request the only records that have been modified, inserted, or deleted since the last execution of the scheduler</li><li>If there are newly added, updated, and deleted records, the business logic is invoked to perform CRUD operations both on Elasticsearch and Database(<em>when there are records deleted</em>)</li><li>Scheduler runtime is stored for use in the next execution period</li></ul><p>This pattern has some assumptions and disadvantages. Firstly, it has an estimate of how often the database is updated and runs the scheduler accordingly. The Database may be updating more frequently than assumed. In this case, users are likely to view stale data. When it’s the opposite we waste resources because one of the main purposes of using the cache layer is to reduce I/O operations on the database.</p><p>Another additional overhead for situations where you’re not returning results from the cache is that database queries should be written to exclude records marked as “<em>deleted</em>“.</p><h3>HIBERNATE SEARCH</h3><p>Hibernate Search is a library that allows keeping your local Apache Lucene indexes or ElasticSearch cluster in sync with your data that extracts from Hibernate ORM based on your domain model. You can get this ability for your application by a few settings and annotations.</p><h3>BASE COMPONENTS</h3><p>Hibernate Search is based on two key components. Since these key components are directly related to the efficient use of the library, let’s take a closer look at them now.</p><h3>MAPPER</h3><p>The mapper component maps your entities to a Lucene index and provides some APIs to perform indexing and searching. The mapper is configured both through annotations on the entities and through configuration properties which are key-value based.</p><h3>BACKEND</h3><p>The backend is the abstraction over the full-text engines. It implements generic indexing and searching interfaces for use by the mapper and delegates to the engine you chose to use in your application for instance Lucene library or a remote Elasticsearch cluster. The mapper configures the backend partly by telling which indexes must exist and what fields they must have. In addition, the backend is configured partly also through configuration properties.</p><p>For providing the following main features, the mapper and backend work together.</p><ul><li><strong>Mass indexing</strong> to import data from a database</li><li><strong>Automatic indexing</strong> to keeping indexes in sync with a database</li><li><strong>Searching</strong> to query an index</li></ul><h3>DEPENDENCIES</h3><p>In order to use Hibernate Search, you will need at least two direct dependencies. One of these dependencies is related to the mapper component.</p><pre>&lt;dependency&gt;<br>   &lt;groupId&gt;org.hibernate.search&lt;/groupId&gt;<br>   &lt;artifactId&gt;hibernate-search-mapper-orm&lt;/artifactId&gt;<br>   &lt;version&gt;6.0.0.CR2&lt;/version&gt;<br>&lt;/dependency&gt;</pre><p>The other one is related to the backend component and depends on your single or multiple node choice. For Lucene:</p><pre>&lt;dependency&gt;<br>   &lt;groupId&gt;org.hibernate.search&lt;/groupId&gt;<br>   &lt;artifactId&gt;hibernate-search-backend-lucene&lt;/artifactId&gt;<br>   &lt;version&gt;6.0.0.CR2&lt;/version&gt;<br>&lt;/dependency&gt;</pre><p>The Lucene backend allows indexing of the entities in a single node and storing these indexes on the local filesystem. The indexes are accessed through direct calls to the Lucene library, without going through the network. Hence, <em>the Lucene backend is only relevant to single-node applications</em>. So if you have a single-node application you can prefer the Lucene backend.</p><p>For Elasticsearch:</p><pre>&lt;dependency&gt;<br>   &lt;groupId&gt;org.hibernate.search&lt;/groupId&gt;<br>   &lt;artifactId&gt;hibernate-search-backend-elasticsearch&lt;/artifactId&gt;<br>   &lt;version&gt;6.0.0.CR2&lt;/version&gt;<br>&lt;/dependency&gt;</pre><p>The Elasticsearch backend allows indexing of the entities on multiple nodes and storing these indexes on a remote Elasticsearch cluster. These indexes are not tied to the application, therefore, accessed through calls to REST APIs.</p><p>Note that you can use both Lucene and Elasticsearch backends at the same time.</p><h3>CONFIGURATION</h3><p>The configuration properties of Hibernate Search can be added to any file from which Hibernate ORM takes its configuration because they are sourced from Hibernate ORM.</p><p>These files can be</p><ul><li>hibernate.properties</li><li>hibernate.cfg.xml</li><li>persistence.xml</li></ul><p>In addition to these files, application properties files of Java runtimes such as <em>Quarkus</em> and <em>Spring</em> can also be used for configuration when you use them.</p><p>Hibernate Search provides sensible defaults for all configuration properties but there are few basic configuration parameters that you cannot avoid explicitly setting for your application in some cases.</p><p>hibernate.search.backend.directory.root This setting is about where indexes will be stored in the file system. It works when you use the Lucene backend. It will store indexes in the current working directory by default</p><ul><li><strong>hibernate.search.backend.hosts</strong> This setting is about defining the Elasticsearch host URL, so it works when you use the Elasticsearch backend. By default, the backend will attempt to connect to localhost:9200</li><li><strong>hibernate.search.backend.protocol</strong> This setting is about defining the protocol. You use this setting explicitly when you need to use https because its default value is http</li><li><strong>hibernate.search.backend.username</strong> and <strong>hibernate.search.backend.password</strong> These settings are about defining the username and password for basic HTTP authentication</li><li><strong>hibernate.search.backend.analysis.configurer</strong> This setting is about defining a bean reference pointing to the analyzer implementation. You use this setting when you need to custom analysis</li></ul><h3>CODING TIME</h3><p>Let’s assume that JUG Istanbul uses a meetup app for meetings organized by itself and the data is stored in a relational database. Their domain models contain an event and host entity.</p><p>Adding a few settings to the application and a few annotations to the entities will be sufficient to take advantage of Elasticsearch’s powerful search capabilities via Hibernate Search. The entities are seen as follows.</p><blockquote>Note: As the reader is assumed to be familiar with the basic concepts of Elasticsearch, these concepts will not be explained in detail.</blockquote><pre>@Entity<br>@Indexed //(1)<br>public class Host<br>{<br>    @Id<br>    @GeneratedValue<br>    @GenericField //(2)<br>    private int id;<br><br>    @KeywordField //(3)<br>    private String firstname;<br><br>    @KeywordField<br>    private String lastname;<br><br>    @FullTextField(analyzer = &quot;english&quot;) //(4)<br>    private String title;<br><br>    @OneToMany(mappedBy = &quot;host&quot;, cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)<br>    @IndexedEmbedded //(5)<br>    private List&lt;Event&gt; events;</pre><p>1) <strong>@Indexed</strong> annotation registers the Host entity for indexing by the full-text search engine i.e Elasticsearch.</p><p>2) <strong>@GenericField</strong> annotation maps the id field to an index field.</p><p>3) <strong>@KeywordField</strong> annotation maps the firstname and lastname fields as a non-analyzed index field, which means that the fields are not tokenized.</p><p>4) <strong>@FullTextField</strong> annotation maps the title field as a specifically full-text search field to an index field. In addition, it defines an analyzer named “<em>english</em>” to gain capabilities like make matches implicitly on words (“<em>tokens</em>“) instead of the full string and return documents consultant while searching for consultation by tokenizing and filtering the string.</p><p>5) <strong>@IndexedEmbedded</strong> annotation includes the associated Event entities into the Host index. The main benefit of this annotation is that it can automatically re-index Host if one of its events is updated, thanks to the bidirectional relation.</p><pre>@Entity<br>@Indexed<br>public class Event<br>{<br>    @Id<br>    @GeneratedValue<br>    @GenericField<br>    private int id;<br><br>    @FullTextField(analyzer = &quot;english&quot;)<br>    private String name;<br><br>    @ManyToOne<br>    @JsonIgnore<br>    private Host host;<br>}</pre><p>These are our entities, so let’s look at how to perform search and CRUD operations on these entities.</p><pre>@GetMapping(path = &quot;/search/event/{name}&quot;, produces = &quot;application/json&quot;)<br>    public List&lt;Event&gt; searchEventsByName(@PathVariable(&quot;name&quot;) String name){<br>        SearchResult&lt;Event&gt; result = searchSession.search(Event.class)<br>                .where( f -&gt; f.simpleQueryString()<br>                        .field(&quot;name&quot;)<br>                        .matching(name))<br>                .fetch(20);<br><br>        logger.info(&quot;Hit count is {}&quot;, result.total().hitCount());<br>        return result.hits();<br>    }<br><br>    @GetMapping(path = &quot;/search/host/name/{name}&quot;, produces = &quot;application/json&quot;)<br>    public List&lt;Host&gt; searchHostsByName(@PathVariable(&quot;name&quot;) String name){<br>        SearchResult&lt;Host&gt; result = searchSession.search(Host.class)<br>                .where( f -&gt; f.simpleQueryString()<br>                        .fields(&quot;firstname&quot;, &quot;lastname&quot;)<br>                        .matching(name))<br>                .fetch(20);<br><br>        logger.info(&quot;Hit count is {}&quot;, result.total().hitCount());<br>        return result.hits();<br>    }<br><br>    @GetMapping(path = &quot;/search/host/title/{title}&quot;, produces = &quot;application/json&quot;)<br>    public List&lt;Host&gt; searchHostsByTitle(@PathVariable(&quot;title&quot;) String title){<br>        SearchResult&lt;Host&gt; result = searchSession.search(Host.class)<br>                .where( f -&gt; f.simpleQueryString()<br>                        .fields(&quot;title&quot;)<br>                        .matching(title))<br>                .fetch(20);<br><br>        logger.info(&quot;Hit count is {}&quot;, result.total().hitCount());<br>        return result.hits();<br>    }<br><br>    @GetMapping(path = &quot;/search/events&quot;, produces = &quot;application/json&quot;)<br>    public List&lt;Event&gt; allEvents(){<br>        SearchResult&lt;Event&gt; result = searchSession.search(Event.class)<br>                .where( f -&gt; f.matchAll())<br>                .fetch(20);<br><br>        logger.info(&quot;Hit count is {}&quot;, result.total().hitCount());<br>        return result.hits();<br>    }<br><br>    @GetMapping(path = &quot;/search/hosts&quot;, produces = &quot;application/json&quot;)<br>    public List&lt;Host&gt; allHosts(){<br>        SearchResult&lt;Host&gt; result = searchSession.search(Host.class)<br>                .where( f -&gt; f.matchAll())<br>                .fetch(20);<br><br>        logger.info(&quot;Hit count is {}&quot;, result.total().hitCount());<br>        return result.hits();<br>    }<br><br>    @Transactional<br>    @PostMapping(path = &quot;/event/add&quot;, consumes = &quot;application/json&quot;, produces = &quot;application/json&quot;)<br>    public Event addEvent(@RequestBody Event event){<br>        entityManager.persist(event);<br>        return event;<br>    }<br><br>    @Transactional<br>    @PostMapping(path = &quot;/event/update&quot;, consumes = &quot;application/json&quot;, produces = &quot;application/json&quot;)<br>    public Event updateEvent(@RequestBody Event event){<br>        entityManager.merge(event);<br>        return event;<br>    }<br><br>    @Transactional<br>    @PostMapping(path = &quot;/host/add&quot;, consumes = &quot;application/json&quot;, produces = &quot;application/json&quot;)<br>    public Host addHost(@RequestBody Host host){<br>        entityManager.persist(host);<br>        return host;<br>    }<br><br>    @Transactional<br>    @PostMapping(path = &quot;/host/update&quot;, consumes = &quot;application/json&quot;, produces = &quot;application/json&quot;)<br>    public Host updateHost(@RequestBody Host host){<br>        entityManager.merge(host);<br>        return host;<br>    }<br><br>    @Transactional<br>    @DeleteMapping(path = &quot;/event/delete/{id}&quot;, produces = &quot;text/plain&quot;)<br>    public String deleteEventById(@PathVariable(&quot;id&quot;) int id){<br>        Event event = entityManager.find(Event.class, id);<br>        entityManager.remove(event);<br>        return String.join(&quot; : &quot;, &quot;Removed&quot;, event.toString());<br>    }</pre><p>When you look at the addEvent, updateEvent, and deleteEvent methods, you won’t notice any difference from the standard JPA usage. The difference is seen in methods such as searchEventsByName and searchHostsByName. In these methods, indices are queried over the Hibernate Search session which is obtained from the injected entity manager by setting the “<em>WHERE</em>” clause.</p><p>In this <a href="https://github.com/hakdogan/hibernate-search">GitHub repository</a> that shows you how to use Hibernate Search with Spring and Quarkus Java runtimes, you can find other details of this example such as configuration, mass indexing, and custom analyzer usage.</p><h3>CONCLUSION</h3><p>Today, the use of full-text search engines such as Elasticsearch as a cache is widespread. In that case, it is essential to keep Elasticsearch synchronized with the database. Hibernate Search meets this requirement elegantly. It indexes your domain model with the help of a few annotations and keeps your local Apache Lucene indexes or ElasticSearch cluster in sync with your data that extracts from Hibernate ORM based on your domain model. While it provides these facilities, it does not distract the developer from the familiar syntax.</p><h3>REFERENCES</h3><p><a href="https://docs.jboss.org/hibernate/search/6.0/reference/en-US/html_single/#preface">Hibernate Search Reference</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a8c4c2b4c9fe" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Prepare Native Image Configuration Files in The Most Complete Format?]]></title>
            <link>https://hakdogan.medium.com/how-to-prepare-native-image-configuration-files-in-the-most-complete-format-b0c21eef6c92?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/b0c21eef6c92</guid>
            <category><![CDATA[graalvm]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[native-image]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Wed, 04 Nov 2020 06:02:16 GMT</pubDate>
            <atom:updated>2020-11-04T06:02:16.182Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="http://www.peoplefinderdirect.co.uk/" src="https://cdn-images-1.medium.com/max/1024/1*sBfHTylm5fhAKdo7ttT9Zw.jpeg" /><figcaption>from <a href="http://www.peoplefinderdirect.co.uk/">http://www.peoplefinderdirect.co.uk/</a></figcaption></figure><p>GraalVM is a high-performance runtime that supports additional programming languages and execution modes but the main thing that makes it popular is a technology to ahead-of-time compile Java code to a standalone executable called native image.</p><h3>Why are Native Image Configuration Files Needed?</h3><p>As every rose has it’s a thorn, although the native image is an exciting technology, it has some limitations due to the nature of ahead-of-time compilation. The native image builder statically analyzes all classes of the application and their dependencies to determine which classes and methods are reachable during the application execution. This is an optimization process and it&#39;s executed according to the closed-world assumption that all application classes need to be known at native image generation time so that the static analysis can process them.</p><p>On the other hand, in the open-world approach, Java developers can look up classes, methods, and fields with their names and access/invoke them by Java Reflection. At this point, a clear conflict arises between the closed-world assumption and the open-world approach. However, the native image builder tries to resolve the target elements in the static analysis time mentioned above to detects calls to the Reflection API but in all cases, it cannot be successful.</p><p>This is the reason GraalVM needs configuration files to use at native image build time for features that follow the open-world approach, such as Dynamic Class Loading, Dynamic Proxy, Reflection, etc.</p><h3>Tracing Agent</h3><p>It could be so easy to prepare the configuration files from scratch for the above-mentioned features when we do not use 3rd party libraries in our application. However, it is an undeniable fact that we needed and used 3rd party libraries widely in real-world applications.</p><p>Let’s think about the difficulty of manual providing configuration files from scratch when using 3rd party libraries with an example. Suppose we have an application that consumes a Kafka topic. The application uses explicitly some classes of the Kafka client depending on record types due to Deserializing need and we know these classes must be defined in the configuration file for the native image generation process. However, other classes can also be accessed via reflection by the client under the hood for consumption and the same need. It is not easy to detect these classes always that are used implicitly from our point of view and this difficulty makes manual preparing the configuration troublesome and error-prone when you want to generate a native image from the application.</p><p>Fortunately, thanks to the tracing agent, preparing these configuration files becomes easier and more convenient. The agent tracks all usages of dynamic features of execution on a regular Java VM and creates configuration files in the directory you defined at the command-line.</p><h3>How Can I Use?</h3><p>You can enable the agent on the command line of the GraalVM java command.</p><pre>$GRAAL_HOME/bin/java -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/ -jar /path/to/jar-dir/</pre><p>Notice that, -agentlib option must be specified before the -jar option(<em>similarly before the class name</em>) and any other application parameters in the java command line.</p><p>During execution, the agent intercepts all calls related to the limitations mentioned earlier, and after the JVM process terminates, it generates the configuration files based on the calls it interrupts in the specified output directory. You will have the following files after execution.</p><ul><li>jni-config.json</li><li>reflect-config.json</li><li>proxy-config.json</li><li>resource-config.json</li></ul><p>These files are standalone configuration files in JSON format which contain all intercepted dynamic accesses. For our hypothetical example mentioned above, the contents of the reflect-config.json file would be as follows.</p><pre>{<br> &quot;name&quot;:&quot;org.apache.kafka.clients.consumer.RangeAssignor&quot;,<br> &quot;methods&quot;:[{&quot;name&quot;:&quot;&lt;init&gt;&quot;,&quot;parameterTypes&quot;:[] }]<br>},<br>{<br> &quot;name&quot;:&quot;org.apache.kafka.common.serialization.StringDeserializer&quot;<br>},<br>{<br> &quot;name&quot;:&quot;org.apache.kafka.common.utils.AppInfoParser$AppInfo&quot;,<br> &quot;allPublicConstructors&quot;:true<br>},<br>{<br> &quot;name&quot;:&quot;org.apache.kafka.common.utils.AppInfoParser$AppInfoMBean&quot;,<br> &quot;allPublicMethods&quot;:true<br>}</pre><p><em>Lines unrelated to our 3rd party library have been omitted to reduce the length of the file.</em></p><p>In most cases, to get the most better coverage of dynamic accesses, you want to run the target application more than once with different inputs to trigger separate execution paths. In this case, you can use config-merge-dir option which augments the configuration files by adding the intercepted accesses to existing files.</p><h3>Manually Inspection The Configuration Files</h3><p>The developers of GraalVM suggest manual inspection of the generated configuration files because the agent observes only code that was executed. Depending on your usage scenario, it&#39;s always possible was missed some elements in the resulting configuration files. In addition, the agent <a href="https://github.com/oracle/graal/issues/2951">isn&#39;t perfect</a>, so it can generate non-compatible entries with the runtime environment hence you shouldn&#39;t hesitate to make changes manually on the files when the need arises.</p><h3>Conclusion</h3><p>GraalVM executes the native image build process according to the closed-world assumption that means all application classes need to be known at native image generation time. Hence, it needs configuration files to use at native image build time for supporting some features that follow the open-world approach, such as Dynamic Class Loading, Dynamic Proxy, Reflection, etc.</p><p>It is difficult and error-prone to manual provide configuration files from scratch when using 3rd party libraries. The tracing agent is a facilitating solution at this point. It intercepts all dynamic calls and then generates the configuration files based on the calls. Because the agent observes only code that was executed, it is most important to run the target application more than once with different inputs to trigger separate execution paths for getting better coverage of dynamic accesses.</p><h3>References</h3><p><a href="https://www.graalvm.org/docs/introduction/">GraalVM Documentation</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b0c21eef6c92" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Write Embedded Integration and E2E Tests for JakartaEE]]></title>
            <link>https://hakdogan.medium.com/how-to-write-embedded-integration-and-e2e-tests-for-jakartaee-6373931cbb94?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/6373931cbb94</guid>
            <category><![CDATA[integration-testing]]></category>
            <category><![CDATA[jakarta-ee]]></category>
            <category><![CDATA[end-to-end-testing]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Tue, 30 Jun 2020 17:19:45 GMT</pubDate>
            <atom:updated>2020-06-30T17:19:45.662Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="from IWA website https://interwork.org" src="https://cdn-images-1.medium.com/max/960/1*2HlFrOord_aDT4VBspniSA.jpeg" /><figcaption>from IWA website <a href="https://interwork.org">https://interwork.org</a></figcaption></figure><p>The end-to-end testing in enterprise applications is important as long as it covers the real use cases. Therefore, even although companies focus more on integration tests, end-to-end tests are not neglected. Another common need, called System Integration Testing, present-day is that perform to verify the interactions between the modules of a software system.</p><p>To be honest, outside the dev environment(<em>for example in CI/CD pipelines</em>), meet all these needs is a little harder at JakartaEE(<em>previously Java EE</em>) compared to Spring Framework. You must provide additional dependencies and configurations because by naturally there is no built-in embedded server support.</p><p>In this article, I will try to introduce <a href="http://arquillian.org/">Arquillian</a> and <a href="https://microshed.org/microshed-testing/">MicroShed</a> test frameworks and explain how you can use them to meet the mentioned needs. You can find the example that we will discuss in this article on <a href="https://github.com/hakdogan/jakartaee-testing">GitHub</a>.</p><h3>Before Started</h3><p>To embody the mentioned needs we will consider a microservices example consisting of two services.</p><ul><li>Order Service</li><li>Validation Service</li></ul><p>The Order Service is responsible for the persisting of the Order Demand object from the client request body to the Database after the credit card number inside the object is verified by the Validation Service. The Validation Service is responsible for validating the credit card number that passed by the Order Service. It returns a flag about whether the number is validated or not with short info.</p><p>It can be noticed immediately, that the Validation Service does not depend on any other service or system component due to its mission. Conversely, the Order Service depends on the Validation Service and it must persist the validated object to the Database.</p><p>So we need an integration test to evaluate the compliance of the Validation Service with the specified functional requirement. As for the Order Service, we can&#39;t just do integration testing because it is dependent on other system components. We need an end-to-end test to detect defects within all layers.</p><p>For these reasons, we will use Arquillian for integration testing and MicroShed Testing for end-to-end testing.</p><h3>How to Write Embedded Tests with Arquillian?</h3><p>Arquillian is a testing framework for Java applications. Its main benefit is to handles the application server lifecycle for you. This facility provided by container adapters. Arquillian has many container adapters. Because the adapter depends on the application server you want to use so the details of these adapters and how to configure these are out of scope this article. You can be found more details about Arquillian Container Adapters <a href="http://arquillian.org/modules/">here</a>.</p><p>I used <a href="http://arquillian.org/modules/arquillian-liberty-managed-container-adapter/">Liberty Managed Container Adapter</a> with Liberty Maven plug-in in this example for managing Arquillian dependencies and the setup to Arquillian Managed Container. All these configuration details can be found on the <a href="https://github.com/hakdogan/jakartaee-testing">repository</a>.</p><p>Let’s now focus on how to write tests with Arquillian. We’ll develop test to verify the Validation Service as an endpoint and the functions of the OrderController class. The test looks like below:</p><pre><a href="http://twitter.com/RunWith">@RunWith</a>(Arquillian.class) //(1)<br>public class ValidationServiceIT <br>{</pre><pre>private final Client client;<br>   private static final String PATH = &quot;api/validation/{cardNumber}&quot;;</pre><pre>public ValidationServiceIT() {<br>       this.client = ClientBuilder.newClient();<br>       client.register(JsrJsonpProvider.class);<br>   }</pre><pre><a href="http://twitter.com/ArquillianResource">@ArquillianResource</a> //(2)<br>   private URL baseURL;</pre><pre><a href="http://twitter.com/Deployment">@Deployment</a> //(3)<br>   public static WebArchive createDeployment() {<br>       final WebArchive archive = ShrinkWrap.create(WebArchive.class,<br>               &quot;arquillian-validation-service.war&quot;) //(4)<br>               .addClasses(ValidationController.class, ValidationService.class); //(5)<br>       return archive;<br>   }</pre><pre><a href="http://twitter.com/Test">@Test</a><br>   <a href="http://twitter.com/RunAsClient">@RunAsClient</a> //(6)<br>   <a href="http://twitter.com/InSequence">@InSequence</a>(1) //(7)<br>   public void invalidCardNumberTest() {</pre><pre>final WebTarget webTarget = client.target(baseURL.toString()).path(PATH)<br>               .resolveTemplate(&quot;cardNumber&quot;, &quot;hello&quot;);</pre><pre>final Response response = webTarget.request().get();<br>       final JsonObject result = response.readEntity(JsonObject.class);<br>       Assert.assertFalse(result.getBoolean(&quot;approval&quot;));<br>   }</pre><pre><a href="http://twitter.com/Test">@Test</a><br>   <a href="http://twitter.com/RunAsClient">@RunAsClient</a><br>   <a href="http://twitter.com/InSequence">@InSequence</a>(2)<br>   public void validCardNumberTest() {</pre><pre>final WebTarget webTarget = client.target(baseURL.toString()).path(PATH)<br>               .resolveTemplate(&quot;cardNumber&quot;, &quot;12345&quot;);</pre><pre>final Response response = webTarget.request().get();<br>       final JsonObject result = response.readEntity(JsonObject.class);<br>       Assert.assertTrue(result.getBoolean(&quot;approval&quot;));<br>   }</pre><pre>}</pre><p>Let’s examine how this works in detail by explaining all the marked pieces.</p><p>1) Firstly, with the @RunWith annotation, we tell JUnit to run the tests using Arquillian, so JUnit runs the tests with Arquillian runner instead of the JUnit runner.</p><p>2) To avoid hardcoding define of hostname, port number, and web archive information we use the @ArquillianResource annotation and in this way retrieve the base URL(<em>http://localhost:9090/arquillian-validation-service/, in our example</em>).</p><p>3) We must define a method that returns a web archive to deploy our application onto the server we use(<em>Open Liberty, in this example</em>). The method should be annotated with @Deployment annotation(<em>it has an attribute of testable which enables the deployment to run the tests in the managed container, use in here is redundant because its default value is true</em>) and have public static access modifiers with no arguments. The createDeployment method fulfills these responsibilities.</p><p>4) Notice the arquillian-validation-service.war name passed as the second parameter of the ShrinkWrap.create method. You should provide a name if you don’t want a randomly generated web archive name.</p><p>5) To avoid injection failures, we must add the dependencies that our test needs because Arquillian does not simply tap the entire classpath, unlike unit tests. We can add what we need to use by addClass, addClassess, addPackages, addAsResource, addAsWebInfResourc, etc methods.</p><p>6) We use @RunAsClient annotation in invalidCardNumberTest and validCardNumberTest methods because we want to verify the Validation Service as an endpoint. The annotation indicates that test cases are to be run on the client-side, so these tests are run against the managed container.</p><p>7) To guarantee the test sequence we use @InSequence annotation.</p><p>In both invalidCardNumberTest and validCardNumberTest methods, we send card numbers by calls the <em>baseURL + api/validation/{cardNumber}</em> endpoint to verify card number. The test checks the validity of the numbers by the approval field of the object returned from the endpoint.</p><p>That is all. The test cases are ready to run. After execute mvn verfy command, in the console output, you can see that the tests are passed.</p><h3>How to Write E2E Tests with MicroShed Testing?</h3><p>Another testing framework is MicroShed for Java microservice applications. It uses <a href="https://www.testcontainers.org/">Testcontainers</a> under the hood hence your application runs inside a Docker container. The main benefit of MicroShed emerges at this point, it allows you to use your containerized application from outside the container, so it offers running true-to-production tests.</p><p>Remember that, in our example, the Order service was dependent on the Validation Service and a Database. This is exactly why we chose MicroShed for this example because it enables us to access the Validation Service and the Database in the test environment by running these components in Docker containers.</p><p>Minimum requirements for a MicroShed test are a class with @MicroShedTest annotation and an ApplicationContainer object in which access modifiers are public static.</p><p>Let’s examine our configuration and test classes.</p><pre>public class AppContainerConfig implements SharedContainerConfiguration // (1)<br>{</pre><pre>private static final String IMAGE_NAME = &quot;hakdogan/validation-service:01&quot;; <br>   private static final String SERVICE_NAME = &quot;validation-service&quot;; <br>   private static final String POSTGRES_NETWORK_ALIASES = &quot;postgres&quot;;<br>   private static final String POSTGRES_USER = &quot;testUser&quot;;<br>   private static final String POSTGRES_PASSWORD = &quot;testPassword&quot;;<br>   private static final String POSTGRES_DB = &quot;orderDB&quot;;</pre><pre>private static final int VALIDATION_SERVICE_HTTP_PORT = 9080;<br>   private static final int VALIDATION_SERVICE_HTTPS_PORT = 9443;<br>   private static final int APPLICATION_SERVICE_HTTP_PORT = 9082;<br>   private static final int APPLICATION_SERVICE_HTTPS_PORT = 9445;<br>   private static final int POSTGRES_DEFAULT_PORT = 5432;</pre><pre>private static Network network = Network.newNetwork();</pre><pre><a href="http://twitter.com/Container">@Container</a> //(2)<br>   public static GenericContainer validationService = new GenericContainer(IMAGE_NAME) //(3)<br>                   .withNetwork(network) //(4)<br>                   .withNetworkAliases(SERVICE_NAME) //(5)<br>                   .withEnv(&quot;HTTP_PORT&quot;, String.valueOf(VALIDATION_SERVICE_HTTP_PORT)) //(6)<br>                   .withEnv(&quot;HTTPS_PORT&quot;, String.valueOf(VALIDATION_SERVICE_HTTPS_PORT)) //(7)<br>                   .withExposedPorts(VALIDATION_SERVICE_HTTP_PORT) //(8)<br>                   .waitingFor(Wait.forListeningPort()); //(9)</pre><pre><a href="http://twitter.com/Container">@Container</a><br>   public static PostgreSQLContainer&lt;?&gt; postgres = new PostgreSQLContainer&lt;&gt;() //(10)<br>           .withNetwork(network)<br>           .withNetworkAliases(POSTGRES_NETWORK_ALIASES)<br>           .withUsername(POSTGRES_USER)<br>           .withPassword(POSTGRES_PASSWORD)<br>           .withDatabaseName(POSTGRES_DB)<br>           .withExposedPorts(POSTGRES_DEFAULT_PORT);</pre><pre><a href="http://twitter.com/Container">@Container</a><br>   public static ApplicationContainer app = new ApplicationContainer() //(11)<br>           .withNetwork(network)<br>           .withEnv(&quot;POSTGRES_HOSTNAME&quot;, POSTGRES_NETWORK_ALIASES)<br>           .withEnv(&quot;POSTGRES_PORT&quot;, String.valueOf(POSTGRES_DEFAULT_PORT))<br>           .withEnv(&quot;POSTGRES_USER&quot;, POSTGRES_USER)<br>           .withEnv(&quot;POSTGRES_PASSWORD&quot;, POSTGRES_PASSWORD)<br>           .withEnv(&quot;POSTGRES_DB&quot;, POSTGRES_DB)<br>           .withEnv(&quot;VALIDATION_SERVICE_HOSTNAME&quot;, SERVICE_NAME)<br>           .withEnv(&quot;HTTP_PORT&quot;, String.valueOf(APPLICATION_SERVICE_HTTP_PORT))<br>           .withEnv(&quot;HTTPS_PORT&quot;, String.valueOf(APPLICATION_SERVICE_HTTPS_PORT))<br>           .withExposedPorts(APPLICATION_SERVICE_HTTP_PORT)<br>           .withAppContextRoot(&quot;/&quot;)<br>           .waitingFor(Wait.forListeningPort())<br>           .dependsOn(validationService, postgres); //(12)<br>}</pre><p>Let’s examine how this works in detail by explaining all the marked pieces.</p><p>1) To avoid started a new container for each class we implement SharedContainerConfiguration. In this way, multiple test classes can share the same container instances.</p><p>2) The @Container annotation is used to mark containers that should be managed by the Testcontainers. Apart from Application Container, we have defined two containers in this common configuration class for the components the Order service is dependent on, these are Validation Service and Postgresql database. Notice that the annotation used in all.</p><p>3) The IMAGE_NAME variable contains the Docker image name of the Validation Service that dockerized before.</p><p>4) We use the Network object to create custom networks because we need to communicate between the Validation Service and its dependent components. There fore, we place these components on the same network with the Application Container.</p><p>5) The SERVICE_NAME variable contains the alias name for accessing the Validation Service in the Application Container.</p><p>6–7) The HTTP_PORT and HTTPS_PORT environment variables tell the application server(<em>Open Liberty, in this example</em>) which ports to use. These are included before as placeholders in the server.xml file.</p><p>8) We tell the Testcontainers to expose the HTTP Port of Validation Service.</p><p>9) We tell the Testcontainers to listen to the exposed port to check whether the container is ready for use as a wait strategy.</p><p>10) We define a Postgres container with bootstrap parameters.</p><p>11) We define the application’s container. You can define it in several ways. Putting a Dockerfile in your repository or passing image name to the constructor of ApplicationContainer object as an argument or using vendor-specific adapters as a runtime option that will provide the default logic for building an application container. In this example, we use the last option by added microshed-testing-liberty dependency in pom.xml to automatically producing a testable container image. You can be found other runtime options <a href="https://microshed.org/microshed-testing/features/SupportedRuntimes.html">here</a>.</p><p>12) With that setting, we tell that the application’s container depends on the Validation Service and Postgres containers.</p><p>Let’s examine our test class. It looks like below.</p><pre><a href="http://twitter.com/MicroShedTest">@MicroShedTest</a> //(1)<br><a href="http://twitter.com/SharedContainerConfi">@SharedContainerConfi</a>g(AppContainerConfig.class) //(2)<br><a href="http://twitter.com/TestMethodOrder">@TestMethodOrder</a>(MethodOrderer.OrderAnnotation.class) //(3)<br>public class SystemTest<br>{<br>   <a href="http://twitter.com/RESTClient">@RESTClient</a> //(4)<br>   public static OrderController orderController;</pre><pre><a href="http://twitter.com/Test">@Test</a><br>   <a href="http://twitter.com/Order">@Order</a>(1)<br>   public void invalidCardNumberTest(){<br>       final OrderDemand order = new OrderDemand(1, 1, &quot;&quot;, &quot;hello&quot;);<br>       final Response response = orderController.saveOrder(order);<br>       Assert.assertEquals(false, response.readEntity(JsonObject.class).getBoolean(&quot;approval&quot;));<br>   }</pre><pre><a href="http://twitter.com/Test">@Test</a><br>   <a href="http://twitter.com/Order">@Order</a>(2)<br>   public void validCardNumberTest(){<br>       final OrderDemand order = new OrderDemand(1, 1, &quot;&quot;, &quot;1234567&quot;);<br>       final Response response = orderController.saveOrder(order);<br>       Assert.assertNotNull(response.readEntity(OrderDemand.class).getId());<br>   }<br>  <br>   <a href="http://twitter.com/Test">@Test</a><br>   <a href="http://twitter.com/Order">@Order</a>(3)<br>   public void getAllOrderTest(){<br>       final Response response = orderController.getAllOrders();<br>       final List&lt;OrderDemand&gt; list = response.readEntity(List.class);<br>       Assert.assertFalse(list.isEmpty());<br>   }</pre><pre><a href="http://twitter.com/Test">@Test</a><br>   <a href="http://twitter.com/Order">@Order</a>(4)<br>   public void getAllOrderByProductIdTest(){<br>       final Response response = orderController.getAllOrdersByProductId(1);<br>       final List&lt;OrderDemand&gt; list = response.readEntity(List.class);<br>       Assert.assertFalse(list.isEmpty());<br>    }<br>}</pre><p>Let’s examine how this works in detail by explaining all the marked pieces.</p><p>1) We indicate with the annotation that the test class uses MicroShed Testing.</p><p>2) We define our shared configuration to use by the test class.</p><p>3) MicroShed Testing runs with JUnit Jupiter. We define ordering method with the TestMethodOrder annotation to guarantee the test sequence.</p><p>4) The annotation identifies an injection point for a JAX-RS REST Client. Any method calls to the injected object will be translated to an equivalent REST request via HTTP. The annotated field must be public static and non-final.</p><p>In both invalidCardNumberTest and validCardNumberTest methods we call <em>api/order/save</em> endpoint via orderController reference that annotated with @RESTClient. This endpoint triggers the validation process by calling the Validation Service then persists the object transmitted to it to the Database with request body if the card number is valid.</p><p>In both getAllOrderTest and getAllOrderByProductIdTest methods, after the test case which contains the valid credit card number, we check whether the object persisted or not in the Database.</p><p>In this way, we have done an end-to-end test. After execute mvn verfy command, in the console output, you can see that the tests are passed.</p><h3>Conclusion</h3><p>Embedded tests are almost indispensable in today’s microservices and multitier architectures world, especially in the CI/CD pipelines/environments. Test frameworks like Arquillian and MicroShed(<em>of course also </em><em>Testcontainers</em>) responds to this important need for JakartaEE applications. If we compare the two frameworks, we can tell quickly go through some of the differences.</p><p>Arquillian allows you to inject all objects managed by the CDI container into your test class. MicroShed, on the other hand, only allows JAX-RS resources classes injection to the test class. Arquillian has ceremony and verbosity for XML configuration. MicroShed does not require XML configuration. Arquillian does not give you an option to test the system components that your application depends on, but MicroShed offers. We can say that Arquillian has a strong community, but we cannot say the same for MicroShed.</p><h3>References</h3><p><a href="http://arquillian.org/guides/">Arquillian Guides</a></p><p><a href="https://microshed.org/microshed-testing/">MicroShed Testing</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6373931cbb94" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Java ile Özel Notasyon Geliştirimi]]></title>
            <link>https://hakdogan.medium.com/java-ile-%C3%B6zel-notasyon-geli%C5%9Ftirimi-5875ec5723c8?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/5875ec5723c8</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[annotations]]></category>
            <category><![CDATA[reflections]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Mon, 23 Dec 2019 06:46:35 GMT</pubDate>
            <atom:updated>2019-12-23T06:46:35.773Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/520/1*GOVDlgdAcfUkctkNecYmpg.png" /></figure><p>JDK 1.5 ve üstü bir sürümle geliştirim yapmış her seviyeden Java geliştiricisi notasyon kullanmıştır. @Inject, @Entity, @Autowired, hiç olmadıysa @Override notasyonunu görmemiş, kullanmamış herhalde yoktur. Java dilinin güçlü yanlarından biri olan notasyonlar, birer dekoratör gibi çalışarak; sınıf, yapılandırıcı, metot, alan gibi program yapılarına meta verisi eklememizi sağlar. Geliştiriciye belirli bir eylem/davranışı adeta markalayıp, uygulamanın ihtiyaç duyulan noktalarına enjekte etme olanağı sağlayan notasyonlar, mükerrer kod yazımını azaltıp, kod okunurluğunu artırırlar.</p><p>Notasyonların gücünden, Java geliştiricileri kendi özel notasyonlarını oluşturarak yeterince yararlanmakta mıdır? Başta kendi geliştirim tecrübem olmak üzere kişisel gözlemim ve çeşitli yazı, makale, yayınlanmış anketlerden anladığım; Javacılar notasyon kullanmayı yazmaktan daha çok seviyor. Bu yazıyla amacım, notasyonları daha yakından tanımanıza yardımcı olmak, çalışma mantıklarını göstermek ve basit bir örnek aracılığıyla kendi notasyonunuzu nasıl yazıp kullanabileceğinizi örneklendirerek, özel notasyonların sağladığı avantajlara dikkatinizi çekmek.</p><h4>Nasıl Çalışıyor?</h4><blockquote>An annotation is a marker which associates information with a program construct, but has no effect at run time. <a href="https://docs.oracle.com/javase/specs/jls/se13/html/jls-9.html#jls-9.7">JLS Section 9.7</a></blockquote><p>Java dil belirtiminde ifade edildiği gibi, notasyonlar kendi başlarına çalışma zamanında herhangi bir etkiye sahip değildir. Daha açık bir ifadeyle, <strong>bir notasyon tek başına eklendiği programın çalışma zamanı davranışını değiştirmez.</strong> Aslında bir notasyon, uygulandığı noktada elde edilmek istenen davranışı bildiren bir işaretçi(<em>an annotation is a marker - JSL</em>) gibi davranır. Bu sebeple, notasyonların geliştirici tarafından belirlenmiş davranış/eylemi gerçekleştirmesi için çalışma zamanı çerçeveleri(<em>runtime frameworks</em>) veya derleyici tarafından işlenmesi gerekir. Notasyonlar, derleme zamanında Java derleyicisinin bir tür eklentisi sayılabilecek notasyon işleyiciler(<em>annotation processors</em>), çalışma zamanında ise <em>Java Reflection API</em> tarafından işlenir. Bu yazıda, çalışma zamanında Reflection API ile işlenecek bir notasyon örneğini inceleyeceğiz.</p><h4>Nasıl Tanımlanır?</h4><p>Bir notasyon tanımlamak, arayüz tanımlamaya benzer. Sözdizimsel fark, <em>interface</em> anahtarı başına <em>@ </em>sembolünün getirilmesinden ibarettir.</p><pre><strong>public </strong>@<strong>interface </strong>Monitor {}</pre><p>Bir notasyon oluşturmak için temelde iki bilgiyi sağlamak gerekmektedir. Bunlardan biri <strong>Retention</strong> politikası, diğeri <strong>Target</strong>. Retention politikası, notasyona erişim zamanını tanımlarken, target hangi yapıya(<em>sınıf, method, alan</em>) uygulanacağını tanımlamaktadır.</p><p>Retention politikası, <em>RetentionPolicy </em>ile tanımlanır.<em> </em>RetentionPolicy enum tipinde bir veri yapısıdır ve <em>java.lang.annotation</em> paketi altında bulunmaktadır.</p><pre><strong>package </strong>java.lang.annotation;</pre><pre><em>/**<br>* Annotation retention policy.  The constants of this enumerated type<br>* describe the various policies for retaining annotations.  They are used<br>* in conjunction with the {</em><strong><em>@link </em></strong><em>Retention} meta-annotation type to specify<br>* how long annotations are to be retained.<br>*<br>* </em><strong><em>@author  </em></strong><em>Joshua Bloch<br>* </em><strong><em>@since </em></strong><em>1.5<br>*/</em></pre><pre><strong>public enum </strong>RetentionPolicy {<br><em>/**<br>* Annotations are to be discarded by the compiler.<br>*/<br></em><strong><em>SOURCE</em></strong>,</pre><pre><em>/**<br>* Annotations are to be recorded in the class file by the compiler<br>* but need not be retained by the VM at run time.  This is the default<br>* behavior.<br>*/<br></em><strong><em>CLASS</em></strong>,</pre><pre><em>/**<br>* Annotations are to be recorded in the class file by the compiler and<br>* retained by the VM at run time, so they may be read reflectively.<br>*<br>* </em><strong><em>@see </em></strong><em>java.lang.reflect.AnnotatedElement<br>*/<br></em><strong><em>RUNTIME<br></em></strong>}</pre><p>Görüldüğü üzere 3 retention politikası vardır.</p><ul><li><strong>SOURCE:</strong> Notasyon derleyici tarafından atılır.</li><li><strong>CLASS:</strong> Notasyon derleyici tarafından oluşturulan sınıf dosyasına kaydedilir ve JVM tarafından saklanması gerekmez. <em>Varsayılan davranış biçimidir.</em></li><li><strong>RUNTIME:</strong> Notasyon sınıf dosyasına derleyici tarafından kaydedilir ve çalışma zamanında JVM tarafından saklanır, <em>böylece reflection ile okunabilir</em>.</li></ul><p>Runtime, uygulamaların notasyonlara ve ilişkili verilerine reflection ile erişip kod yürütülmesine izin verdiği için en bilinen ve yaygın olarak kullanılan retention politikasıdır.</p><p>Java 9 sonrası, 11 target vardır; bir başka deyişle 11 yapıya notasyon uygulayabiliriz.</p><ul><li><strong>TYPE:</strong> Sınıf, arayüz, notasyon, enum gibi tipleri hedefler</li><li><strong>FIELD:</strong> Sınıf değişkenleri, enum sabitleri gibi alan tiplerini hedefler</li><li><strong>METHOD:</strong> Sınıf metotlarını hedefler</li><li><strong>MODULE:</strong> <em>Java 9 ile gelmiştir</em>, modülleri hedefler</li><li><strong>PARAMETER:</strong> Metot, yapılandırıcı parametrelerini hedefler</li><li><strong>CONSTRUCTOR:</strong> Yapılandırıcıları hedefler</li><li><strong>LOCAL_VARIABLE:</strong> Yerel değişkenleri hedefler</li><li><strong>ANNOTATION_TYPE:</strong> Notasyonları hedefler ve başka bir notasyon ekler</li><li><strong>PACKAGE:</strong> Paketleri hedefler</li><li><strong>TYPE_PARAMETER:</strong> <em>Java 1.8 ile gelmiştir</em>, MyClass&lt;T&gt;’deki T gibi jenerik parametreleri hedefler</li><li><strong>TYPE_USE:</strong> <em>Java 1.8 ile gelmiştir</em>, herhangi bir türün kullanımını(<em>örneğin new ile oluşturulma, arayüz implementasyonu, cast işlemi vb</em>) hedefler</li></ul><h4>Notasyon Parametreleri ve Notasyon Tipleri</h4><p>Notasyonlar program yapılarına meta verisini, parametreleri aracılığıyla ekler. Bir notasyonun parametreye sahip olup olmaması tipini belirler. Parametre bildirimi içermeyen notasyonlar işaretçi notasyon(<em>marker annotation type</em>) türünü, tek bir parametre bildirimi içeren notasyonlar tek elemanlı(<em>single element annotation type</em>), birden fazla parametre bildirimi içeren notasyonlar ise kompleks notasyon(<em>complex annotation type</em>) türünü oluşturur. Primitif tipler, String, Class, Enum, bir başka notasyon ve bu anılan tiplerin dizi tipi, bir notasyon parametresi olarak bildirilebilir.</p><h4>Senaryomuz</h4><p>Profiling için kodumuzda çalışma sürelerini ölçmek istediğimiz metotlara sahip olduğumuzu düşünelim. Her metodun değil, bazı metotların çalışma süresini ölçmek istiyoruz; üstelik bu metotlara ilerde yenileri eklenebilir. Bunun için bir notasyon yazmak iyi bir fikirdir çünkü en başta belirttiğimiz üzere kod okunurluğunu bozmadan ek olarak aynı davranışı tekrar tekrar dilediğimiz noktalarda(<em>örneğin kodumuza eklenecek yeni metotlarda</em>) elde etmek için notasyonlar biçilmiş kaftandır.</p><pre>@Retention(RetentionPolicy.<strong><em>RUNTIME</em></strong>)<br>@Target(ElementType.<strong><em>METHOD</em></strong>)<br><strong>public </strong>@<strong>interface </strong>Monitor<br>{<br>MonitorPolicy value();<br>}</pre><p>Retention policy ve Target’tan daha önce bahsettiğimiz için, yukarıda görülen notasyonun çalışma zamanında Reflection API ile işlenebileceğini ve ancak metotlara(<em>başka bir yapıya uygulanırsa derleme zamanında hata alınır</em>) uygulanabileceğini kestirmeniz zor değil. Bu noktada Target ile ilgili şu detayı da paylaşalım, birden fazla hedef tanımlayabilirsiniz.</p><pre>@Target({ElementType.<strong><em>FIELD</em></strong>, ElementType.<strong><em>METHOD</em></strong>})</pre><p>Notasyonumuzun gövdesinde ise enum tipinde <em>MonitorPolicy</em> parametresinin deklare edildiğini görüyorsunuz. İlgili enum değerine çalışma zamanında <em>value()</em> metodu üzerinden erişeceğimiz gibi, notasyonumuza değer geçirmek için value’yu anahtar olarak da kullanabiliriz.</p><pre>@Monitor(value = MonitorPolicy.<strong><em>SHORT</em></strong>)</pre><p>Fakat değer geçirmek için value anahtarını kullanmak zorunlu değildir. Aşağıdaki kullanım ile yukarıdaki eşdeğerdir.</p><pre>@Monitor(MonitorPolicy.<strong><em>SHORT</em></strong>)</pre><p>Value dışında farklı bir ismi kullansaydık bunu belirtmemiz gerekirdi çünkü value, notasyonlarda varsayılan anahtar ismidir. MonitorPolicy <em>SHORT</em> ve <em>DETAILED</em> değerlerine sahiptir. Bu değerlerle, çalışma süresini ölçeceğimiz metotlara dair döndürülecek bilginin biçimini belirliyoruz, ayrıntılı veya kısa.</p><pre><strong>enum </strong>MonitorPolicy <br>{<br><strong><em>SHORT</em></strong>,<strong><em>DETAILED<br></em></strong>}</pre><p>Tanımladığımız parametreye varsayılan bir değer atamak istediğimizde ise default anahtarını kullanırız.</p><pre>MonitorPolicy value() <strong>default </strong>MonitorPolicy.<strong><em>SHORT</em></strong>;</pre><p>Bu durumda aşağıdaki gibi bir kullanımda, monitor policy short olacaktır.</p><pre>@Monitor<br><strong>public </strong>String getUserInfo(){<br>   //Make HTTP request<br>}</pre><h4>İşleyicimiz</h4><p>Daha önce ifade ettiğimiz gibi, notasyonlar kendi başlarına herhangi bir kod çalıştırmazlar. Monitor notasyonunda Retention policy olarak RUNTIME tanımlandığı için, çalışma zamanında Java Reflection API kullanılarak işlenmesi gerekir. Aşağıdaki metot bu vazifeyi gerçekleştirir.</p><pre><strong>public static </strong>String executor(<strong>final </strong>Object object, <strong>final </strong>Object... passedParameters) {<br>    <em>checkObjectReference</em>(object);<br>    <strong>final </strong>StringBuilder result = <strong>new </strong>StringBuilder();<br>    <strong>final </strong>Method[] methods = object.getClass().getDeclaredMethods();<br>    <strong>for</strong>(Method method :methods){<br>        <strong>if</strong>(method.isAnnotationPresent(Monitor.<strong>class</strong>)){<br>            <strong>if</strong>(passedParameters.<strong>length </strong>&gt; 0){<br>                result.append(<em>invoker</em>(method, object, passedParameters));<br>            } <strong>else </strong>{<br>                result.append(<em>invoker</em>(method, object));<br>            }<br>        }<br>    }<br>    <strong>return </strong>result.toString();<br>}</pre><p>Executor metodu, biri Monitor notasyonunu kullanan sınıf referansı, diğeri <em>varargs</em> tipinde; ölçüm yapılacak metotların parametreleri olmak üzere 2 argüman alıyor.</p><p>Önce object referansı üzerinden, ilgili nesnenin deklare edilmiş metotlarını çekip ardından bir döngü yardımıyla gezilen metotlarda Monitor notasyonunun uygulanıp uygulanmadığını Reflection API’ye ait <em>isAnnotationPresent()</em> metoduyla(<em>metoda notasyon nesnesini geçirdiğimize dikkat edin</em>) kontrol ediyoruz. Monitor notasyonunu uygulayan metod varsa, koşturulması için <em>invoker</em> metodunu çağırıyoruz.</p><pre><strong>private static </strong>String invoker(<strong>final </strong>Method method, Object object, Object... passedParameters) {<br><br>    method.setAccessible(<strong>true</strong>);<br>    <strong>final </strong>StringBuilder result = <strong>new </strong>StringBuilder();<br>    <strong>final </strong>MonitorPolicy policy = method.getAnnotation(Monitor.<strong>class</strong>).value();<br>    <strong>long </strong>start = System.<em>currentTimeMillis</em>();<br><br>    <strong>try </strong>{<br>        <strong>if </strong>(passedParameters.<strong>length </strong>&gt; 0) {<br>            <em>checkTypeMismatch</em>(method.getName(), method.getParameters(), passedParameters);<br>            method.invoke(object, passedParameters);<br>        } <strong>else if</strong>(method.getGenericParameterTypes().<strong>length </strong>&gt; 0){<br>            <strong>throw new </strong>MissingArgumentException(<strong>&quot;The parameter(s) of the &quot; </strong>+ method.getName() + <strong>&quot; method are missing&quot;</strong>);<br>        } <strong>else </strong>{<br>            method.invoke(object);<br>        }<br><br>        <strong>final long </strong>end = System.<em>currentTimeMillis</em>();<br>        <strong>if</strong>(policy.equals(MonitorPolicy.<strong><em>SHORT</em></strong>)){<br>            result.append(end - start).append(<strong>&quot; ms&quot;</strong>);<br>            <strong><em>logger</em></strong>.info( <strong>&quot;{} ms&quot;</strong>, (end - start));<br>        } <strong>else </strong>{<br>            result.append(<strong>&quot;Total execution time of &quot;</strong>)<br>                    .append(method.getName())<br>                    .append(<strong>&quot; method is &quot;</strong>)<br>                    .append(end - start)<br>                    .append(<strong>&quot; ms&quot;</strong>);<br>            <strong><em>logger</em></strong>.info(<strong>&quot;Total execution time of {} method is {} ms&quot;</strong>,  method.getName(), (end - start));<br>        }<br><br>    } <strong>catch ...</strong></pre><p>Public olarak deklare edilmemiş metotlara da erişebilmek için, invoker metodunda ilk olarak <strong>method.setAccessible(true);</strong> ile erişim kontrolünü yapılandırıyoruz; aksi halde private metotlar için <em>IllegalAccessException</em> istisnasıyla karşılaşırız. Sonraki adımda, çağırıldığı yapıyla(<em>bizim örneğimizde metot</em>) ilişkilendirilmiş, belirtilen tipteki(<em>metoda notasyon nesnesini geçirdiğimize dikkat edin</em>) notasyonu döndüren Reflection API’ye ait <em>getAnnotation </em>metodunu kullanarak,<em> </em>notasyonumuzda tanımlanmış değeri çekiyoruz. Bu değeri, çalışma süresine dair bilgiyi çıktılama biçimizi belirlemede kullanacağız. Bu aşamadan sonra, o anki zaman mührünü milisaniye cinsinden <em>start</em> değişkeninde depoluyoruz; Monitor notasyonunu uygulamış metodu, Reflection API’nin <em>invoke</em> metoduyla koşturduktan sonra elde edilen zaman mührünü ise <em>end</em> değişkeninde. Son aşamada ise, <em>MonitorPolicy</em>’ye bağlı olarak çalışma süresini çıktılıyoruz.</p><p>Aşağıda, paylaşılan örnekteki gibi bir kullanımda alacağımız muhtemel çıktıyı görüyorsunuz.</p><pre>@Monitor(MonitorPolicy.<strong><em>DETAILED</em></strong>)<br><strong>public </strong>String getUserInfo(){<br>   //Make HTTP request<br>}</pre><pre>Profiler.<em>executor</em>(<strong>new </strong>User());</pre><blockquote>Total execution time of getUserInfo method is 1459 ms</blockquote><p>Monitor notasyonunu içeren uygulamaya <a href="https://github.com/hakdogan/simpleprofiler">buradan</a> ulaşabilirsiniz.</p><h4>Sonuç</h4><p>Java notasyonları sınıf, yapılandırıcı, metot, alan gibi Java program yapılarına meta verisi eklememizi sağlayan, bu şekilde mükerrer kod yazımını azaltıp, kod okunurluğunu artıran Java dilinin güçlü yanlarından biridir. Notasyonlar kendi başlarına herhangi bir kod çalıştırmazlar, bunun yerine derleyici veya ait oldukları çerçeve(<em>framework</em>) için, uygulandığı noktada elde edilmek istenen davranışı bildiren bir işaretçi gibi davranıp, derleme zamanında <em>Java</em> A<em>nnotation Processors</em>’ler, çalışma zamanında ise <em>Java Reflection API</em> tarafından işlenirler.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5875ec5723c8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Call the Next Handler in Vert.x?]]></title>
            <link>https://hakdogan.medium.com/how-to-call-the-next-handler-in-vert-x-c498506c427c?source=rss-1c6d42742f90------2</link>
            <guid isPermaLink="false">https://medium.com/p/c498506c427c</guid>
            <category><![CDATA[routing]]></category>
            <category><![CDATA[handler]]></category>
            <category><![CDATA[vertx]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Hüseyin Akdoğan]]></dc:creator>
            <pubDate>Tue, 04 Jun 2019 16:44:51 GMT</pubDate>
            <atom:updated>2019-06-05T11:39:58.090Z</atom:updated>
            <content:encoded><![CDATA[<p>In Vert.x, when a Router takes an HTTP request, it finds a matching route (if any) and then it calls the handler of the route passing in an instance of RoutingContext. More than one handler can be bounded to a route. This means that you can tell the router to route this context to the next matching route without ending the response in your handler.</p><p>Let’s assume we want to control and limit the amount of incoming and outgoing network traffic. For example, let’s say we provide a service that is configured to allow 10 requests/second. Similarly, let’s assume we use a circuit breaker for fault detection related to the service that the incoming request wants to access. In this case, If the incoming requests exceed the defined limit, or the service is unavailable, it will be necessary to refuse the request.</p><p>Calling the next handler offers us a useful way to manage the kind of need that’s requiring different controls for the same purpose.</p><h3>Calling the Next Handler</h3><pre>@Override<br><strong>public void </strong>start(Future&lt;Void&gt; future) {<br><br>    <strong>final </strong>ConfigStoreOptions rateOptions = <strong>new </strong>ConfigStoreOptions()<br>            .setType(<strong>&quot;file&quot;</strong>)<br>            .setOptional(<strong>true</strong>)<br>            .setConfig(<strong>new </strong>JsonObject().put(<strong>&quot;path&quot;</strong>, System.<em>getProperty</em>(<strong>&quot;user.dir&quot;</strong>) + <strong>&quot;/Routing/src/main/resources/config.json&quot;</strong>));<br><br>    <strong>final </strong>ConfigRetrieverOptions options = <strong>new </strong>ConfigRetrieverOptions().addStore(rateOptions);<br><br>    <strong>final </strong>Router router = RouterHelper.<em>createRouter</em>(<strong>vertx</strong>, <strong>&quot;Hello from routing example!&quot;</strong>);<br>    router.get(<strong>&quot;/limiting&quot;</strong>).handler(<strong>new </strong>CircuitBreakerHandler(options));<br>    router.get(<strong>&quot;/limiting&quot;</strong>).handler(<strong>new </strong>RateLimiterHandler(options));<br>    HttpServerHelper.<em>createAnHttpServer</em>(<strong>vertx</strong>, router, config(), future);<br>}</pre><p>In the above code, we created two routes for the same path and bounded different handlers. When a GET /limiting request arrives the CircuitBreakerHandler will work first.</p><pre>@Override<br><strong>public void </strong>handle(RoutingContext context) {<br><br>    <strong>final </strong>ConfigRetriever retriever = ConfigRetriever.<em>create</em>(context.vertx(), <strong>options</strong>);<br><br>    retriever.getConfig(ar -&gt; {<br>        <strong>if </strong>(ar.failed()) {<br>            <strong><em>log</em></strong>.error(<strong>&quot;Failed to retrieve the configuration&quot;</strong>);<br>        } <strong>else </strong>{<br><br>            <strong>final </strong>JsonObject config = ar.result();<br>            <strong>final boolean </strong>circuitbreaker = config.getBoolean(<strong>&quot;circuitbreaker&quot;</strong>);<br><br>            <strong>if </strong>(!circuitbreaker) {<br>                context.next();<br>            } <strong>else </strong>{<br>                context.response()<br>                        .putHeader(<strong><em>CONTENT_TYPE</em></strong>, <strong><em>HTML_PRODUCE</em></strong>)<br>                        .setStatusCode(<strong><em>HTTP_SERVICE_UNAVAILABLE</em></strong>)<br>                        .end(<strong>&quot;Service unavailable!&quot;</strong>);<br>            }<br>        }<br>    });<br><br>}</pre><p>In the handler, we are checking firstly to CircuitBreaker and if it’s closed we call next method of the RoutingContext. The next method tell the router to route this context to the next matching route (if any). In our example, this will provide calling RateLimiterHandler. I created a <a href="https://github.com/hakdogan/IntroduceToEclicpseVert.x/tree/master/Routing">repository</a> for this example, you can examine.</p><h3>Conclusion</h3><p>Vert.x allows multiple handlers binding to a route. This provides routing the handled context to the next matching route and so encapsulates your handlers for different logic by linking together such as a chain.</p><h3>References</h3><ul><li><a href="https://vertx.io/docs/vertx-web/java/#_handling_requests_and_calling_the_next_handler">Vert.x-Web for Java</a></li><li><a href="https://vertx.io/docs/apidocs/io/vertx/ext/web/RoutingContext.html">RoutingContext</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c498506c427c" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>