This feed does not validate.
<language>en,de</language>
^
<pubdate>Mon, 23 Jun 2025 14:08:23 +0000</pubdate>
^
line 20, column 38: (10 occurrences) [help]
<link>2025/06/html-templates-spa.html</link>
^
line 21, column 26: (10 occurrences) [help]
<author>Stephan H. Wissel</author>
^
line 22, column 43: (10 occurrences) [help]
<guid>bfdb1860-5009-11f0-9a8e-691adff7d010</guid>
^
line 23, column 22: (10 occurrences) [help]
<pubDate>23 June 2025</pubDate>
^
In addition, interoperability with the widest range of feed readers could be improved by implementing the following recommendations.
line 206, column 355: (2 occurrences) [help]
... code></a> settles it:</p></description>
^
</channel>
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>wissel.net Usability - Productivity - Business - The web - Singapore and Twins</title>
<link>https://wissel.net/blog/stories.rss</link>
<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>
<language>en,de</language>
<copyright>(C) 2003 - 2021 Stephan H. Wissel, All rights reserved</copyright>
<pubdate>Mon, 23 Jun 2025 14:08:23 +0000</pubdate>
<item>
<title>HTML's template element in single page applications</title>
<description><p>"<em>We need to use [insert-framework-of-the-day]!</em>" is the typical answer when asking for a light web single page application (SPA).</p>
<p>It doesn't need to be that way, <a href="https://paulswithers.github.io/">Paul</a> and myself shared in a <a href="https://github.com/paulswithers/super-procode-mode-openntf">recent webinar</a>.</p>
<h3>Serving the long tail</h3>
<p><a href="https://www.wavemaker.com/long-tail-apps-shadow-it-problem/">Long Tail Apps</a> tend to be outside of IT control, since they bypass the (usually heavy) standup of an IT development project.</p>
<p>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 <a href="https://opensource.hcltechsw.com/Domino-rest-api/references/hostingstatic.html">definded point of deployment</a>.</p>
<p>The typical objection goes: "<em>But it is never one HTML file, I need a login, a list and a form in read and edit mode</em>"</p>
<h3>template to the rescue</h3>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/template"><code>&lt;template&gt;</code></a> element is part of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components">WebComponents</a> specification and it is useful in simple SPA applications.</p></description>
<link>2025/06/html-templates-spa.html</link>
<author>Stephan H. Wissel</author>
<guid>bfdb1860-5009-11f0-9a8e-691adff7d010</guid>
<pubDate>23 June 2025</pubDate>
</item>
<item>
<title>Fun with AI system prompts</title>
<description><p><a href="https://www.google.com/search?q=ai+chatbots">AI Chatbots</a> are a popular topic. As part of a session at <a href="https://engage.ug/">Engage 2025</a> 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.</p>
<p>I settled sending the same user prompt with vastly different system prompts. Here is what I got.</p>
<h3>Romeo at the balcony</h3>
<p>Mercutio?s mocking my love and he?s never been in love himself.</p>
<p>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.</p>
<p>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?</p>
<p>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!</p></description>
<link>2025/05/fun-with-ai-system-prompts.html</link>
<author>Stephan H. Wissel</author>
<guid>d4495700-365d-11f0-87fb-618e413f1645</guid>
<pubDate>07 May 2025</pubDate>
</item>
<item>
<title>Deploying a Single Page Application using the Domino REST API</title>
<description><p>The <a href="https://opensource.hcltechsw.com/Domino-rest-api/">Domino REST API</a> not only provides secure access to "jsonified" Domino data,<br>
but also comes with capabilities to ease integration. This enables one to quickly cater to <a href="https://en.wikipedia.org/wiki/Long_tail">the long tail</a> of applications, giving them a home instead of loosing them to the shadow IT.</p>
<p>Once you know the steps, you can deploy new <a href="https://developer.mozilla.org/en-US/docs/Glossary/SPA">Single Purpose Applications</a> (I modified the meaning of SPA a little) in no time.</p>
<h3>No CORS, no headache</h3>
<p>DRAPI allows to <a href="https://opensource.hcltechsw.com/Domino-rest-api/references/hostingstatic.html">host static applications</a> in the <code>keepweb.d</code> 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 <a href="https://developer.mozilla.org/en-US/docs/Glossary/CORS">CORS</a></p>
<h3>Preparation</h3>
<p>Your SPA will live in a sub directory of <code>keepweb.d</code>, so think about a name, we shall use <code>demo42</code> here. Add a suitable icon (e.g. 72x72 px png), name it <code>demo42.png</code> and you are ready to roll. Let's assume our Domino API is running on <code>https://api.demo.io</code></p>
<h3>Work faster with vitejs</h3>
<p><a href="https://vite.dev/">viteJS</a> is one of the fronteand tools you <strong>want</strong> to learn. It features "hot module reload" to speed up development and, when done, packages your application nice and tidy.</p>
<p>It is easy to get started. You need a current version (22.x at time of writing) of <a href="https://nodejs.org/en">nodeJS</a> installed as development tooling.</p>
<pre><code class="language-bash">npm create vite@latest demo42 -- --template vanilla
cd demo42
npm install
</code></pre>
<p>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 <code>vite.config.js</code></p>
<pre><code class="language-js">import { defineConfig } from 'vite';
export default defineConfig({
base: '/keepweb/demo42/',
server: {
proxy: {
'/api': {
target: 'https://api.demo.io',
changeOrigin: true
}
}
}
});
</code></pre>
<p>This allows you to develop in the comfort of your local machine's <a href="https://vite.dev/guide/api-hmr">hot module reload</a> which refreshes your app on svae automagically. It also fixes the path matching to its final destination. Next create in <code>public</code> the file <code>manifest.json</code>. This file defines the tile layout for the landing page.</p>
<pre><code class="language-json">{
"short_name": "Demo 42",
"name": "The final answer to all Demos",
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#aacccc",
"icon": "vite.svg"
}
</code></pre>
<p>You can play with colors and icons as you deem fit. Now we are ready to run the application:</p>
<pre><code class="language-bash">npm run dev
</code></pre></description>
<link>2025/03/deploying-a-spa-to-drapi.html</link>
<author>Stephan H. Wissel</author>
<guid>7e85c300-0339-11f0-b3bc-e33450aa6e10</guid>
<pubDate>17 March 2025</pubDate>
</item>
<item>
<title>ufw cheatsheet</title>
<description><p>Mainly as a note to self.</p>
<h3>My default firewall setup</h3>
<pre><code class="language-bash">sudo ufw status
sudo ufw default allow outgoing
sudo ufw default deny incoming
grep IPV6 /etc/default/ufw
sudo ufw allow ssh
sudo ufw limit ssh/tcp comment 'Rate limit for openssh server'
sudo ufw allow 80/tcp comment 'Allow nginx HTTP'
sudo ufw limit 80 comment 'limit nginx HTTP'
sudo ufw allow 443/tcp comment 'Allow nginx HTTPS'
# For Domino mail
sudo ufw allow 1352/tcp comment 'Allow Notes replication'
sudo ufw allow 25/tcp comment 'Allow SMTP'
sudo ufw allow 587/tcp comment 'Allow SMTP'
sudo ufw allow 110/tcp comment 'Allow POP3'
sudo ufw allow 995/tcp comment 'Allow POP3s'
sudo ufw allow 143/tcp comment 'Allow IMAP'
sudo ufw allow 993/tcp comment 'Allow IMAPs'
sudo ufw allow from 1.2.3.4 'Allow the othe Domino'
sudo ufw enable
</code></pre></description>
<link>2025/02/ufw-cheatsheet.html</link>
<author>Stephan H. Wissel</author>
<guid>dd7313e0-f3a3-11ef-85ce-6116619fca24</guid>
<pubDate>26 February 2025</pubDate>
</item>
<item>
<title>Java Record Derived Creation (stopgap until JEP 468 arrives)</title>
<description><p>Java 14 (in a preview feature) introduced <a href="https://docs.oracle.com/en/java/javase/14/language/records.html">Records</a>. In a nutshell: Records are (<a href="https://codeadventures.littlebluefrog.nl/posts/06-immutability-in-records/">mostly</a>) immutable objects with a greatly reduced amount of boilerplate code requirements. For a detailed introduction head over to <a href="https://www.baeldung.com/java-record-keyword">Baeldung</a>.</p>
<h3>When records need update</h3>
<p>The short answer: create a new record and use the existing as input. Let's look at an example:</p>
<pre><code class="language-java">public record Billionaire(String name, Long wealth, Temporal assessment) {
public Billionaire cloneWithNewAssesment(Long newWealth, Temporal currentAssesment) {
return new Billionaire(this.name, newWealth,currentAssesment);
}
}
</code></pre>
<p>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.</p>
<p>To address this, <a href="https://openjdk.org/jeps/468">JEP 468</a> has neen proposed. Unfortunately it isn't seen anywhere in <a href="https://openjdk.org/projects/jdk/23/">JDK 23</a> or <a href="https://openjdk.org/projects/jdk/24/">JDK 24</a>. Its syntax follows the spirit of boilerplate avoidance.</p>
<pre><code class="language-java">// Wealth changed
Billonaire theUpdated = oldBillionaire with { newWealth, newAssesment}
// Wealth unchanged
Billonaire anotherUpdated = oldBillionaire with { newAssesment}
</code></pre>
<p>Ultimately that's the way to go. Until then I needed a stopgap measure. It contains quite some boilerplate, following the <a href="https://www.digitalocean.com/community/tutorials/builder-design-pattern-in-java">builder pattern</a> to make use easier</p>
<pre><code class="language-java">public record Billionaire(String name, Long wealth, Temporal assessment) {
public BillionaireUpdater forCloning() {
return new BillionaireUpdater(this);
}
}
public class BillionaireUpdater {
Long wealth = null;
Temporal assessment = null;
final Billionaire old;
public BillionaireUpdater(Billionaire old) {
this.old = old;
}
public BillionaireUpdater wealth(Long wealth) {
this.wealth = wealth;
return this;
}
public BillionaireUpdater assessment(Temporal assessment) {
this.assessment = assessment;
return this;
}
public Billionaire build() {
return new Billionaire(
old.name(),
this.wealth == null ? old.wealth : this.wealth,
this.assesment == null ? old.assesment : this.assesment
);
}
}
</code></pre>
<p>This approach keeps the "bulky" code outside the record, so once <a href="https://openjdk.org/jeps/468">JEP 468</a> becomes available, updating should be managable leading to the ultimate removal of the <code>Updater</code> classes. The use is quite straight forward:</p>
<pre><code class="language-java">Billionaire theUpdated = oldBillionaire.forCloning()
.wealth(insaneAmount)
.assesment(dateOfAssesment)
.build();
</code></pre>
<p>As usual YMMV</p></description>
<link>2024/12/java-record-derived-creation.html</link>
<author>Stephan H. Wissel</author>
<guid>5f44d330-c664-11ef-af6d-a7bb66125fd9</guid>
<pubDate>30 December 2024</pubDate>
</item>
<item>
<title>Building ARM64 on Github</title>
<description><p>Getting your <a href="https://www.redhat.com/en/topics/devops/what-is-ci-cd">CI/CD</a> pipeline right can be a daunting task. Here is one I had to address:</p>
<ul>
<li>Create a <a href="https://quarkus.io/">Quarkus</a> Java application</li>
<li>Compile it to a native executable</li>
<li>Build a container for it</li>
<li>Make the container available to both Linux and MacOS</li>
</ul>
<p>The little irony, Docker on macOS or Windowsruns Linux under the hood.</p>
<h3>The easy part - Quarkus</h3>
<p>As I've <a href="/blog/2023/10/quarkus-and-graalvm-starter.html">written before</a> it is easy to get started with <a href="https://quarkus.io/">Quarkus</a>. It provides <a href="https://quarkus.io/guides/container-image">5 ways to build containers</a>, and <a href="https://quarkus.io/guides/building-native-image">detailed instructions</a> to build a native image.</p>
<p>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 <a href="https://maven.apache.org/guides/introduction/introduction-to-the-pom.html"><code>pom.xml</code></a> settles it:</p></description>
<link>2024/11/building-arm64-on-github.html</link>
<author>Stephan H. Wissel</author>
<guid>d7561d60-a6f8-11ef-97b1-713842e709f4</guid>
<pubDate>20 November 2024</pubDate>
</item>
<item>
<title>Using RBAC with OpenAPI and vert.x</title>
<description><p>I'm stronlgy in favour of <a href="https://openpracticelibrary.com/practice/contract-first-development/">Contract-First Development</a>, when in comes to APIs. All invested parties, including your future self, agree on a neutral format, that both API providers and consumers will stick to. For REST APIs that is the <a href="https://www.openapis.org/">OpenAPI spec</a></p>
<p>A popular critique of that approach is that it reeks of <a href="https://en.wikipedia.org/wiki/Big_design_up_front">Big Design Upfront</a>, happily skipping over the fact that nothing stops the teams to iterate over the specification too, one path, one schema at the time</p>
<h3>The source of truth</h3>
<p>The specification becomes the single authorative source for endpoints, security requirements, data formats and responses. While it is possible to generate the spec from source code, like. e.g. <a href="https://spring.io/projects">Spring</a> or <a href="https://quarkus.io/extensions/io.quarkus/quarkus-smallrye-openapi/">Quarkus</a>, I see clear advantages to provide the specification standalone. Create it <a href="https://tools.openapis.org/">with a tool</a> like <a href="https://studio.apicur.io/">Apicur.io</a>, <a href="https://stoplight.io/">Stoplight</a> or <a href="https://apigit.com/">APIGit</a>. Or use <a href="https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi">a plugin</a> (or <a href="https://marketplace.visualstudio.com/search?term=OpenAPI&amp;target=VSCode">another</a>) in your <a href="https://visualstudio.microsoft.com/#vscode-section">IDE</a> or <a href="https://plugins.jetbrains.com/search?search=OpenAPI">the other one</a></p>
<p>Once you have your first draft, you want to implement it server side. <a href="https://vertx.io">Eclipse vert.x</a> offers the <a href="https://vertx.io/docs/vertx-web-openapi-router/java/">Vert.x OpenAPI Router</a> for exactly that. You can get more details from my <a href="https://stwissel.github.io/presentations/OpenAPI2023/index.html">OpenAPI talk</a>, or by peeking into the <a href="https://github.com/Stwissel/openapi-talk">sample project</a> (which used vert.x inside <a href="https://quarkus.io/">Quarkus</a>).</p></description>
<link>2024/11/using-rbac-with-openapi-and-vertx.html</link>
<author>Stephan H. Wissel</author>
<guid>600b57a0-9dcc-11ef-b719-8793681eb8df</guid>
<pubDate>08 November 2024</pubDate>
</item>
<item>
<title>One-Off IdP with KeyCloak</title>
<description><p>When end-2-end testing applications that use an <a href="https://en.wikipedia.org/wiki/Identity_provider">IdP</a>, an IdP needs to be in a known state to make test repeatable.</p>
<p>Typically a container is used, with a configuration that needs to be reset before (and after) a run. Restoring the IdP configuration isn't ideal, since addring new test cases (e.g. adding a user with different properties to check application behavior). I propose a different approach: One-off IdP</p>
<h3>Container without persistence</h3>
<p>I start with an empty deployment of <a href="https://www.keycloak.org/">KeyCloak</a> running in a docker container.</p>
<pre><code class="language-shell">#!/bin/bash
#Run a clean KeyCloak
docker run --rm -p 8080:8080 \
--name testcloak \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=password \
quay.io/keycloak/keycloak:latest start-dev
</code></pre>
<p>The <code>--rm</code> parameter ensures that the container is discarded after use. There is <strong>no</strong> persistence flag (<code>--mount</code>), so when the container goes down, all data perishes (and that's intendet).</p>
<h3>Configuration sequence</h3>
<p>The empty KeyCloak only knows the realm <code>master</code> and the user <code>admin</code>. To turn it into a fully functional IdP we need to configure it. Since we want this process to be repeatable we shall use <a href="https://www.keycloak.org/docs-api/latest/rest-api/index.html">Keycloak's REST API</a>. The documentation is complete, including an <a href="https://www.openapis.org/">OpenAPI</a> spec, but in a dictionary style, so all is good when you know what you are looking for. To learn what is needed the browser development tools while using the admin UI teach us the what.</p></description>
<link>2024/10/onetime-idp-with-keycloak.html</link>
<author>Stephan H. Wissel</author>
<guid>83111210-8eba-11ef-9eab-1f7495f5460d</guid>
<pubDate>20 October 2024</pubDate>
</item>
<item>
<title>Handle HTTP chunked responses - Java edition</title>
<description><p>The <a href="https://opensource.hcltechsw.com/Domino-rest-api/">Domino REST API</a> delivers collections using <a href="https://en.wikipedia.org/wiki/Chunked_transfer_encoding">chunked transfer encoding</a>. This has the advantage, that you can process results as they arrive. It produces the challenge that the usual client side code is designed to first wait for completion of the request. I wrote about the JavaScript solution <a href="/blog/2023/07/handle-http-chunked-responses.html">a while ago</a>, this is the Java edition.</p>
<h3>Client choices</h3>
<p>In JavaScript land the choice of client is simple: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">the Fetch API</a>. In Java we have some choices:</p>
<ul>
<li>Since Java 11 there's a <a href="https://openjdk.org/groups/net/httpclient/intro.html">HttpClient</a> in the JDK</li>
<li>A very popular library is provided by the <a href="https://hc.apache.org/httpcomponents-client-5.4.x/index.html">Apache HTTP components</a></li>
<li>The SPRING framework, undisputed king of Java web frameworks, offers its <a href="https://docs.spring.io/spring-framework/reference/integration/rest-clients.html">own sset of clients</a></li>
<li>The vert.x framework, which we used to build <a href="https://opensource.hcltechsw.com/Domino-rest-api/references/security/index.html?h=vert.x">DRAPI</a>, features its <a href="https://vertx.io/docs/vertx-web-client/java/">own client</a></li>
</ul>
<p>There are probably more around. This article uses the JDK <a href="https://openjdk.org/groups/net/httpclient/intro.html">HttpClient</a>. I'll skip the parts with Authentication and TLS handling, check the <a href="https://github.com/Stwissel/java11-httpclient-chunked">full example</a> for details.</p>
<h3>How it works</h3>
<p>First we create an <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html">java.net.http.HttpClient</a>. It takes care of the http version and the TLS context.</p>
<pre><code class="language-java">HttpClient getClient(SSLContext sslContext) {
return HttpClient.newBuilder()
.sslContext(sslContext)
.build();
}
</code></pre>
<p>Then we build and execute the request. The <em>magic</em> is the <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpResponse.BodySubscriber.html">BodySubscriber</a> (more on that below).</p>
<pre><code class="language-java">Integer runGetRequest(HttpClient client, String url, String authHeader, BodySubscriber subscriber) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", authHeader)
.GET()
.build();
CompletableFuture&lt;Integer&gt; response =
client.sendAsync(request, responseInfo -&gt; subscriber)
.whenComplete((r, t) -&gt; System.out.println("Response: " + r.statusCode()))
.thenApply(HttpResponse::body);
return response.get();
}
</code></pre></description>
<link>2024/10/handle-http-chunked-responses-java-edition.html</link>
<author>Stephan H. Wissel</author>
<guid>49d83e50-8632-11ef-acaa-2d2a7a285b28</guid>
<pubDate>09 October 2024</pubDate>
</item>
<item>
<title>Quarkus in Multi-Module projects</title>
<description><p>You are developing a web application using <a href="https://quarkus.io/">Quarkus</a> that consists of multiple (micro)services and a bunch of supporting libraries. Since maven modules provide sufficient isolation, you decide to use a parent project to keep dependency versions and parameters in sync and a <a href="https://www.baeldung.com/java-maven-reactor">Maven Reactor</a> to build them together.</p>
<p>This blog post is for you. A special thanks to <a href="https://github.com/aloubyansky">Alexey</a> for helping out.</p>
<h2>Moving parts</h2>
<p>Our objective is to have a development setup where we can edit any of the services or libraries and then run them individually or all together. Ideally without the need to alter configurations between runs and the ability to deploy the setup using devcontainers (note: that's about the development setup, not about deploying the finished application). There are some moving parts:</p>
<ul>
<li><a href="https://quarkus.io/">Quarkus</a> CLI or Maven plugin</li>
<li><a href="https://maven.apache.org/guides/mini/guide-multiple-modules.html">Multi-Module Maven</a> to keep libraries and services together and apart</li>
<li><a href="https://maven.apache.org/guides/introduction/introduction-to-profiles.html">Maven profiles</a> to conditionally modify maven runs</li>
<li>Maven's <a href="https://www.baeldung.com/maven-plugin-management"><code>&lt;pluginManagement&gt;</code></a> and <a href="https://www.baeldung.com/maven-dependencymanagement-vs-dependencies-tags"><code>&lt;dependencyManagement&gt;</code></a> to define configurations without activating them</li>
<li>Your <a href="https://news.ycombinator.com/item?id=26367535">favourite Ide</a> configured for <a href="https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack">Java</a> and <a href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-quarkus">Quarkus</a></li>
<li>Understand how VSCode's <a href="https://code.visualstudio.com/docs/editor/tasks">Tasks</a> work</li>
<li>Know how to setup <a href="https://containers.dev/">DevContainers</a>, especially when you need <a href="https://stackoverflow.com/questions/59231953/what-makes-an-application-a-sidecar">sidecars</a></li>
</ul>
<p>That's a lot, let's dig in.</p></description>
<link>2024/08/quarkus-in-multimodule-projects.html</link>
<author>Stephan H. Wissel</author>
<guid>1b7989c0-6525-11ef-a221-1bdb47be5f49</guid>
<pubDate>28 August 2024</pubDate>
</item>
</channel>
</rss>