Sorry

This feed does not validate.

In addition, interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: https://feeds.feedburner.com/Wisselnetfeed

  1. <?xml version="1.0"?>
  2. <rss version="2.0">
  3. <channel>
  4. <title>wissel.net Usability - Productivity - Business - The web - Singapore and Twins</title>
  5. <link>https://wissel.net/blog/stories.rss</link>
  6. <description>Thoughts, Insights and Opinions of Stephan H. Wissel. Topics included: Salesforce, Lotus Notes and Domino, IBM Websphere, NodeJS, JavaScript,  J2EE, .Net, Software Archtecture, Personcentric Development, Agile Software, SDLC, Singapore and my Twins</description>
  7. <language>en,de</language>
  8. <copyright>(C) 2003 - 2021 Stephan H. Wissel, All rights reserved</copyright>
  9. <pubdate>Mon, 01 Sep 2025 16:33:08 +0000</pubdate>
  10. <item>
  11. <title>Authentication with PKCE and vanilla JavaScript</title>
  12. <description>&lt;p&gt;Finally you got rid of user management in your application since your organisation has standardized on an &lt;a href="https://www.cloudflare.com/en-gb/learning/access-management/what-is-an-identity-provider/"&gt;IdP&lt;/a&gt;. There are plenty to choose from. I usually develop using a &lt;a href="/blog/2024/10/onetime-idp-with-keycloak.html"&gt;Keycloak&lt;/a&gt; IdP before I test it with the target IdP (and yes: Azure Entrada tries to be different).&lt;/p&gt;
  13. &lt;p&gt;So it's time to adjust your &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/SPA"&gt;SPA&lt;/a&gt; to use the IdP. The admins tell you, you need to use &lt;a href="https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce"&gt;PKCE&lt;/a&gt;, part of the &lt;a href="https://openid.net/developers/how-connect-works/"&gt;OIDC&lt;/a&gt; specification&lt;/p&gt;
  14. &lt;h3&gt;Where is the fun in ready made?&lt;/h3&gt;
  15. &lt;p&gt;A &lt;a href="https://www.npmjs.com/search?q=OIDC&amp;amp;sortBy=downloads_monthly"&gt;quick search on npmjs&lt;/a&gt; shows, the topic is popular and AWS takes the crown. But for deeper understanding, let's roll our own.&lt;/p&gt;
  16. &lt;h3&gt;Prerequisites&lt;/h3&gt;
  17. &lt;p&gt;There are just four items you need. The first three are provided by your IdP admins, the forth one you have to provide to them.&lt;/p&gt;
  18. &lt;ul&gt;
  19. &lt;li&gt;The URL of your IdP, the full path where &lt;code&gt;.well-known&lt;/code&gt; can be found. That's usually the root, but does differ for Entrada or Keycloak&lt;/li&gt;
  20. &lt;li&gt;The issuer. That typically is the URL, except for Entrada&lt;/li&gt;
  21. &lt;li&gt;The clientId. A String, usually opaque&lt;/li&gt;
  22. &lt;li&gt;The callback urls. Pick those wisely. Typically you want three: &lt;code&gt;http://localhost:3000/myApp&lt;/code&gt;, &lt;code&gt;https://localhost:8443/myApp&lt;/code&gt; and &lt;code&gt;https://final.place.com/myApp&lt;/code&gt; The first two enable you to test your application locally with both http and https&lt;/li&gt;
  23. &lt;/ul&gt;</description>
  24. <link>2025/09/authentication-with-pkce-and-vanilla-javascript.html</link>
  25. <author>Stephan H. Wissel</author>
  26. <guid>d41aa310-8734-11f0-8a15-a76556d24dc9</guid>
  27. <pubDate>01 September 2025</pubDate>
  28.  
  29. </item>
  30. <item>
  31. <title>Installing a macOS developer workstation</title>
  32. <description>&lt;p&gt;It is sitting on my desk, a shiny M4 MacBook. It wants to be configured. I can take the easy route and use the &lt;a href="https://support.apple.com/en-sg/102613"&gt;Migration Assistant&lt;/a&gt;. But that would carry forward all the cruft the various incarnations of the Migration Assistant have accumulated over the decade. So I went the hard way.&lt;/p&gt;
  33. &lt;h3&gt;Manual with a dash of AppStore&lt;/h3&gt;
  34. &lt;p&gt;First Stop: update macOS. In my case Sequoia 15.1 -&amp;gt; 15.6.1&lt;/p&gt;
  35. &lt;p&gt;Installation falls into 3 categories&lt;/p&gt;
  36. &lt;ul&gt;
  37. &lt;li&gt;command line tooling&lt;/li&gt;
  38. &lt;li&gt;settings &amp;amp; data&lt;/li&gt;
  39. &lt;li&gt;GUI applications&lt;/li&gt;
  40. &lt;/ul&gt;
  41. &lt;p&gt;Followed by the reconfiguration of license keys&lt;/p&gt;</description>
  42. <link>2025/08/installing-a-macos-developer-workstation.html</link>
  43. <author>Stephan H. Wissel</author>
  44. <guid>ab012430-84d3-11f0-a69f-6fd5883f9ade</guid>
  45. <pubDate>29 August 2025</pubDate>
  46.  
  47. </item>
  48. <item>
  49. <title>CouchDB, JWKS and PEM public keys</title>
  50. <description>&lt;p&gt;Depending on &lt;a href="/blog/2024/06/how-deep-do-you-authenticate.html"&gt;how deep you authenticate&lt;/a&gt;, you might be tasked maintaining a user base in &lt;code&gt;_users&lt;/code&gt; (and welcome to "I forgot my password" hell). The standing recommendation is to implement a single source of identity using a directory as &lt;a href="https://www.cloudflare.com/learning/access-management/what-is-an-identity-provider"&gt;Identity Provider (IdP)&lt;/a&gt;. My favorite &lt;a href="https://couchdb.apache.org/"&gt;NoSQL database&lt;/a&gt; can be &lt;a href="https://docs.couchdb.org/en/stable/api/server/authn.html#jwt-authentication"&gt;configured&lt;/a&gt; to trust JWT signed by known IdPs, so let's do that.&lt;/p&gt;
  51. &lt;h3&gt;Some assembly required&lt;/h3&gt;
  52. &lt;p&gt;CouchDB can be configured in three ways: Edit the respective ini file, use the Fauxton UI or use the REST API. I like the later since I'm comfortable with &lt;a href="https://curl.se/"&gt;curl&lt;/a&gt; and &lt;a href="https://www.usebruno.com/"&gt;Bruno&lt;/a&gt; (not a fan of Postman anymore). The steps are:&lt;/p&gt;
  53. &lt;ul&gt;
  54. &lt;li&gt;configure a client on your identity provider&lt;/li&gt;
  55. &lt;li&gt;enable JWT authentication&lt;/li&gt;
  56. &lt;li&gt;specify what claims are mandatory&lt;/li&gt;
  57. &lt;li&gt;specify how to map roles&lt;/li&gt;
  58. &lt;li&gt;add trustedd public keys&lt;/li&gt;
  59. &lt;li&gt;restart your node&lt;/li&gt;
  60. &lt;/ul&gt;</description>
  61. <link>2025/07/couchdb-and-jwks.html</link>
  62. <author>Stephan H. Wissel</author>
  63. <guid>268f01d0-6d46-11f0-802c-d975bb98b8ec</guid>
  64. <pubDate>30 July 2025</pubDate>
  65.  
  66. </item>
  67. <item>
  68. <title>Report your CSP (violations)</title>
  69. <description>&lt;p&gt;I'm a big fan of a strict &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP"&gt;Content Security Policy (CSP)&lt;/a&gt;. It can be a pain to setup (but there is help, &lt;a href="https://report-uri.com/home/generate"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://cybeready.com/top-9-content-security-policy-generators/"&gt;here&lt;/a&gt;, &lt;a href="https://chromewebstore.google.com/detail/content-security-policy-c/ahlnecfloencbkpfnpljbojmjkfgnmdc?hl=en"&gt;here&lt;/a&gt; and &lt;a href="https://www.quantcdn.io/tools/automatic-csp-generator"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;) and &lt;a href="https://csp-evaluator.withgoogle.com/"&gt;evaluate&lt;/a&gt;.&lt;/p&gt;
  70. &lt;h3&gt;Let's report it&lt;/h3&gt;
  71. &lt;p&gt;You won't know if a policy was tried to be violated unless the attempt is reported back to your application. For that purpose we use the CSP directives &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/report-to"&gt;&lt;code&gt;report-to&lt;/code&gt;&lt;/a&gt; and the older, deprecated &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/report-uri"&gt;&lt;code&gt;report-uri&lt;/code&gt;&lt;/a&gt;. Until Firefox catches up, use both. When a browser supports &lt;code&gt;report-to&lt;/code&gt;, &lt;code&gt;report-uri&lt;/code&gt; gets ignored.&lt;/p&gt;
  72. &lt;p&gt;Reporting isn't only useful in production, but already during development and especially during retrofitting. There you can swap the &lt;code&gt;Content-Security-Policy&lt;/code&gt; header for &lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt;. It will allow all content to load, but report back all violations.&lt;/p&gt;
  73. &lt;p&gt;You then run your &lt;a href="https://www.browserstack.com/guide/end-to-end-testing"&gt;E2E Tests&lt;/a&gt; (You have those, haven't you?) and get a free overview what loads from where. Adjust the CSP, rinse and repeat.&lt;/p&gt;
  74. &lt;h3&gt;Where to report to?&lt;/h3&gt;
  75. &lt;p&gt;There are numerous SaaS providers with fancy dashboards, that offer ready made solutions. When you are pressed for time, that might be your best option. I haven't evaluated them, so I can't recommend or endorse them.&lt;/p&gt;</description>
  76. <link>2025/07/report-your-csp.html</link>
  77. <author>Stephan H. Wissel</author>
  78. <guid>e2912cf0-6148-11f0-b6bc-9dae663e3d57</guid>
  79. <pubDate>07 July 2025</pubDate>
  80.  
  81. </item>
  82. <item>
  83. <title>HTML's template element in single page applications</title>
  84. <description>&lt;p&gt;"&lt;em&gt;We need to use [insert-framework-of-the-day]!&lt;/em&gt;" is the typical answer when asking for a light web single page application (SPA).&lt;/p&gt;
  85. &lt;p&gt;It doesn't need to be that way, &lt;a href="https://paulswithers.github.io/"&gt;Paul&lt;/a&gt; and myself shared in a &lt;a href="https://github.com/paulswithers/super-procode-mode-openntf"&gt;recent webinar&lt;/a&gt;.&lt;/p&gt;
  86. &lt;h3&gt;Serving the long tail&lt;/h3&gt;
  87. &lt;p&gt;&lt;a href="https://www.wavemaker.com/long-tail-apps-shadow-it-problem/"&gt;Long Tail Apps&lt;/a&gt; tend to be outside of IT control, since they bypass the (usually heavy) standup of an IT development project.&lt;/p&gt;
  88. &lt;p&gt;That standup could be way lighter, when your application just consists of one html file, one css file, one js file, one manifest and (optionally) one or more image files as well as a &lt;a href="https://opensource.hcltechsw.com/Domino-rest-api/references/hostingstatic.html"&gt;definded point of deployment&lt;/a&gt;.&lt;/p&gt;
  89. &lt;p&gt;The typical objection goes: "&lt;em&gt;But it is never one HTML file, I need a login, a list and a form in read and edit mode&lt;/em&gt;"&lt;/p&gt;
  90. &lt;h3&gt;template to the rescue&lt;/h3&gt;
  91. &lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/template"&gt;&lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt;&lt;/a&gt; element is part of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components"&gt;WebComponents&lt;/a&gt; specification and it is useful in simple SPA applications.&lt;/p&gt;</description>
  92. <link>2025/06/html-templates-spa.html</link>
  93. <author>Stephan H. Wissel</author>
  94. <guid>bfdb1860-5009-11f0-9a8e-691adff7d010</guid>
  95. <pubDate>23 June 2025</pubDate>
  96.  
  97. </item>
  98. <item>
  99. <title>Fun with AI system prompts</title>
  100. <description>&lt;p&gt;&lt;a href="https://www.google.com/search?q=ai+chatbots"&gt;AI Chatbots&lt;/a&gt; are a popular topic. As part of a session at &lt;a href="https://engage.ug/"&gt;Engage 2025&lt;/a&gt; I was looking for an easy to grasp example to understand the difference of user prompt and system prompt, the later typically invisible to the user. My goal was to make it abundantly clear how important the system prompt is.&lt;/p&gt;
  101. &lt;p&gt;I settled sending the same user prompt with vastly different system prompts. Here is what I got.&lt;/p&gt;
  102. &lt;h3&gt;Romeo at the balcony&lt;/h3&gt;
  103. &lt;p&gt;Mercutio?s mocking my love and he?s never been in love himself.&lt;/p&gt;
  104. &lt;p&gt;Wait. What?s that light coming from the window over there? It?s like the east, with Juliet as the morning sun! Rise, Juliet, beautiful sun, and kill the jealous moon who?s already fading and sad because you are far more beautiful than she is. Don?t swear off men like the virgin moon goddess Diana?the moon envies you anyway. Her virginal appearance is weak and pale and only fools want to emulate it. Get rid of it.&lt;/p&gt;
  105. &lt;p&gt;It?s my lady! Oh, it?s my love. Oh, if only she knew I love her. She?s talking but I can?t hear anything. What does it matter?&lt;/p&gt;
  106. &lt;p&gt;Her expression means something and I can answer that. No, I?m being too forward. She?s not talking to me. Oh, if two of the most beautiful stars had to leave heaven on important business, they?d ask her eyes to do the twinkling for them while they were gone! What if her eyes took their places in the sky and those stars became her eyes? Her beautiful face would outshine those stars in her head like daylight outshines lamps, while her eyes in the sky would be so bright at nighttime that birds would be convinced it was day. Look at how she leans her cheek on her hand. I wish I were a glove on her hand so I could touch her cheek!&lt;/p&gt;</description>
  107. <link>2025/05/fun-with-ai-system-prompts.html</link>
  108. <author>Stephan H. Wissel</author>
  109. <guid>d4495700-365d-11f0-87fb-618e413f1645</guid>
  110. <pubDate>07 May 2025</pubDate>
  111.  
  112. </item>
  113. <item>
  114. <title>Deploying a Single Page Application using the Domino REST API</title>
  115. <description>&lt;p&gt;The &lt;a href="https://opensource.hcltechsw.com/Domino-rest-api/"&gt;Domino REST API&lt;/a&gt; not only provides secure access to "jsonified" Domino data,&lt;br&gt;
  116.  but also comes with capabilities to ease integration. This enables one to quickly cater to &lt;a href="https://en.wikipedia.org/wiki/Long_tail"&gt;the long tail&lt;/a&gt; of applications, giving them a home instead of loosing them to the shadow IT.&lt;/p&gt;
  117. &lt;p&gt;Once you know the steps, you can deploy new &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/SPA"&gt;Single Purpose Applications&lt;/a&gt; (I modified the meaning of SPA a little) in no time.&lt;/p&gt;
  118. &lt;h3&gt;No CORS, no headache&lt;/h3&gt;
  119. &lt;p&gt;DRAPI allows to &lt;a href="https://opensource.hcltechsw.com/Domino-rest-api/references/hostingstatic.html"&gt;host static applications&lt;/a&gt; in the &lt;code&gt;keepweb.d&lt;/code&gt; directory. "Static" might be a little misnomer (it only relates to the source files, not the interaction) since a JS file can make your experience quite interactive. Since you run on the same Domain and port as the API, you don't need to worry about &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/CORS"&gt;CORS&lt;/a&gt;&lt;/p&gt;
  120. &lt;h3&gt;Preparation&lt;/h3&gt;
  121. &lt;p&gt;Your SPA will live in a sub directory of &lt;code&gt;keepweb.d&lt;/code&gt;, so think about a name, we shall use &lt;code&gt;demo42&lt;/code&gt; here. Add a suitable icon (e.g. 72x72 px png), name it &lt;code&gt;demo42.png&lt;/code&gt; and you are ready to roll. Let's assume our Domino API is running on &lt;code&gt;https://api.demo.io&lt;/code&gt;&lt;/p&gt;
  122. &lt;h3&gt;Work faster with vitejs&lt;/h3&gt;
  123. &lt;p&gt;&lt;a href="https://vite.dev/"&gt;viteJS&lt;/a&gt; is one of the fronteand tools you &lt;strong&gt;want&lt;/strong&gt; to learn. It features "hot module reload" to speed up development and, when done, packages your application nice and tidy.&lt;/p&gt;
  124. &lt;p&gt;It is easy to get started. You need a current version (22.x at time of writing) of &lt;a href="https://nodejs.org/en"&gt;nodeJS&lt;/a&gt; installed as development tooling.&lt;/p&gt;
  125. &lt;pre&gt;&lt;code class="language-bash"&gt;npm create vite@latest demo42 -- --template vanilla
  126. cd demo42
  127. npm install
  128. &lt;/code&gt;&lt;/pre&gt;
  129. &lt;p&gt;This will create the demo42 directory and scaffold the project for you. Before we get started with athe development, let's adjust the environment. In the root of the project create a file &lt;code&gt;vite.config.js&lt;/code&gt;&lt;/p&gt;
  130. &lt;pre&gt;&lt;code class="language-js"&gt;import { defineConfig } from 'vite';
  131.  
  132. export default defineConfig({
  133.  base: '/keepweb/demo42/',
  134.  server: {
  135.    proxy: {
  136.      '/api': {
  137.        target: 'https://api.demo.io',
  138.        changeOrigin: true
  139.      }
  140.    }
  141.  }
  142. });
  143. &lt;/code&gt;&lt;/pre&gt;
  144. &lt;p&gt;This allows you to develop in the comfort of your local machine's &lt;a href="https://vite.dev/guide/api-hmr"&gt;hot module reload&lt;/a&gt; which refreshes your app on svae automagically. It also fixes the path matching to its final destination. Next create in &lt;code&gt;public&lt;/code&gt; the file &lt;code&gt;manifest.json&lt;/code&gt;. This file defines the tile layout for the landing page.&lt;/p&gt;
  145. &lt;pre&gt;&lt;code class="language-json"&gt;{
  146.  "short_name": "Demo 42",
  147.  "name": "The final answer to all Demos",
  148.  "start_url": ".",
  149.  "display": "standalone",
  150.  "theme_color": "#000000",
  151.  "background_color": "#aacccc",
  152.  "icon": "vite.svg"
  153. }
  154. &lt;/code&gt;&lt;/pre&gt;
  155. &lt;p&gt;You can play with colors and icons as you deem fit. Now we are ready to run the application:&lt;/p&gt;
  156. &lt;pre&gt;&lt;code class="language-bash"&gt;npm run dev
  157. &lt;/code&gt;&lt;/pre&gt;</description>
  158. <link>2025/03/deploying-a-spa-to-drapi.html</link>
  159. <author>Stephan H. Wissel</author>
  160. <guid>7e85c300-0339-11f0-b3bc-e33450aa6e10</guid>
  161. <pubDate>17 March 2025</pubDate>
  162.  
  163. </item>
  164. <item>
  165. <title>ufw cheatsheet</title>
  166. <description>&lt;p&gt;Mainly as a note to self.&lt;/p&gt;
  167. &lt;h3&gt;My default firewall setup&lt;/h3&gt;
  168. &lt;pre&gt;&lt;code class="language-bash"&gt;sudo ufw status
  169. sudo ufw default allow outgoing
  170. sudo ufw default deny incoming
  171. grep IPV6 /etc/default/ufw
  172. sudo ufw allow ssh
  173. sudo ufw limit ssh/tcp comment 'Rate limit for openssh server'
  174. sudo ufw allow 80/tcp comment 'Allow nginx HTTP'
  175. sudo ufw limit 80 comment 'limit nginx HTTP'
  176. sudo ufw allow 443/tcp comment 'Allow nginx HTTPS'
  177. # For Domino mail
  178. sudo ufw allow 1352/tcp comment 'Allow Notes replication'
  179. sudo ufw allow 25/tcp comment 'Allow SMTP'
  180. sudo ufw allow 587/tcp comment 'Allow SMTP'
  181. sudo ufw allow 110/tcp comment 'Allow POP3'
  182. sudo ufw allow 995/tcp comment 'Allow POP3s'
  183. sudo ufw allow 143/tcp comment 'Allow IMAP'
  184. sudo ufw allow 993/tcp comment 'Allow IMAPs'
  185. sudo ufw allow from 1.2.3.4 'Allow the othe Domino'
  186. sudo ufw enable
  187. &lt;/code&gt;&lt;/pre&gt;</description>
  188. <link>2025/02/ufw-cheatsheet.html</link>
  189. <author>Stephan H. Wissel</author>
  190. <guid>dd7313e0-f3a3-11ef-85ce-6116619fca24</guid>
  191. <pubDate>26 February 2025</pubDate>
  192.  
  193. </item>
  194. <item>
  195. <title>Java Record Derived Creation (stopgap until JEP 468 arrives)</title>
  196. <description>&lt;p&gt;Java 14 (in a preview feature) introduced &lt;a href="https://docs.oracle.com/en/java/javase/14/language/records.html"&gt;Records&lt;/a&gt;. In a nutshell: Records are (&lt;a href="https://codeadventures.littlebluefrog.nl/posts/06-immutability-in-records/"&gt;mostly&lt;/a&gt;) immutable objects with a greatly reduced amount of boilerplate code requirements. For a detailed introduction head over to &lt;a href="https://www.baeldung.com/java-record-keyword"&gt;Baeldung&lt;/a&gt;.&lt;/p&gt;
  197. &lt;h3&gt;When records need update&lt;/h3&gt;
  198. &lt;p&gt;The short answer: create a new record and use the existing as input. Let's look at an example:&lt;/p&gt;
  199. &lt;pre&gt;&lt;code class="language-java"&gt;public record Billionaire(String name, Long wealth, Temporal assessment) {
  200.  
  201.  public Billionaire cloneWithNewAssesment(Long newWealth, Temporal currentAssesment) {
  202.    return new Billionaire(this.name, newWealth,currentAssesment);
  203.  }
  204. }
  205. &lt;/code&gt;&lt;/pre&gt;
  206. &lt;p&gt;By itself this is a clean solution. You might add another function for unchanged assesment values. It gets messy when your records have a few more fields.&lt;/p&gt;
  207. &lt;p&gt;To address this, &lt;a href="https://openjdk.org/jeps/468"&gt;JEP 468&lt;/a&gt; has neen proposed. Unfortunately it isn't seen anywhere in &lt;a href="https://openjdk.org/projects/jdk/23/"&gt;JDK 23&lt;/a&gt; or &lt;a href="https://openjdk.org/projects/jdk/24/"&gt;JDK 24&lt;/a&gt;. Its syntax follows the spirit of boilerplate avoidance.&lt;/p&gt;
  208. &lt;pre&gt;&lt;code class="language-java"&gt;// Wealth changed
  209. Billonaire theUpdated = oldBillionaire with { newWealth, newAssesment}
  210.  
  211. // Wealth unchanged
  212. Billonaire anotherUpdated = oldBillionaire with { newAssesment}
  213. &lt;/code&gt;&lt;/pre&gt;
  214. &lt;p&gt;Ultimately that's the way to go. Until then I needed a stopgap measure. It contains quite some boilerplate, following the &lt;a href="https://www.digitalocean.com/community/tutorials/builder-design-pattern-in-java"&gt;builder pattern&lt;/a&gt; to make use easier&lt;/p&gt;
  215. &lt;pre&gt;&lt;code class="language-java"&gt;public record Billionaire(String name, Long wealth, Temporal assessment) {
  216.  
  217.  public BillionaireUpdater forCloning() {
  218.    return new BillionaireUpdater(this);
  219.  }
  220. }
  221.  
  222. public class BillionaireUpdater {
  223.  
  224.  Long wealth = null;
  225.  Temporal assessment = null;
  226.  final Billionaire old;
  227.  
  228.  
  229.  public BillionaireUpdater(Billionaire old) {
  230.    this.old = old;
  231.  }
  232.  
  233.  public BillionaireUpdater wealth(Long wealth) {
  234.    this.wealth = wealth;
  235.    return this;
  236.  }
  237.  
  238.  public BillionaireUpdater assessment(Temporal assessment) {
  239.    this.assessment = assessment;
  240.    return this;
  241.  }
  242.  
  243.  public Billionaire build() {
  244.    return new Billionaire(
  245.      old.name(),
  246.      this.wealth == null ? old.wealth : this.wealth,
  247.      this.assesment == null ? old.assesment : this.assesment
  248.    );
  249.  }
  250. }
  251. &lt;/code&gt;&lt;/pre&gt;
  252. &lt;p&gt;This approach keeps the "bulky" code outside the record, so once &lt;a href="https://openjdk.org/jeps/468"&gt;JEP 468&lt;/a&gt; becomes available, updating should be managable leading to the ultimate removal of the &lt;code&gt;Updater&lt;/code&gt; classes. The use is quite straight forward:&lt;/p&gt;
  253. &lt;pre&gt;&lt;code class="language-java"&gt;Billionaire theUpdated = oldBillionaire.forCloning()
  254.                                    .wealth(insaneAmount)
  255.                                    .assesment(dateOfAssesment)
  256.                                    .build();
  257.  
  258. &lt;/code&gt;&lt;/pre&gt;
  259. &lt;p&gt;As usual YMMV&lt;/p&gt;</description>
  260. <link>2024/12/java-record-derived-creation.html</link>
  261. <author>Stephan H. Wissel</author>
  262. <guid>5f44d330-c664-11ef-af6d-a7bb66125fd9</guid>
  263. <pubDate>30 December 2024</pubDate>
  264.  
  265. </item>
  266. <item>
  267. <title>Building ARM64 on Github</title>
  268. <description>&lt;p&gt;Getting your &lt;a href="https://www.redhat.com/en/topics/devops/what-is-ci-cd"&gt;CI/CD&lt;/a&gt; pipeline right can be a daunting task. Here is one I had to address:&lt;/p&gt;
  269. &lt;ul&gt;
  270. &lt;li&gt;Create a &lt;a href="https://quarkus.io/"&gt;Quarkus&lt;/a&gt; Java application&lt;/li&gt;
  271. &lt;li&gt;Compile it to a native executable&lt;/li&gt;
  272. &lt;li&gt;Build a container for it&lt;/li&gt;
  273. &lt;li&gt;Make the container available to both Linux and MacOS&lt;/li&gt;
  274. &lt;/ul&gt;
  275. &lt;p&gt;The little irony, Docker on macOS or Windowsruns Linux under the hood.&lt;/p&gt;
  276. &lt;h3&gt;The easy part - Quarkus&lt;/h3&gt;
  277. &lt;p&gt;As I've &lt;a href="/blog/2023/10/quarkus-and-graalvm-starter.html"&gt;written before&lt;/a&gt; it is easy to get started with &lt;a href="https://quarkus.io/"&gt;Quarkus&lt;/a&gt;. It provides &lt;a href="https://quarkus.io/guides/container-image"&gt;5 ways to build containers&lt;/a&gt;, and &lt;a href="https://quarkus.io/guides/building-native-image"&gt;detailed instructions&lt;/a&gt; to build a native image.&lt;/p&gt;
  278. &lt;p&gt;Building a native image looked daunting, with quite some prerequisites like GraalVM, CLI and C compiler. Luckily all this is available in a builder image, and a simple property settin in your &lt;a href="https://maven.apache.org/guides/introduction/introduction-to-the-pom.html"&gt;&lt;code&gt;pom.xml&lt;/code&gt;&lt;/a&gt; settles it:&lt;/p&gt;</description>
  279. <link>2024/11/building-arm64-on-github.html</link>
  280. <author>Stephan H. Wissel</author>
  281. <guid>d7561d60-a6f8-11ef-97b1-713842e709f4</guid>
  282. <pubDate>20 November 2024</pubDate>
  283.  
  284. </item>
  285.  
  286. </channel>
  287. </rss>
  288.  
Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda