{"@attributes":{"version":"2.0"},"channel":{"title":"JBake","link":"https:\/\/kostenko.org","description":"JBake Bootstrap Template","language":"en-gb","pubDate":"Mon, 13 Dec 2021 11:58:43 +0200","lastBuildDate":"Mon, 13 Dec 2021 11:58:43 +0200","item":[{"title":"Infinispan Apache Log4j 2 CVE-2021-44228 vulnerability","link":"https:\/\/kostenko.org\/blog\/2021\/12\/infinispan-log4j-2-CVE-2021-44228.html","pubDate":"Mon, 13 Dec 2021 00:00:00 +0200","guid":"blog\/2021\/12\/infinispan-log4j-2-CVE-2021-44228.html","description":"\n\t<p><strong><a href=\"https:\/\/infinispan.org\/\">Infinispan<\/a><\/strong> 10+ uses <a href=\"https:\/\/logging.apache.org\/log4j\/2.x\/index.html\">Log4j<\/a> version <strong>2.0+<\/strong> and can be affected by vulnerability <strong><a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2021-44228\">CVE-2021-44228<\/a><\/strong>, which has a 10.0 CVSS score. The first fixed Log4j version is <strong>2.15.0.<\/strong><br \/>\nSo, until official patch is coming, - you can update used logger version to the latest in few simple steps<\/p>\n<ul>\n<li>Download Log4j version 2.15.0:  <a href=\"https:\/\/www.apache.org\/dyn\/closer.lua\/logging\/log4j\/2.15.0\/apache-log4j-2.15.0-bin.zip\">https:\/\/www.apache.org\/dyn\/closer.lua\/logging\/log4j\/2.15.0\/apache-log4j-2.15.0-bin.zip<\/a><\/li>\n<li>Unpack distributive<\/li>\n<li>Replace affected libraries<\/li>\n<\/ul>\n<pre><code class=\"language-java\">wget https:\/\/downloads.apache.org\/logging\/log4j\/2.15.0\/apache-log4j-2.15.0-bin.zip\nunzip apache-log4j-2.15.0-bin.zip\n\ncd \/opt\/infinispan-server-10.1.8.Final\/lib\/\n\nrm log4j-*.jar\ncp ~\/Downloads\/apache-log4j-2.15.0-bin\/log4j-api-2.15.0.jar .\/\ncp ~\/Downloads\/apache-log4j-2.15.0-bin\/log4j-core-2.15.0.jar .\/\ncp ~\/Downloads\/apache-log4j-2.15.0-bin\/log4j-jul-2.15.0.jar .\/\ncp ~\/Downloads\/apache-log4j-2.15.0-bin\/log4j-slf4j-impl-2.15.0.jar .\/\n<\/code><\/pre>\n<p>Please, note - patch above is not official, but according to initial tests it works with no issues<\/p>\n\n\t"},{"title":"Undertow AJP balancer. UT005028: Proxy request failed: java.nio.BufferOverflowException","link":"https:\/\/kostenko.org\/blog\/2021\/04\/undertow-ajp-balancer-.html","pubDate":"Sat, 3 Apr 2021 00:00:00 +0300","guid":"blog\/2021\/04\/undertow-ajp-balancer-.html","description":"\n\t<p>Wildfly provides great out of the box <a href=\"https:\/\/kostenko.org\/blog\/2019\/04\/wildfly-cluster-domain-mode.html\">load balancing support<\/a> by <strong>Undertow<\/strong> and <strong>modcluster<\/strong> subsystems<br \/>\nUnfortunately, in case  HTTP headers size is huge enough (close to 16K),  which is so actual in JWT era - pity error happened:<\/p>\n<pre><code class=\"language-java\">ERROR [io.undertow.proxy] (default I\/O-10) UT005028: Proxy request to \/ee-jax-rs-examples\/clusterdemo\/serverinfo failed: java.io.IOException: java.nio.BufferOverflowException\n at io.undertow.server.handlers.proxy.ProxyHandler$HTTPTrailerChannelListener.handleEvent(ProxyHandler.java:771)\n at io.undertow.server.handlers.proxy.ProxyHandler$ProxyAction$1.completed(ProxyHandler.java:646)\n at io.undertow.server.handlers.proxy.ProxyHandler$ProxyAction$1.completed(ProxyHandler.java:561)\n at io.undertow.client.ajp.AjpClientExchange.invokeReadReadyCallback(AjpClientExchange.java:203)\n at io.undertow.client.ajp.AjpClientConnection.initiateRequest(AjpClientConnection.java:288)\n at io.undertow.client.ajp.AjpClientConnection.sendRequest(AjpClientConnection.java:242)\n at io.undertow.server.handlers.proxy.ProxyHandler$ProxyAction.run(ProxyHandler.java:561)\n at io.undertow.util.SameThreadExecutor.execute(SameThreadExecutor.java:35)\n at io.undertow.server.HttpServerExchange.dispatch(HttpServerExchange.java:815)\n...\nCaused by: java.nio.BufferOverflowException\n at java.nio.Buffer.nextPutIndex(Buffer.java:521)\n at java.nio.DirectByteBuffer.put(DirectByteBuffer.java:297)\n at io.undertow.protocols.ajp.AjpUtils.putString(AjpUtils.java:52)\n at io.undertow.protocols.ajp.AjpClientRequestClientStreamSinkChannel.createFrameHeaderImpl(AjpClientRequestClientStreamSinkChannel.java:176)\n at io.undertow.protocols.ajp.AjpClientRequestClientStreamSinkChannel.generateSendFrameHeader(AjpClientRequestClientStreamSinkChannel.java:290)\n at io.undertow.protocols.ajp.AjpClientFramePriority.insertFrame(AjpClientFramePriority.java:39)\n at io.undertow.protocols.ajp.AjpClientFramePriority.insertFrame(AjpClientFramePriority.java:32)\n at io.undertow.server.protocol.framed.AbstractFramedChannel.flushSenders(AbstractFramedChannel.java:603)\n at io.undertow.server.protocol.framed.AbstractFramedChannel.flush(AbstractFramedChannel.java:742)\n at io.undertow.server.protocol.framed.AbstractFramedChannel.queueFrame(AbstractFramedChannel.java:735)\n at io.undertow.server.protocol.framed.AbstractFramedStreamSinkChannel.queueFinalFrame(AbstractFramedStreamSinkChannel.java:267)\n at io.undertow.server.protocol.framed.AbstractFramedStreamSinkChannel.shutdownWrites(AbstractFramedStreamSinkChannel.java:244)\n at io.undertow.channels.DetachableStreamSinkChannel.shutdownWrites(DetachableStreamSinkChannel.java:79)\n at io.undertow.server.handlers.proxy.ProxyHandler$HTTPTrailerChannelListener.handleEvent(ProxyHandler.java:754)\n<\/code><\/pre>\n<p>The same request directly to backend server works well.  Tried to play with <strong>ajp-listener<\/strong> and <strong>mod-cluster<\/strong> filter <strong>&quot;max-*&quot;<\/strong> parameters, but have no luck.<\/p>\n<p>Possible solution here is switch protocol from AJP to HTTP which can be bit less effective, but works well with big headers:<\/p>\n<pre><code class=\"language-java\">\/profile=full-ha\/subsystem=modcluster\/proxy=default:write-attribute(name=listener, value=default)\n<\/code><\/pre>\n\n\t"},{"title":"Improve Oracle JDBC performance by fetch size tuning","link":"https:\/\/kostenko.org\/blog\/2020\/12\/oracle-jdbc-defaultrowprefetch.html","pubDate":"Mon, 28 Dec 2020 00:00:00 +0200","guid":"blog\/2020\/12\/oracle-jdbc-defaultrowprefetch.html","description":"\n\t<p>By default, when Oracle JDBC driver executes query, it retrieves a result set of <strong>10 rows<\/strong> at a time from the database cursor. Low fetch size value might cause more roundtrips to DB and this leads to a longer time to fetch results from queries. You can change the number of rows retrieved with each trip to the database cursor by changing the row fetch size value.<\/p>\n<p><strong>Statement, PreparedStatement, CallableStatement<\/strong>, and <strong>ResultSet<\/strong> provides next methods for dealing with fetch size:<\/p>\n<pre><code class=\"language-java\">void setFetchSize(int rows) throws SQLException\n\nint getFetchSize() throws SQLException\n<\/code><\/pre>\n<p>Default fetch size value  can be changed by <strong>defaultRowPrefetch<\/strong> connection property:<\/p>\n<p>On Wildfly Application Server DataSource level by:<\/p>\n<pre><code class=\"language-bash\">[standalone@localhost:9990 \/] \/subsystem=datasources\/data-source=ExampleOraDS\/connection-properties=defaultRowPrefetch:add(value=1000)\n<\/code><\/pre>\n<p>On Hibernate level by  <strong><code>hibernate.jdbc.fetch_size<\/code><\/strong> property:<\/p>\n<pre><code class=\"language-xml\">&lt;properties&gt;\n  ...\n  &lt;property name=&quot;hibernate.jdbc.fetch_size&quot; value=&quot;1000&quot; \/&gt;\n  ...\n&lt;\/properties&gt;\n<\/code><\/pre>\n<p>I did simple test:<\/p>\n<pre><code class=\"language-java\">@Test\npublic void defaultRowPrefetchTest() throws Exception {\n   EntityManager em = Persistence.createEntityManagerFactory(&quot;myDSTestOra&quot;).createEntityManager();\n\n   Long time = System.currentTimeMillis();\n\n   Query q = em.createNativeQuery(&quot;SELECT * FROM MY_TABLE&quot;, Tuple.class);\n   List&lt;Tuple&gt; resultList = q.getResultList();\n\n   System.out.println(System.currentTimeMillis() - time);\n}\n<\/code><\/pre>\n<p>And on my laptop, fetching of <strong>16K<\/strong> records takes <strong>~185 ms<\/strong> with default value and <strong>~86 ms<\/strong> with <code>defaultRowPrefetch = 20000<\/code>. As you can see from the result - there is more than <strong>x2<\/strong> performance improvement.<\/p>\n<p>Source code of test case on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-jpa-examples\">GitHub<\/a><\/p>\n\n\t"},{"title":"Microprofile metrics with Wildfly Application Server","link":"https:\/\/kostenko.org\/blog\/2020\/12\/wildfly-microprofile-metrics.html","pubDate":"Sun, 27 Dec 2020 00:00:00 +0200","guid":"blog\/2020\/12\/wildfly-microprofile-metrics.html","description":"\n\t<p>Any enterprise application can't be completely successful on production without good monitoring solution. For years vendors and developers provided custom tooling for it. Since <strong><a href=\"https:\/\/github.com\/eclipse\/microprofile-metrics\">Eclipse Microprofile Metrics<\/a><\/strong> specification we have a unified way to export monitoring data to the management agents and  unified Java API, that developers can use to expose their telemetry data.<\/p>\n<p>Wildfly application server provides  microprofile metrics support, but unfortunately <strong>only for standalone configurations<\/strong>  yet.  In case <strong>domain mode<\/strong> you can provide necessary dependencies<\/p>\n<pre><code class=\"language-java\">dependencies {\n    compile group: 'org.eclipse.microprofile.metrics', name: 'microprofile-metrics-api', version: '2.3'\n    compile group: 'io.smallrye', name: 'smallrye-metrics', version: '2.4.0'\n}\n<\/code><\/pre>\n<p>and then expose application scope metrics through custom endpoint like<\/p>\n<pre><code class=\"language-java\">import io.smallrye.metrics.exporters.JsonExporter;\nimport io.smallrye.metrics.exporters.OpenMetricsExporter;\n...\n@Singleton\n@Path(&quot;\/metrics&quot;)\npublic class MetricsTestResource {\n\n  private OpenMetricsExporter openMetricsExporter = new OpenMetricsExporter();\n  private JsonExporter jsonExporter = new JsonExporter();\n\n  @GET\n  @Path(&quot;\/prmths&quot;)\n  public String prometheus() {\n    return openMetricsExporter.exportAllScopes().toString();\n  }\n\n  @GET\n  @Path(&quot;\/json&quot;)\n  public String json() {\n    return jsonExporter.exportAllScopes().toString();\n  }\n<\/code><\/pre>\n<p>JVM and subsystems metrics will not be available by endpoint above, but them  you can obtain through old good JMX.<\/p>\n<p>Standalone server from the box provides metrics in  <strong>prometheus<\/strong> format for all scopes over management interface (port <strong>9990<\/strong> ) using <strong><code>org.wildfly.extension.microprofile.metrics-smallrye<\/code><\/strong> extension and <strong><code>microprofile-metrics-smallrye<\/code><\/strong> subsystem.<\/p>\n<pre><code class=\"language-bash\">kostenko@kostenko:$ curl http:\/\/127.0.0.1:9990\/metrics\/\n# HELP base_classloader_loadedClasses_count Displays the number of classes that are currently loaded in the Java virtual machine.\n# TYPE base_classloader_loadedClasses_count gauge\nbase_classloader_loadedClasses_count 11826.0\n# HELP base_cpu_availableProcessors Displays the number of processors available to the Java virtual machine. This value may change during a particular invocation of the virtual machine.\n# TYPE base_cpu_availableProcessors gauge\nbase_cpu_availableProcessors 8.0\n...\n<\/code><\/pre>\n<p>For developers available next annotations (sorry for the low output examples values):<\/p>\n<ul>\n<li><strong>@Counted<\/strong> - counter, which counts the invocations of the annotated object.\n<pre><code class=\"language-bash\"># TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_total counter\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_total 1.0\n<\/code><\/pre>\n<\/li>\n<li><strong>@ConcurrentGauge<\/strong> - gauge which counts the parallel invocations of the annotated object.\n<pre><code class=\"language-bash\"># TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_current gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_current 1.0\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_max gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_max 1.0\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_min gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_min 0.0\n<\/code><\/pre>\n<\/li>\n<li><strong>@Gauge<\/strong> - gauge, which samples the value of the annotated object.\n<pre><code class=\"language-bash\"># TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_json gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_json 123.0\n<\/code><\/pre>\n<\/li>\n<li><strong>@Metered<\/strong> - meter, which tracks the frequency of invocations of the annotated object.\n<pre><code class=\"language-bash\"># TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_total counter\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_total 6.0\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_rate_per_second gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_rate_per_second 0.209682602430885\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_one_min_rate_per_second gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_one_min_rate_per_second 0.015991117074135343\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_five_min_rate_per_second gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_five_min_rate_per_second 0.0033057092356765017\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_fifteen_min_rate_per_second gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_fifteen_min_rate_per_second 0.0011080303990206543\n<\/code><\/pre>\n<\/li>\n<li><strong>@Metric<\/strong> - annotation that contains the metadata information when requesting a metric to be injected.\n<pre><code class=\"language-bash\"><\/code><\/pre>\n<\/li>\n<li><strong>@Timed<\/strong> - timer, which tracks duration of the annotated object.\n<pre><code class=\"language-bash\"># TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_rate_per_second gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_rate_per_second 0.09811766798116955\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_one_min_rate_per_second gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_one_min_rate_per_second 0.030703655021877174\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_five_min_rate_per_second gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_five_min_rate_per_second 0.0065567799035988195\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_fifteen_min_rate_per_second gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_fifteen_min_rate_per_second 0.002209922141215539\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_min_seconds gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_min_seconds 5.88813E-4\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_max_seconds gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_max_seconds 0.005724684\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_mean_seconds gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_mean_seconds 0.0030220556126073638\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_stddev_seconds gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_stddev_seconds 0.0025644006235855748\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_seconds summary\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_seconds_count 2.0\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_seconds{quantile=&quot;0.5&quot;} 5.88813E-4\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_seconds{quantile=&quot;0.75&quot;} 0.005724684\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_seconds{quantile=&quot;0.95&quot;} 0.005724684\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_seconds{quantile=&quot;0.98&quot;} 0.005724684\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_seconds{quantile=&quot;0.99&quot;} 0.005724684\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_seconds{quantile=&quot;0.999&quot;} 0.005724684\n<\/code><\/pre>\n<\/li>\n<li><strong>@SimplyTimed<\/strong> - simple timer, which tracks duration and invocations of the annotated object.\n<pre><code class=\"language-bash\"># TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_total counter\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_total 1.0\n# TYPE application_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_elapsedTime_seconds gauge\napplication_org_kostenko_examples_microprofile_metrics_MetricsTestResource_prometheus_elapsedTime_seconds 0.005032859\n<\/code><\/pre>\n<\/li>\n<\/ul>\n<p><a href=\"https:\/\/prometheus.io\/docs\/introduction\/overview\/\">Prometheus<\/a> is a free software application used for event monitoring and alerting. It records real-time metrics in a time series database (allowing for high dimensionality) built using a HTTP pull model, with flexible queries and real-time alerting.<\/p>\n<p>Let's setup above and check how metrics monitoring with Prometheus looks on practice:<\/p>\n<pre><code class=\"language-bash\">wget https:\/\/github.com\/prometheus\/prometheus\/releases\/download\/v2.23.0\/prometheus-2.23.0.linux-amd64.tar.gz\ntar xvfz prometheus-*.tar.gz\ncd prometheus-*\n<\/code><\/pre>\n<p>To provide path to the metrics endpoint edit <strong><code>prometheus.yml<\/code><\/strong> and provide correct <strong>metrics_path<\/strong> and <strong>targets<\/strong><\/p>\n<pre><code class=\"language-yaml\"># Here it's Prometheus itself.\nscrape_configs:\n  # The job name is added as a label `job=&lt;job_name&gt;` to any timeseries scraped from this config.\n  - job_name: 'prometheus'\n\n    # metrics_path defaults to '\/metrics'\n    # scheme defaults to 'http'.\n\n    static_configs:\n    - targets: ['127.0.0.1:9990']\n<\/code><\/pre>\n<p>This is it! <strong><code>http:\/\/localhost:9090\/graph<\/code><\/strong> :<br \/>\n<img src=\"\/img\/2020-12-wildfly-mp-metrics.png\" alt=\"wildfly-microprofile-metrics\" \/><\/p>\n<p>Now our metrics is collecting and can be visualized over standard prometheus UI(shown above) or easy integrated with <a href=\"https:\/\/prometheus.io\/docs\/visualization\/grafana\/\">grafana<\/a><\/p>\n<p>Source code of custom metrics endpoint example available on <a href=\"https:\/\/github.com\/kostenkoserg\/wildfly-microprofile-example\">GitHub<\/a><\/p>\n\n\t"},{"title":"Infinispan Server as Wildfly remote cache container for your Jakarta EE application","link":"https:\/\/kostenko.org\/blog\/2020\/11\/infinispan-server-wildfly-integration.html","pubDate":"Sun, 29 Nov 2020 00:00:00 +0200","guid":"blog\/2020\/11\/infinispan-server-wildfly-integration.html","description":"\n\t<p><img src=\"\/img\/2020-11-wildfly-infinispan-server-1.png\" alt=\"pager\" \/><\/p>\n<p>Recently i wrote a few articles about <a href=\"https:\/\/kostenko.org\/tags\/infinispan.html\">using infinispan cache<\/a> based on Wildfly infinispan subsystem. But even though Wildfly provides well cache containers management support, - from the high load and high availability points of view, make sense to take a look to separate clustered cache instances.<\/p>\n<p><strong>PROS:<\/strong><\/p>\n<ul>\n<li>Heap, threads, GC pauses separated between application and cache containers.<\/li>\n<li>Application or cache can be scaled separately depends on needs<\/li>\n<li>More configuration possibilities (like ASYNC replication etc)<\/li>\n<li>Minimizing affect of application to cache distribution and visa verse<\/li>\n<li>Application containers restart keeps stored cache data<\/li>\n<\/ul>\n<p><strong>CONS:<\/strong><\/p>\n<ul>\n<li>Increase infrastructure complexity<\/li>\n<li>Additional support and monitoring unit<\/li>\n<li>Additional costs in case separate cache cloud nodes<\/li>\n<\/ul>\n<p>Fortunately, with Wildfly Application Server it easy enough to <strong>switch between embedded and remote cache containers<\/strong> even in runtime (just another JNDI lookup). So, let's try it out! And first, we need to download  stable <strong><a href=\"https:\/\/infinispan.org\/download-archive\/\">infinispan server release<\/a><\/strong>. I have chosen <strong>10.1.8<\/strong> as my Wildfly 20 uses this one and  potential compatibility issues should be excluded.<\/p>\n<p>After download, please extract distribution archive and run infinispan server<\/p>\n<pre><code class=\"language-bash\">kostenko@kostenko:\/opt\/infinispan-server-10.1.8.Final\/bin$ .\/server.sh\n<\/code><\/pre>\n<p>By default infinispan server will use port <strong>11222<\/strong> on <strong>127.0.0.1<\/strong>. To bind another IP just use <strong>-b<\/strong> binding parameter like <strong><code>-b 0.0.0.0<\/code><\/strong> on startup.<\/p>\n<p>To create named cache you can use provided UI (<a href=\"http:\/\/127.0.0.1:11222\/\">http:\/\/127.0.0.1:11222\/<\/a>) or cli console like<\/p>\n<pre><code class=\"language-bash\">\/opt\/iplatform\/infinispan\/bin\/cli.sh\n[disconnected]&gt; connect\ncreate cache --template=org.infinispan.REPL_ASYNC myremotecache\n<\/code><\/pre>\n<p>Now let's perform Wildfly configuration to use remote cache container<\/p>\n<pre><code class=\"language-bash\">\/socket-binding-group=standard-sockets\/remote-destination-outbound-socket-binding=ispn1:add(host=127.0.0.1, port=11222)\nbatch\n\/subsystem=infinispan\/remote-cache-container=myRemoteContainer:add(default-remote-cluster=data-grid-cluster)\n\/subsystem=infinispan\/remote-cache-container=myRemoteContainer\/remote-cluster=data-grid-cluster:add(socket-bindings=[ispn1])\nrun-batch\n<\/code><\/pre>\n<p>Actually, we just have finished with environment configuration and now we are ready for application development. As usual, <strong>Jakarta EE<\/strong>  <strong><code>build.gradle<\/code><\/strong> looks pretty laconical:<\/p>\n<pre><code class=\"language-java\">apply plugin: 'war'\ndependencies {\n    providedCompile &quot;jakarta.platform:jakarta.jakartaee-api:8.0.0&quot;\n    providedCompile &quot;org.infinispan:infinispan-core:10.1.8.Final&quot;\n    providedCompile &quot;org.infinispan:infinispan-client-hotrod:10.1.8.Final&quot;\n}\n<\/code><\/pre>\n<p>To use configured cache container just inject registered <strong>@Resource<\/strong>:<\/p>\n<pre><code class=\"language-java\">@Named\npublic class TestCacheService {\n\n    public static final String REMOTE_CACHE_NAME = &quot;myremotecache&quot;;\n\n    @Resource(lookup = &quot;java:jboss\/infinispan\/remote-container\/myRemoteContainer&quot;)\n    org.infinispan.client.hotrod.RemoteCacheContainer remoteCacheContainer;\n\n    public void putRemoteCache(String key, String value) {\n        remoteCacheContainer.getCache(REMOTE_CACHE_NAME).put(key, String.format(&quot;%s (%s)&quot;, value, new Date()));\n    }\n\n    public Object getRemoteCache(String key) {\n        return remoteCacheContainer.getCache(REMOTE_CACHE_NAME).get(key);\n    }\n}\n<\/code><\/pre>\n<p>Also, you can provide resource reference by <strong><code>WEB-INF\/web.xml<\/code><\/strong> descriptor and use shorter resource lookup <strong>by name<\/strong> like <code>@Resource(name = &quot;myremotecontainer&quot;)<\/code><\/p>\n<pre><code class=\"language-xml\">&lt;resource-env-ref&gt;\n    &lt;resource-env-ref-name&gt;myremotecontainer&lt;\/resource-env-ref-name&gt;\n    &lt;lookup-name&gt;java:jboss\/infinispan\/remote-container\/myRemoteContainer&lt;\/lookup-name&gt;\n&lt;\/resource-env-ref&gt;\n<\/code><\/pre>\n<p>Last thing we need, - is provide module dependencies by <strong><code>MANIFEST.MF<\/code><\/strong>:<\/p>\n<pre><code class=\"language-java\">Manifest-Version: 1.0\nDependencies: org.infinispan, org.infinispan.commons, org.infinispan.client.hotrod export\n<\/code><\/pre>\n<p>OR through <strong><code>jboss-deployment-structure.xml<\/code><\/strong> :<\/p>\n<pre><code class=\"language-xml\">&lt;jboss-deployment-structure&gt;\n   &lt;deployment&gt;\n      &lt;dependencies&gt;\n         &lt;module name=&quot;org.infinispan&quot; export=&quot;TRUE&quot; \/&gt;\n         &lt;module name=&quot;org.infinispan.commons&quot; export=&quot;TRUE&quot; \/&gt;\n         &lt;module name=&quot;org.infinispan.client.hotrod&quot; export=&quot;TRUE&quot; \/&gt;\n      &lt;\/dependencies&gt;\n   &lt;\/deployment&gt;\n&lt;\/jboss-deployment-structure&gt;\n<\/code><\/pre>\n<p>This is it! Build, deploy, and test it out.<\/p>\n<pre><code class=\"language-bash\">curl -o - &quot;http:\/\/localhost:8080\/jcache-examples\/jcache\/ispn-remote-put?key=KEY1&amp;value=VALUE1&quot;\nok\ncurl -o - &quot;http:\/\/localhost:8080\/jcache-examples\/jcache\/ispn-remote-get?key=KEY1&quot;\nVALUE1 (Sat Nov 28 20:48:51 EET 2020)\n<\/code><\/pre>\n<p>To check remote cache container statistics you can use UI or  Infinispan <strong>CLI<\/strong> console:<\/p>\n<pre><code class=\"language-bash\">[disconnected]&gt; connect\ncd caches\nstats myremotecache\n<\/code><\/pre>\n<pre><code class=\"language-bash\">{\n  &quot;time_since_start&quot; : 23866,\n  &quot;time_since_reset&quot; : 23866,\n  &quot;current_number_of_entries&quot; : 1,\n  &quot;current_number_of_entries_in_memory&quot; : 1,\n  &quot;total_number_of_entries&quot; : 1,\n  &quot;off_heap_memory_used&quot; : 0,\n  ...\n<\/code><\/pre>\n<p>Last point i would like to pay attention is cache container <strong>height availability<\/strong> with <strong><code>Infinispan clustering<\/code><\/strong>.  By default, Infinispan uses MPING (multicast) protocol to cluster auto discovery. You can easy check it just by running another ISPN instances on some network. For example:<\/p>\n<pre><code class=\"language-bash\">$ cd &lt;ISPN_HOME&gt;\n$ cp -r server server2\n$ bin\/server.sh -o 100 -s server2\n\n$ bin\/cli.sh\nconnect\ndescribe\n<\/code><\/pre>\n<pre><code class=\"language-bash\">{\n  &quot;version&quot; : &quot;10.1.8.Final&quot;,\n  ...\n  &quot;cluster_members_physical_addresses&quot; : [ &quot;127.0.0.1:7800&quot;, &quot;127.0.0.1:7801&quot; ],\n  &quot;cluster_size&quot; : 2,\n  ...\n}\n<\/code><\/pre>\n<p>Do not forget to add new ISPN node to your Wildfly configuration<\/p>\n<pre><code class=\"language-bash\">\/socket-binding-group=standard-sockets\/remote-destination-outbound-socket-binding=ispn2:add(host=127.0.0.1, port=11322)\n\/subsystem=infinispan\/remote-cache-container=myRemoteContainer\/remote-cluster=data-grid-cluster:write-attribute(name=socket-bindings, value=[ispn1,ispn2])\n<\/code><\/pre>\n<p>Please, notice if you perform cloud deployment or have some network restrictions, - auto discovery with <strong>MPING<\/strong> can be not accessible. In this case you can use a <strong>static list of IP addresses<\/strong>  by providing  <strong>TCPPING<\/strong> configuration via <strong><code>server\/conf\/infinispan.xml<\/code><\/strong>. Just add <code>jgroups<\/code> section and edit <code>transport<\/code> stack for default <code>cache-container<\/code> :<\/p>\n<pre><code class=\"language-xml\">&lt;infinispan&gt;\n\n &lt;jgroups&gt;\n    &lt;stack name=&quot;mytcpping&quot;&gt;\n      &lt;TCP bind_port=&quot;7800&quot; port_range=&quot;30&quot; recv_buf_size=&quot;20000000&quot; send_buf_size=&quot;640000&quot;\/&gt;\n      &lt;TCPPING   initial_hosts=&quot;${jgroups.tcpping.initial_hosts:127.0.0.1[7800],127.0.0.1[7800]}&quot;\/&gt;\n      &lt;MERGE3 \/&gt;\n      &lt;FD_SOCK \/&gt;\n      &lt;FD_ALL timeout=&quot;3000&quot; interval=&quot;1000&quot; timeout_check_interval=&quot;1000&quot; \/&gt;\n      &lt;VERIFY_SUSPECT timeout=&quot;1000&quot; \/&gt;\n      &lt;pbcast.NAKACK2 use_mcast_xmit=&quot;false&quot; xmit_interval=&quot;100&quot; xmit_table_num_rows=&quot;50&quot; xmit_table_msgs_per_row=&quot;1024&quot; xmit_table_max_compaction_time=&quot;30000&quot; \/&gt;\n      &lt;UNICAST3 xmit_interval=&quot;100&quot; xmit_table_num_rows=&quot;50&quot; xmit_table_msgs_per_row=&quot;1024&quot; xmit_table_max_compaction_time=&quot;30000&quot; \/&gt;\n      &lt;pbcast.STABLE stability_delay=&quot;200&quot; desired_avg_gossip=&quot;2000&quot; max_bytes=&quot;1M&quot; \/&gt;\n      &lt;pbcast.GMS print_local_addr=&quot;false&quot; join_timeout=&quot;${jgroups.join_timeout:2000}&quot; \/&gt;\n      &lt;UFC max_credits=&quot;4m&quot; min_threshold=&quot;0.40&quot; \/&gt;\n      &lt;MFC max_credits=&quot;4m&quot; min_threshold=&quot;0.40&quot; \/&gt;\n      &lt;FRAG3 \/&gt;\n    &lt;\/stack&gt;\n  &lt;\/jgroups&gt;\n\n   &lt;cache-container name=&quot;default&quot; statistics=&quot;true&quot;&gt;\n     &lt;transport stack=&quot;mytcpping&quot; node-name=&quot;${infinispan.node.name:}&quot;\/&gt;\n   &lt;\/cache-container&gt;\n...\n<\/code><\/pre>\n<p>For more details about configuration, please refer to <a href=\"https:\/\/docs.wildfly.org\/20\/wildscribe\/subsystem\/infinispan\/remote-cache-container\/index.html\">WildFly 20 Infinispan Model Reference<\/a> and <a href=\"https:\/\/infinispan.org\/documentation\/\">Infinispan community documentation<\/a><\/p>\n<p>Source code of described example available on <a href=\"https:\/\/github.com\/kostenkoserg\/wildfly-infinispan-example\">GitHub<\/a><\/p>\n\n\t"},{"title":"ORA-01795 and JPA function workaround","link":"https:\/\/kostenko.org\/blog\/2020\/11\/ora-01795-jpa-function-workaround.html","pubDate":"Fri, 27 Nov 2020 00:00:00 +0200","guid":"blog\/2020\/11\/ora-01795-jpa-function-workaround.html","description":"\n\t<p>Few posts ago i wrote about Hibernate Interceptor to solve <strong><a href=\"https:\/\/kostenko.org\/blog\/2020\/10\/jpa-ora-01795-hibernate-interceptor.html\">ORA-01795: maximum number of expressions in a list is 1000 error<\/a><\/strong>. This way can be very helpful in case you got this limitation, but by some reasons not able to perform refactoring.<\/p>\n<p>Another way to get it done with  <strong>JPQL<\/strong> is a <strong>JPA function()<\/strong>. We used similar approach to implement <a href=\"https:\/\/kostenko.org\/blog\/2020\/10\/jpa-count-over.html\">JPA paging with COUNT(*) OVER()<\/a>.<\/p>\n<p>So, let's see how less code we need to get it work with custom <em><code>Dialect<\/code><\/em>  workaround.<\/p>\n<p><code>Custom dialect:<\/code><\/p>\n<pre><code class=\"language-java\">public class MyOraDialect extends Oracle10gDialect {\n    public MyOraDialect () {\n        super();\n        \/\/ sql tuples workaround\n        registerFunction( &quot;safeTupleIn&quot;, new VarArgsSQLFunction( StandardBasicTypes.INTEGER, &quot;(&quot;, &quot;,0),(&quot;, &quot;,0)&quot;));\n        \/\/ custom SQLFunction workaround\n        registerFunction( &quot;safeIn&quot;, new SafeInFunction());\n    }\n}\n<\/code><\/pre>\n<p><code>Usage example:<\/code><\/p>\n<pre><code class=\"language-java\">@Test\npublic void safeTupleIn1000Test() throws Exception {\n     EntityManager em = Persistence.createEntityManagerFactory(&quot;myDSTestOra&quot;).createEntityManager();\n     \/\/ this.generateTestData(em);\n     ...\n     Query query =  em.createQuery(&quot;SELECT b as post FROM OraBlogEntity b where (id, 0) in (function('safeTupleIn',:ids))&quot;, Tuple.class);\n     query.setParameter(&quot;ids&quot;, idsList);\n     List&lt;Tuple&gt; tpList = query.getResultList();\n     System.out.println(tpList.size());\n}\n<\/code><\/pre>\n<p>or bit cleaner:<\/p>\n<pre><code class=\"language-java\">...\nQuery query =  em.createQuery(&quot;SELECT b as post FROM OraBlogEntity b where id in (function('safeIn', id, :ids))&quot;, Tuple.class);\nquery.setParameter(&quot;ids&quot;, idsList);\n...\n<\/code><\/pre>\n<p>Result SQL in this case SQL tuples will looks like<\/p>\n<pre><code class=\"language-bash\">Hibernate: select orablogent0_.id as id1_0_, orablogent0_.body as body2_0_, orablogent0_.title as title3_0_ from orablogentity orablogent0_ where (orablogent0_.id , 0) in ((?,0),(?,0),(?....)\n<\/code><\/pre>\n<p>In case custom SQLFunction implementation:<\/p>\n<pre><code class=\"language-bash\">Hibernate: select orablogent0_.id as id1_0_, orablogent0_.body as body2_0_, orablogent0_.title as title3_0_ from orablogentity orablogent0_ where orablogent0_.id in (?,...,?) or orablogent0_.id in (?,...,?)\n<\/code><\/pre>\n<p>Below is simple example how custom <strong><code>org.hibernate.dialect.function.SQLFunction<\/code><\/strong> can be implemented.<\/p>\n<pre><code class=\"language-java\">public class SafeInFunction implements SQLFunction {\n    private final static int IN_CAUSE_LIMIT = 1000;\n    ...\n    @Override\n    public String render(Type firstArgumentType, List arguments, SessionFactoryImplementor factory) throws QueryException {\n        final StringBuilder buf = new StringBuilder();\n        String fieldName = (String) arguments.get(0);\n        for (int i = 1; i &lt; arguments.size(); i++) {\n            if (i % IN_CAUSE_LIMIT == 0) {\n                buf.deleteCharAt(buf.length() - 1).append(&quot;) or &quot;).append(fieldName).append(&quot; in (&quot;);\n            }\n            buf.append(&quot;?,&quot;);\n        }\n        return buf.deleteCharAt(buf.length() - 1).toString();\n    }\n}\n<\/code><\/pre>\n<p>PS. Hibernate provides <strong><code>org.hibernate.dialect.Dialect<\/code><\/strong> method to overwrite<\/p>\n<pre><code class=\"language-java\">\/**\n * Return the limit that the underlying database places on the number of elements in an {@code IN} predicate.\n * If the database defines no such limits, simply return zero or less-than-zero.\n *\n * @return int The limit, or zero-or-less to indicate no limit.\n *\/\npublic int getInExpressionCountLimit() {\n  return 0;\n}\n<\/code><\/pre>\n<p>But unfortunately did not provides properly implementation yet and just throw warning<\/p>\n<pre><code class=\"language-bash\">WARN: HHH000443: Dialect limits the number of elements in an IN predicate to 1000 entries.  However, the given parameter list [ids] contained 1111 entries, which will likely cause failures to execute the query in the database\n<\/code><\/pre>\n<p>Source code of described example available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-jpa-examples\">GitHub<\/a><\/p>\n\n\t"},{"title":"Wildfly\/Infinispan domain. Keep distributed cache on separate nodes","link":"https:\/\/kostenko.org\/blog\/2020\/11\/wildfly-infinspan-scaling.html","pubDate":"Tue, 3 Nov 2020 00:00:00 +0200","guid":"blog\/2020\/11\/wildfly-infinspan-scaling.html","description":"\n\t<p>Previously i wrote about development of Jakarta EE application using <a href=\"https:\/\/kostenko.org\/blog\/2020\/08\/wildfly-infinspan.html\">distributed cache with Wildfly and Infinispan<\/a>. This solution has a good fit for a small clustered environments where data distribution between nodes will not costs too much. In case you are looking for clustered environment where application scaling should have minimum impact on cache and vice versa, but by some reason you wouldn't like to use a separate infinispan-server cluster as <strong>remote-cache-container<\/strong> then next topology can be a solution:<br \/>\n<img src=\"\/img\/2020-11-cache-server-group.png\" alt=\"cache-server-group\" \/><\/p>\n<p>To make it work we need to configure <strong>distributed-cache<\/strong> for two server groups and provide <strong>zero capacity-factor<\/strong> for one of them. Below is simple configuration example:<\/p>\n<pre><code class=\"language-bash\"># clone current profile\n\/profile=full-ha:clone(to-profile=full-ha-cache)\n# Create cache server group based on new profile\n\/server-group=cache-servers:add(profile=full-ha-cache, socket-binding-group=full-ha-sockets)\n# Add cache container and distributed cache for both profiles\n\/profile=full-ha\/subsystem=infinispan\/cache-container=mycachecontainer:add(statistics-enabled=true)\n\/profile=full-ha-cache\/subsystem=infinispan\/cache-container=mycachecontainer:add(statistics-enabled=true)\n\/profile=ful-ha-cache\/subsystem=infinispan\/cache-container=mycachecontainer\/distributed-cache=mycache:add()\n\/profile=full-ha\/subsystem=infinispan\/cache-container=mycachecontainer\/distributed-cache=mycache:add()\n# Create cache servers\n\/host=master\/server-config=cache1:add(group=cache-servers,socket-binding-port-offset=500)\n\/host=master\/server-config=cache1:start(blocking=true)\n\/host=master\/server-config=cache2:add(group=cache-servers,socket-binding-port-offset=600)\n\/host=master\/server-config=cache2:start(blocking=true)\n# Configure ZERO capacity for profile which we will use for application\n\/profile=full-ha\/subsystem=infinispan\/cache-container=mycachecontainer\/distributed-cache=mycache:write-attribute(name=capacity-factor, value=0)\n# Provide transport\n\/profile=full-ha\/subsystem=infinispan\/cache-container=mycachecontainer\/transport=jgroups:add()\n\/profile=ful-ha-cache\/subsystem=infinispan\/cache-container=mycachecontainer\/transport=jgroups:add()\n<\/code><\/pre>\n<p>Now let's deploy our application on two server groups<\/p>\n<pre><code class=\"language-bash\">deploy jcache-examples.war --server-groups=backend-servers,cache-servers\n<\/code><\/pre>\n<p>You can check cached <strong>number-of-entries<\/strong> on each server by<\/p>\n<pre><code class=\"language-bash\">\/host=master\/server=backend1\/subsystem=infinispan\/cache-container=mycachecontainer\/distributed-cache=mycache:read-resource(include-runtime=true)\n\/host=master\/server=cache1\/subsystem=infinispan\/cache-container=mycachecontainer\/distributed-cache=mycache:read-resource(include-runtime=true)\n<\/code><\/pre>\n<p>And be sure that application backend-servers will always show <code>&quot;number-of-entries&quot; =&gt; 0<\/code><\/p>\n\n\t"},{"title":"JPA and \"ORA-01795: maximum number of expressions in a list is 1000 error\" workaround","link":"https:\/\/kostenko.org\/blog\/2020\/10\/jpa-ora-01795-hibernate-interceptor.html","pubDate":"Tue, 13 Oct 2020 00:00:00 +0300","guid":"blog\/2020\/10\/jpa-ora-01795-hibernate-interceptor.html","description":"\n\t<p>Oracle RDBMS has a known <strong>1000 elements<\/strong> limitation on count of parameters for the <strong><code>IN<\/code><\/strong> clause.<\/p>\n<pre><code class=\"language-sql\">SELECT * FROM TABLE WHERE ID IN (?,?,?.....?)\n<\/code><\/pre>\n<p>In case count  of parameters more than 1000, - Oracle throws error: <code>ORA-01795: maximum number of expressions in a list is 1000 error<\/code><\/p>\n<p>Exists few ways to deal with it from the SQL point of view:<\/p>\n<ul>\n<li>Split clause  <code>field IN (n1,...n9999)<\/code> to portions  like <strong><code>(field IN (n1...n999) or field IN (n1000...n1999)...)<\/code><\/strong><\/li>\n<li>Use temporary table to insert IDs and use sub select like <strong><code>field IN (select id from TMP_IDS)<\/code><\/strong><\/li>\n<li>Use tuples like <strong><code>where (id, 0) IN ((1, 0)...(n, 0))<\/code><\/strong><\/li>\n<\/ul>\n<p>Some data mapping frameworks provides solution for above by default, but unfortunately, <strong>Hibernate<\/strong> (most popular JPA provider) does not yet.<\/p>\n<p>Fortunately, we can provide custom solution here by overriding <strong>EmptyInterceptor.onPrepareStatement(String sql)<\/strong> which is called when SQL string is being prepared and perform some String manipulation with the SQL.<\/p>\n<p>First, we need for regular expression to find <strong>IN<\/strong> clause matches in the query. <a href=\"https:\/\/regex101.com\/\">regex101.com<\/a> provides great help here<br \/>\n<img src=\"\/img\/2020-10-jpa-in-regexp-s.png\" alt=\"pager\" \/><\/p>\n<p>Now we are ready to implement interceptor:<\/p>\n<pre><code class=\"language-java\">public class SafeInInterceptor extends EmptyInterceptor {\n\n    private final static Pattern pattern = Pattern.compile(&quot;[^\\\\s]+\\\\s+in\\\\s*\\\\(\\\\s*\\\\?[^\\\\(]*\\\\)&quot;, Pattern.CASE_INSENSITIVE);\n    private final static int IN_CAUSE_LIMIT = 1000;\n\n    @Override\n    public String onPrepareStatement(String sql) {\n        return super.onPrepareStatement(this.rewriteSqlToAvoidORA_01795(sql));\n    }\n\n    private String rewriteSqlToAvoidORA_01795(String sql) {\n        Matcher matcher = pattern.matcher(sql);\n        while (matcher.find()) {\n            String inExpression = matcher.group();\n            long countOfParameters = inExpression.chars().filter(ch -&gt; ch == '?').count();\n\n            if (countOfParameters &lt;= IN_CAUSE_LIMIT) {\n                continue;\n            }\n\n            String fieldName = inExpression.substring(0, inExpression.indexOf(' '));\n            StringBuilder transformedInExpression = new StringBuilder(&quot; ( &quot;).append(fieldName).append(&quot; in (&quot;);\n\n            for (int i = 0; i &lt; countOfParameters; i++) {\n                if (i != 0 &amp;&amp; i % IN_CAUSE_LIMIT == 0) {\n                    transformedInExpression\n                            .deleteCharAt(transformedInExpression.length() - 1)\n                            .append(&quot;) or &quot;).append(fieldName).append(&quot; in (&quot;);\n                }\n                transformedInExpression.append(&quot;?,&quot;);\n            }\n            transformedInExpression.deleteCharAt(transformedInExpression.length() - 1).append(&quot;))&quot;);\n            sql = sql.replaceFirst(Pattern.quote(inExpression), transformedInExpression.toString());\n        }\n        return sql;\n    }\n}\n<\/code><\/pre>\n<p>To enable interceptor, -  add next property to the your <strong><code>persistence.xml<\/code><\/strong><\/p>\n<pre><code class=\"language-xml\">&lt;property name=&quot;hibernate.ejb.interceptor&quot; value=&quot;org.kostenko.example.jpa.dialect.SafeInInterceptor&quot; \/&gt;\n<\/code><\/pre>\n<p>Time to test:<\/p>\n<pre><code class=\"language-java\">@Test\npublic void transformSelectToSafeIn() throws Exception {\n    EntityManager em = Persistence.createEntityManagerFactory(&quot;myDSTestOra&quot;).createEntityManager();\n\n    List&lt;Long&gt; idsList = new ArrayList&lt;&gt;();\n    for (int i = 0; i &lt; 1199; i++) {\n        idsList.add((long)i);\n    }\n\n    Query q =  \n            em.createQuery(&quot;SELECT b FROM OraBlogEntity b WHERE b.id IN (:idsList)&quot;, OraBlogEntity.class)\n            .setParameter(&quot;idsList&quot;, idsList);\n\n    List&lt;OraBlogEntity&gt; blogEntitys = q.getResultList();\n    System.out.println(blogEntitys.size());\n}\n<\/code><\/pre>\n<p>Output:<\/p>\n<pre><code class=\"language-bash\">Hibernate:select orablogent0_.id as id1_0_, orablogent0_.body as body2_0_, orablogent0_.title as title3_0_ from orablogentity orablogent0_\nwhere  ( orablogent0_.id in (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)\nor orablogent0_.id in (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?))\n<\/code><\/pre>\n<p>As you can see SQL was splited. No source code changes required and no ORA-01795 anymore.<\/p>\n<p>Source code of described example as usual available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-jpa-examples\">GitHub<\/a><\/p>\n\n\t"},{"title":"Jakarta EE JPA paging and COUNT(*) OVER()","link":"https:\/\/kostenko.org\/blog\/2020\/10\/jpa-count-over.html","pubDate":"Fri, 2 Oct 2020 00:00:00 +0300","guid":"blog\/2020\/10\/jpa-count-over.html","description":"\n\t<p><img src=\"\/img\/2020-10-pager.png\" alt=\"pager\" \/><\/p>\n<p>Almost all data related applications and UI\\UX practices need for paging. Jakarta EE JPA specification helps to do it on backend side  by providing simple <strong>Query API:<\/strong><\/p>\n<ul>\n<li><strong><code>setFirstResult(int startPosition)<\/code><\/strong> - Set the position of the first result to retrieve.<\/li>\n<li><strong><code>setMaxResults(int maxResult)<\/code><\/strong> -  Set the maximum number of results to retrieve.<\/li>\n<\/ul>\n<p>Typically, to implement paging with JPA you need for two queries: one to <strong>select page<\/strong> and second to <strong>select total count<\/strong> to calculate count of pages. It works well with simple queries and well described in many articles. But real world enterprise application often enough operates with complex queries with complex filters on big amount of data and unfortunately <strong>second query is not for free<\/strong> here from performance point of view.<\/p>\n<p>Fortunately, since <strong>JPA 2.1<\/strong> developers can use <strong><code>function()<\/code><\/strong> to call not standard DB functions. Let's play around it to use power of database window functions and JPA usability.<\/p>\n<p>Actually, in case Hibernate JPA provider all we need is register our custom function for our custom dialect like:<\/p>\n<pre><code class=\"language-java\">public class MyOraDialect extends Oracle10gDialect {\n    public MyOraDialect () {\n        super();\n        registerFunction(&quot;countover&quot;, new SQLFunctionTemplate(StandardBasicTypes.INTEGER, &quot;count(*) over()&quot;));\n    }\n}\n<\/code><\/pre>\n<p>and use dialect above in the our application <code>persistence.xml<\/code>:<\/p>\n<pre><code class=\"language-xml\">  &lt;property name=&quot;hibernate.dialect&quot; value=&quot;org.kostenko.example.jpa.dialect.MyOraDialect&quot;\/&gt;\n<\/code><\/pre>\n<p>Looks so easy, - time to test!<\/p>\n<pre><code class=\"language-java\">public class OraTest {\n    @Test\n    public void countOver() throws Exception {\n        EntityManager em = Persistence.createEntityManagerFactory(&quot;myDSTestOra&quot;).createEntityManager();\n        this.generateTestData(em);\n        Query query =  em.createQuery(&quot;SELECT b as post, function('countover') as cnt FROM OraBlogEntity b&quot;, Tuple.class);\n        query.setFirstResult(10);\n        query.setMaxResults(5);\n        List&lt;Tuple&gt; tpList = query.getResultList();\n        for (Tuple tp : tpList) {\n            System.out.println(tp.get(&quot;post&quot;));\n            System.out.println(&quot;Total:&quot; + tp.get(&quot;cnt&quot;));\n        }\n    }\n    ...\n}\n<\/code><\/pre>\n<p>Output:<\/p>\n<pre><code class=\"language-bash\">Hibernate: select * from ( select row_.*, rownum rownum_ from ( select orablogent0_.id as col_0_0_, count(*) over() as col_1_0_, orablogent0_.id as id1_0_, orablogent0_.body as body2_0_, orablogent0_.title as title3_0_ from orablogentity orablogent0_ ) row_ where rownum &lt;= ?) where rownum_ &gt; ?\nOraBlogEntity{id=151, title=title7, body=body7}\nTotal:3003\nOraBlogEntity{id=152, title=title8, body=body8}\nTotal:3003\n...\n<\/code><\/pre>\n<p>Please, note: <strong>count(*) over()<\/strong> construction is not supported by <strong>all<\/strong> RDBMS, but in turn supports by Oracle, Postgres, MSSQL Server and others.<\/p>\n<p>Source code of described example as usual available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-jpa-examples\">GitHub<\/a><\/p>\n\n\t"},{"title":"JPA @ManyToOne. Keep separate reference by ID and by Entity","link":"https:\/\/kostenko.org\/blog\/2020\/10\/jpa-manytoone-get-id-one-query.html","pubDate":"Thu, 1 Oct 2020 00:00:00 +0300","guid":"blog\/2020\/10\/jpa-manytoone-get-id-one-query.html","description":"\n\t<p>Some time you may need to keep reference by class and reference by ID for your <strong>JPA @Entity<\/strong>. It can be very helpful, for example, to do some default JSON serialization with no risk to stuck with well known <strong>N+1<\/strong> issue. In this case i would like to avoid <strong>@OneToMany<\/strong> and <strong>@ManyToOne<\/strong> fields serialization by default and use ID reference instead.<\/p>\n<p>So, below is simple example how to do above.<\/p>\n<pre><code class=\"language-java\">@Entity\n@Table(name = &quot;book&quot;)\npublic class Book {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private long id;\n\n    @Column(name = &quot;name&quot;)\n    private String name;\n\n    @JoinColumn(name = &quot;author&quot;, insertable = false, updatable = false)\n    @ManyToOne(targetEntity = Author.class, fetch = FetchType.LAZY)\n    private Author author;\n\n    @Column(name = &quot;author&quot;)\n    private long authorId;\n    ...\n    public void setAuthor(Author author) {\n        setAuthorId(author.getId());\n        this.author = author;\n    }\n    ...\n}\n<\/code><\/pre>\n<p>Testing time:<\/p>\n<pre><code class=\"language-java\">public class ManyToOneTest {\n    @Test\n    public void relationManyToOneTest() {\n        EntityManager em = Persistence.createEntityManagerFactory(&quot;myDSTest&quot;).createEntityManager();\n        this.generateTestData(em);\n\n        List &lt;Book&gt; books =em.createQuery(&quot;FROM Book&quot;, Book.class).getResultList();\n        \/\/ lazy loading test\n        for (Book b : books) {\n            System.out.println(&quot;Bookd:&quot; + b.getName());\n            System.out.println(&quot;AuthorId:&quot; + b.getAuthorId());\n            \/\/ lazy load\n            System.out.println(&quot;Author:&quot; + b.getAuthor());\n        }\n        \/\/ JPQL with direct id reference\n        books = em.createQuery(&quot;FROM Book where authorId = 1&quot;, Book.class).getResultList();\n        \/\/ JPQL with author.id reference\n        books = em.createQuery(&quot;FROM Book where author.id = 1&quot;, Book.class).getResultList();\n    }\n\n    private void generateTestData(EntityManager em) {\n        em.getTransaction().begin();\n\n        Author author = new Author();\n        author.setName(&quot;A Name&quot;);\n        em.persist(author);\n\n        Book book = new Book();\n        book.setName(&quot;Book Name&quot;);\n        book.setAuthorId(author.getId());\n        \/\/book.setAuthor(author);\n        em.persist(book);\n        em.getTransaction().commit();\n        em.clear();\n    }\n}\n<\/code><\/pre>\n<p>Test Output:<\/p>\n<pre><code class=\"language-bash\">...\nHibernate: select book0_.id as id1_2_, book0_.author as author2_2_, book0_.name as name3_2_ from book book0_\nBookd:Book Name\nAuthorId:1\n# call book.getAuthor():\nHibernate: select author0_.id as id1_0_0_, author0_.name as name2_0_0_ from author author0_ where author0_.id=?\nAuthor:Author{id=1, name=A Name}\n\n<\/code><\/pre>\n<p><strong>PS:<\/strong> <code>book.getAuthor().getId()<\/code> <strong>will not trigger Author lazy loading<\/strong>, but book.getAuthor().getName() will.<\/p>\n<p>Source code of described application available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-jpa-examples\">GitHub<\/a><\/p>\n\n\t"},{"title":"Simple trick to reload application on Tomcat","link":"https:\/\/kostenko.org\/blog\/2020\/09\/tomcat-reload-application.html","pubDate":"Wed, 30 Sep 2020 00:00:00 +0300","guid":"blog\/2020\/09\/tomcat-reload-application.html","description":"\n\t<p>Reload tomcat application without accessing to manager console you can just by touch<\/p>\n<pre><code class=\"language-bash\">cd tomcat\/webapps\/&lt;application&gt;\/WEB-INF\/\ntouch web.xml\n<\/code><\/pre>\n<p>The trick above <strong>will work on other application servers<\/strong> with &quot;hot deploy&quot; support.<\/p>\n\n\t"},{"title":"Distributed caching with Wildfly\/Infinispan and poor JCache support.","link":"https:\/\/kostenko.org\/blog\/2020\/08\/wildfly-infinspan.html","pubDate":"Wed, 26 Aug 2020 00:00:00 +0300","guid":"blog\/2020\/08\/wildfly-infinspan.html","description":"\n\t<p>Latest trends teach us to do development of stateless applications, and if you can - keep your design stateless. But, by some reason, you may need to cache and share state between nodes.<\/p>\n<p>It would be nice to have <strong><a href=\"https:\/\/jcp.org\/en\/jsr\/detail?id=107\">JSR 107: JCACHE - Java Temporary Caching API<\/a><\/strong> support in Wildfly Application Server, but unfortunately, JCache still not a part of JakartaEE specification (i hope one day it will) and pity to realize that Wildfly does not support JCache by default.<\/p>\n<p>From other point of view many well known vendors like <a href=\"https:\/\/hazelcast.org\/\">Hazelcast<\/a>, <a href=\"https:\/\/infinispan.org\/\">Infinispan<\/a>, <a href=\"https:\/\/www.ehcache.org\/\">Ehcache<\/a> etc, supports JCache API as well. In turn significant Infinispan part integrated into Wildfly Application Server and can be used as distributed cache provider over  separate <strong><a href=\"https:\/\/docs.wildfly.org\/20\/wildscribe\/subsystem\/infinispan\/index.html\">infinispan subsystem<\/a><\/strong> configuration.<\/p>\n<p>So, let's design sample Jakarta EE application to see how <strong>distrubuted cache<\/strong> looks and works on practice.<\/p>\n<p>First, we need for at least two node Wildfly cluster - please refer to my article about <a href=\"https:\/\/kostenko.org\/blog\/2019\/04\/wildfly-cluster-domain-mode.html\">Wildfly domain mode cluster and load balancing from the box<\/a>. And then we are ready to configure distributed cache for our application:<\/p>\n<pre><code class=\"language-bash\">\/profile=full-ha\/subsystem=infinispan\/cache-container=mycachecontainer:add\n\/profile=full-ha\/subsystem=infinispan\/cache-container=mycachecontainer\/distributed-cache=mycache:add\n<\/code><\/pre>\n<p>After simply server configuration above, we are ready to create our sample application. And as usual with Jakarta EE - <strong><code>build.gradle<\/code><\/strong> looks pretty simple and clear :<\/p>\n<pre><code class=\"language-java\">apply plugin: 'war'\ndependencies {\n    providedCompile &quot;jakarta.platform:jakarta.jakartaee-api:8.0.0&quot;\n    providedCompile &quot;org.infinispan:infinispan-core:10.1.8.Final&quot;\n}\n<\/code><\/pre>\n<p>Now to use configured above <code>mycache<\/code> we need to register cache resource in the one from two ways :<\/p>\n<pre><code class=\"language-java\">@Startup\n@Singleton\n@LocalBean\npublic class MyCacheResource {\n    @Resource(lookup = &quot;java:jboss\/infinispan\/cache\/mycachecontainer\/mycache&quot;)\n    private org.infinispan.Cache&lt;String, Object&gt; myCache;\n<\/code><\/pre>\n<p><strong>OR<\/strong> provide  resource reference in your <strong>WEB-INF\/web.xml<\/strong> descriptor:<\/p>\n<pre><code class=\"language-xml\">&lt;web-app version=&quot;2.5&quot;  xmlns=&quot;http:\/\/java.sun.com\/xml\/ns\/javaee&quot;  xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http:\/\/java.sun.com\/xml\/ns\/javaee http:\/\/java.sun.com\/xml\/ns\/javaee\/web-app_2_5.xsd&quot;&gt;\n    &lt;display-name&gt;JCache API example&lt;\/display-name&gt;\n    &lt;resource-env-ref&gt;\n        &lt;resource-env-ref-name&gt;mycache&lt;\/resource-env-ref-name&gt;\n        &lt;lookup-name&gt;java:jboss\/infinispan\/cache\/mycachecontainer\/mycache&lt;\/lookup-name&gt;\n    &lt;\/resource-env-ref&gt;    \n&lt;\/web-app&gt;\n<\/code><\/pre>\n<p>I personally prefer second one because it allows move vendor specific code and dependencies from application source level to the descriptor which is designed for. Actually, i recommend to use standard API as much as possible and <strong>refer to custom vendor specific stuff very carefully<\/strong>.<\/p>\n<p>Also to help Wildfly avoid casting exception like <strong><code>java.lang.IllegalArgumentException: Can not set org.infinispan.Cache field to org.jboss.as.clustering.infinispan.DefaultCache<\/code><\/strong> we need to configure module dependencies over <strong>MANIFEST.MF<\/strong>:<\/p>\n<pre><code class=\"language-bash\">Manifest-Version: 1.0\nDependencies: org.infinispan export\n<\/code><\/pre>\n<p><strong>OR<\/strong> over <strong>jboss-deployment-structure.xml<\/strong> :<\/p>\n<pre><code class=\"language-xml\">&lt;jboss-deployment-structure&gt;\n   &lt;deployment&gt;\n      &lt;dependencies&gt;\n         &lt;module name=&quot;org.infinispan&quot; export=&quot;TRUE&quot; \/&gt;\n      &lt;\/dependencies&gt;\n   &lt;\/deployment&gt;\n&lt;\/jboss-deployment-structure&gt;\n<\/code><\/pre>\n<p>And again, I prefer second way as <strong>vendor specific descriptor is a right place for vendor specific stuff<\/strong>.  Please refer to <strong><a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/jboss_enterprise_application_platform\/6\/html\/development_guide\/add_an_explicit_module_dependency_to_a_deployment1\">deployment module dependencies<\/a><\/strong> explanation for the details<\/p>\n<p>Now when all preparation is complete, - let's implement simple service and JAX-RS resource to check how cache distribution works:<\/p>\n<p><code>TestCacheService.java:<\/code><\/p>\n<pre><code class=\"language-java\">@Named\npublic class TestCacheService {\n\n    @Resource(name = &quot;mycache&quot;)\n    org.infinispan.Cache cache;\n\n    public void putIspnCache(String key, String value) {\n        cache.put(key, String.format(&quot;%s (%s)&quot;, value, new Date()));\n    }\n\n    public Object getIspnCache(String key) {\n        return cache.get(key);\n    }\n}\n<\/code><\/pre>\n<p><code>TestCacheEndpoint.java:<\/code><\/p>\n<pre><code class=\"language-java\">@Stateless\n@ApplicationPath(&quot;\/&quot;)\n@Path(&quot;\/jcache&quot;)\npublic class TestCacheEndpoint extends Application {\n\n    @Inject\n    TestCacheService service;\n\n    @GET\n    @Path(&quot;\/ispn-put&quot;)\n    public Response putIspn(@QueryParam(&quot;key&quot;) String key, @QueryParam(&quot;value&quot;) String value) {\n        service.putIspnCache(key, value);\n        return Response.ok(&quot;ok&quot;).build();\n    }\n\n    @GET\n    @Path(&quot;\/ispn-get&quot;)\n    public Response getIspn(@QueryParam(&quot;key&quot;) String key) {\n        return Response.ok(service.getIspnCache(key)).build();\n    }\n}    \n<\/code><\/pre>\n<p>Time to do deploy and test:<\/p>\n<pre><code class=\"language-bash\">[domain@localhost:9990 \/] deploy ~\/work\/kostenko\/wildfly-infinispan-example\/build\/libs\/jcache-examples.war --server-groups=backend-servers\n<\/code><\/pre>\n<pre><code class=\"language-bash\">curl -o - &quot;http:\/\/localhost:8180\/jcache-examples\/jcache\/ispn-put?key=KEY1&amp;value=VALUE1&quot;\nok\ncurl -o - &quot;http:\/\/localhost:8280\/jcache-examples\/jcache\/ispn-get?key=KEY1&quot;\nVALUE1 (Mon Aug 24 21:26:56 EEST 2020)\ncurl -o - &quot;http:\/\/localhost:8280\/jcache-examples\/jcache\/ispn-put?key=KEY2&amp;value=VALUE2&quot;\nok\ncurl -o - &quot;http:\/\/localhost:8180\/jcache-examples\/jcache\/ispn-get?key=KEY2&quot;\nVALUE2 (Mon Aug 24 21:27:52 EEST 2020)\n<\/code><\/pre>\n<p>As you can see from above, value we put on node1 available on node2 and vice versa. Even if we add new node to the cluster - cached values will be available on the fresh node as well:<\/p>\n<pre><code class=\"language-bash\">[domain@localhost:9990 \/] \/host=master\/server-config=backend3:add(group=backend-servers, socket-binding-port-offset=300)\n[domain@localhost:9990 \/] \/host=master\/server-config=backend3:start(blocking=true)\n<\/code><\/pre>\n<pre><code class=\"language-bash\">curl -o - &quot;http:\/\/localhost:8380\/jcache-examples\/jcache\/ispn-get?key=KEY2&quot;\nVALUE2 (Mon Aug 24 21:27:52 EEST 2020)\n<\/code><\/pre>\n<p>Great! So for now we able to share state between cluster members and, actually, this is enough for lot of typical use cases.<br \/>\nSo, what about some  standardization of our application ? As was noticed above <strong>JCache<\/strong> can be helpful here, but unfortunately enabling last one on Wildfly is not trivial at all.<\/p>\n<p>To get JCache worked you can patch your Wildfly Application Server with <a href=\"https:\/\/infinispan.org\/download-archive\/\">Infinispan wildfly modules<\/a> or just put missed libraries to the your application and exclude transitive ones to avoid conflicts with libraries that already present in the Wildfly.<\/p>\n<p><code>build.gradle:<\/code><\/p>\n<pre><code class=\"language-java\">...\ndependencies {\n    providedCompile &quot;jakarta.platform:jakarta.jakartaee-api:8.0.0&quot;\n    compile &quot;javax.cache:cache-api:1.0.0&quot;\n    compile &quot;org.infinispan:infinispan-jcache:10.1.8.Final&quot;\n    compile &quot;org.infinispan:infinispan-cdi-embedded:10.1.8.Final&quot;\n}\nconfigurations {\n  runtime.exclude group: &quot;org.infinispan&quot;, module: &quot;infinispan-core&quot;\n  runtime.exclude group: &quot;org.infinispan&quot;, module: &quot;infinispan-commons&quot;\n  runtime.exclude group: &quot;org.infinispan.protostream&quot;, module: &quot;protostream&quot;\n}\n<\/code><\/pre>\n<p><code>jboss-deployment-structure.xml:<\/code><\/p>\n<pre><code class=\"language-xml\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;jboss-deployment-structure&gt;\n    &lt;deployment&gt;\n        &lt;dependencies&gt;\n           &lt;module name=&quot;org.infinispan&quot; export=&quot;TRUE&quot; \/&gt;\n           &lt;module name=&quot;org.infinispan.commons&quot; export=&quot;TRUE&quot; \/&gt;\n           &lt;module name=&quot;org.infinispan.protostream&quot; export=&quot;TRUE&quot; \/&gt;\n        &lt;\/dependencies&gt;\n    &lt;\/deployment&gt;\n&lt;\/jboss-deployment-structure&gt;\n<\/code><\/pre>\n<p>After that you should be able to use JCache in the usual way:<\/p>\n<p><code>TestCacheService.java:<\/code><\/p>\n<pre><code class=\"language-java\">...\n@CacheResult(cacheName = &quot;mycache&quot;)\npublic String getJCacheResult() {\n    System.out.println(&quot;getJCacheResult&quot;);\n    return new Date().toString();\n}\n...\n<\/code><\/pre>\n<p><code>beans.xml:<\/code><\/p>\n<pre><code class=\"language-xml\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;beans xmlns=&quot;http:\/\/xmlns.jcp.org\/xml\/ns\/javaee&quot; xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http:\/\/xmlns.jcp.org\/xml\/ns\/javaee  http:\/\/xmlns.jcp.org\/xml\/ns\/javaee\/beans_1_1.xsd&quot; bean-discovery-mode=&quot;all&quot;&gt;\n    &lt;interceptors&gt;\n        &lt;class&gt;org.infinispan.jcache.annotation.CacheResultInterceptor&lt;\/class&gt;\n    &lt;\/interceptors&gt;\n&lt;\/beans&gt;\n<\/code><\/pre>\n<p><strong>@CacheResult<\/strong> works and caching the result  <strong>BUT it is not related to the configured on Wildfly <code>mycache<\/code> and ignores configured options<\/strong> like lifespans, distributions etc because Infinispan's JCache CachingProvider implementation created caches from an Infinispan native configuration file (based on the provided URI, interpreted as a file path) instead of WF configuration.<\/p>\n<p>I did some digging about possibility to produce custom JCache CachingProvider but unfortunately did not find any workable solution for it. Also refer to my post about <a href=\"https:\/\/kostenko.org\/blog\/2020\/01\/infinispan-distributed-cache-issues.html\">ispn distributed cache issues<\/a> workaround.<\/p>\n<p>As usual, sample source code available on <a href=\"https:\/\/github.com\/kostenkoserg\/wildfly-infinispan-example\">GitHub<\/a><\/p>\n\n\t"},{"title":"Caucho Resin datasource configuration","link":"https:\/\/kostenko.org\/blog\/2020\/08\/resin-datasource-configuration.html","pubDate":"Sun, 16 Aug 2020 00:00:00 +0300","guid":"blog\/2020\/08\/resin-datasource-configuration.html","description":"\n\t<p>There is few possible ways to do datasource configuration  for Jakarta EE application on Resin Application Server:<\/p>\n<p>Way #1 - <strong>Application level<\/strong>. Place JDBC driver to the application classpath and edit <strong><code>WEB-INF\/resin-web.xml<\/code><\/strong><\/p>\n<pre><code class=\"language-xml\">&lt;web-app xmlns=&quot;http:\/\/caucho.com\/ns\/resin&quot;&gt;\n    &lt;database jndi-name='jdbc\/myds'&gt;\n        &lt;driver type=&quot;com.microsoft.sqlserver.jdbc.SQLServerDriver&quot;&gt;\n            &lt;url&gt;jdbc:sqlserver:\/\/localhost:1433&lt;\/url&gt;\n            &lt;user&gt;user&lt;\/user&gt;\n            &lt;password&gt;password&lt;\/password&gt;\n        &lt;\/driver&gt;\n    &lt;\/database&gt;\n&lt;\/web-app&gt;\n<\/code><\/pre>\n<p>Way #2 - <strong>Application Server level<\/strong>. Put JDBC driver to <strong><code>&lt;resin_home&gt;\/lib<\/code><\/strong>  directory and edit <strong><code>&lt;resin_home&gt;\/conf\/resin.xml<\/code><\/strong><\/p>\n<pre><code class=\"language-xml\">...\n&lt;cluster id=&quot;app&quot;&gt;\n  ...\n  &lt;database&gt;\n    &lt;jndi-name&gt;jdbc\/myds&lt;\/jndi-name&gt;\n    &lt;driver type=&quot;com.microsoft.sqlserver.jdbc.SQLServerDriver&quot;&gt;\n      &lt;url&gt;jdbc:sqlserver:\/\/localhost:1433&lt;\/url&gt;\n      &lt;user&gt;user&lt;\/user&gt;\n      &lt;password&gt;password&lt;\/password&gt;\n     &lt;\/driver&gt;\n     &lt;prepared-statement-cache-size&gt;8&lt;\/prepared-statement-cache-size&gt;\n     &lt;max-connections&gt;20&lt;\/max-connections&gt;\n     &lt;max-idle-time&gt;30s&lt;\/max-idle-time&gt;\n   &lt;\/database&gt;\n&lt;\/cluster&gt;\n...\n<\/code><\/pre>\n\n\t"},{"title":"Migration from Wildfly 18 to Wildfly 20","link":"https:\/\/kostenko.org\/blog\/2020\/08\/migration-wildfly-18-to-20.html","pubDate":"Thu, 6 Aug 2020 00:00:00 +0300","guid":"blog\/2020\/08\/migration-wildfly-18-to-20.html","description":"\n\t<p>Some time ago i wrote article about migration from <a href=\"https:\/\/kostenko.org\/blog\/2019\/10\/migration-wildfly-10-to-18.html\">Wildfly 10 to Wildfly 18 and application level migration issues<\/a>. Migration from Wildfly 18 to <strong>Wildfly 20<\/strong> does not provoke any application level issues and can be done in minutes:<\/p>\n<pre><code class=\"language-java\">git clone https:\/\/github.com\/wildfly\/wildfly-server-migration.git\ncd .\/wildfly-server-migration\/\nmvn clean install\ncd .\/dist\/standalone\/target\/\nunzip jboss-server-migration-1.10.0-SNAPSHOT.zip\ncd .\/jboss-server-migration\n\n.\/jboss-server-migration.sh -s \/opt\/wildfly-18.0.0.Final -t \/opt\/wildfly-20.0.1.Final\/\n<\/code><\/pre>\n<p><strong>Why should i do migration to Wildfly 20 ?<\/strong><\/p>\n<ul>\n<li>Supports the <a href=\"https:\/\/download.eclipse.org\/microprofile\/microprofile-3.3\/microprofile-spec-3.3.html\">Eclipse MicroProfile 3.3 platform specifications<\/a><\/li>\n<li>Possible to use TLS 1.3 with WildFly when running against JDK 11 or higher.<\/li>\n<li>RESTEasy (integrated in WildFly via the jaxrs subsystem) can now be configured using MicroProfile Config.<\/li>\n<li>Many component upgrades and bug fixes<\/li>\n<\/ul>\n\n\t"},{"title":"Unzip without root but with java","link":"https:\/\/kostenko.org\/blog\/2020\/08\/java-way-to-unzip.html","pubDate":"Wed, 5 Aug 2020 00:00:00 +0300","guid":"blog\/2020\/08\/java-way-to-unzip.html","description":"\n\t<p>If you need to <strong>unzip<\/strong> file on the server, where is no root and no <code>unzip<\/code> installed then time to ask <strong>java<\/strong> about:<\/p>\n<pre><code class=\"language-bash\">jar xvf wildfly-20.0.1.Final.zip\n<\/code><\/pre>\n\n\t"},{"title":"Rich web application on pure Java with Vaadin and Quarkus","link":"https:\/\/kostenko.org\/blog\/2020\/04\/quarkus-vaadin-8.html","pubDate":"Wed, 29 Apr 2020 00:00:00 +0300","guid":"blog\/2020\/04\/quarkus-vaadin-8.html","description":"\n\t<p>Recently I wrote about <a href=\"https:\/\/kostenko.org\/blog\/2020\/02\/jwt-openapi-microprofile-quarkus.html\">REST API with Eclipse Microprofile and Quarkus<\/a> - and it is very useful for\u00a0the microservices development, but from time to time every backend Java developer <strong>needs for\u00a0the UI<\/strong>. With <strong><a href=\"https:\/\/vaadin.com\/\">Vaadin web framework<\/a><\/strong> you can write UI 100% in Java without getting bogged down in JS, HTML, and CSS.<\/p>\n<p>Quarkus provides <strong><code>Servlet<\/code><\/strong> and  <strong><code>Websocket<\/code><\/strong> support as well, so there is no any blockers to run web application.<br \/>\nTo bootstrap Quarkus from the scratch you can visit  <strong><a href=\"https:\/\/code.quarkus.io\/\">code.quarkus.io<\/a><\/strong> and select build tool you like and extensions you need. In our case we need for:<\/p>\n<ul>\n<li><strong>Undertow Servlet<\/strong><\/li>\n<li><strong>Undertow WebSockets<\/strong><\/li>\n<\/ul>\n<p>With <strong>Vaadin 8<\/strong> dependencies my <strong><code>build.gradle<\/code><\/strong> looks pretty clear:<\/p>\n<pre><code class=\"language-java\">plugins {\n    id 'java'\n    id 'io.quarkus'\n}\nrepositories {\n     mavenLocal()\n     mavenCentral()\n}\ndependencies {\n    compile 'com.vaadin:vaadin-server:8.10.3'\n    compile 'com.vaadin:vaadin-push:8.10.3'\n    compile 'com.vaadin:vaadin-client-compiled:8.10.3'\n    compile 'com.vaadin:vaadin-themes:8.10.3'\n    implementation 'io.quarkus:quarkus-undertow-websockets'\n    implementation 'io.quarkus:quarkus-undertow'\n    implementation enforcedPlatform(&quot;${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}&quot;)\n}\n\ngroup 'org.kostenko'\nversion '1.0.0-SNAPSHOT'\n\ncompileJava {\n    options.encoding = 'UTF-8'\n    options.compilerArgs &lt;&lt; '-parameters'\n}\n<\/code><\/pre>\n<p>Now we able to create <strong><code>com.vaadin.ui.UI<\/code><\/strong><\/p>\n<pre><code class=\"language-java\">@Theme(&quot;dashboard&quot;)\npublic class MyUI extends UI {\n\n    @Override\n    protected void init(VaadinRequest vaadinRequest) {\n      ...\n    }\n\n    \/**\n     * VaadinServlet configuration\n     *\/\n    @WebServlet(urlPatterns = &quot;\/*&quot;, name = &quot;MyUIServlet&quot;, asyncSupported = true, initParams = {\n        @WebInitParam(name = &quot;org.atmosphere.websocket.suppressJSR356&quot;, value = &quot;true&quot;)}\n    )\n    @VaadinServletConfiguration(ui = MyUI.class, productionMode = false)\n    public static class MyUIServlet extends VaadinServlet {\n    }\n}\n<\/code><\/pre>\n<p>Put Vaadin static files to the <code>\/src\/main\/resources\/META-INF\/resources\/VAADIN<\/code> and run quarkus in dev mode as usual <strong>.\/gradlew quarkusDev<\/strong>:<\/p>\n<pre><code class=\"language-bash\">Listening for transport dt_socket at address: 5005\n__  ____  __  _____   ___  __ ____  ______\n --\/ __ \\\/ \/ \/ \/ _ | \/ _ \\\/ \/\/_\/ \/ \/ \/ __\/\n -\/ \/_\/ \/ \/_\/ \/ __ |\/ , _\/ ,&lt; \/ \/_\/ \/\\ \\   \n--\\___\\_\\____\/_\/ |_\/_\/|_\/_\/|_|\\____\/___\/   \n2020-04-29 09:49:37,718 WARN  [io.qua.dep.QuarkusAugmentor] (main) Using Java versions older than 11 to build Quarkus applications is deprecated and will be disallowed in a future release!\n2020-04-29 09:49:38,389 INFO  [io.und.servlet] (Quarkus Main Thread) Initializing AtmosphereFramework\n2020-04-29 09:49:38,579 INFO  [io.quarkus] (Quarkus Main Thread) Quarkus 1.4.1.Final started in 0.995s. Listening on: http:\/\/0.0.0.0:8080\n2020-04-29 09:49:38,579 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.\n2020-04-29 09:49:38,579 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, servlet, undertow-websockets]\n2020-04-29 09:49:46,423 WARNING [com.vaa.ser.DefaultDeploymentConfiguration] (executor-thread-1)                                                                                                                                                             \n=================================================================                                                                                                                                                                                            \nVaadin is running in DEBUG MODE.\nAdd productionMode=true to web.xml to disable debug features.\nTo show debug window, add ?debug to your application URL.\n=================================================================\n<\/code><\/pre>\n<p>Example application I did based on <strong><a href=\"https:\/\/github.com\/vaadin\/dashboard-demo\">vaadin\/dashboard-demo<\/a><\/strong> that uses nicely looking and responsive <strong><a href=\"https:\/\/demo.vaadin.com\/valo-theme\/#!common\">Valo theme<\/a><\/strong><\/p>\n<p><img src=\"\/img\/2020-04-quarkus-vaadin-sm.gif\" alt=\"quarkus + vaadin\" \/><\/p>\n<p><strong>Current solution limitations and workaround:<\/strong><\/p>\n<ul>\n<li>Latest Vaadin version (14+) does not work from the box and needs for custom Quarkus extensions like <a href=\"https:\/\/github.com\/moewes\/quarkus-vaadin-lab\">moewes\/quarkus-vaadin-lab<\/a> and there is still no official one :(<\/li>\n<li>Vaadin CDI doesn't work as expected, so to access your CDI beans from the UI components you should use <strong><code>CDI.current().select(Bean.class).get();<\/code><\/strong><\/li>\n<li>By default Quarkus removes CDI beans from the runtime if no one @Inject them. Use <strong><code>io.quarkus.arc.Unremovable<\/code><\/strong> annotation for keep beans you need.<\/li>\n<li>In case <code>java.lang.IllegalStateException:Unable to configure jsr356 at that stage. ServerContainer is null<\/code> - provide <code>org.atmosphere.websocket.suppressJSR356<\/code> VaadinServlet parameter as was shown in the code snippet above<\/li>\n<li>Quarkus native mode doesn't work<\/li>\n<\/ul>\n<p>Described example application source code available on <a href=\"https:\/\/github.com\/kostenkoserg\/quarkus-vaadin8-example\">GitHub<\/a><\/p>\n\n\t"},{"title":"Load huge amount of data with Jakarta EE Batch","link":"https:\/\/kostenko.org\/blog\/2020\/03\/data-processing-with-jakarta-ee-batch-api.html","pubDate":"Wed, 25 Mar 2020 00:00:00 +0200","guid":"blog\/2020\/03\/data-processing-with-jakarta-ee-batch-api.html","description":"\n\t<p>Processing huge amount of data is a challenge for every enterprise system. Jakarta EE specifications provides useful approach to get it done through <strong><a href=\"https:\/\/projects.eclipse.org\/projects\/ee4j.batch\">Jakarta Batch<\/a><\/strong> (JSR-352):<\/p>\n<blockquote>\n<p>Batch processing is a pervasive workload pattern, expressed by a distinct application organization and execution model. It is found across virtually every industry, applied to such tasks as statement generation, bank postings, risk evaluation, credit score calculation, inventory management, portfolio optimization, and on and on. Nearly any bulk processing task from any business sector is a candidate for batch processing.<br \/>\nBatch processing is typified by bulk-oriented, non-interactive, background execution. Frequently long-running, it may be data or computationally intensive, execute sequentially or in parallel, and may be initiated through various invocation models, including ad hoc, scheduled, and on-demand.<br \/>\nBatch applications have common requirements, including logging, checkpointing, and parallelization. Batch workloads have common requirements, especially operational control, which allow for initiation of, and interaction with, batch instances; such interactions include stop and restart.<\/p>\n<\/blockquote>\n<p>One of the typical use case is a import data from different sources and formats to internal database. Below we will design sample application to import data, for example, from  <code>json<\/code> and <code>xml<\/code> files to the database and see how well structured it can be.<\/p>\n<p>Using <strong>Eclipse Red Hat CodeReady Studio plugin<\/strong>, we can easily design our solution diagram:<br \/>\n<img src=\"\/img\/2020-02-jakarta-batch-import.png\" alt=\"import batch diagram\" \/><\/p>\n<p>Jakarta Batch descriptor in this case will looks like:<br \/>\n<code>META-INF\/batch-jobs\/hugeImport.xml:<\/code><\/p>\n<pre><code class=\"language-java\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;job id=&quot;hugeImport&quot; xmlns=&quot;http:\/\/xmlns.jcp.org\/xml\/ns\/javaee&quot; xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http:\/\/xmlns.jcp.org\/xml\/ns\/javaee http:\/\/xmlns.jcp.org\/xml\/ns\/javaee\/jobXML_1_0.xsd&quot; version=&quot;1.0&quot;&gt;\n    &lt;step id=&quot;fileSelector&quot; next=&quot;decider&quot;&gt;\n        &lt;batchlet ref=&quot;fileSelectorBatchlet&quot;&gt;\n            &lt;properties&gt;\n                &lt;property name=&quot;path&quot; value=&quot;\/tmp\/files2import&quot;\/&gt;\n            &lt;\/properties&gt;\n        &lt;\/batchlet&gt;\n    &lt;\/step&gt;\n    &lt;decision id=&quot;decider&quot; ref=&quot;myDecider&quot;&gt;\n        &lt;next on=&quot;xml&quot; to=&quot;xmlParser&quot;\/&gt;\n        &lt;next on=&quot;json&quot; to=&quot;jsonParser&quot;\/&gt;\n    &lt;\/decision&gt;\n    &lt;step id=&quot;xmlParser&quot; next=&quot;chunkProcessor&quot;&gt;\n        &lt;batchlet ref=&quot;xmlParserBatchlet&quot;\/&gt;\n    &lt;\/step&gt;\n    &lt;step id=&quot;jsonParser&quot; next=&quot;chunkProcessor&quot;&gt;\n        &lt;batchlet ref=&quot;jsonParserBatchlet&quot;\/&gt;\n    &lt;\/step&gt;\n    &lt;step id=&quot;chunkProcessor&quot;&gt;\n        &lt;chunk&gt;\n            &lt;reader ref=&quot;itemReader&quot;\/&gt;\n            &lt;processor ref=&quot;itemMockProcessor&quot;\/&gt;\n            &lt;writer ref=&quot;itemJpaWriter&quot;\/&gt;\n        &lt;\/chunk&gt;\n        &lt;partition&gt;\n            &lt;plan partitions=&quot;5&quot;&gt;&lt;\/plan&gt;\n        &lt;\/partition&gt;\n    &lt;\/step&gt;\n&lt;\/job&gt;\n<\/code><\/pre>\n<p>So, now we need to implement each brick above and try to keep each batchlet independent as much as possible. As you can see from above our sample job consist from:<\/p>\n<ul>\n<li><strong>fileSelector<\/strong> - batchlet do file selection based on supported by configuration file extension<\/li>\n<li><strong>decider<\/strong> - decision maker, responsible for choosing right parser<\/li>\n<li><strong>xml\\jsonParser<\/strong> - parser batchlets, responsible for file parsing to a list of items<\/li>\n<li><strong>chunkProcessor<\/strong> - items processing chunk(<strong>reader<\/strong>, optional <strong>processor<\/strong> and <strong>writer<\/strong>) with partitioning to boost performance<\/li>\n<\/ul>\n<p>Before start with implementation, let's design useful solution to <strong>share state between steps<\/strong>. Unfortunately, Jakarta Batch Specification does not provide job scoped CDI beans yet (JBeret implementation does, specification doesn't). But we able to use <strong><code>JobContext.set\\getTransientUserData()<\/code><\/strong> to deal with the current batch context. In our case we want to share <code>File<\/code> and <code>Queue<\/code> with  items for processing:<\/p>\n<pre><code class=\"language-java\">@Named\npublic class ImportJobContext {\n    @Inject\n    private JobContext jobContext;\n\n    private Optional&lt;File&gt; file = Optional.empty();\n    private Queue&lt;ImportItem&gt; items = new ConcurrentLinkedQueue&lt;&gt;();\n\n    public Optional&lt;File&gt; getFile() {\n        return getImportJobContext().file;\n    }\n    public void setFile(Optional&lt;File&gt; file) {\n        getImportJobContext().file = file;\n    }\n    public Queue&lt;ImportItem&gt; getItems() {\n        return getImportJobContext().items;\n    }\n\n    private ImportJobContext getImportJobContext() {\n        if (jobContext.getTransientUserData() == null) {\n            jobContext.setTransientUserData(this);\n        }\n        return (ImportJobContext) jobContext.getTransientUserData();\n    }\n}\n<\/code><\/pre>\n<p>Now we can inject our custom <strong><code>ImportJobContext<\/code><\/strong> to share type-safe state between batchlets. First step is search file for processing by provided in step properties path:<\/p>\n<pre><code class=\"language-java\">@Named\npublic class FileSelectorBatchlet extends AbstractBatchlet {\n\n    @Inject\n    private ImportJobContext jobContext;\n\n    @Inject\n    @BatchProperty\n    private String path;\n\n    @Override\n    public String process() throws Exception {\n        Optional&lt;File&gt; file = Files.walk(Paths.get(path)).filter(Files::isRegularFile).map(Path::toFile).findAny();\n        if (file.isPresent()) {\n            jobContext.setFile(file);\n        }\n        return BatchStatus.COMPLETED.name();\n    }\n}\n<\/code><\/pre>\n<p>After we need to make decision about parser, for example, based on extension. Decider just returns file extension as string and then  <strong>batch runtime<\/strong>  should give control to the corresponding parser batchlet. Please, check <code>&lt;decision id=&quot;decider&quot; ref=&quot;myDecider&quot;&gt;<\/code> section in the XML batch descriptor above.<\/p>\n<pre><code class=\"language-java\">@Named\npublic class MyDecider implements Decider {\n\n    @Inject\n    private ImportJobContext jobContext;\n\n    @Override\n    public String decide(StepExecution[] ses) throws Exception {\n        if (!jobContext.getFile().isPresent()) {\n            throw new FileNotFoundException();\n        }\n        String name = jobContext.getFile().get().getName();\n        String extension = name.substring(name.lastIndexOf(&quot;.&quot;)+1);\n        return extension;\n    }\n}\n<\/code><\/pre>\n<p>ParserBatchlet in turn should parse file using <strong>JSON-B<\/strong> or <strong>JAXB<\/strong> depends on type and fill Queue with <strong><code>ImportItem<\/code><\/strong> objects. I would like to use <strong><code>ConcurrentLinkedQueue<\/code><\/strong> to share items between partitions, but if you need for some other behavior here, you can provide <strong><code>javax.batch.api.partition.PartitionMapper<\/code><\/strong> with your own implementation<\/p>\n<pre><code class=\"language-java\">@Named\npublic class JsonParserBatchlet  extends AbstractBatchlet {\n\n    @Inject\n    ImportJobContext importJobContext;\n\n    @Override\n    public String process() throws Exception {\n\n        List&lt;ImportItem&gt; items = JsonbBuilder.create().fromJson(\n                new FileInputStream(importJobContext.getFile().get()),\n                new ArrayList&lt;ImportItem&gt;(){}.getClass().getGenericSuperclass());\n\n        importJobContext.getItems().addAll(items);\n        return BatchStatus.COMPLETED.name();\n    }\n}\n<\/code><\/pre>\n<p>ItemReader then will looks as simple as possible, just pool item from the Queue:<\/p>\n<pre><code class=\"language-java\">@Named\npublic class ItemReader  extends AbstractItemReader {\n\n    @Inject\n    ImportJobContext importJobContext;\n\n    @Override\n    public ImportItem readItem() throws Exception {\n\n        return importJobContext.getItems().poll();\n    }\n}\n<\/code><\/pre>\n<p>And persist time...<\/p>\n<pre><code class=\"language-java\">@Named\npublic class ItemJpaWriter  extends AbstractItemWriter  {\n\n    @PersistenceContext\n    EntityManager entityManager;\n\n    @Override\n    public void writeItems(List&lt;Object&gt; list) throws Exception {\n        for (Object obj : list) {\n            ImportItem item = (ImportItem) obj;\n            entityManager.merge(item);\n        }\n    }\n}\n<\/code><\/pre>\n<p>Actually, this is it! Now we able to easily extend our application with new parsers, processors and writers without any existing code changes,  - just describe new (update existing) flows over Jakarta Batch descriptor.<br \/>\nOf course, <strong>Jakarta Batch specification<\/strong> provides much more helpful functionality than i have covered in this post (<strong>Checkpoints<\/strong>, <strong>Exception Handling<\/strong>, <strong>Listeners<\/strong>, <strong>Flow Control<\/strong>, <strong>Failed job restarting<\/strong> etc.), but even it enough to see how simple, power and well structured it can be.<\/p>\n<p><strong>Note!<\/strong> <strong>Wildfly Application Server<\/strong> implements Jakarta Batch specification through the <strong>batch-jberet subsystem<\/strong>. By default last one configured to use only <strong>10<\/strong> threads.<\/p>\n<pre><code class=\"language-xml\">&lt;subsystem xmlns=&quot;urn:jboss:domain:batch-jberet:2.0&quot;&gt;\n    ...\n    &lt;thread-pool name=&quot;batch&quot;&gt;\n        &lt;max-threads count=&quot;10&quot;\/&gt;\n        &lt;keepalive-time time=&quot;30&quot; unit=&quot;seconds&quot;\/&gt;\n    &lt;\/thread-pool&gt;\n&lt;\/subsystem&gt;\n<\/code><\/pre>\n<p>So, if you are planing intensive usage of <strong>Batch runtime<\/strong> - feel free to increase this parameter:<\/p>\n<pre><code class=\"language-bash\">\/subsystem=batch-jberet\/thread-pool=batch\/:write-attribute(name=max-threads, value=100)\n<\/code><\/pre>\n<p>Described sample application source code available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-batch-processing-examples\">GitHub<\/a><\/p>\n\n\t"},{"title":"Slow SQL logging with JPA and Wildfly","link":"https:\/\/kostenko.org\/blog\/2020\/03\/jpa-wildfly-slow-sql.html","pubDate":"Fri, 20 Mar 2020 00:00:00 +0200","guid":"blog\/2020\/03\/jpa-wildfly-slow-sql.html","description":"\n\t<p>Recently I wrote about <strong><a href=\"https:\/\/kostenko.org\/blog\/2020\/01\/sql-spying-with-wildfly.html\">Logging for JPA SQL queries with Wildfly<\/a><\/strong>. In this post I'll show you how to configure <strong>logging for slow SQL queries<\/strong>.<\/p>\n<p>Wildfly uses Hibernate as JPA provider. So, to enable <strong>slow sql feature<\/strong> you just need to provide <code>hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS<\/code> property in your <strong>persistence.xml<\/strong> :<\/p>\n<pre><code class=\"language-java\">&lt;properties&gt;\n    ...\n    &lt;property name=&quot;hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS&quot; value=&quot;25&quot;\/&gt;\n    ...\n&lt;\/properties&gt;    \n<\/code><\/pre>\n<p>To log slow queries to separate file, please configure logging like:<\/p>\n<pre><code class=\"language-bash\">\/subsystem=logging\/periodic-rotating-file-handler=slow_sql_handler:add(level=INFO, file={&quot;path&quot;=&gt;&quot;slowsql.log&quot;}, append=true, autoflush=true, suffix=.yyyy-MM-dd,formatter=&quot;%d{yyyy-MM-dd HH:mm:ss,SSS}&quot;)\n\/subsystem=logging\/logger=org.hibernate.SQL_SLOW:add(use-parent-handlers=false,handlers=[&quot;slow_sql_handler&quot;])\n<\/code><\/pre>\n<p><strong>Note!<\/strong><br \/>\nDescribed above functionality available since Hibernate version <strong>5.4.5<\/strong>, but latest for today <strong>Wildfly 19<\/strong> uses Hibernate version <strong>5.3<\/strong>.  Fortunately, if you can't wait to enjoy the latest version of Hibernate, you can use <strong><a href=\"https:\/\/docs.jboss.org\/hibernate\/orm\/5.4\/topical\/html_single\/wildfly\/Wildfly.html\">WildFly feature packs<\/a><\/strong> to create a <strong>custom server<\/strong> with a different version of Hibernate ORM in few simple steps:<\/p>\n<p>Create provisioning configuration file (provision.xml)<\/p>\n<pre><code class=\"language-xml\">&lt;server-provisioning xmlns=&quot;urn:wildfly:server-provisioning:1.1&quot; copy-module-artifacts=&quot;true&quot;&gt;\n    &lt;feature-packs&gt;\n\t&lt;feature-pack\n\t\tgroupId=&quot;org.hibernate&quot;\n\t\tartifactId=&quot;hibernate-orm-jbossmodules&quot;\n\t\tversion=&quot;${hibernate-orm.version}&quot; \/&gt;\n\t&lt;feature-pack\n\t\tgroupId=&quot;org.wildfly&quot;\n\t\tartifactId=&quot;wildfly-feature-pack&quot;\n\t\tversion=&quot;${wildfly.version}&quot; \/&gt;\n    &lt;\/feature-packs&gt;\n&lt;\/server-provisioning&gt;\n<\/code><\/pre>\n<p>Create gradle build file (build.gradle)<\/p>\n<pre><code class=\"language-java\">plugins {\n  id &quot;org.wildfly.build.provision&quot; version '0.0.6'\n}\nrepositories {\n    mavenLocal()\n    mavenCentral()\n    maven {\n        name 'jboss-public'\n        url 'https:\/\/repository.jboss.org\/nexus\/content\/groups\/public\/'\n    }\n}\nprovision {\n    \/\/Optional destination directory:\n    destinationDir = file(&quot;wildfly-custom&quot;)\n\n    \/\/Update the JPA API:\n    override( 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api' ) {\n        groupId = 'javax.persistence'\n        artifactId = 'javax.persistence-api'\n        version = '2.2'\n    }\n    configuration = file( 'provision.xml' )\n    \/\/Define variables which need replacing in the provisioning configuration!\n    variables['wildfly.version'] = '17.0.0.Final'\n    variables['hibernate-orm.version'] = '5.4.5.Final'\n}\n<\/code><\/pre>\n<p>Build custom Wildfly version<\/p>\n<pre><code class=\"language-bash\">gradle provision\n<\/code><\/pre>\n<p>Switch to a different Hibernate ORM slot in your persistence.xml<\/p>\n<pre><code class=\"language-java\">&lt;properties&gt;\n    &lt;property name=&quot;jboss.as.jpa.providerModule&quot; value=&quot;org.hibernate:5.4&quot;\/&gt;\n&lt;\/properties&gt;\n<\/code><\/pre>\n<p>Enjoy!<\/p>\n\n\t"},{"title":"Firebase push notifications with Eclipse Microprofile Rest Client","link":"https:\/\/kostenko.org\/blog\/2020\/03\/firebase-push-microprofile-rest-client.html","pubDate":"Thu, 5 Mar 2020 00:00:00 +0200","guid":"blog\/2020\/03\/firebase-push-microprofile-rest-client.html","description":"\n\t<p>Nowadays <strong>Push notifications<\/strong> is a must have feature for any trend application. Firebase Cloud Messaging (<strong>FCM<\/strong>) is a free (at least in this moment) cross-platform solution for messages and notifications for <strong>Android<\/strong>, <strong>iOS<\/strong> and <strong>Web applications<\/strong>.<\/p>\n<p><img src=\"\/img\/2020-03-firebase-mp-rest-client.png\" alt=\"firebase, push, microprofile, rest client\" \/><\/p>\n<p>To enable push notification on client side you should create Firebase project and follow the <a href=\"https:\/\/firebase.google.com\/docs\/cloud-messaging\">manual<\/a> or  <a href=\"https:\/\/github.com\/firebase\/quickstart-js\/tree\/master\/messaging\">examples<\/a>. From the server side perspective all you need to send push notification is:<\/p>\n<ul>\n<li><strong>Server key<\/strong> - will be created for your firebase project<\/li>\n<li><strong>Instance ID token<\/strong> - id of specific subscribed instance (instance destination id)<\/li>\n<\/ul>\n<p>Firebase provides <strong><code>https:\/\/fcm.googleapis.com\/fcm\/send<\/code><\/strong> endpoint and very simple <a href=\"https:\/\/firebase.google.com\/docs\/cloud-messaging\/http-server-ref\">HTTP API<\/a> like<\/p>\n<pre><code class=\"language-java\">{\n    &quot;to&quot;: &quot;&lt;Instance ID token&gt;&quot;,\n    &quot;notification&quot;: {\n      &quot;title&quot;: &quot;THIS IS MP REST CLIENT!&quot;,\n      &quot;body&quot;: &quot;The quick brown fox jumps over the lazy dog.&quot;\n      }\n}\n<\/code><\/pre>\n<p>So, let's design simple Microprofile REST client to deal with above:<\/p>\n<pre><code class=\"language-java\">@Path(&quot;\/&quot;)\n@RegisterRestClient(configKey = &quot;push-api&quot;)\npublic interface PushClientService {\n\n    @POST\n    @Path(&quot;\/fcm\/send&quot;)\n    @Produces(&quot;application\/json&quot;)\n    @ClientHeaderParam(name = &quot;Authorization&quot;, value = &quot;{generateAuthHeader}&quot;)\n    void send(PushMessage msg);\n\n    default String generateAuthHeader() {\n        return &quot;key=&quot; + ConfigProvider.getConfig().getValue(&quot;firebase.server_key&quot;, String.class);\n    }\n}\n<\/code><\/pre>\n<pre><code class=\"language-java\">public class PushMessage {\n\n    public String to;\n    public PushNotification notification;\n\n    public static class PushNotification {\n        public String title;\n        public String body;\n    }\n}\n<\/code><\/pre>\n<p>and application.properties<\/p>\n<pre><code class=\"language-bash\"># firebase server key\nfirebase.server_key=&lt;SERVER_KEY&gt;\n# rest client\npush-api\/mp-rest\/url=https:\/\/fcm.googleapis.com\/\n<\/code><\/pre>\n<p>Actually, this is it! Now you able to <code>@Inject<\/code>  PushClientService and enjoy push notifications as well.<\/p>\n<pre><code class=\"language-java\">@Inject\n@RestClient\nPushClientService pushService;\n...\npushService.send(message);\n<\/code><\/pre>\n<p>If you would like to test how it works from client side perspective, - feel free to use <strong><a href=\"https:\/\/kostenko.org\/blog\/2020\/03\/firebase-push-microprofile-rest-client\/index.htm\">Test web application<\/a><\/strong> to generate instance ID token and check notifications delivery.<\/p>\n<p>Described sample application source code with swagger-ui endpoint and firebase.server_key available on <a href=\"https:\/\/github.com\/kostenkoserg\/microprofile-quarkus-example\">GitHub<\/a><\/p>\n\n\t"},{"title":"Well secured and documented REST API with Eclipse Microprofile and Quarkus","link":"https:\/\/kostenko.org\/blog\/2020\/02\/jwt-openapi-microprofile-quarkus.html","pubDate":"Thu, 20 Feb 2020 00:00:00 +0200","guid":"blog\/2020\/02\/jwt-openapi-microprofile-quarkus.html","description":"\n\t<p>Eclipse Microprofile specification provides several many helpful sections about building well designed microservice-oriented applications. <strong>OpenAPI<\/strong>, <strong>JWT Propagation<\/strong> and <strong>JAX-RS<\/strong> - the ones of them.<br \/>\n<img src=\"\/img\/2020-02-jwt-openapi-jaxrs-microprofile.png\" alt=\"microprofile, jwt, openapi, jax-rs\" \/><br \/>\nTo see how it works on practice let's design two typical REST resources: insecured <strong>token<\/strong> to generate JWT and secured  <strong>user<\/strong>, based on Quarkus Microprofile implementation.<\/p>\n<p>Easiest way to bootstrap Quarkus application from scratch is generation project structure by provided starter page - <strong><a href=\"https:\/\/code.quarkus.io\/\">code.quarkus.io<\/a><\/strong>. Just select build tool you like and extensions you need. In our case it is:<\/p>\n<ul>\n<li><strong>SmallRye JWT<\/strong><\/li>\n<li><strong>SmallRye OpenAPI<\/strong><\/li>\n<\/ul>\n<p>I prefer <strong>gradle<\/strong>, - and my <code>build.gradle<\/code> looks pretty simple<\/p>\n<pre><code class=\"language-java\">group 'org.kostenko'\nversion '1.0.0'\nplugins {\n    id 'java'\n    id 'io.quarkus'\n}\nrepositories {\n     mavenLocal()\n     mavenCentral()\n}\ndependencies {\n    implementation 'io.quarkus:quarkus-smallrye-jwt'\n    implementation 'io.quarkus:quarkus-smallrye-openapi'\n    implementation 'io.quarkus:quarkus-resteasy-jackson'    \n    implementation 'io.quarkus:quarkus-resteasy'\n    implementation enforcedPlatform(&quot;${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}&quot;)\n    testImplementation 'io.quarkus:quarkus-junit5'\n    testImplementation 'io.rest-assured:rest-assured'\n}\ncompileJava {\n    options.compilerArgs &lt;&lt; '-parameters'\n}\n<\/code><\/pre>\n<p>Now we are ready to improve standard <strong>JAX-RS<\/strong> service with <strong>OpenAPI<\/strong> and <strong>JWT<\/strong> stuff:<\/p>\n<pre><code class=\"language-java\">@RequestScoped\n@Path(&quot;\/user&quot;)\n@Consumes(MediaType.APPLICATION_JSON)\n@Produces(MediaType.APPLICATION_JSON)\n@Tags(value = @Tag(name = &quot;user&quot;, description = &quot;All the user methods&quot;))\n@SecurityScheme(securitySchemeName = &quot;jwt&quot;, type = SecuritySchemeType.HTTP, scheme = &quot;bearer&quot;, bearerFormat = &quot;jwt&quot;)\npublic class UserResource {\n\n    @Inject\n    @Claim(&quot;user_name&quot;)\n    Optional&lt;JsonString&gt; userName;\n\n    @POST\n    @PermitAll\n    @Path(&quot;\/token\/{userName}&quot;)\n    @APIResponses(value = {\n        @APIResponse(responseCode = &quot;400&quot;, description = &quot;JWT generation error&quot;),\n        @APIResponse(responseCode = &quot;200&quot;, description = &quot;JWT successfuly created.&quot;, content = @Content(schema = @Schema(implementation = User.class)))})\n    @Operation(summary = &quot;Create JWT token by provided user name&quot;)\n    public User getToken(@PathParam(&quot;userName&quot;) String userName) {\n        User user = new User();\n        user.setJwt(TokenUtils.generateJWT(userName));\n        return user;    \n    }\n\n    @GET\n    @RolesAllowed(&quot;user&quot;)\n    @Path(&quot;\/current&quot;)\n    @SecurityRequirement(name = &quot;jwt&quot;, scopes = {})\n    @APIResponses(value = {\n        @APIResponse(responseCode = &quot;401&quot;, description = &quot;Unauthorized Error&quot;),\n        @APIResponse(responseCode = &quot;200&quot;, description = &quot;Return user data&quot;, content = @Content(schema = @Schema(implementation = User.class)))})\n    @Operation(summary = &quot;Return user data by provided JWT token&quot;)\n    public User getUser() {\n        User user = new User();\n        user.setName(userName.get().toString());\n        return user;\n    }\n}\n<\/code><\/pre>\n<p>First let's take a brief review of used <strong><a href=\"https:\/\/github.com\/eclipse\/microprofile-open-api\">Open API<\/a><\/strong> annotations:<\/p>\n<ul>\n<li><code>@Tags(value = @Tag(name = &quot;user&quot;, description = &quot;All the user methods&quot;))<\/code> -  Represents a tag. Tag is a meta-information you can use to help organize your API end-points.<\/li>\n<li><code>@SecurityScheme(securitySchemeName = &quot;jwt&quot;, type = SecuritySchemeType.HTTP, scheme = &quot;bearer&quot;, bearerFormat = &quot;jwt&quot;)<\/code> - Defines a security scheme that can be used by the operations.<\/li>\n<li><code>@APIResponse(responseCode = &quot;401&quot;, description = &quot;Unauthorized Error&quot;)<\/code> - Corresponds to the OpenAPI response model object which  describes a single response from an API Operation.<\/li>\n<li><code>@Operation(summary = &quot;Return user data by provided JWT token&quot;)<\/code> - Describes an operation or typically a HTTP method against a specific path.<\/li>\n<li><code>@Schema(implementation = User.class)<\/code> - Allows the definition of input and output data types.<\/li>\n<\/ul>\n<p>To more details about Open API annotations, please refer to the <strong><a href=\"https:\/\/github.com\/eclipse\/microprofile-open-api\/blob\/master\/spec\/src\/main\/asciidoc\/microprofile-openapi-spec.adoc\">MicroProfile OpenAPI Specification<\/a><\/strong>.<\/p>\n<p>After start the application, you will able to get your Open API description in the  <strong>.yaml<\/strong> format by the next URL <a href=\"http:\/\/0.0.0.0:8080\/openapi\">http:\/\/0.0.0.0:8080\/openapi<\/a> or even enjoy <strong>Swagger UI<\/strong> as well by <a href=\"http:\/\/0.0.0.0:8080\/swagger-ui\/\">http:\/\/0.0.0.0:8080\/swagger-ui\/<\/a> :<br \/>\n<img src=\"\/img\/2020-02-swagger-ui.png\" alt=\"microprofile, openapi, swagger-ui\" \/><\/p>\n<p><strong>Note<\/strong> By default swagger-ui available in the dev mode only. If you would like to keep swagger on production, - add next property to your <code>application.properties<\/code><\/p>\n<pre><code class=\"language-java\">quarkus.swagger-ui.always-include=true\n<\/code><\/pre>\n<p>Second part of this post is a <strong><a href=\"https:\/\/github.com\/eclipse\/microprofile-jwt-auth\">JWT role based access control(RBAC)<\/a><\/strong> for microservice endpoints. JSON Web Tokens are an open, industry standard  <a href=\"https:\/\/tools.ietf.org\/html\/rfc7519\">RFC 7519<\/a> method for representing claims securely between two parties and below we will see how easy it can be integrated in your application with Eclipse Microprofile.<\/p>\n<p>As JWT suggests usage of cryptography - we need to generate public\\private key pair before start coding:<\/p>\n<pre><code class=\"language-bash\"># Generate a private key\nopenssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048\n\n# Derive the public key from the private key\nopenssl rsa -pubout -in private_key.pem -out public_key.pem\n<\/code><\/pre>\n<p>Now we are able to generate JWT and sign data with our private key in the, for example, next way:<\/p>\n<pre><code class=\"language-java\">public static String generateJWT(String userName) throws Exception {\n\n    Map&lt;String, Object&gt; claimMap = new HashMap&lt;&gt;();\n    claimMap.put(&quot;iss&quot;, &quot;https:\/\/kostenko.org&quot;);\n    claimMap.put(&quot;sub&quot;, &quot;jwt-rbac&quot;);\n    claimMap.put(&quot;exp&quot;, currentTimeInSecs + 300)\n    claimMap.put(&quot;iat&quot;, currentTimeInSecs);\n    claimMap.put(&quot;auth_time&quot;, currentTimeInSecs);\n    claimMap.put(&quot;jti&quot;, UUID.randomUUID().toString());\n    claimMap.put(&quot;upn&quot;, &quot;UPN&quot;);\n    claimMap.put(&quot;groups&quot;, Arrays.asList(&quot;user&quot;));\n    claimMap.put(&quot;raw_token&quot;, UUID.randomUUID().toString());\n    claimMap.put(&quot;user_bane&quot;, userName);\n\n    return Jwt.claims(claimMap).jws().signatureKeyId(&quot;META-INF\/private_key.pem&quot;).sign(readPrivateKey(&quot;META-INF\/private_key.pem&quot;));\n}\n<\/code><\/pre>\n<p>For additional information about JWT structure, please refer <strong><a href=\"https:\/\/jwt.io\/introduction\/\">https:\/\/jwt.io<\/a><\/strong><\/p>\n<p>Time to review our application security stuff:<br \/>\n<code>@RequestScoped<\/code> -  It is not about security as well. But as JWT is request scoped we need this one to work correctly;<br \/>\n<code>@PermitAll<\/code> - Specifies that all security roles are allowed to invoke the specified method;<br \/>\n<code>@RolesAllowed(&quot;user&quot;)<\/code> - Specifies the list of roles permitted to access method;<br \/>\n<code>@Claim(&quot;user_name&quot;)<\/code> - Allows us inject provided by JWT field;<\/p>\n<p>To configure JWT in your <code>application.properties<\/code>, please add<\/p>\n<pre><code class=\"language-bash\">quarkus.smallrye-jwt.enabled=true\nmp.jwt.verify.publickey.location=META-INF\/public_key.pem\nmp.jwt.verify.issuer=https:\/\/kostenko.org\n\n# quarkus.log.console.enable=true\n# quarkus.log.category.&quot;io.quarkus.smallrye.jwt&quot;.level=TRACE\n# quarkus.log.category.&quot;io.undertow.request.security&quot;.level=TRACE\n<\/code><\/pre>\n<p>And actually that is it, - if you try to reach <code>\/user\/current<\/code> service without or with bad JWT token in the <code>Authorization<\/code> header - you will get  <strong>HTTP 401 Unauthorized<\/strong> error.<\/p>\n<p>curl example:<\/p>\n<pre><code class=\"language-java\">curl -X GET &quot;http:\/\/localhost:8080\/user\/current&quot; -H &quot;accept: application\/json&quot; -H &quot;Authorization: Bearer eyJraWQiOiJNRVRBLUlORi9wcml2YXRlX2tleS5wZW0iLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJqd3QtcmJhYyIsInVwbiI6IlVQTiIsInJhd190b2tlbiI6IjQwOWY3MzVkLTQyMmItNDI2NC1iN2UyLTc1YTk0OGFjMTg3MyIsInVzZXJfbmFtZSI6InNlcmdpaSIsImF1dGhfdGltZSI6MTU4MjE5NzM5OSwiaXNzIjoiaHR0cHM6Ly9rb3N0ZW5rby5vcmciLCJncm91cHMiOlsidXNlciJdLCJleHAiOjkyMjMzNzIwMzY4NTQ3NzU4MDcsImlhdCI6MTU4MjE5NzM5OSwianRpIjoiMzNlMGMwZjItMmU0Yi00YTczLWJkNDItNDAzNWQ4NTYzODdlIn0.QteseKKwnYJWyj8ccbI1FuHBgWOk98PJuN0LU1vnYO69SYiuPF0d9VFbBada46N_kXIgzw7btIc4zvHKXVXL5Uh3IO2v1lnw0I_2Seov1hXnzvB89SAcFr61XCtE-w4hYWAOaWlkdTAmpMSUt9wHtjc0MwvI_qSBD3ol_VEoPv5l3_W2NJ2YBnqkY8w68c8txL1TnoJOMtJWB-Rpzy0XrtiO7HltFAz-Gm3spMlB3FEjnmj8-LvMmoZ3CKIybKO0U-bajWLPZ6JMJYtp3HdlpsiXNmv5QdIq1yY7uOPIKDNnPohWCgOhFVW-bVv9m-LErc_s45bIB9djwe13jFTbNg&quot;\n<\/code><\/pre>\n<p>Source code of described sample application available on <a href=\"https:\/\/github.com\/kostenkoserg\/microprofile-quarkus-example\">GitHub<\/a><\/p>\n\n\t"},{"title":"Simple note about using JPA relation  mappings","link":"https:\/\/kostenko.org\/blog\/2020\/02\/jpa-relation-mappings.html","pubDate":"Fri, 14 Feb 2020 00:00:00 +0200","guid":"blog\/2020\/02\/jpa-relation-mappings.html","description":"\n\t<p>There is a lot of typical examples how to build JPA <code>@OneToMany<\/code> and <code>@ManyToOne<\/code> relationships in your Jakarta EE application. And usually it looks like:<\/p>\n<pre><code class=\"language-java\">@Entity\n@Table(name = &quot;author&quot;)\npublic class Author {\n    @OneToMany\n    private List&lt;Book&gt; book;\n    ...\n}\n<\/code><\/pre>\n<pre><code class=\"language-java\">@Entity\n@Table(name = &quot;book&quot;)\npublic class Book {\n    @ManyToOne\n    private Author author;\n    ...\n}\n<\/code><\/pre>\n<p>This code looks pretty clear, but on my opinion <strong>you should NOT USE this style<\/strong> in your real world application. From years of JPA using experience i definitely can say that sooner or later your project will stuck with known performance issues and holy war questions about: <strong>N+1<\/strong>, <strong>LazyInitializationException<\/strong>, <strong>Unidirectional @OneToMany<\/strong> , <strong>CascadeTypes<\/strong> ,<strong>LAZY vs EAGER<\/strong>, <strong>JOIN FETCH<\/strong>, <strong>Entity Graph<\/strong>, <strong>Fetching lot of unneeded data<\/strong>, <strong>Extra queries (for example: select Author by id before persist Book)<\/strong> etcetera.  Even if you are have answers for each potential issue above, usually proposed solution will add unreasonable complexity to the project.<\/p>\n<p>To avoid potential issues i recommend to follow next rules:<\/p>\n<ul>\n<li>Avoid using of <code>@OneToMany<\/code> at all<\/li>\n<li>Use <code>@ManyToOne<\/code> to build constrains but work with  <strong>ID<\/strong> instead of Entity<\/li>\n<\/ul>\n<p>Unfortunately, simple snippet below does not work as expected in case <code>persist<\/code><\/p>\n<pre><code class=\"language-java\">@ManyToOne(targetEntity = Author.class)\nprivate long authorId;\n<\/code><\/pre>\n<p>But,we can use next one instead of<\/p>\n<pre><code class=\"language-java\">@JoinColumn(name = &quot;authorId&quot;, insertable = false, updatable = false)\n@ManyToOne(targetEntity = Author.class)\nprivate Author author;\n\nprivate long authorId;\n\npublic long getAuthorId() {\n    return authorId;\n}\n\npublic void setAuthorId(long authorId) {\n    this.authorId = authorId;\n}\n<\/code><\/pre>\n<p>Hope, this two simple rules helps you enjoy all power of JPA with KISS and decreasing count of complexity.<\/p>\n\n\t"},{"title":"ISPN000299: Unable to acquire lock after 15 seconds for key","link":"https:\/\/kostenko.org\/blog\/2020\/01\/infinispan-distributed-cache-issues.html","pubDate":"Wed, 5 Feb 2020 00:00:00 +0200","guid":"blog\/2020\/01\/infinispan-distributed-cache-issues.html","description":"\n\t<p>Distributed cache is a wide used technology that provides useful possibilities to share state whenever it necessary. Wildfly supports distributed cache through <a href=\"https:\/\/infinispan.org\/\">infinispan<\/a> subsystem and actually it works well, but in case height load and concurrent data access you may run into a some issues like:<\/p>\n<ul>\n<li>ISPN000299: Unable to acquire lock after 15 seconds for key<\/li>\n<li>ISPN000924: beforeCompletion() failed for SynchronizationAdapter<\/li>\n<li>ISPN000160: Could not complete injected transaction.<\/li>\n<li>ISPN000136: Error executing command PrepareCommand on Cache<\/li>\n<li>ISPN000476: Timed out waiting for responses for request<\/li>\n<li>ISPN000482: Cannot create remote transaction GlobalTx<\/li>\n<\/ul>\n<p>and others.<\/p>\n<p>In my case i had two node cluster with next infinispan configuration:<\/p>\n<pre><code class=\"language-java\">\/profile=full-ha\/subsystem=infinispan\/cache-container=myCache\/distributed-cache=userdata:add()\n\/profile=full-ha\/subsystem=infinispan\/cache-container=myCache\/distributed-cache=userdata\/component=transaction:add(mode=BATCH)\n<\/code><\/pre>\n<p><strong>distributed<\/strong> cache above means that number of copies are maintained, however this is typically less than the number of nodes in the cluster. From other point of view, to provide redundancy and fault tolerance you should configure enough amount of <strong>owners<\/strong> and obviously <strong>2<\/strong> is the necessary minimum here. So, in case usage small cluster and keep in mind the <a href=\"https:\/\/issues.redhat.com\/browse\/JDG-1318\">BUG<\/a>, - i recommend use <strong>replicated-cache<\/strong> (all nodes in a cluster hold all keys)<\/p>\n<p>Please, compare <a href=\"https:\/\/infinispan.org\/docs\/dev\/titles\/clustering\/clustering.html#which_cache_mode_should_i_use\">Which cache mode should I use?<\/a> with your needs.<\/p>\n<p>Solution:<\/p>\n<pre><code class=\"language-java\">\/profile=full-ha\/subsystem=infinispan\/cache-container=myCache\/distributed-cache=userdata:remove()\n\/profile=full-ha\/subsystem=infinispan\/cache-container=myCache\/replicated-cache=userdata:add()\n\/profile=full-ha\/subsystem=infinispan\/cache-container=myCache\/replicated-cache=userdata\/component=transaction:add(mode=NON_DURABLE_XA, locking=OPTIMISTIC)\n<\/code><\/pre>\n<p>Note!, <code>NON_DURABLE_XA<\/code> doesn't keep any transaction recovery information and if you still getting <code>Unable to acquire lock<\/code> errors on application critical data - you can try to resolve it by some <strong>retry<\/strong> policy and <strong>fail-fast<\/strong> transaction:<\/p>\n<pre><code class=\"language-java\">\/profile=full-ha\/subsystem=infinispan\/cache-container=myCache\/distributed-cache=userdata\/component=locking:write-attribute(name=acquire-timeout, value=0)\n<\/code><\/pre>\n\n\t"},{"title":"Logging for JPA SQL queries with Wildfly","link":"https:\/\/kostenko.org\/blog\/2020\/01\/sql-spying-with-wildfly.html","pubDate":"Fri, 10 Jan 2020 00:00:00 +0200","guid":"blog\/2020\/01\/sql-spying-with-wildfly.html","description":"\n\t<p>Logging for real SQL queries is very important in case using any ORM solution, - as you never can be sure <strong>which<\/strong> and <strong>how many<\/strong> requests will send JPA provider to do <code>find<\/code>, <code>merge<\/code>, <code>query<\/code> or some other operation.<\/p>\n<p>Wildfly uses Hibernate as JPA provider and provides few standard ways to enable SQL logging:<\/p>\n<p><strong>1.<\/strong> Add <code>hibernate.show_sql<\/code> property to your <strong>persistence.xml<\/strong> :<\/p>\n<pre><code class=\"language-java\">&lt;properties&gt;\n    ...\n    &lt;property name=&quot;hibernate.show_sql&quot; value=&quot;true&quot; \/&gt;\n    ...\n&lt;\/properties&gt;\n<\/code><\/pre>\n<pre><code class=\"language-java\">INFO  [stdout] (default task-1) Hibernate: insert into blogentity (id, body, title) values (null, ?, ?)\nINFO  [stdout] (default task-1) Hibernate: select blogentity0_.id as id1_0_, blogentity0_.body as body2_0_, blogentity0_.title as title3_0_ from blogentity blogentity0_ where blogentity0_.title=?\n<\/code><\/pre>\n<p><strong>2.<\/strong> Enable <code>ALL<\/code> log level for <code>org.hibernate<\/code> category like:<\/p>\n<pre><code class=\"language-java\">\/subsystem=logging\/periodic-rotating-file-handler=sql_handler:add(level=ALL, file={&quot;path&quot;=&gt;&quot;sql.log&quot;}, append=true, autoflush=true, suffix=.yyyy-MM-dd,formatter=&quot;%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n&quot;)\n\/subsystem=logging\/logger=org.hibernate.SQL:add(use-parent-handlers=false,handlers=[&quot;sql_handler&quot;])\n\/subsystem=logging\/logger=org.hibernate.type.descriptor.sql.BasicBinder:add(use-parent-handlers=false,handlers=[&quot;sql_handler&quot;])\n<\/code><\/pre>\n<pre><code class=\"language-java\">DEBUG [o.h.SQL] insert into blogentity (id, body, title) values (null, ?, ?)\nTRACE [o.h.t.d.s.BasicBinder] binding parameter [1] as [VARCHAR] - [this is body]\nTRACE [o.h.t.d.s.BasicBinder] binding parameter [2] as [VARCHAR] - [title]\nDEBUG [o.h.SQL] select blogentity0_.id as id1_0_, blogentity0_.body as body2_0_, blogentity0_.title as title3_0_ from blogentity blogentity0_ where blogentity0_.title=?\nTRACE [o.h.t.d.s.BasicBinder] binding parameter [1] as [VARCHAR] - [title]\n<\/code><\/pre>\n<p><strong>3.<\/strong> Enable spying of SQL statements:<\/p>\n<pre><code class=\"language-java\">\/subsystem=datasources\/data-source=ExampleDS\/:write-attribute(name=spy,value=true)\n\/subsystem=logging\/logger=jboss.jdbc.spy\/:add(level=DEBUG)\n<\/code><\/pre>\n<pre><code class=\"language-java\">DEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [DataSource] getConnection()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [Connection] prepareStatement(insert into blogentity (id, body, title) values (null, ?, ?), 1)\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [PreparedStatement] setString(1, this is body)\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [PreparedStatement] setString(2, title)\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [PreparedStatement] executeUpdate()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [PreparedStatement] getGeneratedKeys()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] next()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] getMetaData()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] getLong(1)\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] close()\n...\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [DataSource] getConnection()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [Connection] prepareStatement(select blogentity0_.id as id1_0_, blogentity0_.body as body2_0_, blogentity0_.title as title3_0_ from blogentity blogentity0_ where blogentity0_.title=?)\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [PreparedStatement] setString(1, title)\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [PreparedStatement] executeQuery()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] next()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] getLong(id1_0_)\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] wasNull()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] getString(body2_0_)\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] wasNull()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] getString(title3_0_)\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] wasNull()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] next()\nDEBUG [j.j.spy] java:jboss\/datasources\/ExampleDS [ResultSet] close()\n<\/code><\/pre>\n<p>So, from above we can see that variants <strong>2<\/strong> and <strong>3<\/strong> is most useful as allows to log queries with parameters. From other point of view - SQL logging can generate lot of unneeded debug information on production. To avoid garbage data in your log files, feel free to use <strong><a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_jboss_enterprise_application_platform\/6.4\/html\/administration_and_configuration_guide\/chap-the_logging_subsystem#Filter_Expressions_for_Logging\">Filter Expressions for Logging<\/a><\/strong><\/p>\n\n\t"},{"title":"Why Jakarta EE beats other java solutions from security point of view","link":"https:\/\/kostenko.org\/blog\/2019\/12\/jakarta-ee-asvs-security.html","pubDate":"Fri, 27 Dec 2019 00:00:00 +0200","guid":"blog\/2019\/12\/jakarta-ee-asvs-security.html","description":"\n\t<p>No one care about security until security incident. In case enterprise development last one can costs too much, so any preventive steps can help.  Significant part part of the OWASP Application Security Verification Standard (<strong>ASVS<\/strong>) reads:<\/p>\n<blockquote>\n<p><strong>10.2.1<\/strong> Verify that the application source code and third party libraries do not contain unauthorized phone home or data collection capabilities. Where such functionality exists, obtain the user's permission for it to operate before collecting any data.<br \/>\n<strong>10.2.3<\/strong> Verify that the application source code and third party libraries do not contain back doors, such as hard-coded or additional undocumented accounts or keys, code obfuscation, undocumented binary blobs, rootkits, or anti-debugging, insecure debugging features, or otherwise out of date, insecure, or hidden functionality that could be used maliciously if discovered.<br \/>\n<strong>10.2.4<\/strong> Verify that the application source code and third party libraries does not contain time bombs by searching for date and time related functions.<br \/>\n<strong>10.2.5<\/strong> Verify that the application source code and third party libraries does not contain malicious code, such as salami attacks, logic bypasses, or logic bombs.<br \/>\n<strong>10.2.6<\/strong> Verify that the application source code and third party libraries do not contain Easter eggs or any other potentially unwanted functionality.<br \/>\n<strong>10.3.2<\/strong> Verify that the application employs integrity protections, such as code signing or sub-resource integrity. The application must not load or execute code from untrusted sources, such as loading includes, modules, plugins, code, or libraries from untrusted sources or the Internet.<br \/>\n<strong>14.2.4<\/strong> Verify that third party components come from pre-defined, trusted and continually maintained repositories.<\/p>\n<\/blockquote>\n<p>In other words that meaning you should: <strong>&quot;Verify all code including third-party binaries, libraries, frameworks are reviewed for hardcoded credentials (backdoors).&quot;<\/strong><\/p>\n<p>In case development according to Jakarta EE specification you shouldn't be able to use poor controlled  third party libraries, as all you need already came with Application Server. In turn, last one is responsible for in time security  updates, ussage of verified libraries and many more...<\/p>\n\n\t"},{"title":"How to setup Darcula LAF on Netbeans 11","link":"https:\/\/kostenko.org\/blog\/2019\/12\/setup-darcula-laf-netbeans-11.html","pubDate":"Thu, 26 Dec 2019 00:00:00 +0200","guid":"blog\/2019\/12\/setup-darcula-laf-netbeans-11.html","description":"\n\t<p>It is pity, but Apache Netbeans IDE still comes without support default <strong>dark<\/strong> mode. Enabling <code>Netbeans 8.2 Plugin portal<\/code> does not have any effect, so to use plugins from previous versions we need to add <code>New Provider<\/code> (Tools-&gt;Plugins) with next URL:<\/p>\n<pre><code class=\"language-java\">http:\/\/plugins.netbeans.org\/nbpluginportal\/updates\/8.2\/catalog.xml.gz\n<\/code><\/pre>\n<p><img src=\"\/img\/2019-12-new-provider.png\" alt=\"add provider\" \/><\/p>\n<p>After that you should be able setup Darcula LAF in standard way<\/p>\n<p><img src=\"\/img\/2019-12-select-laf.png\" alt=\"add provider\" \/><\/p>\n\n\t"},{"title":"Understanding JMS(MDB) transaction scopes in JakartaEE application","link":"https:\/\/kostenko.org\/blog\/2019\/11\/jakartaee-understanding-jms-transactions.html","pubDate":"Thu, 14 Nov 2019 00:00:00 +0200","guid":"blog\/2019\/11\/jakartaee-understanding-jms-transactions.html","description":"\n\t<p>Most useful way to deal with JMS in JakartaEE application is MDB(<strong>M<\/strong>essage <strong>D<\/strong>riven <strong>B<\/strong>eans). This type of bean acts as a JMS message listener to which messages can be delivered from either a queue or a topic.<\/p>\n<p>Message Driven Bean supports only <code>Required<\/code> and <code>NotSupported<\/code> scopes as there is no incoming transaction context.<\/p>\n<ul>\n<li>\n<p><strong>@Required:<\/strong> Transaction starts before read from queue (before onMessage). All next resource calls will use this transaction context. In case transaction rollback or some RuntimeException, - message will be roll back to destination. Container acknowledges delivery after TX commit;<\/p>\n<\/li>\n<li>\n<p><strong>@NotSupported:<\/strong> No transaction started. Application server acknowledges delivery on successful onMessage(). In case RuntimeException, - message will be returned to destination;<\/p>\n<\/li>\n<\/ul>\n<p>In both cases above, when message was returned to the destination, container will do redelivery according to application server configuration. For example on Wildfly it is: <code>max-delivery-attempts<\/code> and <code>redelivery-delay<\/code>.<\/p>\n<pre><code class=\"language-java\">\/subsystem=messaging-activemq\/server=default\/address-setting=#:read-attribute(name=max-delivery-attempts)\n<\/code><\/pre>\n<p>Be careful with redelivery configuration as in case <strong>&quot;poisen message&quot;<\/strong> it can negative affect performance of your application or even server.<\/p>\n<p>When you use container-managed transactions, you can invoke next <code>MessageDrivenContext<\/code> methods:<\/p>\n<ul>\n<li>setRollbackOnly: marks the current transaction to rollback.<\/li>\n<li>getRollbackOnly: check current transaction has been marked for rollback or not.<\/li>\n<\/ul>\n<p>In case bean-managed transactions you need to manually control transaction by <code>UserTransaction<\/code> methods and you also can set the activation configuration property acknowledgeMode to <code>Auto-acknowledge<\/code> or <code>Dups-ok-acknowledge<\/code> to specify how the message received by the message-driven bean to be acknowledged.<\/p>\n<p>Ok. Let's pay attention on typical use cases and potentially issues with default configurations. Often enough developers use MDB to do relatively long tasks that should be executed asynchronously. So typical message bean in this case will looks like:<\/p>\n<pre><code class=\"language-java\">@JMSDestinationDefinition(\n        name = TxRequiredMessagerDrivenBean.TX_REQUIRED_QUEUE,\n        interfaceName = &quot;javax.jms.Queue&quot;\n)\n@MessageDriven(activationConfig = {\n    @ActivationConfigProperty(propertyName = &quot;destinationLookup&quot;, propertyValue = TxRequiredMessagerDrivenBean.TX_REQUIRED_QUEUE),\n    @ActivationConfigProperty(propertyName = &quot;destinationType&quot;, propertyValue = &quot;javax.jms.Queue&quot;)\n})\n\/\/@TransactionAttribute(TransactionAttributeType.REQUIRED)\npublic class TxRequiredMessagerDrivenBean implements MessageListener {\n\n    public final static String TX_REQUIRED_QUEUE = &quot;java:global\/jms\/txRequiredQueue&quot;;\n\n    @Resource\n    MessageDrivenContext messageDrivenContext;\n\n    @Override\n    public void onMessage(Message msg) {\n        System.out.println(&quot;Got new message.&quot;);\n        try {\n            System.out.println(&quot;Hello TxRequiredMessagerDrivenBean!&quot;);\n            for (int x = 1; x &lt; 40; x++) {\n                Thread.sleep(10_000l);\n                System.out.println(&quot;Long transaction: &quot; + (10 * x) + &quot; sec.&quot;);\n            }\n        } catch (Exception ex) {\n            System.err.println(ex);\n            messageDrivenContext.setRollbackOnly();\n        }\n        System.out.println(&quot;Message  successfully processed&quot;);\n    }\n}\n<\/code><\/pre>\n<p>Now take a look to result of our bean invocation:<\/p>\n<pre><code class=\"language-java\">INFO  (Thread-1 (ActiveMQ-client-global-threads)) Got new message.\nINFO  (Thread-1 (ActiveMQ-client-global-threads)) Hello TxRequiredMessagerDrivenBean!\nINFO  (Thread-1 (ActiveMQ-client-global-threads)) Long transaction: 10 sec.\n...\nINFO  (Thread-1 (ActiveMQ-client-global-threads)) Long transaction: 290 sec.\n...\nWARN  [com.arjuna.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check timeout for TX 0:ffff7f000101:3b3ecbca:5dcc2894:13 in state  RUN\nWARN  [com.arjuna.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012095: Abort of action id 0:ffff7f000101:3b3ecbca:5dcc2894:13 invoked while multiple threads active within it.\nWARN  [com.arjuna.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012381: Action id 0:ffff7f000101:3b3ecbca:5dcc2894:13 completed with multiple threads - thread Thread-1 (ActiveMQ-client-global-threads) was in progress with java.lang.Thread.sleep(Native Method) org.kostenko.example.jms.transaction.TxRequiredMessagerDrivenBean.onMessage(TxRequiredMessagerDrivenBean.java:40)\n...\nWARN  [com.arjuna.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012108: CheckedAction::check - atomic action 0:ffff7f000101:3b3ecbca:5dcc2894:13 aborting with 1 threads active!\n...\nWARN  [com.arjuna.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012121: TransactionReaper::doCancellations worker Thread[Transaction Reaper Worker 0,5,main] successfully canceled TX 0:ffff7f000101:3b3ecbca:5dcc2894:13\n...\nINFO  (Thread-3 (ActiveMQ-client-global-threads)) Got new message.\nINFO  (Thread-3 (ActiveMQ-client-global-threads)) Hello TxRequiredMessagerDrivenBean!\nINFO  (Thread-1 (ActiveMQ-client-global-threads)) Long transaction: 300 sec.\nINFO  (Thread-3 (ActiveMQ-client-global-threads)) Long transaction: 10 sec.\nINFO  (Thread-1 (ActiveMQ-client-global-threads)) Long transaction: 310 sec.\nINFO  (Thread-3 (ActiveMQ-client-global-threads)) Long transaction: 20 sec.\nINFO  (Thread-1 (ActiveMQ-client-global-threads)) Long transaction: 320 sec.\n...\nINFO  (Thread-3 (ActiveMQ-client-global-threads)) [] Long transaction: 90 sec.\nINFO  (Thread-1 (ActiveMQ-client-global-threads)) [] Long transaction: 390 sec.\nINFO  (Thread-1 (ActiveMQ-client-global-threads)) [] Message  successfully processed\nWARN  [com.arjuna.ats.arjuna] (Thread-1 (ActiveMQ-client-global-threads)) [] ARJUNA012077: Abort called on already aborted atomic action 0:ffff7f000101:3b3ecbca:5dcc2894:13\nWARN  [org.apache.activemq.artemis.ra] (Thread-1 (ActiveMQ-client-global-threads)) [] AMQ152006: Unable to call after delivery: javax.resource.spi.LocalTransactionException: javax.transaction.RollbackException: ARJUNA016102: The transaction is not active! Uid is 0:ffff7f000101:3b3ecbca:5dcc2894:13\n  Caused by: javax.transaction.RollbackException: ARJUNA016102: The transaction is not active! Uid is 0:ffff7f000101:3b3ecbca:5dcc2894:13\n...\nWARN  [org.apache.activemq.artemis.core.client] (Thread-1 (ActiveMQ-client-global-threads)) [] AMQ212009: resetting session after failure\n<\/code><\/pre>\n<p>From log above we can see that:<\/p>\n<ul>\n<li><code>TransactionAttributeType.REQUIRED<\/code> was used by default;<\/li>\n<li>Started transaction was canceled by default timeout in <code>300 sec<\/code>;<\/li>\n<li>Container detected TX cancellation - did message redelivery and MDB starts new transaction;<\/li>\n<li>Old thread continue work with first message processing, but the transaction already is not active;<\/li>\n<\/ul>\n<p>So, keep this behavior in mind if you planning to play with long tasks and Message Driven Beans then depends on requirements few <strong>solutions<\/strong> is possible here:<\/p>\n<ul>\n<li>Avoid long transaction usage. If long TX is not necessary - always use <code>TransactionAttributeType.NOT_SUPPORTED<\/code><\/li>\n<li>Increase default transaction timeout<\/li>\n<li>Use an annotation @ActivationConfigProperty(propertyName=&quot;transactionTimeout&quot;, propertyValue=&quot;xxx&quot;) to specify custom transaction timeout for MDB like:<\/li>\n<\/ul>\n<pre><code class=\"language-java\">@MessageDriven(activationConfig = {\n    @ActivationConfigProperty(propertyName = &quot;destinationLookup&quot;, propertyValue = TxRequiredMessagerDrivenBean.TX_REQUIRED_QUEUE),\n    @ActivationConfigProperty(propertyName = &quot;destinationType&quot;, propertyValue = &quot;javax.jms.Queue&quot;)\n    @ActivationConfigProperty(propertyName = &quot;transactionTimeout&quot;, propertyValue=&quot;500&quot;)\n})\n<\/code><\/pre>\n<p>Source code of test application available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-jms-examples\">GitHub<\/a><\/p>\n\n\t"},{"title":"Never use Java primitives for math calculation","link":"https:\/\/kostenko.org\/blog\/2019\/11\/java-primitive-types-calculation.html","pubDate":"Fri, 8 Nov 2019 00:00:00 +0200","guid":"blog\/2019\/11\/java-primitive-types-calculation.html","description":"\n\t<p>This is well known stuff about representation of <a href=\"https:\/\/docs.oracle.com\/cd\/E19957-01\/806-3568\/ncg_goldberg.html\">Floating point types in java<\/a>, but time from time each developer can forget about<\/p>\n<pre><code class=\"language-java\">@Test\npublic void primitiveTest() {\n\n    \/\/ right way:\n    BigDecimal bgDcml = BigDecimal.valueOf(100000f).multiply(BigDecimal.valueOf(750f)).multiply(BigDecimal.valueOf(15f)).setScale(0);\n    BigDecimal bgDcml2 = BigDecimal.valueOf(0.04d).multiply(BigDecimal.valueOf(15.0d));\n\n    \/\/ wrong way:\n    float flt = 100000f * 750f * 15f;\n    float flt2 = 0.04f * 15.0f;\n\n    System.out.println(&quot;BigDecimal (correct): &quot; + bgDcml);\n    System.out.println(String.format(&quot;Float (incorrect): %s (%s)&quot;, flt, new BigDecimal(flt)));\n    System.out.println(&quot;BigDecimal (correct): &quot; + bgDcml2);\n    System.out.println(String.format(&quot;Float (incorrect): %s&quot;, flt2));\n}\n<\/code><\/pre>\n<pre><code class=\"language-java\">-------------------------------------------------------\n T E S T S\n-------------------------------------------------------\nBigDecimal (correct): 1125000000\nFloat (incorrect): 1.12499994E9 (1124999936)\nBigDecimal (correct): 0.600\nFloat (incorrect): 0.59999996\n<\/code><\/pre>\n\n\t"},{"title":"Jakarta Batch garbage collection with Jberet","link":"https:\/\/kostenko.org\/blog\/2019\/11\/jakarta-batch-garbage-collection-jberet.html","pubDate":"Mon, 4 Nov 2019 00:00:00 +0200","guid":"blog\/2019\/11\/jakarta-batch-garbage-collection-jberet.html","description":"\n\t<p>To implement Jakarta Batch Specification Wildfly uses JBeret as implementation of JSR 352 (Batch Applications for the Java Platform). During processing, last one persists some working data to the memory, JDBC or another repository depends on configuration.<\/p>\n<p>In case intensive usage it can collect lot of data and as result provoke some application server performance issues. To cleanup  <strong>unwanted job data<\/strong> you can design your own solution or use provided by Jberet <a href=\"https:\/\/docs.jboss.org\/jberet\/1.3.0.Final\/javadoc\/jberet-core\/org\/jberet\/repository\/PurgeBatchlet.html\">org.jberet.repository.PurgeBatchlet<\/a> in standard way:<\/p>\n<pre><code class=\"language-java\">&lt;job id=&quot;batchGarbageCollector&quot; xmlns=&quot;http:\/\/xmlns.jcp.org\/xml\/ns\/javaee&quot;\n     xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;\n     xsi:schemaLocation=&quot;http:\/\/xmlns.jcp.org\/xml\/ns\/javaee http:\/\/xmlns.jcp.org\/xml\/ns\/javaee\/jobXML_1_0.xsd&quot;\n     version=&quot;1.0&quot;&gt;\n    &lt;step id=&quot;batchGarbageCollector.step1&quot;&gt;\n        &lt;batchlet ref=&quot;org.jberet.repository.PurgeBatchlet&quot;&gt;\n            &lt;properties&gt;\n                &lt;property name=&quot;sqlFile&quot; value=&quot;#{jobParameters['sqlFile']}&quot;\/&gt;\n            &lt;\/properties&gt;\n        &lt;\/batchlet&gt;\n    &lt;\/step&gt;\n&lt;\/job&gt;\n<\/code><\/pre>\n<p>From the documentation <code>PurgeBatchlet<\/code> supports rich set of properties and looks pretty good, <strong>BUT<\/strong> on practice lot of them does not work as expected. I tried <code>numberOfRecentJobExecutionsToKeep<\/code> and <code>batchStatuses<\/code> on both WF repositories (inMemory and JDBC) and on both of them <strong>it does not work<\/strong> for me.<\/p>\n<p>I am getting output like below, but garbage still was with me :(<\/p>\n<pre><code class=\"language-java\">...\nINFO  [org.jberet] (Batch Thread - 8) [] JBERET000023: Removing javax.batch.runtime.JobExecution 35256804\nINFO  [org.jberet] (Batch Thread - 8) [] JBERET000023: Removing javax.batch.runtime.JobExecution 35256806\n...\n<\/code><\/pre>\n<p>Good news is, that in case using JDBC repository job parameter <code>sqlFile<\/code> works as expected and PurgeBatchlet executes provided SQL... without any log outputs.<\/p>\n<p>Source code of test application available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-batch-processing-examples\">GitHub<\/a><\/p>\n\n\t"},{"title":"Migration from Wildfly 10 to Wildfly 18","link":"https:\/\/kostenko.org\/blog\/2019\/10\/migration-wildfly-10-to-18.html","pubDate":"Tue, 22 Oct 2019 00:00:00 +0300","guid":"blog\/2019\/10\/migration-wildfly-10-to-18.html","description":"\n\t<p>Usually vendors declares easy migration, provides how-to documentation and even migration tools. But depends on complexity of your application you can stuck with some compatibility issues. Below i will explain my Wildfliy 10 to Wildfliy 18 migration steps.<\/p>\n<p>First of all you can use provided by WF <a href=\"https:\/\/github.com\/wildfly\/wildfly-server-migration\">migration tool<\/a> to migrate configuration files and compatible modules to the needed release:<\/p>\n<pre><code class=\"language-java\">git clone https:\/\/github.com\/wildfly\/wildfly-server-migration.git\ncd .\/wildfly-server-migration\/\nmvn clean install\ncd .\/dist\/standalone\/target\/\nunzip jboss-server-migration-1.8.0.Final-SNAPSHOT.zip\ncd .\/jboss-server-migration\n\n.\/jboss-server-migration.sh -s \/opt\/wildfly-10.1.0.Final -t \/opt\/wildfly-18.0.0.Final\/\n<\/code><\/pre>\n<p>Now let's see application level migration issues:<\/p>\n<p>Issue #1:<\/p>\n<pre><code class=\"language-java\">Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'org.kostenko.STATUS.ACTIVE'\n<\/code><\/pre>\n<p>Error above related to the Hibernate 5.2 <a href=\"https:\/\/vladmihalcea.com\/the-performance-penalty-of-class-forname-when-parsing-jpql-and-criteria-queries\/\">performance improvement<\/a> that avoids unnecessary calls to Class.forName(). Solution here is <strong>using Java Naming conventions for a constant.<\/strong> (for example rename STATUS to Status) or in case  using non-conventional Java constants set the<\/p>\n<pre><code class=\"language-java\">&lt;property name=&quot;hibernate.query.conventional_java_constants&quot; value=&quot;false&quot;\/&gt;\n<\/code><\/pre>\n<p>in your <strong>persistence.xml<\/strong><\/p>\n<p>Issue #2:<\/p>\n<pre><code class=\"language-java\">java.lang.IllegalArgumentException: ArquillianServletRunner not found. Could not determine ContextRoot from ProtocolMetadata, please contact DeployableContainer developer.\n<\/code><\/pre>\n<p>In case using Arquillian you need just update version <code>org.wildfly.arquillian:wildfly-arquillian-container-managed<\/code> to version <code>2.2.0.Final<\/code><\/p>\n<p>Issue #3:<\/p>\n<pre><code class=\"language-java\">org.jboss.weld.exceptions.UnsupportedOperationException:\n  at org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:49)\n<\/code><\/pre>\n<p>Seems to old <a href=\"https:\/\/issues.jboss.org\/browse\/WELD-2407\">BUG<\/a> happened and Weld does not support Java 8 default methods completely. So, pity but same refactoring here is needed.<\/p>\n<p>Issue #4:<\/p>\n<pre><code class=\"language-java\">WFLYRS0018: Explicit usage of Jackson annotation in a JAX-RS deployment; the system will disable JSON-B processing for the current deployment. Consider setting the 'resteasy.preferJacksonOverJsonB' property to 'false' to restore JSON-B.\n...\njavax.ws.rs.client.ResponseProcessingException: javax.ws.rs.ProcessingException: RESTEASY008200: JSON Binding deserialization error  \n  at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:156)  \n  at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:473)  \n  at org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder.get(ClientInvocationBuilder.java:195)  \n<\/code><\/pre>\n<p>Since latest versions, WF uses <code>org.eclipse.yasson<\/code> as <strong>JSON-B<\/strong> provider. It can provoke some compatibility problems in case using different  implementations. Solution here is refactoring according to the JSON-B specification or excluding <code>resteasy-json-binding-provider<\/code> from application class loader by providing <code>WEB-INF\/jboss-deployment-structure.xml<\/code>:<\/p>\n<pre><code class=\"language-java\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;jboss-deployment-structure&gt;\n    &lt;deployment&gt;\n        &lt;exclusions&gt;\n            &lt;module name=&quot;org.jboss.resteasy.resteasy-json-binding-provider&quot;\/&gt;\n        &lt;\/exclusions&gt;\n    &lt;\/deployment&gt;\n&lt;\/jboss-deployment-structure&gt;\n<\/code><\/pre>\n<p>or in case using EARs, do exclusion from submodules like<\/p>\n<pre><code class=\"language-java\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;jboss-deployment-structure&gt;\n    &lt;deployment&gt;\n        &lt;exclusions&gt;\n            &lt;module name=&quot;org.jboss.resteasy.resteasy-json-binding-provider&quot;\/&gt;\n        &lt;\/exclusions&gt;\n    &lt;\/deployment&gt;\n    &lt;sub-deployment name=&quot;module-1.jar&quot;&gt;\n        &lt;exclusions&gt;\n            &lt;module name=&quot;org.jboss.resteasy.resteasy-json-binding-provider&quot;\/&gt;\n        &lt;\/exclusions&gt;\n    &lt;\/sub-deployment&gt;    \n&lt;\/jboss-deployment-structure&gt;\n<\/code><\/pre>\n<p>Issue #5:<br \/>\nAccording to the fixed Hibernate <a href=\"https:\/\/hibernate.atlassian.net\/browse\/HHH-11278\">BUG<\/a>, for now JPA call <code>setMaxResult(0)<\/code> <strong>returns empty List<\/strong> instead of <strong>ALL<\/strong> elements in previous versions. So, just check it and do some refactoring if needed.<\/p>\n\n\t"},{"title":"JAX-RS Client ThreadPool leak","link":"https:\/\/kostenko.org\/blog\/2019\/10\/jax-rs-jersey-thread-leak.html","pubDate":"Fri, 4 Oct 2019 00:00:00 +0300","guid":"blog\/2019\/10\/jax-rs-jersey-thread-leak.html","description":"\n\t<p>Recently got resource(ThreadPool\\Thread) leak with JAX-RS Client implementation on WF10.0.1 (RestEasy).<br \/>\n<img src=\"\/img\/2019-10-thraed-leak.png\" alt=\"jax-rs thread leak\" \/><\/p>\n<p>From the dump above we can see, that pool number is extremely height, the same time thread number is always 1. That means that some code uses <code>Executors.new*<\/code>, which returns <code>java.util.concurrent.ThreadPoolExecutor<\/code> using the DefaultThreadFactory.<\/p>\n<p>Actually in this situation, it is <strong>ALL<\/strong> than we can see from thread and heap dumps when debugging leak like above. Because in case classes containing these executors was garbage collected, the executors get orphaned (but are still alive and uncollectable), making it difficult\/impossible to detect from a heap dump where the executors came from.<\/p>\n<p><strong>Lesson #1<\/strong> is: Doing <code>Executors.new*<\/code>, would be nice to little bit think about guys who will support your code and provide non default thread names with custom ThreadFactory like :)<\/p>\n<pre><code class=\"language-java\">ExecutorService es = Executors.newCachedThreadPool(new CustomThreadFactory());\n\n...\n\nclass CustomThreadFactory implements ThreadFactory {\n\n    @Override\n    public Thread newThread(final Runnable r) {\n        return new Thread(r, &quot;nice_place_for_helpful_name&quot;);\n    }\n}\n<\/code><\/pre>\n<p>So, after many times of investigation and &quot;heap walking&quot;(paths to GC root) i found few <code>Executors$DefaultThreadFactory<\/code> like<\/p>\n<p><img src=\"\/img\/2019-10-thraed-leak-1.png\" alt=\"jax-rs thread leak\" \/><\/p>\n<p>what made me see the code with REST services invocations. Something like<\/p>\n<pre><code class=\"language-java\">public void doCall() {\n    Client client = ClientBuilder.newClient();\n    Future&lt;Response&gt; future = client.target(&quot;http:\/\/...&quot;)\n                                 .request()\n                                 .async().get();\n}\n<\/code><\/pre>\n<p>According to WF10 JAX-RS implementation each <code>newClient()<\/code> will build ResteasyClient that uses <code>ExecutorService asyncInvocationExecutor<\/code> to do requests and potentially it is can be the reason of the leak.<\/p>\n<p><strong>Lesson #2<\/strong> is: Always! do <code>close()<\/code> client after usage. Check that implementation closes connection and shutdowns ThreadPool in case errors (timeouts, socket resets, etc).<\/p>\n<p><strong>Lesson #3<\/strong> is: Try to construct only a small number of Client instances in the application. Last one is still bit unclear from the pure JakartaEE application point of view, as it not works as well in  multi-threaded environment. (<code>Invalid use of BasicClientConnManager: connection still allocated. Make sure to release the connection before allocating another one.<\/code>)<\/p>\n<p>P.S. Many thanks for JProfiler tool trial version to make me happy with ThreadDump walking.<\/p>\n\n\t"},{"title":"Migration from JEE to JakartaEE","link":"https:\/\/kostenko.org\/blog\/2019\/09\/jee-to-jakartaee-migration.html","pubDate":"Mon, 30 Sep 2019 00:00:00 +0300","guid":"blog\/2019\/09\/jee-to-jakartaee-migration.html","description":"\n\t<p>As you probably know Java EE was moved from Oracle to the Eclipse Foundation where will evolve under the <strong>Jakarta EE<\/strong> brand.  Sept. 10, 2019 Jakarta EE Full Platform and Web Profile specifications was released by Eclipse Foundation during <a href=\"https:\/\/jakartaone.org\/\">JakartaOne Livestream<\/a>. Few days later Wildfly declared that <strong>WildFly 17.0.1<\/strong> has passed the Jakarta EE 8 TCK and certification request has been approved by the Jakarta EE Spec Committee. So, now WildFly is a Jakarta EE Full platform compatible implementation.<\/p>\n<p>Let's do migration of typical <a href=\"https:\/\/kostenko.org\/blog\/2019\/08\/ee-application-multi-module-template.html\">gradle EE project<\/a> to the Jakarta EE and look how hard is it. Current JakartaEE version <code>8.0.0<\/code> is fully compatible with JavaEE version <code>8.0<\/code>, that means no need to change project sources, just update dependency from <code>javax:javaee-api:8.0<\/code> to <code>jakarta.platform:jakarta.jakartaee-api:8.0.0<\/code><\/p>\n<p><code>updated build.gradle:<\/code><\/p>\n<pre><code class=\"language-java\">apply plugin: 'war'\ndependencies {\n    providedCompile &quot;jakarta.platform:jakarta.jakartaee-api:8.0.0&quot;\n}\n<\/code><\/pre>\n<p>That is it! Application builds and works well under WF17.0.1<\/p>\n<p>Source code of demo application available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-application-multi-module-gradle-template\">GitHub<\/a><\/p>\n\n\t"},{"title":"Wildfly JMX connection problems (so slow and terminates)","link":"https:\/\/kostenko.org\/blog\/2019\/08\/wildfly-jconsole-mbeans-list-problem.html","pubDate":"Mon, 19 Aug 2019 00:00:00 +0300","guid":"blog\/2019\/08\/wildfly-jconsole-mbeans-list-problem.html","description":"\n\t<p>JMX (Java Management Extensions ) - is a technology that provide us possibility to monitoring applications (application servers) by <strong>MBeans (Managed Bean)<\/strong> objects.<br \/>\nList of supported MBeans can be obtained by <strong>JConsole<\/strong> tool that already included to JDK. As JMX does not provide strong defined communication protocol, - implementations can be different depends on vendor.<br \/>\nFor example, to connect to Wildfly Application Server you need to use included in distribution <code>jconsole.sh<\/code> script:<\/p>\n<pre><code class=\"language-java\">&lt;WFLY_HOME&gt;\/bin\/jconsole.sh\n<\/code><\/pre>\n<p>or add <code>&lt;WFLY_HOME&gt;\/bin\/client\/jboss-client.jar<\/code> to classpath:<\/p>\n<pre><code class=\"language-java\">jconsole J-Djava.class.path=$JAVA_HOME\\lib\\tools.jar;$JAVA_HOME\\lib\\jconsole.jar;jboss-client.jar\n<\/code><\/pre>\n<p>By default, Wildfly uses <code>timeout = 60s<\/code> for <strong>remote JMX connections<\/strong>, after that connection will terminated:<br \/>\n<img src=\"\/img\/2019-08-jmx-jconsole.png\" alt=\"jconsole terminated connection\" \/><br \/>\nTo change default timeout value, use <code>org.jboss.remoting-jmx.timeout<\/code> property:<\/p>\n<pre><code class=\"language-java\">.\/jconsole.sh -J-Dorg.jboss.remoting-jmx.timeout=300\n<\/code><\/pre>\n<p>But increasing timeouts, is not always good solution. So, lets search for the reason of slowness. To construct list of MBeans, jconsole recursively requests ALL MBeans, that can be extremely slow in case many deployments and many loggers. (Reported issue: <a href=\"https:\/\/issues.jboss.org\/browse\/WFCORE-3186\">WFCORE-3186<\/a>). Partial solution here is reducing count of log files by changing rotating type from <code>periodic-size-rotating-file-handler<\/code>  to <code>size-rotating-file-handler<\/code>.<\/p>\n<p>Other reason of extremely slowness can be <code>Batch subsystem (JBeret)<\/code>. Last one stores a lot of working information in their tables (in memory or on remote DB, depends on configuration). If this tables big enough - it can negative affect performance of server. So, if you, no need for this data then just cleanup this stuff periodically. (for example, every redeploy in case you do it often enough):<\/p>\n<pre><code class=\"language-java\">TRUNCATE TABLE PARTITION_EXECUTION CASCADE;\nTRUNCATE TABLE STEP_EXECUTION CASCADE;\nTRUNCATE TABLE JOB_EXECUTION CASCADE;\nTRUNCATE TABLE JOB_INSTANCE CASCADE;  \n<\/code><\/pre>\n<p>From other point of view, obtaining ALL MBeans is not good decision as well. So, just use tooling that allows to find MBeans by path.<\/p>\n\n\t"},{"title":"Jakarta EE application multi module gradle template","link":"https:\/\/kostenko.org\/blog\/2019\/08\/ee-application-multi-module-template.html","pubDate":"Thu, 8 Aug 2019 00:00:00 +0300","guid":"blog\/2019\/08\/ee-application-multi-module-template.html","description":"\n\t<p>In this post i will share simple and useful <strong>gradle<\/strong> template to organize multi module Jakarta EE application. We will implement typical one which consists from REST controller (<strong>module1<\/strong>) and some main logic (<strong>module2<\/strong>). Big picture of our application architecture is:<\/p>\n<p><img src=\"\/img\/2019-08-ee-multimodule-template-arch.png\" alt=\"EE multi module application\" \/><\/p>\n<p>So, lets do initialization of project with next  gradle template:<br \/>\n<code>settings.gradle:<\/code><\/p>\n<pre><code class=\"language-java\">rootProject.name = 'ee-application-multi-module-gradle-template'\ninclude 'module1'\ninclude 'module2:module2-api', 'module2:module2-core'\n<\/code><\/pre>\n<p><code>root build.gradle:<\/code><\/p>\n<pre><code class=\"language-java\">defaultTasks 'clean', 'build'\nsubprojects {\n    ext.libraryVersions = [\n        javaee                  : '8.0',\n    ]\n    defaultTasks 'clean', 'build'\n    repositories {\n        jcenter()\n    }\n}\n<\/code><\/pre>\n<p>Above, we described initial application structure, where <strong>module1<\/strong> is flat sub project for our controller and <strong>module2<\/strong> is our main logic which consists from <code>API<\/code> and <code>Core<\/code> sub projects. As controller will use main logic API and we decided to separate application to modules (that means no big enterprise archive) - our sub projects should be simple enough:<\/p>\n<p><code>module1 build.gradle:<\/code><\/p>\n<pre><code class=\"language-java\">apply plugin: 'war'\ndependencies {\n    compile project(':module2:module2-api')\n    providedCompile &quot;javax:javaee-api:${libraryVersions.javaee}&quot;\n}\n<\/code><\/pre>\n<p><code>module2:module2-api:<\/code><\/p>\n<pre><code class=\"language-java\">apply plugin: 'java'\ndependencies {\n}\n<\/code><\/pre>\n<p><code>module2:module2-core:<\/code><\/p>\n<pre><code class=\"language-java\">apply plugin: 'war'\ndependencies {\n    compile project(':module2:module2-api')\n    providedCompile &quot;javax:javaee-api:${libraryVersions.javaee}&quot;\n}\n<\/code><\/pre>\n<p>Actually, that's it!<br \/>\nNow we can implement our controller like:<\/p>\n<pre><code class=\"language-java\">@Path(&quot;\/&quot;)\n@Stateless\n@Consumes(MediaType.APPLICATION_JSON)\n@Produces(MediaType.APPLICATION_JSON)\npublic class TestEndpoint {\n\n    @EJB(lookup = TestService.TEST_SERVICE_JNDI)\n    TestService testService;\n\n    @GET\n    @Path(&quot;\/test&quot;)\n    public Response test() {\n        SomethingDto something = testService.doSomething();\n        return Response.ok().entity(something.getMessage()).build();\n    }\n<\/code><\/pre>\n<p>In turn, main logic <code>API<\/code> contents from <code>Interface<\/code> and <code>DTO<\/code>:<br \/>\n<code>TestService.java:<\/code><\/p>\n<pre><code class=\"language-java\">public interface TestService {\n\n  String TEST_SERVICE_NAME = &quot;test-service&quot;;\n  String TEST_SERVICE_JNDI =&quot;java:global\/module2-core\/&quot; + TEST_SERVICE_NAME;\n\n  SomethingDto doSomething();\n}\n<\/code><\/pre>\n<p><code>SomethingDto.java:<\/code><\/p>\n<pre><code class=\"language-java\">public class SomethingDto implements Serializable{\n  ...\n}\n<\/code><\/pre>\n<p>In the end, main logic <code>Core<\/code> contents from the logic that implements API:<br \/>\n<code>TestServiceImpl.java<\/code><\/p>\n<pre><code class=\"language-java\">@Remote(TestService.class)\n@Stateless(name = TestService.TEST_SERVICE_NAME)\npublic class TestServiceImpl implements TestService {\n\n    @PersistenceContext\n    EntityManager entityManager;\n\n    @Override\n    public SomethingDto doSomething() {\n        TestEntity entity = entityManager.find(TestEntity.class, Long.MAX_VALUE);\n        return new SomethingDto(&quot;Hello Jakarta EE world!&quot;);\n    }\n}\n<\/code><\/pre>\n<p>Described Jakarta EE application architecture allows us enjoy all power of EE with absolutely transparent inter module interactions and, the same time, stay close to micro service design - as we have no limits with using one container for all modules.<\/p>\n<p>Source code of this demo available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-application-multi-module-gradle-template\">GitHub<\/a><\/p>\n\n\t"},{"title":"How to catch 'kill' signals in java","link":"https:\/\/kostenko.org\/blog\/2019\/08\/java-catch-os-signals.html","pubDate":"Wed, 7 Aug 2019 00:00:00 +0300","guid":"blog\/2019\/08\/java-catch-os-signals.html","description":"\n\t<p>You can send different signals to your application using <strong>kill -l<\/strong> command. By default <strong>kill<\/strong> will sent <code>TERM<\/code> signal. Java by default catches some types of signals, for example<\/p>\n<pre><code class=\"language-java\">kill -3 &lt;PID&gt;\n<\/code><\/pre>\n<p>will dump Java stack traces to the standard error stream.<\/p>\n<p>Also, you can catch <code>signal<\/code> inside your application, like<\/p>\n<pre><code class=\"language-java\">public class App {\n    public static void main(String... s) throws Exception {\n\n        Signal.handle(new Signal(&quot;HUP&quot;), signal -&gt; {\n            System.out.println(signal.getName() + &quot; (&quot; + signal.getNumber() + &quot;)&quot;);\n        });\n\n        new Thread(new Runnable() {\n            @Override\n            public void run() {\n                while (true) {\n                    try {\n                        Thread.sleep(1000l);\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n        }).start();\n    }\n}\n<\/code><\/pre>\n<p>List of available signals you can get by executing <code>kill -l<\/code>:<\/p>\n<pre><code class=\"language-java\">kostenko@kostenko:~$ kill -l\n 1) SIGHUP\t 2) SIGINT\t 3) SIGQUIT\t 4) SIGILL\t 5) SIGTRAP\n 6) SIGABRT\t 7) SIGBUS\t 8) SIGFPE\t 9) SIGKILL\t10) SIGUSR1\n11) SIGSEGV\t12) SIGUSR2\t13) SIGPIPE\t14) SIGALRM\t15) SIGTERM\n16) SIGSTKFLT\t17) SIGCHLD\t18) SIGCONT\t19) SIGSTOP\t20) SIGTSTP\n21) SIGTTIN\t22) SIGTTOU\t23) SIGURG\t24) SIGXCPU\t25) SIGXFSZ\n26) SIGVTALRM\t27) SIGPROF\t28) SIGWINCH\t29) SIGIO\t30) SIGPWR\n31) SIGSYS\t34) SIGRTMIN\t35) SIGRTMIN+1\t36) SIGRTMIN+2\t37) SIGRTMIN+3\n38) SIGRTMIN+4\t39) SIGRTMIN+5\t40) SIGRTMIN+6\t41) SIGRTMIN+7\t42) SIGRTMIN+8\n43) SIGRTMIN+9\t44) SIGRTMIN+10\t45) SIGRTMIN+11\t46) SIGRTMIN+12\t47) SIGRTMIN+13\n48) SIGRTMIN+14\t49) SIGRTMIN+15\t50) SIGRTMAX-14\t51) SIGRTMAX-13\t52) SIGRTMAX-12\n53) SIGRTMAX-11\t54) SIGRTMAX-10\t55) SIGRTMAX-9\t56) SIGRTMAX-8\t57) SIGRTMAX-7\n58) SIGRTMAX-6\t59) SIGRTMAX-5\t60) SIGRTMAX-4\t61) SIGRTMAX-3\t62) SIGRTMAX-2\n63) SIGRTMAX-1\t64) SIGRTMAX\n<\/code><\/pre>\n<p>Notice! Not all signals can be catched in application, some of them reserved by OS. For example, if you will try to handle <strong>kill -SIGKILL (kill -9)<\/strong> , then you get:<\/p>\n<pre><code class=\"language-java\">Exception in thread &quot;main&quot; java.lang.IllegalArgumentException: Signal already used by VM or OS: SIGKILL\n\tat java.base\/jdk.internal.misc.Signal.handle(Signal.java:173)\n\tat jdk.unsupported\/sun.misc.Signal.handle(Signal.java:157)\n<\/code><\/pre>\n\n\t"},{"title":"Wildfly. Configure load balancing metrics","link":"https:\/\/kostenko.org\/blog\/2019\/08\/wildfly-load-balancing-metrics.html","pubDate":"Tue, 6 Aug 2019 00:00:00 +0300","guid":"blog\/2019\/08\/wildfly-load-balancing-metrics.html","description":"\n\t<p>Previously i wrote about <a href=\"https:\/\/kostenko.org\/blog\/2019\/04\/wildfly-cluster-domain-mode.html\">Wildfly domain mode cluster and load balancing from the box<\/a>. But what if we would like to do balancing depends on specific server behavior ?<\/p>\n<p>Wildfly subsystem <code>mod_cluster<\/code> provide us several predefined metric types to determine best request balancing:<\/p>\n<ul>\n<li><strong>cpu<\/strong>: based on CPU load<\/li>\n<li><strong>mem<\/strong>: based on system memory usage<\/li>\n<li><strong>heap<\/strong>: based on heap usage<\/li>\n<li><strong>sessions<\/strong>: based on number of web sessions<\/li>\n<li><strong>requests<\/strong>: based on amount of requests\/sec<\/li>\n<li><strong>send-traffic<\/strong>: based on outgoing requests traffic<\/li>\n<li><strong>receive-traffic<\/strong>: based on incoming requests POST traffic<\/li>\n<li><strong>busyness<\/strong>: computes based on amount of Thread from Thread Pool usage that are busy servicing requests<\/li>\n<\/ul>\n<p>As well you also can configure <strong>weight<\/strong> (impact of a metric respect to other metrics) and <strong>capacity<\/strong> properties;<br \/>\nBelow is example, how to change default based on CPU balancing to balancing based on busyness + CPU:<\/p>\n<pre><code class=\"language-java\">\/subsystem=modcluster\/mod-cluster-config=configuration\/dynamic-load-provider=configuration\/load-metric=cpu:remove()\n\/subsystem=modcluster\/mod-cluster-config=configuration:add-metric(type=busyness,weight=2)\n\/subsystem=modcluster\/mod-cluster-config=configuration:add-metric(type=cpu,weight=1)\n<\/code><\/pre>\n<p>If predefined types is not enough, - you can provide <code>custom-load-metric<\/code> by implementing <code>org.jboss.modcluster.load.metric.impl.AbstractLoadMetric<\/code>. To possibility of using your custom metric,- you need to copy packaged JAR to <code>modcluster<\/code> module and update <code>module.xml<\/code>. Now you can use your custom metric with your configuration like<\/p>\n<pre><code class=\"language-java\"> &lt;custom-load-metric class=&quot;org.kostenko.examples.wldfly.modcluster.MyBalancingMetric&quot;&gt;  \n<\/code><\/pre>\n\n\t"},{"title":"Embedded Jetty server truncates responses","link":"https:\/\/kostenko.org\/blog\/2019\/08\/embedded-jetty-server-cut-responses.html","pubDate":"Tue, 6 Aug 2019 00:00:00 +0300","guid":"blog\/2019\/08\/embedded-jetty-server-cut-responses.html","description":"\n\t<p>Jetty server has lot of configuration options. One of them is <code>OutputBufferSize<\/code><\/p>\n<pre><code class=\"language-java\">HttpConfiguration httpConfig = new HttpConfiguration();\nhttpConfig.setOutputBufferSize(1024);\n<\/code><\/pre>\n<p>If this property set to value less than your respopnse - jetty just will truncate last one.<\/p>\n\n\t"},{"title":"WFLYEJB0054: Failed to marshal EJB parameters","link":"https:\/\/kostenko.org\/blog\/2019\/08\/WFLYEJB0054.html","pubDate":"Mon, 5 Aug 2019 00:00:00 +0300","guid":"blog\/2019\/08\/WFLYEJB0054.html","description":"\n\t<p>Usually error <code>WFLYEJB0054: Failed to marshal EJB parameters<\/code> can be throw by next reason:<\/p>\n<ul>\n<li>Your data transfer object does not implement Serializable<\/li>\n<li>Your transfered object does not exist in destination module classpath (for example, if you are using DTO without strong typing)<\/li>\n<\/ul>\n<p>Also, you can catch this error with absolutely unexpected scenario and unclear stacktrace when your EJB throws some unchecked exception with stacktrace that has objects from points above.<\/p>\n\n\t"},{"title":"SQL trick. Insert if not exists","link":"https:\/\/kostenko.org\/blog\/2019\/07\/sql-trick-insert-if-noe-exists.html","pubDate":"Wed, 24 Jul 2019 00:00:00 +0300","guid":"blog\/2019\/07\/sql-trick-insert-if-noe-exists.html","description":"\n\t<p>Next SQL trick allows you perform conditional <code>INSERT<\/code> with your query.<\/p>\n<p>For example, lets do insert if record not exists yet:<\/p>\n<p>SQL:<\/p>\n<pre><code class=\"language-sql\">INSERT INTO my_table (id, name)  \n    SELECT 1, 'name' FROM dual  WHERE NOT EXISTS (SELECT 1 FROM my_table WHERE ID = 1);\n<\/code><\/pre>\n\n\t"},{"title":"JMS Duplicate Message Detection with Wildfly","link":"https:\/\/kostenko.org\/blog\/2019\/07\/wildfly-jms-duplicate-detection.html","pubDate":"Fri, 19 Jul 2019 00:00:00 +0300","guid":"blog\/2019\/07\/wildfly-jms-duplicate-detection.html","description":"\n\t<p>To support JMS specification Wildfly uses Apache ActiveMQ Artemis over active-mq subsystem. Last one provides mechanism to filtering out duplicate messages without application code changes.<\/p>\n<p>To enable duplicate message detection you just need to set a special property on the message to a unique value<\/p>\n<pre><code class=\"language-java\">message.setStringProperty(&quot;_AMQ_DUPL_ID&quot;, uniqueId);\n<\/code><\/pre>\n<p>So, lets see how it works on practice and create simple Message Driven Bean to consume messages:<\/p>\n<pre><code class=\"language-java\">@JMSDestinationDefinition(\n        name = DuplicateJMSTestBean.DUPLICATE_QUEUE,\n        interfaceName = &quot;javax.jms.Queue&quot;\n)\n@MessageDriven(activationConfig = {\n    @ActivationConfigProperty(propertyName = &quot;destinationLookup&quot;, propertyValue = DuplicateJMSTestBean.DUPLICATE_QUEUE),\n    @ActivationConfigProperty(propertyName = &quot;destinationType&quot;, propertyValue = &quot;javax.jms.Queue&quot;)\n})\n@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)\npublic class DuplicateJMSTestBean implements MessageListener {\n\n    public final static String DUPLICATE_QUEUE = &quot;java:global\/jms\/duplicateTestQueue&quot;;\n\n    @Override\n    public void onMessage(Message msg) {\n        System.out.println(&quot;Got new message.&quot;);\n        MessageStorage.messages.add(msg);\n        try {\n            Thread.sleep(5_000l);\n        } catch(Exception ignore) {}\n        System.out.println(&quot;Message  successfully processed&quot;);\n    }\n}\n<\/code><\/pre>\n<p>And simple JAX-RS endpoint to produce messages<\/p>\n<pre><code class=\"language-java\">@Path(&quot;\/&quot;)\n@Stateless\n@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)\npublic class DuplicateTestEndpoint {\n\n    @Inject\n    private JMSContext context;\n    @Resource(lookup = DuplicateJMSTestBean.DUPLICATE_QUEUE)\n    private Queue queue;\n\n    @GET\n    @Path(&quot;\/sendmessage&quot;)\n    public Response sendMessage(@QueryParam(&quot;duplicate-id&quot;) String duplicateId) {\n        try {\n            ObjectMessage message = context.createObjectMessage();\n            if (duplicateId == null) {\n                context.createProducer().send(queue, message);\n            } else {\n                message.setStringProperty(&quot;_AMQ_DUPL_ID&quot;, duplicateId);\n                context.createProducer().send(queue, message);\n            }\n            return Response.ok().entity(&quot;Message was sent.  Recieved &quot; + MessageStorage.messages.size() + &quot; messagges: &quot; + MessageStorage.messages).build();\n        } catch (Throwable e) {\n            return Response.ok().entity(&quot;Error: &quot; + e).build();\n        }\n    }\n}\n<\/code><\/pre>\n<p>Now in case we send message with the same <code>_AMQ_DUPL_ID<\/code> without transaction by <code>http:\/\/127.0.0.1:8080\/jms-examples\/sendmessage?duplicate-id=myuniqueid<\/code> we will get in logs:<\/p>\n<pre><code class=\"language-java\">WARN [org.apache.activemq.artemis.core.server] (Thread-448 (ActiveMQ-server-org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl$5@e47887a)) AMQ222059: Duplicate message detected - message will not be routed. Message information:\nCoreMessage[messageID=1505,durable=true,userID=3d27afde-a9fa-11e9-af5d-0242e352ec80,priority=4, timestamp=Fri Jul 19 10:53:04 EEST 2019,expiration=0, durable=true, address=jms.queue.jms-examples_jms-examples_jms-examples_java:global\/jms\/duplicateTestQueue,size=416,properties=TypedProperties[__AMQ_CID=38587489-a9fa-11e9-af5d-0242e352ec80,_AMQ_DUPL_ID=myuniqueid,_AMQ_ROUTING_TYPE=1]]@145077408\n<\/code><\/pre>\n<p>and message will NOT consume by consumer. In case you send message in transaction - you will get <code>Exception<\/code> on commit.<\/p>\n<p>Keep in mind, that to store IDs activemq uses circular fixed size cache<\/p>\n<pre><code class=\"language-java\">\/subsystem=messaging-activemq\/server=default:read-attribute(name=id-cache-size)\n{\n    &quot;outcome&quot; =&gt; &quot;success&quot;,\n    &quot;result&quot; =&gt; 20000\n}\n<\/code><\/pre>\n<p>so, this value should be big enough to avoid rewriting. Also, you can configure persist cache or not (by default: <code>true<\/code>)<\/p>\n<pre><code class=\"language-java\">\/subsystem=messaging-activemq\/server=default:write-attribute(name=persist-id-cache,value=false)\n<\/code><\/pre>\n<p>Source code available on <a href=\"https:\/\/github.com\/kostenkoserg\/ee-jms-examples\">GitHub<\/a><\/p>\n\n\t"},{"title":"Jenkins. Nice to have plugins","link":"https:\/\/kostenko.org\/blog\/2019\/07\/jenkins-nice-to-have-plugins.html","pubDate":"Fri, 5 Jul 2019 00:00:00 +0300","guid":"blog\/2019\/07\/jenkins-nice-to-have-plugins.html","description":"\n\t<p>Jenkins is leading open source automation tool that provides lot of plugins to make your CI better. Below is few of them that, on my opinion, can be helpful for any project.<\/p>\n<blockquote>\n<p><strong>1. <a href=\"https:\/\/plugins.jenkins.io\/build-monitor-plugin\">Build Monitor Plugin<\/a><\/strong> - provides a highly visible view of the status of selected Jenkins jobs;<\/p>\n<\/blockquote>\n<p><img src=\"\/img\/2019-07-jenkins-build-monitor-plugin.png\" alt=\"Build Monitor Plugin\" \/><\/p>\n<blockquote>\n<p><strong>2. <a href=\"https:\/\/plugins.jenkins.io\/git-parameter\">Git Parameter Plugin<\/a><\/strong> - adds ability to choose branches, tags or revisions from git repository configured in project;<\/p>\n<\/blockquote>\n<p><img src=\"\/img\/2019-07-jenkins-git-parameter-plugin.png\" alt=\"Git Parameter Plugin\" \/><\/p>\n<blockquote>\n<p><strong>3. <a href=\"https:\/\/plugins.jenkins.io\/htmlpublisher\">HTML Publisher Plugin<\/a><\/strong> - publish the html reports that your build generates to the job and build pages;<\/p>\n<\/blockquote>\n<p><img src=\"\/img\/2019-07-jenkins-html-report-plugin.png\" alt=\"Git Parameter Plugin\" \/><\/p>\n\n\t"},{"title":"Wildfly active-mq subsystem deadlock","link":"https:\/\/kostenko.org\/blog\/2019\/06\/wildfly-activemq-deadlock.html","pubDate":"Sat, 29 Jun 2019 00:00:00 +0300","guid":"blog\/2019\/06\/wildfly-activemq-deadlock.html","description":"\n\t<p>Recently got unusual height CPU utilizaton on random wildly cluster instance. Thread dump shows the reason of a problem:<\/p>\n<pre><code class=\"language-java\">Found one Java-level deadlock:\n=============================\n\n&quot;Thread-1 (ActiveMQ-server-org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl$2@46fcd20a-1114701218)&quot;:\n  waiting to lock Monitor@0x00007f45f02e20f8 (Object@0x0000000603407950, a org\/apache\/activemq\/artemis\/core\/server\/cluster\/impl\/ClusterConnectionImpl$MessageFlowRecordImpl),\n  which is held by &quot;Thread-29 (ActiveMQ-client-global-threads-2129186403)&quot;\n&quot;Thread-29 (ActiveMQ-client-global-threads-2129186403)&quot;:\n  waiting to lock Monitor@0x00007f46203b5518 (Object@0x00000004cc79a7b8, a org\/apache\/activemq\/artemis\/core\/server\/impl\/QueueImpl),\n  which is held by &quot;Thread-1 (ActiveMQ-server-org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl$2@46fcd20a-1114701218)&quot;\n\nFound a total of 1 deadlock.\n<\/code><\/pre>\n<p>Below is part of official documentation:<\/p>\n<blockquote>\n<p>&quot;If thread-pool-max-size is set to a positive integer greater than zero, the thread pool is bounded. If requests come in and there are no free threads available in the pool, requests will block until a thread becomes available. It is recommended that a bounded thread pool be used with caution since it can lead to <strong>deadlock situations<\/strong> if the upper bound is configured too low.&quot;<\/p>\n<\/blockquote>\n<p>So, solution is:<\/p>\n<pre><code class=\"language-java\">\/subsystem=messaging-activemq\/server=default:write-attribute(name=thread-pool-max-size,value=-1)\n<\/code><\/pre>\n\n\t"},{"title":"How to use custom ClassLoader to load jars in runtime","link":"https:\/\/kostenko.org\/blog\/2019\/06\/runtime-class-loading.html","pubDate":"Fri, 28 Jun 2019 00:00:00 +0300","guid":"blog\/2019\/06\/runtime-class-loading.html","description":"\n\t<p>To load calsses in runtime java uses ClassLoader mechanism which is based on next core principles:<\/p>\n<ul>\n<li><strong>delegation<\/strong> - by default uses <code>parent-first delegation<\/code>, - child ClassLoader will be used if parent is not able to find or load class. This behavior can be changed to <code>child-first<\/code> by overwriting <code>ClassLoader.loadClass(...)<\/code>;<\/li>\n<li><strong>visibility<\/strong> - child ClassLoader is able to see all the classes loaded by parent but vice-versa is not true;<\/li>\n<li><strong>uniqueness<\/strong> - allows to load a class exactly once, which is basically achieved by delegation and ensures that child ClassLoader doesn't reload the class already loaded by parent;<\/li>\n<\/ul>\n<p>The main scenarios to use custom ClassLoader is:<\/p>\n<ul>\n<li><strong>Class Instrumentation<\/strong> - modifying classes at runtime. For example, to unit testing, debugging or monitoring;<\/li>\n<li><strong>Isolation of executions<\/strong> - isolate several execution environments within a single process by making visible only a subset of classes for a particular thread, like it does in EE environments;<\/li>\n<\/ul>\n<p>So, let's see how using of custom ClassLoader looks from source code perspective:<\/p>\n<pre><code class=\"language-java\">List&lt;File&gt; jars = Arrays.asList(new File(&quot;\/tmp\/jars&quot;).listFiles());\nURL[] urls = new URL[files.size()];\nfor (int i = 0; i &lt; jars.size(); i++) {\n    try {\n        urls[i] = jars.get(i).toURI().toURL();\n    } catch (Exception e) {\n        e.printStackTrace();\n    }\n}\nURLClassLoader childClassLoader = new URLClassLoader(urls, ClassLoader.getSystemClassLoader());\n<\/code><\/pre>\n<p>Then load class with custom ClassLoader:<\/p>\n<pre><code class=\"language-java\">Class.forName(&quot;org.kostenko.examples.core.classloader.ClassLoaderTest&quot;, true , childClassLoader);\n<\/code><\/pre>\n<p>Note! If your loaded libraries uses some resources like properties or something else, you need to provide context class loader:<\/p>\n<pre><code class=\"language-java\">Thread.currentThread().setContextClassLoader(childClassLoader);  \n<\/code><\/pre>\n<p>Also, you can use custom ClassLoaders to load services with Java Service Provider Interface(SPI)<\/p>\n<pre><code class=\"language-java\">ServiceLoader&lt;MyProvider&gt; serviceLoader = ServiceLoader.load(MyProvider.class, childClassLoader);\n...\n<\/code><\/pre>\n\n\t"},{"title":"Design DSL API in Java","link":"https:\/\/kostenko.org\/blog\/2019\/05\/design-dsl-api-java.html","pubDate":"Mon, 27 May 2019 00:00:00 +0300","guid":"blog\/2019\/05\/design-dsl-api-java.html","description":"\n\t<p>Well designed API is very important in case you expect your API will use someone else instead of just you. To build readable and writable DSL(domain specific language) in Java usually uses Builder pattern with few simple rules:<\/p>\n<ul>\n<li>Think twice about names for methods<\/li>\n<li>Restrict available values for each step<\/li>\n<\/ul>\n<p>So, lets see how it looks from source code perspective...<\/p>\n<p>Design API entry point<\/p>\n<pre><code class=\"language-java\">public class MyAPI {\n    public static UserBuilder.Registration asUser() {\n        return new UserBuilder.User();\n    }\n}\n<\/code><\/pre>\n<p>Design builder using interfaces to restrict available values depends on current step<\/p>\n<pre><code class=\"language-java\">public class UserBuilder {\n    public static class User implements Registration, Login, Password, Apply {\n        private String login;\n        private String password;\n\n        @Override\n        public Login doRegistration() {\n            return this;\n        }\n        @Override\n        public Password withLogin(String login) {\n            this.login = login;\n            return this;\n        }\n        @Override\n        public Apply withPassword(String password) {\n            this.password = password;\n            return this;\n        }\n        @Override\n        public void apply() {\n            \/\/ ...\n        }\n    }\n\n    public interface Registration {\n        Login doRegistration();\n    }\n    public interface Login {\n        Password withLogin(String login);\n    }\n    public interface Password {\n        Apply withPassword(String password);\n    }\n    public interface Apply {\n        void apply();\n    }\n}\n<\/code><\/pre>\n<p>Then usage, with no chance to mistake, looks like<\/p>\n<pre><code class=\"language-java\">asUser().doRegistration()\n        .withLogin(&quot;login&quot;).withPassword(&quot;password&quot;)\n        .apply();\n<\/code><\/pre>\n\n\t"},{"title":"My video about Wildfly domain mode clustering","link":"https:\/\/kostenko.org\/blog\/2019\/05\/wildfly-domain-mode-cluster-video.html","pubDate":"Thu, 2 May 2019 00:00:00 +0300","guid":"blog\/2019\/05\/wildfly-domain-mode-cluster-video.html","description":"\n\t\nHave published new YouTube video about Wildfly AS domain mode clustering\n\n<br\/><br\/>\n<div class=\"row\">\n    <iframe align =\"center\" class=\"col-md-offset-3 col-lg-6 col-md-6 col-sm-12 col-xs-12\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/dIT9e945OHs\" frameborder=\"0\" allowfullscreen=\"true\"><\/iframe>\n<\/div>\n\n\t"},{"title":"Improve performance of random number generation","link":"https:\/\/kostenko.org\/blog\/2019\/04\/java-spedup-random-generation.html","pubDate":"Thu, 18 Apr 2019 00:00:00 +0300","guid":"blog\/2019\/04\/java-spedup-random-generation.html","description":"\n\t<p>Directly or indirectly every developer uses random number generation during application development by different reasons:<\/p>\n<ul>\n<li>cryptography<\/li>\n<li>simulations<\/li>\n<li>game engines<\/li>\n<li>UUID generation<\/li>\n<\/ul>\n<p>and many more...<\/p>\n<p>In Java we have <strong>insecure<\/strong>: <code>java.util.Random<\/code> and <strong>secure<\/strong>: <code>java.security.SecureRandom<\/code> random generators. Main differences between is<\/p>\n<ul>\n<li><strong>Size<\/strong> - 48(Random) vs 128(SecureRandom) bits, so the chances of repeating for last one are smaller.<\/li>\n<li><strong>Seed Generation<\/strong> - Random uses the system clock and, so can be reproduced. SecureRandom takes random data from your OS (hardware)<\/li>\n<li><strong>Security<\/strong> - Consequently, the java.util.Random class must not be used either for security-critical applications or for protecting sensitive data.<\/li>\n<\/ul>\n<p>As result of above, for described reasons using of SecureRandom much preferable. You may never get performance issues with it until you need for number of random numbers which can be generated per time unit. Especially on cloud environment because of poor entropy.<\/p>\n<p>Simple ussage and speed comparison example:<\/p>\n<pre><code class=\"language-java\">public class RandomGenerationTest {\n\n    private static int count = 100_000_000;\n\n    public static void main(String... s) throws Exception {\n        System.out.println(&quot;Start...&quot;);\n        doGeneration(new Random());\n        doGeneration(new SecureRandom());\n    }\n\n    private static void doGeneration(Random random) {\n        long time = System.currentTimeMillis();\n        for (int i = 0; i &lt; count; i++) {\n            random.nextInt();\n        }\n        time = System.currentTimeMillis() - time;\n        System.out.println(String.format(&quot;Generation of %s random numbers with %s time %s ms.&quot;, count, random.getClass().getName() ,time));\n    }\n}\n<\/code><\/pre>\n<pre><code class=\"language-java\">Generation of 100000000 random numbers with java.util.Random time 930 ms.\nGeneration of 100000000 random numbers with java.security.SecureRandom time 22036 ms.\n<\/code><\/pre>\n<p>By default SecureRandom will use random data from Linux kernel entropy pool <code>\/dev\/random<\/code>. So in case pool went empty -  next generation can be delayed for <strong>several minutes<\/strong>. You also can switch to the pseudo random number generator <code>\/dev\/urandom<\/code> which is can be must faster (non blocking) but little bit less secure.<\/p>\n<p>To make Java use <code>\/dev\/urandom<\/code> you need to change <code>securerandom.source<\/code> property in the file <code>jre\/lib\/security\/java.security<\/code><\/p>\n<pre><code class=\"language-java\">securerandom.source=file:\/dev\/urandom\n<\/code><\/pre>\n<p>The entropy gathering device can also be specified with the System property <code>java.security.egd<\/code>. For example:<\/p>\n<pre><code class=\"language-java\">java -Djava.security.egd=file:\/dev\/urandom MainClass\n<\/code><\/pre>\n<p>To check how much random data is currently available in the entropy pool, use next command:<\/p>\n<pre><code class=\"language-java\">cat \/proc\/sys\/kernel\/random\/entropy_avail\n<\/code><\/pre>\n<p>Every number lower than 1.000 can be considered too low for normal operation; if you request more data than available the requesting process will block. To increase entropy of Linux environment you can use <strong>HA<\/strong>rdware <strong>V<\/strong>olatile <strong>E<\/strong>ntropy <strong>G<\/strong>athering and <strong>E<\/strong>xpansion with <code>haveged<\/code> open source implementation<\/p>\n<pre><code class=\"language-java\">apt-get install haveged\n<\/code><\/pre>\n<p>It will use additional hardware(CPU) statistic to increase entropy and as result speedup your application.<\/p>\n\n\t"},{"title":"Wildfly domain mode cluster and load balancing from the box","link":"https:\/\/kostenko.org\/blog\/2019\/04\/wildfly-cluster-domain-mode.html","pubDate":"Mon, 15 Apr 2019 00:00:00 +0300","guid":"blog\/2019\/04\/wildfly-cluster-domain-mode.html","description":"\n\t<p>Wildfly Application Server provide us two possible modes to setup cluster environment for the Java EE applications.<\/p>\n<ol>\n<li>\n<p><strong>Standalone mode<\/strong> - every standalone instance has its own management interface and configuration. You can manage one instance at a time. Configuration placed in <code>standalone.xml<\/code> file.<\/p>\n<\/li>\n<li>\n<p><strong>Domain mode<\/strong> - all Wildfly instances manage by special orchestration process called <code>domain controller<\/code>. Using domain controller you can manage group of servers. Also you can mange groups as well. Each servers group can has its own configuration, deployments etc. Configuration placed in <code>domain.xml<\/code> and <code>host.xml<\/code> files.<br \/>\nExample of a Wildfly server groups:<br \/>\n<img src=\"\/img\/2019-04-wildfly-cluster-domain-mode.png\" alt=\"wildfly-cluster-domain-mode\" \/><\/p>\n<\/li>\n<\/ol>\n<p>From the version 10 Wildfly adds support for using the <code>Undertow<\/code> subsystem as a load balancer. So, now all we need to build Java EE clustered infrastructure is Wildfly only. Let's do it.<\/p>\n<p>Download latest version of application server from the <a href=\"https:\/\/wildfly.org\/downloads\/\">https:\/\/wildfly.org\/downloads\/<\/a> and unzip distributive after. To run Wildfly in domain mode, please execute:<\/p>\n<pre><code class=\"language-java\">kostenko@kostenko:\/opt\/wildfly-16.0.0.Final\/bin$ .\/domain.sh\n<\/code><\/pre>\n<p>Connect to the Wildfly CLI concole<\/p>\n<pre><code class=\"language-java\">kostenko@kostenko:\/opt\/wildfly-16.0.0.Final\/bin$ .\/jboss-cli.sh -c\n[domain@localhost:9990 \/]\n<\/code><\/pre>\n<p>By default Wildfly has preconfigured server groups <code>main-server-group<\/code> and <code>other-server-group<\/code>, so we need cleanup existing servers:<\/p>\n<pre><code class=\"language-java\">:stop-servers(blocking=true)\n\/host=master\/server-config=server-one:remove\n\/host=master\/server-config=server-two:remove\n\/host=master\/server-config=server-three:remove\n\/server-group=main-server-group:remove\n\/server-group=other-server-group:remove\n<\/code><\/pre>\n<p>Create new server group and servers, using the <code>full-ha<\/code> profile so <code>mod_cluster<\/code> support is included:<\/p>\n<pre><code class=\"language-java\">\/server-group=backend-servers:add(profile=full-ha, socket-binding-group=full-ha-sockets)\n\/host=master\/server-config=backend1:add(group=backend-servers, socket-binding-port-offset=100)\n\/host=master\/server-config=backend2:add(group=backend-servers, socket-binding-port-offset=200)\n\n#start the backend servers\n\/server-group=backend-servers:start-servers(blocking=true)\n\n#add system properties (so we can tell them apart)\n\/host=master\/server-config=backend1\/system-property=server.name:add(boot-time=false, value=backend1)\n\/host=master\/server-config=backend2\/system-property=server.name:add(boot-time=false, value=backend2)\n<\/code><\/pre>\n<p>Then  set up the server group for load balancer<\/p>\n<pre><code class=\"language-java\">\/server-group=load-balancer:add(profile=load-balancer, socket-binding-group=load-balancer-sockets)\n\/host=master\/server-config=load-balancer:add(group=load-balancer)\n\/socket-binding-group=load-balancer-sockets\/socket-binding=modcluster:write-attribute(name=interface, value=public)\n\/server-group=load-balancer:start-servers\n<\/code><\/pre>\n<p>Now let's develop simple JAX-RS endpoint to show how it works:<\/p>\n<pre><code class=\"language-java\">@Path(&quot;\/clusterdemo&quot;)\n@Stateless\npublic class ClusterDemoEndpoint {\n\n    @GET\n    @Path(&quot;\/serverinfo&quot;)\n    public Response getServerInfo() {\n\n        return Response.ok().entity(&quot;Server: &quot; + System.getProperty(&quot;server.name&quot;)).build();\n    }\n}\n<\/code><\/pre>\n<p>Build project and deploy it to the <code>backend-servers<\/code> group:<\/p>\n<pre><code class=\"language-java\">[domain@localhost:9990 \/] deploy ee-jax-rs-examples.war --server-groups=backend-servers\n<\/code><\/pre>\n<p>And check the result by <code>http:\/\/localhost:8080\/ee-jax-rs-examples\/clusterdemo\/serverinfo<\/code> :<br \/>\n<img src=\"\/img\/2019-04-wildfly-cluster-domain-mode-1-2.gif\" alt=\"wildfly-cluster-domain-mode-1-2\" \/><\/p>\n<p>Now we can easily add  servers to the group at runtime and requests will balancing automatically:<\/p>\n<pre><code class=\"language-java\">[domain@localhost:9990 \/] \/host=master\/server-config=backend3:add(group=backend-servers, socket-binding-port-offset=300)\n[domain@localhost:9990 \/] \/host=master\/server-config=backend3\/system-property=server.name:add(boot-time=false, value=backend3)\n[domain@localhost:9990 \/] \/server-group=backend-servers\/:start-servers(blocking=true)\n<\/code><\/pre>\n<p><img src=\"\/img\/2019-04-wildfly-cluster-domain-mode-1-2-3.gif\" alt=\"wildfly-cluster-domain-mode-1-2-3\" \/><\/p>\n<p>That is it!<br \/>\nSource code available on GitHub:  <a href=\"https:\/\/github.com\/kostenkoserg\/ee-jax-rs-examples\/blob\/master\/src\/main\/java\/org\/kostenko\/example\/jaxrs\/ClusterDemoEndpoint.java\">Demo application<\/a>,  <a href=\"https:\/\/github.com\/kostenkoserg\/wildfly-configuration-examples\/blob\/master\/wildfly-domain-mode-cluster.cli\">Wildlfly CLI <\/a><\/p>\n\n\t"},{"title":"JBake blog pagination","link":"https:\/\/kostenko.org\/blog\/2019\/04\/jbake-blog-pagination.html","pubDate":"Wed, 10 Apr 2019 00:00:00 +0300","guid":"blog\/2019\/04\/jbake-blog-pagination.html","description":"\n\t<p>To enable pagintation support on your JBake based blog you need to provide next properties in your <code>jbake.properties<\/code> file:<\/p>\n<pre><code class=\"language-java\">index.paginate=true\nindex.posts_per_page=5\n<\/code><\/pre>\n<p>After that JBake will generate subdirectories <code>2,3,4...<\/code> for your <code>index.html<\/code>. Next, you need to update <code>index<\/code> template to generate necessary count of posts per each index page and provide &quot;previous&quot;,&quot;next&quot; navigation buttons.<\/p>\n<p>Below, I will show you freemarker template with pagination support, that I am using for this blog<\/p>\n<pre><code class=\"language-java\">&lt;#include &quot;header.ftl&quot;&gt;\n\t&lt;#include &quot;menu.ftl&quot;&gt;\n\t&lt;#list posts as post&gt;\n  \t\t&lt;#if (post.status == &quot;published&quot;  &amp;&amp; post?index &gt;= (currentPageNumber-1) * config.index_posts_per_page?eval &amp;&amp; post?index &lt; currentPageNumber * config.index_posts_per_page?eval)&gt;\n\t\t\t\t&lt;a href=&quot;${post.uri}&quot;&gt;&lt;h1&gt;&lt;#escape x as x?xml&gt;${post.title}&lt;\/#escape&gt;&lt;\/h1&gt;&lt;\/a&gt;\n\t\t\t\t&lt;p&gt;${post.date?string(&quot;dd MMMM yyyy&quot;)}&lt;\/p&gt;\n  \t\t\t&lt;p&gt;${post.body}&lt;\/p&gt;\n\t\t\t\t&lt;hr\/&gt;\n  \t\t&lt;\/#if&gt;\n  \t&lt;\/#list&gt;\n\t\t&lt;ul class=&quot;pager&quot;&gt;\n\t\t\t&lt;#if (currentPageNumber &gt; 1)&gt;&lt;li class=&quot;previous&quot;&gt;&lt;a href=&quot;${config.site_host}\/${(currentPageNumber==2)?then('', currentPageNumber-1)}&quot;&gt;Previous&lt;\/a&gt;&lt;\/li&gt;&lt;\/#if&gt;\n\t\t\t&lt;li&gt;Page: ${currentPageNumber}\/${numberOfPages} (&lt;a href=&quot;${content.rootpath}${config.archive_file}&quot;&gt;archive&lt;\/a&gt;)&lt;\/li&gt;\n\t\t\t&lt;#if (currentPageNumber &lt; numberOfPages)&gt;&lt;li class=&quot;next&quot;&gt;&lt;a href=&quot;${config.site_host}\/${currentPageNumber + 1}&quot;&gt;Next&lt;\/a&gt;&lt;\/li&gt;&lt;\/#if&gt;\n\t\t&lt;\/ul&gt;\n&lt;#include &quot;footer.ftl&quot;&gt;\n<\/code><\/pre>\n<p>Blog sources available on <a href=\"https:\/\/github.com\/kostenkoserg\/kostenko.blog.src\">GitHub<\/a><\/p>\n\n\t"},{"title":"Java EE CDI events. Dynamic qualifier.","link":"https:\/\/kostenko.org\/blog\/2019\/04\/java-ee-cdi-events.html","pubDate":"Mon, 8 Apr 2019 00:00:00 +0300","guid":"blog\/2019\/04\/java-ee-cdi-events.html","description":"\n\t<p>Java EE provides us really nice mechanism for event processing. Which is part of the CDI for Java specification. Dynamic qualifier for CDI Events can be very useful, for example, in domain driven design, web socket messages routing or any other stuff depends on needs.<\/p>\n<p>Firing simple event looks like:<\/p>\n<pre><code class=\"language-java\">@Named\npublic class MyEventSource {\n\n    @Inject\n    private Event&lt;String&gt; myEvent;\n\n    public void fireEvent(){\n        myEvent.fire(&quot;Hello World!&quot;);\n    }\n}\n<\/code><\/pre>\n<p>then event observer like:<\/p>\n<pre><code class=\"language-java\">@Named\npublic class MyEventObserver {\n    public void observeEvent(@Observes String message){\n        System.out.println(message);\n    }\n}\n<\/code><\/pre>\n<p>With CDI Qualifier (fancy annotation) you can specify which observer should serve the event<\/p>\n<pre><code class=\"language-java\">@Qualifier\n@Retention(RUNTIME)\n@Target({METHOD, FIELD, PARAMETER, TYPE})\npublic @interface Important {\n}\n<\/code><\/pre>\n<p>For  example:<\/p>\n<pre><code class=\"language-java\">@Named\npublic class MyEventSource {\n\n    @Inject\n    @Important\n    private Event&lt;String&gt; myEvent;\n    ...\n<\/code><\/pre>\n<pre><code class=\"language-java\">@Named\npublic class MyEventObserver {\n  public void observeEvent(@Observes @Important String message){\n    ...\n<\/code><\/pre>\n<p>By default event will be fired in current transaction, but you can change this behavior with <code>@Observes<\/code> attribute  <code>during<\/code><\/p>\n<pre><code class=\"language-java\">@Named\npublic class TransactionEventObserver {\n    public void observeImportantMessage(@Observes(during = TransactionPhase.AFTER_SUCCESS) String message){\n        System.out.println(message);\n    }\n}\n<\/code><\/pre>\n<p>Available next values:<\/p>\n<ul>\n<li>IN_PROGRESS<\/li>\n<li>BEFORE_COMPLETION<\/li>\n<li>AFTER_COMPLETION<\/li>\n<li>AFTER_FAILURE<\/li>\n<li>AFTER_SUCCESS<\/li>\n<\/ul>\n<p>Now, let's take a look on dynamically qualification of CDI event. In the example below we will create observer to serve user events like login, logout, registration etc from the abstract event source. As was noticed earlier, event can be fired from different sources depends on your needs.<\/p>\n<p>So, first we need to create <code>Qualifier<\/code> with available events values<\/p>\n<pre><code class=\"language-java\">@Qualifier\n@Target({METHOD, FIELD, PARAMETER, TYPE})\n@Retention(RUNTIME)\npublic @interface UserEvent {\n\n    Routes value();\n}\n<\/code><\/pre>\n<p>where Routes is enum with available values, for example:<\/p>\n<pre><code class=\"language-java\">public enum Routes {\n  LOGIN,\n  LOGOUT,\n  REGISTRATION\n}\n<\/code><\/pre>\n<p>Then we need to create child class of <code>javax.enterprise.util.AnnotationLiteral<\/code> to possibility of inline instantiation of annotation type instance.<\/p>\n<pre><code class=\"language-java\">public class UserEventBinding extends AnnotationLiteral&lt;UserEvent&gt; implements UserEvent {\n\n    Routes routes;\n\n    public UserEventBinding(Routes routes) {\n        this.routes = routes;\n    }\n\n    @Override\n    public Routes value() {\n        return routes;\n    }\n}\n<\/code><\/pre>\n<p>Now, let's fire event with dynamically observer selection<\/p>\n<pre><code class=\"language-java\">@Named\npublic class UserEventSource {\n\n    @Inject\n    private Event&lt;String&gt; userEvent;\n\n    public void fireEvent(Routes route){\n        userEvent.select(new UserEventBinding(route)).fire(&quot;Instead of string you can use your object&quot;);\n    }\n}\n<\/code><\/pre>\n<p>So, time to show how our Observer looks like<\/p>\n<pre><code class=\"language-java\">import static Routes.*;\n...\n\n@Named\npublic class UserObserver {\n\n    public void registration(@Observes @UserEvent(REGISTRATION) String eventData) {\n      ....\n    }\n\n    public void login(@Observes @UserEvent(LOGIN) String eventData) {\n      ....\n    }\n\n    public void logout(@Observes @UserEvent(LOGOUT) String eventData) {\n      ....\n    }\n}\n<\/code><\/pre>\n<p>P.S. From Java EE 8 with CDI 2.0 you can use <strong>asynchronous CDI Events<\/strong> whith <code>fireAsync<\/code> method and  <code>@ObservesAsync<\/code> annotation...<\/p>\n\n\t"},{"title":"Wildfly large request processing","link":"https:\/\/kostenko.org\/blog\/2019\/03\/wildfly-large-request.html","pubDate":"Tue, 26 Mar 2019 00:00:00 +0200","guid":"blog\/2019\/03\/wildfly-large-request.html","description":"\n\t<p>By default Undertow subsystem on Wildfly AS configured to process requests with <code>max-post-size<\/code>= 10MB. So, in case your request larger than 10MB you will get<\/p>\n<pre><code class=\"language-java\">java.io.IOException: UT000020: Connection terminated as request was larger than 10485760\n<\/code><\/pre>\n<p>To increase this parameter you can edit directly <code>standalone<\/code> or <code>domain<\/code> configuration, like<\/p>\n<pre><code class=\"language-xml\">&lt;subsystem xmlns=&quot;urn:jboss:domain:undertow:3.1&quot;&gt;\n  &lt;buffer-cache name=&quot;default&quot;\/&gt;\n  &lt;server name=&quot;default-server&quot;&gt;\n    &lt;http-listener name=&quot;default&quot; socket-binding=&quot;http&quot; max-post-size=&quot;15728640&quot; redirect-socket=&quot;https&quot; enable-http2=&quot;true&quot;\/&gt;\n    &lt;https-listener name=&quot;https&quot; socket-binding=&quot;https&quot; max-post-size=&quot;15728640&quot; security-realm=&quot;SSLRealm&quot;\/&gt;\n....\n<\/code><\/pre>\n<p>or use CLI commands as shown below:<\/p>\n<pre><code class=\"language-bash\">\/subsystem=undertow\/server=default-server\/http-listener=default\/:write-attribute(name=max-post-size,value=15728640)\n\/subsystem=undertow\/server=default-server\/https-listener=https\/:write-attribute(name=max-post-size,value=15728640)\n<\/code><\/pre>\n<p>Notice! If you are using Wildfly in domain mode with AJP load balancer, you also may need to change  <code>max-post-size<\/code> for <code>ajp-listener<\/code><\/p>\n<pre><code class=\"language-bash\">\/subsystem=undertow\/server=default-server\/ajp-listener=ajp\/:write-attribute(name=max-post-size,value=15728640)\n<\/code><\/pre>\n\n\t"},{"title":"My Hibernate Search introduction video","link":"https:\/\/kostenko.org\/blog\/2019\/03\/hibernate-search-intro-video.html","pubDate":"Wed, 20 Mar 2019 00:00:00 +0200","guid":"blog\/2019\/03\/hibernate-search-intro-video.html","description":"\n\t\nHave published my second YouTube video (about Hibernate Search and integration with Wildfly)!\n\n<br\/><br\/>\n<div class=\"row\">\n    <iframe align =\"center\" class=\"col-md-offset-3 col-lg-6 col-md-6 col-sm-12 col-xs-12\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/RuGyErfhmL0\" frameborder=\"0\" allowfullscreen=\"true\"><\/iframe>\n<\/div>\n\n\t"},{"title":"SQL trick. Conditional count for select clause","link":"https:\/\/kostenko.org\/blog\/2019\/03\/sql-trick-conditional-count.html","pubDate":"Sat, 16 Mar 2019 00:00:00 +0200","guid":"blog\/2019\/03\/sql-trick-conditional-count.html","description":"\n\t<p>To perform conditional logic in your SQL <code>SELECT<\/code> clause you can use <code>CASE<\/code> expression. Next SQL trick allows you perform conditional <code>count()<\/code> with your query.<\/p>\n<p>For example, to  select count of records with <code>id &gt; 5<\/code>:<\/p>\n<p>SQL:<\/p>\n<pre><code class=\"language-sql\">SELECT SUM(CASE WHEN id &gt; 5 THEN 1 ELSE 0 END) FROM Table\n<\/code><\/pre>\n<p>JPQL:<\/p>\n<pre><code class=\"language-java\">entityManager.createQuery(&quot;SELECT SUM(CASE WHEN b.id &gt; 5 THEN 1 ELSE 0 END) FROM BlogEntity b&quot;).getSingleResult()\n<\/code><\/pre>\n<p>Criteria API:<\/p>\n<pre><code class=\"language-java\">CriteriaBuilder cb = em.getCriteriaBuilder();\nCriteriaQuery&lt;Number&gt; query = cb.createQuery(Number.class);\nRoot&lt;BlogEntity&gt; blogEntity = query.from(BlogEntity.class);\n\nquery.select(\n        cb.sum(\n                cb.&lt;Number&gt;selectCase()\n                        .when(cb.gt(blogEntity.get(&quot;id&quot;), 5), 1)\n                        .otherwise(0)\n        )\n);\n\nNumber result = em.createQuery(query).getSingleResult();\n<\/code><\/pre>\n<p>Test cases source code available on  <a href=\"https:\/\/github.com\/kostenkoserg\/jpa-examples\/blob\/master\/src\/test\/java\/org\/kostenko\/example\/jpa\/JpaConditionalCountTest.java\">GitHub<\/a><\/p>\n\n\t"},{"title":"How to build ssh tunnel on Linux","link":"https:\/\/kostenko.org\/blog\/2019\/03\/linux-build-ssh-tunnel.html","pubDate":"Fri, 15 Mar 2019 00:00:00 +0200","guid":"blog\/2019\/03\/linux-build-ssh-tunnel.html","description":"\n\t<p>SSH tunneling is routing local network traffic through SSH to remote hosts. Can be used, for example, to  connect to the remote application that was bound on remote local port.<\/p>\n<p>For example, to connect to mysql instance that was bound on remote local port <code>3306<\/code> you can use:<\/p>\n<pre><code class=\"language-bash\">ssh -L 3366:localhost:3306 [USERNAME]@remotehost.com\n<\/code><\/pre>\n<p>or if you would like to connect with <a href=\"https:\/\/kostenko.org\/blog\/2019\/02\/linux-generate-private-shh-key.html\">SSH keys<\/a> :<\/p>\n<pre><code class=\"language-bash\">ssh -i [KEY_FILENAME] -L 3366:localhost:3306 [USERNAME]@remotehost.com\n<\/code><\/pre>\n<p>After you can connect to the database, using your favorite tool on localhost:3366<\/p>\n\n\t"},{"title":"Hibernate Search introduction. Deploying on WildFly.","link":"https:\/\/kostenko.org\/blog\/2019\/02\/wildfly-hibernate-search.html","pubDate":"Thu, 21 Feb 2019 00:00:00 +0200","guid":"blog\/2019\/02\/wildfly-hibernate-search.html","description":"\n\t<p>Hibernate Search is a powerful solution to implement full text search capabilities (like google or amazon) in your EE application. Under the hood it will use Apache Lucene directly or over Elasticsearch to build the index. Hibernate Search can be easy integrated with JPA, Hibernate ORM, Infinispan and other sources. If you are use Wildfly - you are lucky, - Hibernate Search already integrated with last one.<\/p>\n<p>So, will see how it works on practice in few simple steps...<\/p>\n<p><strong>1. Let's start with gradle project using EE and hibernate-search dependencies<\/strong><br \/>\n<code>build.gradle:<\/code><\/p>\n<pre><code class=\"language-java\">apply plugin: 'java'\napply plugin: 'war'\n\nsourceCompatibility = '1.8'\ndefaultTasks 'clean', 'build'\next.libraryVersions = [\n    javaee                  : '8.0',\n    wildfly                 : '15.0.1.Final',\n    hibernatesearch         : '5.11.1.Final',\n    hibernateentitymanager  : '5.4.1.Final',\n    h2                      : '1.4.198',\n    dom4j                   : '2.1.1',\n    junit                   : '4.12'\n]\nconfigurations {\n    wildfly\n}\nrepositories {\n    mavenCentral()\n}\ndependencies {\n    wildfly &quot;org.wildfly:wildfly-dist:${libraryVersions.wildfly}@zip&quot;\n    providedCompile &quot;javax:javaee-api:${libraryVersions.javaee}&quot;\n    providedCompile &quot;org.hibernate:hibernate-search-orm:${libraryVersions.hibernatesearch}&quot;\n    testCompile &quot;junit:junit:${libraryVersions.junit}&quot;\n    testCompile &quot;com.h2database:h2:${libraryVersions.h2}&quot;\n    testCompile &quot;org.hibernate:hibernate-entitymanager:${libraryVersions.hibernateentitymanager}&quot;\n    testCompile &quot;org.hibernate:hibernate-search-orm:${libraryVersions.hibernatesearch}&quot;\n    testCompile &quot;org.dom4j:dom4j:${libraryVersions.dom4j}&quot;\n}\n<\/code><\/pre>\n<p><strong>2. Create standart JPA entity with hibernate-search annotations<\/strong><br \/>\n<code>src\/main\/java\/org\/...\/BlogEntity.java:<\/code><\/p>\n<pre><code class=\"language-java\">package org.kostenko.example.wildfly.hibernatesearch;\n\nimport javax.persistence.*;\nimport org.hibernate.search.annotations.*;\n\n@Entity\n@Indexed\npublic class BlogEntity {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n\n    @Column\n    @Field(store = Store.YES)\n    private String title;\n\n    @Column\n    @Field(store = Store.YES)\n    private String body;\n\n    \/\/ getters, setters\n}\n<\/code><\/pre>\n<p>Main Hibernate Search annotations:<\/p>\n<table>\n<thead>\n<tr><th>Annotation    <\/th><th> Description<\/th><\/tr>\n<\/thead>\n<tbody>\n<tr><td>@Indexed      <\/td><td> Marks which entities shall be indexed; Allows override the index name. Only @Indexed entities can be searched.<\/td><\/tr>\n<tr><td>@Field        <\/td><td> Marks an entity property to be indexed. Supports various options to customize the indexing format: <code>store<\/code> -  enum type indicating whether the value should be stored in the document. Defaults to <code>Store.NO<\/code> (Field value will not be stored in the index. Storing of values can be helpful to use projections and restore objects directly from index instead of mapped ORM entity), <code>index<\/code> -  enum defining whether the value should be indexed or not. Defaults to <code>Index.YES<\/code> <\/td><\/tr>\n<tr><td>@DocumentId   <\/td><td> Override the property being used as primary identifier in the index. Defaults to the property with JPA\u2019s @Id. <\/td><\/tr>\n<tr><td>@SortableField<\/td><td> Marks a property so that it will be indexed in such way to allow efficient sorting on it.<\/td><\/tr>\n<\/tbody>\n<\/table>\n<p><strong>3. Add hibernate-search properties to persistence.xml<\/strong><br \/>\n<code>src\/test\/resources\/META-INF\/persistence.xml :<\/code><\/p>\n<pre><code class=\"language-xml\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;persistence version=&quot;2.0&quot; xmlns=&quot;http:\/\/java.sun.com\/xml\/ns\/persistence&quot; xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http:\/\/java.sun.com\/xml\/ns\/persistence http:\/\/java.sun.com\/xml\/ns\/persistence\/persistence_2_0.xsd&quot;&gt;\n    &lt;persistence-unit name=&quot;myDSTest&quot; transaction-type=&quot;RESOURCE_LOCAL&quot;&gt;\n        &lt;provider&gt;org.hibernate.jpa.HibernatePersistenceProvider&lt;\/provider&gt;\n        &lt;class&gt;org.kostenko.example.wildfly.hibernatesearch.BlogEntity&lt;\/class&gt;\n        &lt;exclude-unlisted-classes&gt;false&lt;\/exclude-unlisted-classes&gt;\n        &lt;properties&gt;\n            &lt;property name=&quot;hibernate.dialect&quot; value=&quot;org.hibernate.dialect.HSQLDialect&quot;\/&gt;\n            &lt;property name=&quot;hibernate.hbm2ddl.auto&quot; value=&quot;create-drop&quot;\/&gt;\n            &lt;property name=&quot;hibernate.connection.driver_class&quot; value=&quot;org.hsqldb.jdbcDriver&quot;\/&gt;\n            &lt;property name=&quot;hibernate.connection.username&quot; value=&quot;sa&quot;\/&gt;\n            &lt;property name=&quot;hibernate.connection.password&quot; value=&quot;&quot;\/&gt;\n            &lt;property name=&quot;hibernate.connection.url&quot; value=&quot;jdbc:hsqldb:mem:testdb&quot;\/&gt;\n            &lt;property name=&quot;hibernate.showSql&quot; value=&quot;true&quot;\/&gt;\n            &lt;!-- Hibernate Search --&gt;\n            &lt;property name=&quot;hibernate.search.default.directory_provider&quot; value=&quot;filesystem&quot; \/&gt;\n            &lt;property name=&quot;hibernate.search.default.indexBase&quot; value=&quot;\/tmp\/index1&quot; \/&gt;\n            &lt;property name=&quot;hibernate.search.default.indexmanager&quot; value=&quot;near-real-time&quot; \/&gt;\n        &lt;\/properties&gt;\n    &lt;\/persistence-unit&gt;\n&lt;\/persistence&gt;\n<\/code><\/pre>\n<p>As you can see from above, it is easy enough (just with few annotations) add Hibernate Search into your application. Now Hibernate will automatically build index each time the entity persisted, updated or removed through Hibernate ORM. The index can be stored in <code>ram<\/code> or on  <code>filesystem<\/code>. Others directory providers also available - refer official documentation for details.<\/p>\n<p>So, time to do simple test and see how it works with <strong>Lucene queries<\/strong><\/p>\n<p><code>src\/test\/java\/org\/...\/JpaHibernateSearchTest :<\/code><\/p>\n<pre><code class=\"language-java\">public class JpaHibernateSearchTest {\n\n    private static EntityManager entityManager;\n    private static FullTextEntityManager fullTextEntityManager;\n    private static QueryBuilder queryBuilder;\n\n    @BeforeClass\n    public static void init() {\n        entityManager = Persistence.createEntityManagerFactory(&quot;myDSTest&quot;).createEntityManager();\n        fullTextEntityManager = Search.getFullTextEntityManager(entityManager);\n        queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(BlogEntity.class).get();\n        for (int i = 0; i &lt; 1000; i++) {\n            BlogEntity blogEntity = new BlogEntity();\n            blogEntity.setTitle(&quot;Title&quot; + i);\n            blogEntity.setBody(&quot;BodyBody Body&quot; + i + &quot; look at my horse my horse is a amazing &quot; + i);\n            entityManager.getTransaction().begin();\n            entityManager.persist(blogEntity);\n            entityManager.getTransaction().commit();\n        }\n        Assert.assertEquals(1000, entityManager.createQuery(&quot;SELECT COUNT(b) FROM BlogEntity b&quot;, Number.class).getSingleResult().intValue());\n    }\n    \/**\n     * Keyword Queries - searching for a specific word.\n     *\/\n    @Test\n    public void shouldSearchByKeywordQuery() throws Exception {\n        Query query = queryBuilder.keyword().onFields(&quot;title&quot;, &quot;body&quot;).matching(&quot;Body999&quot;).createQuery();\n        javax.persistence.Query persistenceQuery = fullTextEntityManager.createFullTextQuery(query, BlogEntity.class); \/\/ wrap Lucene query in a javax.persistence.Query\n        List&lt;BlogEntity&gt; result = persistenceQuery.getResultList();\/\/ execute search\n        Assert.assertFalse(result.isEmpty());\n        Assert.assertEquals(&quot;Title999&quot;, result.get(0).getTitle());\n    }\n    \/**\n     * Fuzzy Queries - we can define a limit of \u201cfuzziness\u201d\n     *\/\n    @Test\n    public void shouldSearchByFuzzyQuery() throws Exception {\n        Query query = queryBuilder.keyword().fuzzy().withEditDistanceUpTo(2).withPrefixLength(0).onField(&quot;title&quot;).matching(&quot;TAtle999&quot;).createQuery();\n        javax.persistence.Query persistenceQuery = fullTextEntityManager.createFullTextQuery(query, BlogEntity.class);\n        List&lt;BlogEntity&gt; result = persistenceQuery.getResultList();\n        Assert.assertFalse(result.isEmpty());\n        Assert.assertEquals(&quot;Title999&quot;, result.get(0).getTitle());\n    }\n    \/**\n     * Wildcard Queries - queries for which a part of a word is unknown ('?' - single character, '*' - character sequence)\n     *\/\n    @Test\n    public void shouldSearchByWildcardQuery() throws Exception {\n        Query query = queryBuilder.keyword().wildcard().onField(&quot;title&quot;).matching(&quot;?itle*&quot;).createQuery();\n        javax.persistence.Query persistenceQuery = fullTextEntityManager.createFullTextQuery(query, BlogEntity.class);\n        List&lt;BlogEntity&gt; result = persistenceQuery.getResultList();\n        Assert.assertFalse(result.isEmpty());\n        Assert.assertEquals(1000, result.size());\n    }\n    \/**\n     * Phrase Queries - search for exact or for approximate sentences\n     *\/\n    @Test\n    public void shouldSearchByPhraseQuery() throws Exception {\n        Query query = queryBuilder.phrase().withSlop(10).onField(&quot;body&quot;).sentence(&quot;look amazing horse 999&quot;).createQuery();\n        javax.persistence.Query persistenceQuery = fullTextEntityManager.createFullTextQuery(query, BlogEntity.class);\n        List&lt;BlogEntity&gt; result = persistenceQuery.getResultList();\n        Assert.assertFalse(result.isEmpty());\n        Assert.assertEquals(&quot;Title999&quot;, result.get(0).getTitle());\n    }\n\n}\n<\/code><\/pre>\n<p>In the test above I used most basic use-cases. But even it enough to feel how power <code>Apache Lucene search engine<\/code> is. And how easy it can be integrated with your application.  Please, refer to <a href=\"https:\/\/docs.jboss.org\/hibernate\/stable\/search\/reference\/en-US\/html_single\/\">official documentation<\/a> for advanced topics.<\/p>\n<p><strong>4. Use Hibernate Search as Wildfly module<\/strong><br \/>\nAs i already noticed - Hibernate Search included in Wildfly since version 10. It means that activation of this functionality is automatic in case you are using at least one entity with <code>org.hibernate.search.annotations.Indexed<\/code>. So, all we need to show how it works together is just implement simple web service with similar to test logic and run it on the server.<\/p>\n<pre><code class=\"language-java\">@Path(&quot;\/&quot;)\n@Stateless\npublic class HibernateSearchDemoEndpoint {\n\n    @PersistenceContext\n    EntityManager entityManager;\n\n    \/**\n     * Persist 1000 entities and rebuild index\n     * @return\n     *\/\n    @GET\n    @Path(&quot;\/init&quot;)\n    @Transactional\n    public Response init() {\n        int count = entityManager.createQuery(&quot;SELECT COUNT(b) FROM BlogEntity b&quot;, Number.class).getSingleResult().intValue();\n        long time = System.currentTimeMillis();\n        for (int i = count; i &lt; count + 1000; i++) {\n            BlogEntity blogEntity = new BlogEntity();\n            blogEntity.setTitle(&quot;Title&quot; + i);\n            blogEntity.setBody(&quot;Body Body Body&quot; + i + &quot; look at my horse my horse is a amazing &quot; + i);\n            entityManager.persist(blogEntity);\n        }\n        time = System.currentTimeMillis() - time;\n        return Response.ok().entity(String.format(&quot;1000 records persisted. Current records %s Execution time = %s ms.&quot;, count + 1000, time)).build();\n    }\n\n    \/**\n     * Search by index\n     * @param q - query string\n     * @return\n     *\/\n    @GET\n    @Path(&quot;\/search&quot;)\n    public Response search(@QueryParam(&quot;q&quot;) String q) {\n        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);\n        QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(BlogEntity.class).get();\n        long time = System.currentTimeMillis();\n        Query query = queryBuilder.keyword().onFields(&quot;title&quot;, &quot;body&quot;).matching(q).createQuery();\n        javax.persistence.Query persistenceQuery = fullTextEntityManager.createFullTextQuery(query, BlogEntity.class);\n        List&lt;BlogEntity&gt; result = persistenceQuery.getResultList();\n        time = System.currentTimeMillis() - time;\n        String resultStr = result.stream().map(Object::toString).collect(Collectors.joining(&quot;,&quot;));\n        return Response.ok().entity( String.format(&quot;Found %s results. [%s] Execution time = %s ms.&quot;,result.size(),resultStr,time)).build();\n    }\n}\n<\/code><\/pre>\n<p>Now, let's add task  into our <code>build.gradle<\/code> to run Wildfly directly from the project<\/p>\n<pre><code class=\"language-java\">task removeWildfly(type:Delete) {\n    delete &quot;build\/wildfly-${libraryVersions.wildfly}&quot;\n}\ntask resolveWildfly(type:Copy, dependsOn:removeWildfly) {\n    destinationDir = buildDir\n    from {zipTree(configurations.wildfly.singleFile)}\n}\ntask run() {\n    dependsOn 'resolveWildfly'\n    doLast {\n        copy {\n            from projectDir.toString() + &quot;\/build\/libs\/wildfly-hibernate-search-example.war&quot;\n            into projectDir.toString() + &quot;\/build\/wildfly-${libraryVersions.wildfly}\/standalone\/deployments&quot;\n        }\n        exec {\n            workingDir = file(projectDir)\n            commandLine &quot;.\/build\/wildfly-${libraryVersions.wildfly}\/bin\/standalone.sh&quot;, &quot;--debug&quot;, &quot;5005&quot;\n            ext.output = {\n                return standardOutput.toString()\n            }\n        }\n    }\n}\n<\/code><\/pre>\n<p><code>run<\/code> task above will unzip wildfly into project build directory, deploy application and start the server. So, to start - please do<\/p>\n<pre><code class=\"language-bash\">gradle &amp;&amp; gradle run\n<\/code><\/pre>\n<p>check output to be sure that Hiberate created Index directory by provided in <code>persistence.xml<\/code> path<\/p>\n<pre><code class=\"language-bash\">...\n15:15:37,386 INFO  [org.hibernate.search.store.impl.DirectoryProviderHelper] (MSC service thread 1-3) HSEARCH000041: Index directory not found, creating: '\/tmp\/index2\/org.kostenko.example.wildfly.hibernatesearch.BlogEntity'                                  \n...\n<\/code><\/pre>\n<p>and see result in the browser<br \/>\n<img src=\"\/img\/2019-02-hibernate-search-1.png\" alt=\"create_index\" \/><br \/>\n<img src=\"\/img\/2019-02-hibernate-search-2.png\" alt=\"serach_by_index\" \/><\/p>\n<p>Example project source code available on <a href=\"https:\/\/github.com\/kostenkoserg\/wildfly-hibernate-search-example\">GitHub<\/a><\/p>\n\n\t"},{"title":"How to generate ssh keys on Linux","link":"https:\/\/kostenko.org\/blog\/2019\/02\/linux-generate-private-shh-key.html","pubDate":"Wed, 20 Feb 2019 00:00:00 +0200","guid":"blog\/2019\/02\/linux-generate-private-shh-key.html","description":"\n\t<p>Sometimes, by security or usability reasons authentication with SSH keys looks much better than passwords. To generate personal keys, please, do next:<\/p>\n<ul>\n<li>Login your remote instance<\/li>\n<li>Generate ssh keys by<\/li>\n<\/ul>\n<pre><code class=\"language-bash\">ssh-keygen -t rsa -f ~\/.ssh\/[KEY_FILENAME] -C [USERNAME]\ncat [KEY_FILENAME].pub &gt;&gt; ~\/.ssh\/authorized_keys\n<\/code><\/pre>\n<ul>\n<li>Download private key ([KEY_FILENAME]) to your local PC<\/li>\n<li>Try to connect from your local with key:<\/li>\n<\/ul>\n<pre><code class=\"language-bash\">chmod 400 [KEY_FILENAME]\nssh -i [KEY_FILENAME] [USERNAME]@yourhost.com\n<\/code><\/pre>\n<p>To disable root login and password based login refer to  <code>\/etc\/ssh\/sshd_config<\/code> and edid next sections:<\/p>\n<pre><code class=\"language-bash\">PasswordAuthentication no\nPermitRootLogin no\n<\/code><\/pre>\n<p>Then reload ssh server<\/p>\n<pre><code class=\"language-bash\">sudo service ssh restart\n<\/code><\/pre>\n\n\t"},{"title":"My first video","link":"https:\/\/kostenko.org\/blog\/2019\/02\/github-jbake-blog-video.html","pubDate":"Sat, 16 Feb 2019 00:00:00 +0200","guid":"blog\/2019\/02\/github-jbake-blog-video.html","description":"\n\t\nHave published my first YouTube video (about blogging with jbake)!\n\n<br\/><br\/>\n<div class=\"row\">\n    <iframe align =\"center\" class=\"col-md-offset-3 col-lg-6 col-md-6 col-sm-12 col-xs-12\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/_0C2xTa8jsY\" frameborder=\"0\" allowfullscreen=\"true\"><\/iframe>\n<\/div>\n\n\t"},{"title":"Jbake. Add tags, multi languages support and analytics","link":"https:\/\/kostenko.org\/blog\/2019\/01\/jbake-blog-improve.html","pubDate":"Sat, 19 Jan 2019 00:00:00 +0200","guid":"blog\/2019\/01\/jbake-blog-improve.html","description":"\n\t<h4>1. Tags<\/h4>\n<p>Jbake supports tagging out of the box. It means that engine will generate separate page for each tag. To enable this feature on your blog you need to change <code>render.tags<\/code> property in your <code>jbake.properties<\/code> file<\/p>\n<pre><code class=\"language-bash\">render.tags=true\n<\/code><\/pre>\n<p>Next  modify template file depends on where you whant to reneder tags. For this blog I am using freemarker templates and made desition to put tags as part of menu bar. So, chages of my <code>menu.ftl<\/code> below:<\/p>\n<pre><code class=\"language-html\">  &lt;ul class=&quot;dropdown-menu&quot;&gt;\n      &lt;#list tags as tag&gt;\n        &lt;li&gt;&lt;a href=&quot;${content.rootpath}${tag.uri}&quot;&gt;${tag.name}&lt;\/a&gt;&lt;\/li&gt;\n      &lt;\/#list&gt;\n  &lt;\/ul&gt;\n<\/code><\/pre>\n<p>That's is it!<\/p>\n<h4>2. Multi languages<\/h4>\n<p>Now let's talk about multilanguage support. It is pity, but Jbake does not support blogging in different languages at the same time by default. So, we need a some hacks to do that. First idea  I had was about two the same sites  in different languages. It is not big deal, but in case changes for  templates, assets or images  you will need to do it twice. What is not so good.<\/p>\n<p>Instead of full copy  I did additional directory <code>content_ru<\/code> just with content.<\/p>\n<pre><code class=\"language-bash\">\u251c\u2500\u2500 assets  \n\u251c\u2500\u2500 content  \n\u251c\u2500\u2500 content_ru\n\u251c\u2500\u2500 templates\n\u251c\u2500\u2500 jbake.properties\n\u251c\u2500\u2500 README.md  \n<\/code><\/pre>\n<p>In <code>jbake.properies<\/code> you can specify which content should be used.<\/p>\n<p>So, I  choosen english as default language and bake my blog in the next way:<\/p>\n<p>bakeblog.sh:<\/p>\n<pre><code class=\"language-bash\">#!\/bin\/bash\n\n# Helper script to bake the blog\n# Author: kostenko\n\nexport PATH=&quot;\/opt\/jbake-2.6.3-bin\/bin&quot;:$PATH\nrm -R .\/output\n# Building en version\nexport JBAKE_OPTS=&quot;-Duser.language=EN&quot;\njbake -b\n# Build ru version\nexport JBAKE_OPTS=&quot;-Duser.language=RU&quot;\nmv jbake.properties jbake.properties.orig\ncat jbake.properties.orig &gt;&gt; jbake.properties\necho &quot;content.folder=content_ru&quot; &gt;&gt; jbake.properties\njbake -b . output\/ru\n# cleanup\nrm jbake.properties\nmv jbake.properties.orig jbake.properties\n<\/code><\/pre>\n<p>Now let\u2019s add to the menu bar links to choose language:<\/p>\n<pre><code class=\"language-html\">&lt;!-- switch language --&gt;\n&lt;ul class=&quot;nav navbar-nav navbar-right&quot;&gt;\n  &lt;li&gt;&lt;a href=&quot;\/&quot;&gt;en&lt;\/a&gt;&lt;\/li&gt;\n  &lt;li&gt;&lt;a href=&quot;\/ru&quot;&gt;ru&lt;\/a&gt;&lt;\/li&gt;\n&lt;\/ul&gt;\n<\/code><\/pre>\n<p>Done!<\/p>\n<h4>3. Analytics<\/h4>\n<p>To enable <a href=\"https:\/\/analytics.google.com\">Google analytics<\/a> functionality on your Jbake based  site, you need to do few simple steps:<\/p>\n<ul>\n<li>Register your resource on  google analytics<\/li>\n<li>Get provided by GA code snippet<\/li>\n<li>Paste provided snippet to your <code>header.ftl<\/code> as first block of <code>&lt;HEAD&gt;<\/code> section.<\/li>\n<\/ul>\n<pre><code class=\"language-html\">&lt;!-- Global site tag (gtag.js) - Google Analytics --&gt;\n&lt;head&gt;\n  &lt;script async src=&quot;https:\/\/www.googletagmanager.com\/gtag\/js?id=&lt;YOUR_GA_ID&gt;&quot;&gt;&lt;\/script&gt;\n  &lt;script&gt;\n    window.dataLayer = window.dataLayer || [];\n    function gtag(){dataLayer.push(arguments);}\n    gtag('js', new Date());\n    gtag('config', '&lt;YOUR_GA_ID&gt;');\n  &lt;\/script&gt;\n  ...\n<\/code><\/pre>\n<p>Congrats! You are ready to blogging!<\/p>\n<p>P.S. If you want to have comments for your posts, - refer to the services like <a href=\"https:\/\/disqus.com\/\">Disqus<\/a> - it is aloso easy to integrate and nice to have for some reasons.<br \/>\nP.P.S. Blog sources available on <a href=\"https:\/\/github.com\/kostenkoserg\/kostenko.blog.src\">GitHub<\/a><\/p>\n\n\t"},{"title":"Start blogging with GitHub and Jbake","link":"https:\/\/kostenko.org\/blog\/2019\/01\/github-jbake-blog.html","pubDate":"Fri, 18 Jan 2019 00:00:00 +0200","guid":"blog\/2019\/01\/github-jbake-blog.html","description":"\n\t<p>Hosting of personal blog, company blog or landing page of your project - easy enough with <a href=\"https:\/\/pages.github.com\/\">github<\/a>. In this post i will try to explain how to do it in two steps.<\/p>\n<h4>Step 1. Deploy static content to GitHub<\/h4>\n<p>First of all we need an account on <a href=\"https:\/\/github.com\/\">github<\/a> and base knoweledges about  <a href=\"https:\/\/git-scm.com\/\">git<\/a>. Actually, as i know, another popular web-based Git-repository  <a href=\"https:\/\/gitlab.com\/\">GitLab<\/a> also supports hosting of static content, so you can choose what you like more.<\/p>\n<p>Now you need to create new project named as [account].github.io For example: kostenkoserg.github.io<\/p>\n<p><img src=\"\/ru\/img\/my_github_srcshot.png\" alt=\"github pages project screenshot\" \/><\/p>\n<p>Actually, we already did all necessary preparation for our hosting. Now just clone the project, create simple index.html and push it back to the repository:<\/p>\n<pre><code class=\"language-bash\">$ git clone https:\/\/github.com\/kostenkoserg\/kostenkoserg.github.io.git\n$ cd kostenkoserg.github.io\n$ echo &quot;Hello World!&quot;\n$ git commit -m &quot;my first github page&quot;\n$ git push\n<\/code><\/pre>\n<p>Congrats! Our new site currently available over world wide web: <a href=\"https:\/\/kostenkoserg.github.io\">https:\/\/kostenkoserg.github.io<\/a><\/p>\n<p><img src=\"\/ru\/img\/first_github_page.png\" alt=\"first_github_page\" \/><br \/>\nBy the way  you also can use existing domain for your GitHub based site. For do that you just need to<\/p>\n<ul>\n<li>Add <code>A<\/code> records to your DNS provider with GitHub IP's<\/li>\n<li>Provide in GitHub project settings your DNS name<\/li>\n<\/ul>\n<h4>Step 2. Static blog generation with JBake<\/h4>\n<p><a href=\"https:\/\/jbake.org\/\">Jbake<\/a> is a java based open source solution for static site generation. For JBake available integration with Gradle and Maven. Jbake out of the box supports Bootstrap and can be easy integrated with other CSS frameworks. As template engines JBake supports Freemarker, Groovy, Thymeleaf and Jade.<\/p>\n<p>To start with let's download distribution from <a href=\"https:\/\/jbake.org\/download.html\">project site<\/a> and extract the package to your favorite directory. Now we can generate static site with example content<\/p>\n<pre><code class=\"language-bash\">$ \/opt\/jbake\/bin\/jbake -i\n<\/code><\/pre>\n<p>As result we should have site template with next structire:<\/p>\n<pre><code class=\"language-bash\">\u251c\u2500\u2500 assets\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 css\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 asciidoctor.css\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 base.css\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 bootstrap.min.css\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 prettify.css\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 favicon.ico\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 fonts\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 ...\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 js\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 bootstrap.min.js\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 html5shiv.min.js\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 jquery-1.11.1.min.js\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 prettify.js\n\u251c\u2500\u2500 content\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 about.html\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 blog\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 2013\n\u2502\u00a0\u00a0         \u251c\u2500\u2500 first-post.html\n\u2502\u00a0\u00a0         \u251c\u2500\u2500 second-post.md\n\u2502\u00a0\u00a0         \u2514\u2500\u2500 third-post.adoc\n\u251c\u2500\u2500 jbake.properties\n\u2514\u2500\u2500 templates\n    \u251c\u2500\u2500 archive.ftl\n    \u251c\u2500\u2500 feed.ftl\n    \u251c\u2500\u2500 footer.ftl\n    \u251c\u2500\u2500 header.ftl\n    \u251c\u2500\u2500 index.ftl\n    \u251c\u2500\u2500 menu.ftl\n    \u251c\u2500\u2500 page.ftl\n    \u251c\u2500\u2500 post.ftl\n    \u251c\u2500\u2500 sitemap.ftl\n    \u2514\u2500\u2500 tags.ftl\n<\/code><\/pre>\n<p>Let's generate site from above<\/p>\n<pre><code class=\"language-bash\">\/opt\/jbake\/bin\/jbake -b\n<\/code><\/pre>\n<p>After that we will have direcory <code>output<\/code> with our static site.<br \/>\nTo check the result you can start embedded server and open  <a href=\"http:\/\/localhost:8820\/\">http:\/\/localhost:8820\/<\/a><\/p>\n<pre><code class=\"language-bash\">\/opt\/jbake\/bin\/jbake -s\n<\/code><\/pre>\n<p><img src=\"\/ru\/img\/jbake_default_site.png\" alt=\"jbake_default_site\" \/><\/p>\n<p>Well done! Our static site ready for blogging. You just need edit content of  <code>content<\/code> directory, regenerate site and push   <code>output<\/code>  to GitHub repository.<\/p>\n<p>Jbake supports few types of content: HTML, Markdown, AsciiDoc, - that is greate and allow you blogging with your favorite text editor. For this blog I am using <a href=\"https:\/\/atom.io\/\">Atom<\/a> \u0438 <a href=\"https:\/\/www.markdownguide.org\/basic-syntax\/\">Markdown<\/a>.<\/p>\n\n\t"},{"title":"My first blog post","link":"https:\/\/kostenko.org\/blog\/2019\/01\/start-blogging.html","pubDate":"Thu, 17 Jan 2019 00:00:00 +0200","guid":"blog\/2019\/01\/start-blogging.html","description":"\n\t<p>I wanted to start a my own tech blog long ago. But by different reasons have started only now. First i wanted to do own blog engine, after spent lot of time to searching for nice look and feel  and  then sorting out popular solutions like wordpres, wix, blogger etc...<\/p>\n<p>After all i found <a href=\"https:\/\/pages.github.com\/\">pages.github.io<\/a> with their static site generator <a href=\"https:\/\/jekyllrb.com\/\">Jekyll<\/a>. Last one looks good from different points of view. It is simple, it is for free, it is quick enough, it is stable.  Finally if GitHub it is a pretty nice place for work with source code why it can't be the same for a blog source ?<\/p>\n<p>While investigating Jekyll (written on Rubby), i found  JVM based Jekyll analog - project <a href=\"https:\/\/jbake.org\/\">JBake<\/a>. \u041ef course last one seemed to me most closer.<\/p>\n<p>So, decision is made. Let's go!<\/p>\n\n\t"}]}}