<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Java &#8211; Pauls Blog</title>
	<atom:link href="https://sterl.org/tag/java/feed/" rel="self" type="application/rss+xml" />
	<link>https://sterl.org</link>
	<description></description>
	<lastBuildDate>Tue, 30 Dec 2025 15:18:26 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
	<item>
		<title>A Bounded, Thread-Safe In-Memory Store for Java</title>
		<link>https://sterl.org/2025/12/java-simple-bound-memory-store/</link>
					<comments>https://sterl.org/2025/12/java-simple-bound-memory-store/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Tue, 30 Dec 2025 14:55:43 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[java test]]></category>
		<category><![CDATA[memory store]]></category>
		<category><![CDATA[Test]]></category>
		<category><![CDATA[Unit Test]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=1149</guid>

					<description><![CDATA[Problem In test scenarios or lightweight application components, there is a need for a simple, thread-safe, in-memory data store that can temporarily hold a limited number of objects. The store should be easy to use, avoid external dependencies (e.g., databases), support generation and use of unique identifiers as keys, and automatically evict the oldest entries&#8230;]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Problem</h2>



<p>In test scenarios or lightweight application components, there is a need for a simple, thread-safe, in-memory data store that can temporarily hold a limited number of objects. The store should be easy to use, avoid external dependencies (e.g., databases), support generation and use of unique identifiers as keys, and automatically evict the oldest entries when a predefined capacity is exceeded. This enables predictable memory usage while providing fast access to recently stored data.</p>



<h2 class="wp-block-heading">Solution</h2>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Java&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MemoryStore&lt;T&gt; {

    private final Lock lock = new ReentrantLock();
    private final int maxElements;

    private final Map&lt;String, T&gt; data = new LinkedHashMap&lt;&gt;() {
        // called during put and ensures the map doesn't grow
        @Override
        protected boolean removeEldestEntry(Map.Entry&lt;String, T&gt; eldest) {
            return size() &gt; maxElements;
        }
    };

    public MemoryStore(int maxElements) {
        if (maxElements &lt; 1) {
            throw new IllegalArgumentException(&quot;maxElements must be &gt; 1&quot;);
        }
        this.maxElements = maxElements;
    }
    
    public void store(T value) {
        this.store(UUID.randomUUID().toString(), value);
    }

    public void store(String key, T value) {
        lock.lock();
        try {
            data.put(key, value);
        } finally {
            lock.unlock();
        }
    }

    public T get(String key) {
        lock.lock();
        try {
            return data.get(key);
        } finally {
            lock.unlock();
        }
    }
    
    public int size() {
        lock.lock();
        try {
            return data.size();
        } finally {
            lock.unlock();
        }
    }
    
    public LinkedHashMap&lt;String, T&gt; data() {
        lock.lock();
        try {
            return new LinkedHashMap&lt;&gt;(this.data);
        } finally {
            lock.unlock();
        }
    }
}</pre></div>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2025/12/java-simple-bound-memory-store/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Spring Persistent Tasks</title>
		<link>https://sterl.org/2025/04/spring-persistent-tasks/</link>
					<comments>https://sterl.org/2025/04/spring-persistent-tasks/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Sun, 20 Apr 2025 07:16:43 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[dashboard]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Inbound Pattern]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Outbound Pattern]]></category>
		<category><![CDATA[Quartz]]></category>
		<category><![CDATA[quartz daschboard]]></category>
		<category><![CDATA[scheduled]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[task ui]]></category>
		<category><![CDATA[task-scheduling]]></category>
		<category><![CDATA[Transaction]]></category>
		<category><![CDATA[trigger]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=1116</guid>

					<description><![CDATA[A simple task management framework designed to queue and execute asynchronous tasks with support for database persistence and a user-friendly interface. It can be used to implement scheduling patterns or outbound patterns. Focus is the usage with spring boot and JPA. https://github.com/sterlp/spring-persistent-tasks Key Features]]></description>
										<content:encoded><![CDATA[
<p>A simple task management framework designed to queue and execute asynchronous tasks with support for database persistence and a user-friendly interface. It can be used to implement scheduling patterns or outbound patterns.</p>



<p>Focus is the usage with spring boot and JPA.</p>



<p><a href="https://github.com/sterlp/spring-persistent-tasks">https://github.com/sterlp/spring-persistent-tasks</a></p>



<h2 class="wp-block-heading">Key Features</h2>



<ol class="wp-block-list">
<li><strong>JPA-Powered Persistence</strong>&nbsp;&#8211; Automatically persists tasks to your database</li>



<li><strong>Spring Boot Auto-Configuration</strong>&nbsp;&#8211; Simple setup with @EnableSpringPersistentTasks</li>



<li><strong>Clustering Support</strong>&nbsp;&#8211; Built-in lock management for distributed environments</li>



<li><strong>Type-Safe Tasks</strong>&nbsp;&#8211; Generic task definitions with state objects</li>



<li><strong>Retry Mechanisms</strong>&nbsp;&#8211; Automatic retry policies for failed executions</li>



<li><strong>Transactional Integration</strong>&nbsp;&#8211; Works with Spring&#8217;s transaction management</li>



<li><strong>Queue Management</strong> &#8211; Intelligent task queuing and prioritization</li>



<li><strong>Different DB Supports</strong> 
<ul class="wp-block-list">
<li>MsSQL</li>



<li>MariaDB</li>



<li>Postgres</li>
</ul>
</li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2025/04/spring-persistent-tasks/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>React &#038; Spring Boot</title>
		<link>https://sterl.org/2024/12/react-spring-boot/</link>
					<comments>https://sterl.org/2024/12/react-spring-boot/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Wed, 11 Dec 2024 18:36:41 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[ReactJs]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[vite]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=1095</guid>

					<description><![CDATA[Problem We want to combine Spring Boot with a simple React frontend. Use the React development features but also be able to use the Spring IDE. In the end, everything should be built using Maven and nicely packed into a JAR, just like any other Microservice. Let’s get started. Multi-Module project First we create a&#8230;]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Problem</h2>



<p>We want to combine Spring Boot with a simple React frontend. Use the React development features but also be able to use the Spring IDE. In the end, everything should be built using Maven and nicely packed into a JAR, just like any other Microservice. Let’s get started.</p>



<h2 class="wp-block-heading">Multi-Module project</h2>



<p>First we create a spring project here <code>backend</code> folder and a react project in the <code>frontend</code> folder. The root pom should help us to build both projects in one run:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://sterl.org/wp-content/uploads/2024/12/image.png"><img fetchpriority="high" decoding="async" width="294" height="211" src="https://sterl.org/wp-content/uploads/2024/12/image.png" alt="" class="wp-image-1096"/></a></figure></div>


<h3 class="wp-block-heading">Root pom.xml</h3>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

    &lt;groupId&gt;org.foo.bar&lt;/groupId&gt;
    &lt;artifactId&gt;project-root&lt;/artifactId&gt;
    &lt;version&gt;0.1.0-SNAPSHOT&lt;/version&gt;
    &lt;packaging&gt;pom&lt;/packaging&gt;

    &lt;properties&gt;
        &lt;java.version&gt;21&lt;/java.version&gt;
        &lt;maven.compiler.source&gt;${java.version}&lt;/maven.compiler.source&gt;
        &lt;maven.compiler.target&gt;${java.version}&lt;/maven.compiler.target&gt;
        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
        &lt;project.reporting.outputEncoding&gt;UTF-8&lt;/project.reporting.outputEncoding&gt;
    &lt;/properties&gt;

    &lt;modules&gt;
        &lt;module&gt;frontend&lt;/module&gt;
        &lt;module&gt;backend&lt;/module&gt;
    &lt;/modules&gt;

  	&lt;!-- feel free to use spring as root instead of this --&gt;
    &lt;dependencyManagement&gt;
        &lt;dependencies&gt;
            &lt;dependency&gt;
                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                &lt;artifactId&gt;spring-boot-dependencies&lt;/artifactId&gt;
                &lt;version&gt;3.3.6&lt;/version&gt;
                &lt;type&gt;pom&lt;/type&gt;
                &lt;scope&gt;import&lt;/scope&gt;
            &lt;/dependency&gt;
        &lt;/dependencies&gt;
    &lt;/dependencyManagement&gt;
&lt;/project&gt;</pre></div>



<h3 class="wp-block-heading">Backend pom.xml</h3>



<p>This is straight forward the generated pom from spring with just the dependency to the <code>frontend </code>project.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;parent&gt;
        &lt;groupId&gt;org.foo.bar&lt;/groupId&gt;
        &lt;artifactId&gt;project-root&lt;/artifactId&gt;
        &lt;version&gt;0.1.0-SNAPSHOT&lt;/version&gt;
        &lt;relativePath&gt;../pom.xml&lt;/relativePath&gt;
    &lt;/parent&gt;

    &lt;artifactId&gt;project-backend&lt;/artifactId&gt;

    &lt;dependencies&gt;
      	&lt;!-- thats the important part --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.foo.bar&lt;/groupId&gt;
            &lt;artifactId&gt;project-frontend&lt;/artifactId&gt;
            &lt;version&gt;${project.version}&lt;/version&gt;
        &lt;/dependency&gt;
      	&lt;!-- thats the important part end --&gt;
      
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
        &lt;/dependency&gt;  
        &lt;dependency&gt;
            &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
            &lt;artifactId&gt;lombok&lt;/artifactId&gt;
            &lt;optional&gt;true&lt;/optional&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;

&lt;/project&gt;</pre></div>



<h3 class="wp-block-heading">Frontend pom.xml</h3>



<p>Now we have todo more stuff:</p>



<ol class="wp-block-list">
<li>Ensure the <code>dist</code> result is added to the JAR</li>



<li>Generate during the <code>generate-resources</code> phase also the content for the <code>dist</code> folder</li>



<li>Ensure that during a <code>mvn clean</code> all gets deleted</li>
</ol>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;parent&gt;
        &lt;groupId&gt;org.foo.bar&lt;/groupId&gt;
        &lt;artifactId&gt;project-root&lt;/artifactId&gt;
        &lt;version&gt;0.1.0-SNAPSHOT&lt;/version&gt;
        &lt;relativePath&gt;../pom.xml&lt;/relativePath&gt;
    &lt;/parent&gt;

    &lt;artifactId&gt;project-frontend&lt;/artifactId&gt;
    
    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
            &lt;scope&gt;provided&lt;/scope&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
    
    &lt;build&gt;
        &lt;!-- Ensure the dist result is added to the JAR --&gt;
        &lt;resources&gt;
            &lt;resource&gt;
                &lt;directory&gt;dist&lt;/directory&gt;
            &lt;/resource&gt;
        &lt;/resources&gt;

        &lt;plugins&gt;
          	&lt;!--
                Generate during the generate-resources phase 
                also the content for the dist folder 
            --&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
                &lt;artifactId&gt;exec-maven-plugin&lt;/artifactId&gt;
                &lt;version&gt;3.5.0&lt;/version&gt;
                &lt;executions&gt;
                    &lt;execution&gt;
                        &lt;id&gt;npm install&lt;/id&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;exec&lt;/goal&gt;
                        &lt;/goals&gt;
                        &lt;phase&gt;generate-resources&lt;/phase&gt;
                        &lt;configuration&gt;
                            &lt;executable&gt;npm&lt;/executable&gt;
                            &lt;arguments&gt;
                                &lt;argument&gt;install&lt;/argument&gt;
                                &lt;argument&gt;--prefer-offline&lt;/argument&gt;
                                &lt;argument&gt;--no-audit&lt;/argument&gt;
                                &lt;argument&gt;--progress=false&lt;/argument&gt;
                            &lt;/arguments&gt;
                        &lt;/configuration&gt;
                    &lt;/execution&gt;

                    &lt;execution&gt;
                        &lt;id&gt;npm build&lt;/id&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;exec&lt;/goal&gt;
                        &lt;/goals&gt;
                        &lt;phase&gt;generate-resources&lt;/phase&gt;
                        &lt;configuration&gt;
                            &lt;executable&gt;npm&lt;/executable&gt;
                            &lt;arguments&gt;
                                &lt;argument&gt;run&lt;/argument&gt;
                                &lt;argument&gt;build&lt;/argument&gt;
                            &lt;/arguments&gt;
                        &lt;/configuration&gt;
                    &lt;/execution&gt;
                &lt;/executions&gt;
            &lt;/plugin&gt;
            &lt;!-- Ensure that during a mvn clean all gets deleted --&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-clean-plugin&lt;/artifactId&gt;
                &lt;version&gt;3.4.0&lt;/version&gt;
                &lt;configuration&gt;
                    &lt;filesets&gt;
                        &lt;fileset&gt;
                            &lt;directory&gt;node_modules&lt;/directory&gt;
                        &lt;/fileset&gt;
                        &lt;fileset&gt;
                            &lt;directory&gt;dist&lt;/directory&gt;
                        &lt;/fileset&gt;
                    &lt;/filesets&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;

&lt;/project&gt;</pre></div>



<h3 class="wp-block-heading">Ensure the result in the dist folder is compatible to Spring</h3>



<p>Spring will pick up automatically any static resources which are placed in the <code>static</code> folder. Here is an example for <a rel="noreferrer noopener" href="https://vite.dev/guide/" target="_blank">vite</a> to do so in the <code>vite.config.js</code>:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;application/json&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}">export default defineConfig({
  plugins: [react()],
  build: {
    outDir: './dist/static',
    emptyOutDir: true, // also necessary
  }
})</pre></div>



<h2 class="wp-block-heading">Going beyond</h2>



<p>Sometime it is useful to host the UI in a sub path lets say <code>my-ui</code>, so the url would be <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color"><strong>http://localhost:8080/my-ui</strong></mark></p>



<p>For that we have to adjust the <code>vite.config.js</code>:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;application/json&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}">export default defineConfig({
  plugins: [react()],
  base: 'my-ui',
  build: {
    outDir: './dist/static/my-ui',
    emptyOutDir: true,
  }
})</pre></div>



<p>Now it would also be helpful if we don&#8217;t have to directly type the <code>index.html</code> but tell Spring always to re-route.</p>



<p>For that we have to add a Spring Configuration Class:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">package org.foo.bar;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyFrontedConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController(&quot;/my-ui&quot;).setViewName(&quot;/my-ui/index.html&quot;);
        registry.addRedirectViewController(&quot;/my-ui/&quot;, &quot;/my-ui&quot;);
    }
}
</pre></div>



<h2 class="wp-block-heading">Add cache control to static react assets</h2>



<p>In the end int would also be nice that the generated static resources are cached by the client e.g. for a year. We will extend the <code>MyFrontedConfig</code> class with:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(&quot;/my-ui/assets/**&quot;) 
                .addResourceLocations(&quot;classpath:/static/my-ui/assets/&quot;) 
                .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
    }</pre></div>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2024/12/react-spring-boot/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Transaktionsmanagement mit Spring, JPA, Hibernate</title>
		<link>https://sterl.org/2024/08/transaktionsmanagement-mit-spring-jpa-hibernate/</link>
					<comments>https://sterl.org/2024/08/transaktionsmanagement-mit-spring-jpa-hibernate/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Sat, 31 Aug 2024 15:02:17 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[YouTube]]></category>
		<category><![CDATA[@Transactional]]></category>
		<category><![CDATA[Datenbank]]></category>
		<category><![CDATA[DB]]></category>
		<category><![CDATA[Grundlagen]]></category>
		<category><![CDATA[Grundlagen Datenbanken]]></category>
		<category><![CDATA[Grundlagen Transaktionen]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Mandatory]]></category>
		<category><![CDATA[Read only transaction]]></category>
		<category><![CDATA[Required]]></category>
		<category><![CDATA[Spring Data]]></category>
		<category><![CDATA[Spring TransactionTemplate]]></category>
		<category><![CDATA[Transaction Timeout]]></category>
		<category><![CDATA[Transactions]]></category>
		<category><![CDATA[TransactionTemplate]]></category>
		<category><![CDATA[Transkationen]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=1032</guid>

					<description><![CDATA[Lerne die Grundlagen des Transaktionsmanagements in modernen Datenbanken kennen, und erfahre, wie du mit Spring Boot, Spring Data, JPA und Hibernate effektiv arbeitest. In diesem Tutorial starten wir mit den Grundlagen der Datenbanktransaktionen in deiner Anwendung: &#8211; Transaktionen starten: Dieses Video ist perfekt für Entwickler, die ihre Fähigkeiten in Spring Framework erweitern und transaktionssichere Anwendungen&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Lerne die Grundlagen des Transaktionsmanagements in modernen Datenbanken kennen, und erfahre, wie du mit Spring Boot, Spring Data, JPA und Hibernate effektiv arbeitest.</p>



<p>In diesem Tutorial starten wir mit den Grundlagen der Datenbanktransaktionen in deiner Anwendung: &#8211; Transaktionen starten: </p>



<ul class="wp-block-list">
<li><strong>Transaktion starten</strong>: Verstehe, wie Du Transaktionen in Spring Boot richtig initialisierst.</li>



<li><strong>Rollback-Strategien:</strong> Erlerne die wichtigsten Methoden, um Transaktionen bei Fehlern sicher zurückzusetzen. </li>



<li><strong>Annotations</strong>: Setze Annotations gezielt ein, um Transaktionen zu steuern. </li>



<li><strong>Programmatische Transaktionen</strong>: Implementiere Transaktionen programmatisch und gewinne maximale Kontrolle. </li>



<li><strong>Read Only</strong>: Transaktionen für GET Operationen </li>



<li><strong>Timeouts</strong>: Wie stelle ich bei einer Transaktion einen Timeout ein, was muss ich beachten?</li>
</ul>



<p>Dieses Video ist perfekt für Entwickler, die ihre Fähigkeiten in Spring Framework erweitern und transaktionssichere Anwendungen erstellen möchten.</p>



<ul class="wp-block-list">
<li><a href="https://github.com/sterlp/youtube/commit/24f1d4e1576be803ec32142ffb84f438dcd30623">Git Commit</a></li>



<li><a href="https://github.com/sterlp/youtube/tree/main/db-grundlagen">Git Projekt</a></li>
</ul>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Transaktionsmanagement | Datenbanken | Spring Boot &amp; Data, JPA &amp; Hibernate | @Transactional" width="640" height="360" src="https://www.youtube.com/embed/9cY73uCj5wA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2024/08/transaktionsmanagement-mit-spring-jpa-hibernate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Grundlagen Datenbanken &#124; als Entwickler &#124; Datenbank Locks vs Write Ahead &#124; Spring &#124; JPA &#124; Hibernate</title>
		<link>https://sterl.org/2024/01/grundlagen-datenbanken-als-entwickler-datenbank-locks-vs-write-ahead-spring-jpa-hibernate/</link>
					<comments>https://sterl.org/2024/01/grundlagen-datenbanken-als-entwickler-datenbank-locks-vs-write-ahead-spring-jpa-hibernate/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Sat, 13 Jan 2024 10:03:48 +0000</pubDate>
				<category><![CDATA[YouTube]]></category>
		<category><![CDATA[bulk head]]></category>
		<category><![CDATA[concurrent update]]></category>
		<category><![CDATA[Datenbanken]]></category>
		<category><![CDATA[Entwickler]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Locks]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[State Persistence]]></category>
		<category><![CDATA[Write Ahead]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=990</guid>

					<description><![CDATA[Last uns zusammen ein State Persistence Anwendung auf eine Write Ahead Anwendung abändern und die Verbesserung in der Skalierbarkeit dieser betrachten.]]></description>
										<content:encoded><![CDATA[
<p>Last uns zusammen ein State Persistence Anwendung auf eine Write Ahead Anwendung abändern und die Verbesserung in der Skalierbarkeit dieser betrachten. </p>



<ol class="wp-block-list">
<li>Wie synchronisieren wir parallelle Objektzugriffe in Java und Spring Boot, um die Skalierbarkeit unseres Systems zu optimieren? </li>



<li>Praktische Lösungen: Wie verarbeitet ein Java Spring Boot System viele Updates auf einmal nach einer Downtime? </li>



<li>Strategien für Lastspitzen in der Praxis: Einsatz von DB Locks in Java und Spring Boot. </li>



<li>Praktische Tipps und Tricks: Vor- und Nachteile von Locks in der Java Spring Boot Anwendung. </li>



<li>Weitere Optimierungsmöglichkeiten in der Java Spring Boot Architektur: 
<ul class="wp-block-list">
<li>Umsetzung von Write Ahead Log in Java und Spring Boo, welche Modifikationen sind notwendig? </li>



<li>Was bring das an mehr Skalierbarkeit?</li>
</ul>
</li>
</ol>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Grundlagen Datenbanken | als Entwickler | Datenbank Locks vs Write Ahead | Spring | JPA | Hibernate" width="640" height="360" src="https://www.youtube.com/embed/xgUrX2vk8UQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2024/01/grundlagen-datenbanken-als-entwickler-datenbank-locks-vs-write-ahead-spring-jpa-hibernate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Microservices orchestrieren &#124; Workflows &#124; ESB &#124; Event Bus</title>
		<link>https://sterl.org/2023/10/microservices-orchestrieren-workflows-esb-event-bus/</link>
					<comments>https://sterl.org/2023/10/microservices-orchestrieren-workflows-esb-event-bus/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Tue, 03 Oct 2023 09:04:15 +0000</pubDate>
				<category><![CDATA[Cloud]]></category>
		<category><![CDATA[YouTube]]></category>
		<category><![CDATA[ESB]]></category>
		<category><![CDATA[Event Bus]]></category>
		<category><![CDATA[Event Driven]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Microservices]]></category>
		<category><![CDATA[orchestrieren]]></category>
		<category><![CDATA[Workflows]]></category>
		<category><![CDATA[Zeebe]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=960</guid>

					<description><![CDATA[In einer Service- bzw. Microservice-Architektur stellt sich irgendwann unweigerlich die Frage wie man komplexe Workflows, die über mehrere Services hinweg gehen, orchestrieren möchte. Dabei stehen sich die Event- und die Workflow-Architektur anscheinend als unterschiedliche Paradigmen gegenüber. Wie können wir mit einfachen Architekturmaßnahmen die Arbeitsteilung von Teams/Abteilungen unterstützen?]]></description>
										<content:encoded><![CDATA[
<p>In einer Service- bzw. Microservice-Architektur stellt sich irgendwann unweigerlich die Frage wie man komplexe Workflows, die über mehrere Services hinweg gehen, orchestrieren möchte. Dabei stehen sich die Event- und die Workflow-Architektur anscheinend als unterschiedliche Paradigmen gegenüber. Wie können wir mit einfachen Architekturmaßnahmen die Arbeitsteilung von Teams/Abteilungen unterstützen? </p>



<ul class="wp-block-list">
<li>Welche Architektur sollen wir wählen? </li>



<li>Ist es wirklich ein entweder oder? </li>



<li>Was wären die Vor- bzw. Nachteile?</li>
</ul>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Microservices orchestrieren  | Workflows | ESB | Event Bus | Service Bus | als Architekt" width="640" height="360" src="https://www.youtube.com/embed/8z8mXssTVDk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2023/10/microservices-orchestrieren-workflows-esb-event-bus/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Datenbank&#124; Transaktionen &#124; Isolationlevel &#124; Locks &#124; Hibernate &#124; JPA &#124; Spring Boot</title>
		<link>https://sterl.org/2023/10/datenbank-transaktionen-isolationlevel-locks-hibernate-jpa-spring-boot/</link>
					<comments>https://sterl.org/2023/10/datenbank-transaktionen-isolationlevel-locks-hibernate-jpa-spring-boot/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Mon, 02 Oct 2023 11:40:50 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[YouTube]]></category>
		<category><![CDATA[DB Locks]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Isolationlevel]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Transaktionen]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=958</guid>

					<description><![CDATA[Um weiterführende Konzepte besser nachvollziehen zu können, wollen wir uns in den Grundlagen Datenbanken mit Spring Boot, Isolation Level (Isolationsgrad) und Locks beschäftigen.]]></description>
										<content:encoded><![CDATA[
<p>Um weiterführende Konzepte besser nachvollziehen zu können, wollen wir uns in den Grundlagen Datenbanken mit Spring Boot, Isolation Level (Isolationsgrad) und Locks beschäftigen.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Datenbanken Grundlagen | Transaktionen | Isolation Level | Locks | Hibernate | JPA | Spring Boot" width="640" height="360" src="https://www.youtube.com/embed/6ytlI4Sshjc?start=604&#038;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2023/10/datenbank-transaktionen-isolationlevel-locks-hibernate-jpa-spring-boot/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Quartz integration in Spring</title>
		<link>https://sterl.org/2022/07/quartz-integration-in-spring/</link>
					<comments>https://sterl.org/2022/07/quartz-integration-in-spring/#comments</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Fri, 01 Jul 2022 19:50:50 +0000</pubDate>
				<category><![CDATA[Quartz]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[quartz-scheduler]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[timer]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=802</guid>

					<description><![CDATA[Why Quartz? motivation Spring comes already with an own timer and this is fine if we have very simple requirements and we don&#8217;t really care about state or on which pod the timer is actually running. To be more precise the timer/ job is running in each of our spring containers independently. Lets be honest,&#8230;]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Why Quartz? <span class="badge badge-pill badge-primary">motivation</span></h2>



<p>Spring comes already with an own <a rel="noreferrer noopener" href="https://spring.io/guides/gs/scheduling-tasks/" target="_blank">timer</a> and this is fine if we have very simple requirements and we don&#8217;t really care about state or on which pod the timer is actually running. To be more precise the timer/ job is running in each of our spring containers independently.</p>



<p>Lets be honest, this is usually never really the case and so it is common to invite <a rel="noreferrer noopener" href="https://github.com/lukas-krecan/ShedLock" target="_blank">ShedLock</a> to the party. Are we done then?</p>



<p>Usually no, honestly we want in the most cases just a bit more:</p>



<ul class="wp-block-list">
<li>Run jobs in the cluster on different nodes simultaneous</li>



<li>Have a kind of state management </li>



<li>The ability to provide some kind of configuration to each run</li>



<li>Have some kind of way for easy retries etc.</li>
</ul>



<p>Hey why don&#8217;t use Spring Batch then? </p>



<p>Because to have just a timer and not really a batch-job it is somehow the wrong tool. Furthermore Spring-Batch is build with a different goal in mind, where we start a container with one job inside to process mass of data. Quartz is more a timer, which we want to use to trigger either smaller task in our application or run kind of repeating small task and are more concerned to orchestrate and Monitor them.</p>



<ul class="wp-block-list">
<li>Spring Batch = Batch Framework to handle large datasets which should be processed, usually in an own container / pod for the duration of the Job</li>



<li>Quartz = Timer which also supports a JDBC/ REDIS store for smaller timer jobs which should run in our app cluster</li>
</ul>



<h2 class="wp-block-heading">Steps for the integration</h2>



<ul class="wp-block-list">
<li>Setup the DB</li>



<li>Configure <a rel="noreferrer noopener" aria-label="Quartz Scheduler (öffnet in neuem Tab)" href="http://www.quartz-scheduler.org" target="_blank">Quartz Scheduler</a></li>



<li>Configure CDI Job Factory</li>



<li>Register our timers</li>



<li>Set a thread priority for our job</li>
</ul>



<p>Setup the DB</p>



<p>Overall quartz comes with <a rel="noreferrer noopener" href="https://github.com/quartz-scheduler/quartz/tree/master/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore" target="_blank">SQL scripts and liquibase scripts</a> you may just include. <a href="https://sterl.org/2019/09/quartz-scheduler-integration-in-java-jee/#ipt_kb_toc_378_16">Read here</a>. For unit test we can just simply use the build in feature:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;yaml&quot;,&quot;mime&quot;:&quot;text/x-yaml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;YAML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;yaml&quot;}">spring:
  quartz:
    jdbc:
      initialize-schema: always</pre></div>



<h3 class="wp-block-heading">Configure Quartz Scheduler</h3>



<p>We will use the CMT Store here, for more details because of the why <a href="https://sterl.org/2019/09/quartz-scheduler-integration-in-java-jee/#ipt_kb_toc_378_3">please read the following tutorial</a>.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
			&lt;artifactId&gt;spring-boot-starter-quartz&lt;/artifactId&gt;
		&lt;/dependency&gt;
</pre></div>



<p>After adding the dependency we have to configure Quartz, in this example we set the thread count to 2, adjust this value based on your needs. The following configuration will usually create a <code>LocalDataSourceJobStore</code> which is an <code>JobStoreCMT</code>.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;yaml&quot;,&quot;mime&quot;:&quot;text/x-yaml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;YAML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;yaml&quot;}">spring:
  quartz:
    wait-for-jobs-to-complete-on-shutdown: false
    job-store-type: jdbc
    overwrite-existing-jobs: true
    jdbc:
      initialize-schema: always
    properties:
      org.quartz.jobStore.isClustered: true
      org.quartz.scheduler.instanceId: AUTO
      org.quartz.scheduler.skipUpdateCheck: true
      org.quartz.threadPool.threadCount: 2
  
  datasource:
    url: jdbc:h2:file:./quartz-db
    username: sa
    password: 
</pre></div>



<div class="bs-callout bs-callout-info"><strong>Note:</strong>
We init the DB just with quartz itself. But quartz contains in the core a liquibase and a SQL file which you may include into your DB update process.
</div>



<p>Yes thats basically it, we will discuss details in further deep dives, but for now lets gets a job running.</p>



<h3 class="wp-block-heading">Create a timer Job</h3>



<p>To setup a timer we have to:</p>



<ol class="wp-block-list">
<li><span style="color: initial; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen-Sans, Ubuntu, Cantarell, &quot;Helvetica Neue&quot;, sans-serif;">Add a job class</span></li>



<li>Configure the timer</li>
</ol>



<h4 class="wp-block-heading">Add a Spring configuration</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">// runs only one of these jobs in out cluster
// note we have no spring annotation here, but it contains spring beans
@DisallowConcurrentExecution 
public class QuatzTimerJob implements Job {
	// we can use spring beans, yes we cam
    @Autowired YourService yourService;
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
		yourService.doSomething();
    }

}</pre></div>



<h4 class="wp-block-heading">Configure the timer</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@Configuration
public class QuartzTimerConfiguration {
	// this registers our job itself
    @Bean
    public JobDetailFactoryBean quatzTimerJob() {
        final var jobDetailFactory = new JobDetailFactoryBean();
        jobDetailFactory.setJobClass(QuatzTimerJob.class);
        jobDetailFactory.setDescription(&quot;Simple timer like @Scheduled - but already like with ShedLock&quot;);
        jobDetailFactory.setDurability(true);
        return jobDetailFactory;
    }
    // here we add the timer, in this case every 30s, with a lower priority as normal for the job
    @Bean
    public SimpleTriggerFactoryBean trigger(JobDetail quatzTimerJob) {
        final var trigger = new SimpleTriggerFactoryBean();
        trigger.setJobDetail(quatzTimerJob);
        trigger.setRepeatInterval(30_000);
        trigger.setPriority(Thread.NORM_PRIORITY - 1);
        trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
        return trigger;
    }
}</pre></div>



<h3 class="wp-block-heading">Trigger a job</h3>



<p>In difference to a normal Spring timer we may now fire triggers for Quartz Jobs, even add data to the triggers itself, at let Quartz handle the heavy work for us. Handy if we want QUEUE some work, or just distribute the load in our cluster to all available nodes. For this we have to:</p>



<ol class="wp-block-list">
<li>Create a job instance we want to execute</li>



<li>Configure the job &#8211; but now without any default trigger</li>



<li>Create somewhere in our code the triggers, usually with some payload data</li>
</ol>



<h4 class="wp-block-heading">Create a job</h4>



<p>Very simple thing here, just getting one value from the job context and calling out service.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">public class TriggeredJob implements Job {

    @Autowired YourService yourService;
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        long count = context.getMergedJobDataMap().getLong(&quot;count&quot;));
        yourService.doSomething(count);
    }

}</pre></div>



<h4 class="wp-block-heading">Configure the job</h4>



<p>The only special thing here is that we request a recovery on a different node, should this node for some reason die during the execution of the job.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@Configuration
public class QuartzJobConfiguration {
    @Bean
    public JobDetailFactoryBean createStoreItemsJob() {
        final var jobDetailFactory = new JobDetailFactoryBean();
        jobDetailFactory.setJobClass(CreateStoreItemsJob.class);
        jobDetailFactory.setDescription(&quot;Job we directly trigger if we want to run it&quot;);
        jobDetailFactory.setDurability(true);
        jobDetailFactory.setRequestsRecovery(true);
        return jobDetailFactory;
    }
}</pre></div>



<h4 class="wp-block-heading">Trigger the job</h4>



<div class="bs-callout bs-callout-info"><strong>Note:</strong>
The usage of <code>@Transactional</code>, this is by purpose, to ensure the trigger gets removed if we happen to rollback the transaction. If it is missing, quartz will silently create an own one.
</div>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">    @Autowired Scheduler scheduler;
    @Autowired JobDetail createStoreItemsJob;

    @Transactional
    public void triggerStoreItemCreation() throws SchedulerException {
        Trigger t = TriggerBuilder.newTrigger()
            .forJob(createStoreItemsJob)
            .startNow() // run on this node if possible, means we have threads
            .usingJobData(&quot;count&quot;, count)
            .build();
        
        scheduler.scheduleJob(t);
    }</pre></div>



<h2 class="wp-block-heading">Testing it</h2>



<p>You may wonder why we used a file DB in this configuration. Only with a DB which contains the trigger data after a restart you may play around and also kill the running Spring application. After a restart the jobs are triggered again.</p>



<h2 class="wp-block-heading">Alternatives</h2>



<p>We could also go for a command queue using e.g. JMS. This aproach would require  additional infrastructure in form of a persistent broker. Which could be easy in the cloud but rather difficult if you have to operate and maintain it on your own. In the end a data store which have to join our DB transactions in case ACID is an issue and it always is.</p>



<h2 class="wp-block-heading">Links</h2>



<ul class="wp-block-list">
<li><a href="https://github.com/sterlp/training/tree/master/spring-quartz">https://github.com/sterlp/training/tree/master/spring-quartz</a></li>



<li><a href="https://spring.getdocs.org/en-US/spring-boot-docs/boot-features/boot-features-quartz.html">https://spring.getdocs.org/en-US/spring-boot-docs/boot-features/boot-features-quartz.html</a></li>



<li><a href="http://www.quartz-scheduler.org/documentation/quartz-2.3.0/cookbook/">http://www.quartz-scheduler.org/documentation/quartz-2.3.0/cookbook/</a></li>
</ul>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2022/07/quartz-integration-in-spring/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>JPA Model testing with Hibernate Statistics</title>
		<link>https://sterl.org/2021/08/jpa-model-testing-with-hibernate-statistics/</link>
					<comments>https://sterl.org/2021/08/jpa-model-testing-with-hibernate-statistics/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Sun, 01 Aug 2021 11:25:00 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Statistics]]></category>
		<category><![CDATA[Unit Test]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=925</guid>

					<description><![CDATA[Problem Often we write JPA Entity classes an have to ensure in a larger team that refactoring doesn&#8217;t create performance problems or logical errors in the entity model usual problems are: In your test]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Problem</h2>



<p>Often we write JPA Entity classes an have to ensure in a larger team that refactoring doesn&#8217;t create performance problems or logical errors in the entity model usual problems are:</p>



<ul class="wp-block-list">
<li>Missing fetch joins in Queries
<ul class="wp-block-list">
<li>Which leads to slow fetch joins</li>
</ul>
</li>



<li>Wrong direction of Entity relations 
<ul class="wp-block-list">
<li>which leads to updates after inserts</li>



<li>or even to deletes and reinserts of data</li>
</ul>
</li>



<li>Wrong transaction boundaries
<ul class="wp-block-list">
<li>Which leads to multiple transactions for one logical business operation</li>
</ul>
</li>
</ul>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@Component
public class HibernateAsserts {
  private final Statistics statistics;

  public HibernateAsserts(EntityManager entityManager) {
    try (Session session = entityManager.unwrap(org.hibernate.Session.class)) {
      @SuppressWarnings(&quot;resource&quot;)
      SessionFactory factory = session.getSessionFactory();
      factory.getStatistics().setStatisticsEnabled(true);
      statistics = factory.getStatistics();
    }
  }
  
  public HibernateAsserts assertTrxCount(int expected) {
    long value = statistics.getTransactionCount();
    if (value != expected) {
      logSummary();
      fail(&quot;Expected &quot; + expected + &quot; TransactionCount, but found &quot; + value);
    }
    return this;
  }
  
  public HibernateAsserts assertInsertCount(int expected) {
    long value = statistics.getEntityInsertCount();
    if (value != expected) {
      logSummary();
      fail(&quot;Expected &quot; + expected + &quot; EntityInsertCount, but found &quot; + value);
    }
    return this;
  }

  public void reset() {
    statistics.clear();
  }

  public void logSummary() {
    statistics.logSummary();
  }
}</pre></div>



<h2 class="wp-block-heading">In your test</h2>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@SpringBootTest
class MyTestClassTest {

  @Autowired private SubjectUnderTest subject;
  @Autowired private HibernateAsserts hibernateAsserts;
  
  @Test
  void textMyBusinessMethod() {
    // GIVEN
    // custom data setup for the test

    // WHEN
    hibernateAsserts.reset(); // ensure the setup is not in the stats
    subject.runBusinessMethod();
    
    // THEN
    // any business asserts
    hibernateAsserts
      .assertTrxCount(1)
      .assertInsertCount(1);
  }
}</pre></div>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2021/08/jpa-model-testing-with-hibernate-statistics/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Reconnecting JMS listener</title>
		<link>https://sterl.org/2020/04/reconnecting-jms-listener/</link>
					<comments>https://sterl.org/2020/04/reconnecting-jms-listener/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Sat, 04 Apr 2020 13:34:15 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JEE]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[JMS]]></category>
		<category><![CDATA[Reconnect]]></category>
		<guid isPermaLink="false">http://sterl.org/?p=558</guid>

					<description><![CDATA[Problem In some projects we still may need to manually to reconnect to our JMS provider. For what ever reason the framework or the container cannot do the job for us. As so we have to ensure that an once registered JMS listener re-register itself if something bad happens. Note: Check first if your container&#8230;]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Problem</h2>



<p>In some projects we still may need to manually to reconnect to our JMS provider. For what ever reason the framework or the container cannot do the job for us. As so we have to ensure that an once registered JMS listener re-register itself if something bad happens.</p>



<div class="bs-callout bs-callout-info"><strong>Note:</strong>
Check first if your container can handle this for you.
</div>



<h2 class="wp-block-heading">Solution</h2>



<p>Well some <code>JmsConnectionFactory</code> already support a re-connection but they are not always very reliable. For instance, the <a rel="noreferrer noopener" href="https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.ref.dev.doc/q111980_.htm" target="_blank">IBM driver supports</a> in theory a reconnect, but it is just a bit buggy.</p>



<p>Well, what is the straight forward solution? The most easiest way is just to register an exception listener with the connection and rebuild the connection from here:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}"> connection.setExceptionListener((e) -&gt; {
   connection = cf.createConnection();
   session = connection.createSession();
   consumer = session.createConsumer(session.createQueue(&quot;FANCY.QUEUE.NAME&quot;));
   consumer.setMessageListener((m) -&gt; {
     System.out.println(&quot;onMessage: &quot; + m);
   }
   connection.start();
 });
</pre></div>



<p>Not clean but in theory, this is all that we have to do. Of course, we have to handle the state, the old connection and even worse think about a retry if the connection cannot be created immediately again. The last part considering that we have of course also the requirement to stop the connection and avoid race conditions is the hard part.</p>



<h3 class="wp-block-heading">ReconnectinListener</h3>



<p>Let us build a <code>ReconnectingListener</code> step by step. What we have seen above is that we need a way to determine the desired connection state and we have to provide separate methods for <code>connect </code>and <code>disconnect </code>as we will do this more often, in case we have to retry to re-connect again.</p>



<h4 class="wp-block-heading">Connecting and Disconnecting</h4>



<p>Lets us first solve the connect and disconnect problem. The user should be able to:</p>



<ol class="wp-block-list"><li>Have a separate connect method</li><li>Store the user desire if we should be connected or not</li><li>Have a separate disconnect method</li><li>Have a way to clear the resources without to reset the user desire</li><li>Have a way to check if the connection is up and running</li></ol>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@RequiredArgsConstructor
static class ReconnectingListener implements MessageListener,  ExceptionListener {
    final JmsConnectionFactory cf;
    final String destinationQueue;
    
    private Connection connection;
    private Session session;
    private MessageConsumer consumer;
    // 1. Have a separate connect method
    public synchronized void connect() throws JMSException {
        // 2. Store the user desire if we should be connected or not
        shouldRun.set(true);
        if (!isConnected()) {
            connection = cf.createConnection();
            session = connection.createSession();
            consumer = session.createConsumer(session.createQueue(destinationQueue));
            consumer.setMessageListener(this); // register us
            connection.setExceptionListener(this); // react on errors
            connection.start();
        }
    }
    // 3. Have a separate disconnect method 
    public synchronized void disconnect() {
        // 2. Store the user desire if we should be connected or not
        shouldRun.set(false);
        clearConnection();
    }
    // 4. Have a way to clear the resources without to reset the user desire
    private synchronized void clearConnection() {
        JmsUtil.close(consumer);
        JmsUtil.close(session);
        JmsUtil.close(connection);
        consumer = null;
        session = null;
        connection = null;
        LOG.debug(&quot;Connection cleared and stoped&quot;);
   }
   // 5. Have a way to check if the connection is up and running
   public boolean isConnected() {
       return connection != null &amp;&amp; consumer != null &amp;&amp; session != null;
   }</pre></div>



<h4 class="wp-block-heading">Reconnect &#8222;onException&#8220;</h4>



<p>Having solved this we have to re-connect back to the JMS Broker if we lose the connection. For this have to implement the <code>ExceptionListener </code>interface as shown above and now to implement <code>onException</code>.  The goal here is now:</p>



<ol class="wp-block-list"><li>Clear the old connection to avoid a double registration</li><li>Schedule a delayed retry to connect again</li><li>Check if we still should be connected</li><li>Retry again, if we fail in our retry to connect to the broker</li></ol>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">// we need a executer to delay a retry attempt
private final ScheduledExecutorService reconnectScheduler = Executors.newScheduledThreadPool(1);
@Override
public void onException(JMSException exception) {
    // 1. Clear the old connection to avoid a double registration
    clearConnection();
    // 2. Schedule a delayed retry to connect again
    reconnect(5);
}
private void reconnect(final int delay) {            
    reconnectScheduler.schedule(() -&gt; {
        // 3. Check if we still should be connected
        if (shouldRun.get()) {
            try {
                // here we use our connect method from above
                connect();
            } catch (Exception e) {
                // 4. Retry again, if we fail in our retry to connect to the broker
                LOG.info(&quot;Reconnect failed, will retry in {}s. {}&quot;, delay, e.getMessage());
                clearConnection(); // just for savety
                reconnect(delay);
            }
        }
    }, delay, TimeUnit.SECONDS);
}</pre></div>



<p>That&#8217;s it. Basically we solved all basic requirements </p>



<h3 class="wp-block-heading">Going further</h3>



<p>We should of course provide the ability to set a subscription filter and maybe we should just implement the <code>Closeable </code>interface to provide a more modern API. Not to forget that we have now hardcoded that we subscribe always to a queue, means a way to tell the code if it is a topic or not would be too bad.  Maybe we should also consider using the JMS 2.x API like:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">public synchronized void connectJms2() throws JMSException {
    shouldRun.set(true);
    if (!isConnected()) {
        context = cf.createContext();
        context.setExceptionListener(this);
        context.setAutoStart(true);
        consumer = context.createConsumer(context.createQueue(destinationQueue));
        consumer.setMessageListener(this); // register us
    }
}</pre></div>



<p>Last but not least we could also destroy the executor. Looking forward to a pull request :-).</p>



<h2 class="wp-block-heading">Links</h2>



<ul class="wp-block-list"><li><a rel="noreferrer noopener" href="https://github.com/sterlp/training/blob/master/jms-trainging/src/test/java/org/sterl/training/jms/ibm/IbmReconnectExampleTest.java" target="_blank">Source Code on GitHub</a></li><li><a rel="noreferrer noopener" href="https://docs.oracle.com/cd/E19798-01/821-1751/abljw/index.html" target="_blank">Oracle Docs for connection pool and reconnect for JEE</a></li><li><a href="https://eclipse-ee4j.github.io/glassfish/docs/5.1.0/administration-guide/jms.html" target="_blank" rel="noreferrer noopener">Glassfish Doc</a></li></ul>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2020/04/reconnecting-jms-listener/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
