<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jay Yanez</title>
    <description>The latest articles on DEV Community by Jay Yanez (@jayyanez).</description>
    <link>https://dev.to/jayyanez</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4096755%2F81f00910-f0f9-4f42-87e6-8b35b5b4c700.jpg</url>
      <title>DEV Community: Jay Yanez</title>
      <link>https://dev.to/jayyanez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jayyanez"/>
    <language>en</language>
    <item>
      <title>Java Service Steward, an open-source host for Java Windows services that reads wrapper.conf</title>
      <dc:creator>Jay Yanez</dc:creator>
      <pubDate>Thu, 27 Aug 2026 06:38:14 +0000</pubDate>
      <link>https://dev.to/jayyanez/java-service-steward-an-open-source-host-for-java-windows-services-that-reads-wrapperconf-aam</link>
      <guid>https://dev.to/jayyanez/java-service-steward-an-open-source-host-for-java-windows-services-that-reads-wrapperconf-aam</guid>
      <description>&lt;p&gt;Java Service Steward is a new Windows service host for Java applications. It reads the &lt;code&gt;wrapper.conf&lt;/code&gt; format used by the Java Service Wrapper, follows the same command line and log format, and is licensed Apache-2.0 OR MIT. I wrote it because the Community Edition of the Java Service Wrapper has no 64-bit Windows build, and I did not want to buy a license or rewrite the service integration of applications that already had working configuration files.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/jayyanez/java-service-steward" rel="noopener noreferrer"&gt;https://github.com/jayyanez/java-service-steward&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it is
&lt;/h2&gt;

&lt;p&gt;The distribution is two files, &lt;code&gt;wrapper.exe&lt;/code&gt; and &lt;code&gt;wrapper.jar&lt;/code&gt;. The executable is written in Rust and does the Windows part: it registers the service, launches the JVM, keeps a control channel to it over a loopback socket, restarts it when it exits unexpectedly or stops answering pings, writes and rotates &lt;code&gt;wrapper.log&lt;/code&gt;, and handles Service Control Manager requests (stop, pause, resume, custom control codes). The JAR is compiled for Java 8 and contains the launcher classes and a small API. There is no native DLL and no JNI.&lt;/p&gt;

&lt;p&gt;It only runs on 64-bit Windows. There is no Unix version.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is compatible
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Configuration. &lt;code&gt;wrapper.conf&lt;/code&gt; with &lt;code&gt;#include&lt;/code&gt;, &lt;code&gt;#encoding&lt;/code&gt;, &lt;code&gt;set.VAR=value&lt;/code&gt;, &lt;code&gt;%VAR%&lt;/code&gt; expansion and numbered properties such as &lt;code&gt;wrapper.java.additional.&amp;lt;n&amp;gt;&lt;/code&gt;. Relative paths resolve from the executable's directory, as before.&lt;/li&gt;
&lt;li&gt;Command line. &lt;code&gt;-c&lt;/code&gt; runs in a console, &lt;code&gt;-i&lt;/code&gt; and &lt;code&gt;-r&lt;/code&gt; install and remove the service, &lt;code&gt;-t&lt;/code&gt; and &lt;code&gt;-p&lt;/code&gt; start and stop it, &lt;code&gt;-q&lt;/code&gt; queries it, &lt;code&gt;-d&lt;/code&gt; requests a thread dump. Property overrides on the command line and &lt;code&gt;--&lt;/code&gt; pass-through of application arguments work the same way.&lt;/li&gt;
&lt;li&gt;Service registration. An installed service's ImagePath calls &lt;code&gt;wrapper.exe -s &amp;lt;conf&amp;gt;&lt;/code&gt;, so an existing registration keeps working.&lt;/li&gt;
&lt;li&gt;Log format. Records use the same &lt;code&gt;LPTM&lt;/code&gt; layout, the same column widths and the same &lt;code&gt;SIZE&lt;/code&gt;, &lt;code&gt;WRAPPER&lt;/code&gt; and &lt;code&gt;JVM&lt;/code&gt; roll modes, so scripts that parse &lt;code&gt;wrapper.log&lt;/code&gt; do not need changes.&lt;/li&gt;
&lt;li&gt;Launchers. A configuration that names the original &lt;code&gt;SimpleApp&lt;/code&gt;, &lt;code&gt;StartStopApp&lt;/code&gt; or &lt;code&gt;JarApp&lt;/code&gt; launcher in &lt;code&gt;wrapper.java.mainclass&lt;/code&gt; starts with the equivalent bundled launcher; the log records the substitution.&lt;/li&gt;
&lt;li&gt;Supervision. Start-up, ping and shutdown timeouts, restart throttling, exit-code actions, output filters (restart, shutdown, dump, GC, pause, resume), pause and resume.&lt;/li&gt;
&lt;li&gt;Diagnostics. Thread dumps through &lt;code&gt;-d&lt;/code&gt;, control code 255 or CTRL_BREAK; if the JVM runs with &lt;code&gt;-Xrs&lt;/code&gt;, a &lt;code&gt;jcmd&lt;/code&gt; based thread dump instead. On-demand HPROF heap dumps through &lt;code&gt;--heapdump&lt;/code&gt; or control code 254. Each mechanism is detected separately; an unavailable tool produces an error message, not a restart.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unsupported &lt;code&gt;wrapper.*&lt;/code&gt; properties are reported by name in the log and ignored only when ignoring them is safe. Properties whose name contains &lt;code&gt;password&lt;/code&gt;, &lt;code&gt;secret&lt;/code&gt;, &lt;code&gt;token&lt;/code&gt;, &lt;code&gt;key&lt;/code&gt;, &lt;code&gt;credential&lt;/code&gt; or &lt;code&gt;vault&lt;/code&gt; are redacted from the log and are not sent to the JVM.&lt;/p&gt;

&lt;p&gt;The full property-by-property table is at &lt;a href="https://jayyanez.github.io/java-service-steward/compatibility.html" rel="noopener noreferrer"&gt;https://jayyanez.github.io/java-service-steward/compatibility.html&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is not compatible
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The original &lt;code&gt;wrapper.jar&lt;/code&gt; and &lt;code&gt;wrapper.dll&lt;/code&gt; are not loaded. Java Service Steward only works with its own JAR.&lt;/li&gt;
&lt;li&gt;The original Java API is not implemented. An application that imports it has to switch to the project's &lt;code&gt;Steward&lt;/code&gt; and &lt;code&gt;ServiceListener&lt;/code&gt; classes (start, stop, restart, log, control events, start wait hints). Applications that use one of the launchers without touching the API need no source change.&lt;/li&gt;
&lt;li&gt;No JMX, no named-pipe backend, no syslog.&lt;/li&gt;
&lt;li&gt;Features that exist only in the Standard or Professional editions of the original are not there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built the project without reading the original's source code and without copying its documentation. The interface facts come from the public property and command reference, from my own configuration files and logs, and from observing behaviour from the outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Replace &lt;code&gt;wrapper.exe&lt;/code&gt; and &lt;code&gt;wrapper.jar&lt;/code&gt; in the installation directory.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;wrapper.exe -c wrapper.conf&lt;/code&gt; once in a console and read the warnings about unsupported properties.&lt;/li&gt;
&lt;li&gt;Start the service as usual.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;wrapper.conf&lt;/code&gt; and the service registration stay as they are. Going back is copying the two old files over again.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it is built
&lt;/h2&gt;

&lt;p&gt;The supervisor is a single thread running a &lt;code&gt;crossbeam&lt;/code&gt; &lt;code&gt;select!&lt;/code&gt; loop over the JVM's output, Service Control Manager requests, protocol events from a reader thread and a 50 ms tick for timeouts. Output lines are capped at 64 KiB. The JVM runs in a Job Object with kill-on-close, so if the host process dies, the JVM and its child processes die with it. The control socket is bound to loopback and the JVM has to present a key it receives on its command line before the host accepts lifecycle messages.&lt;/p&gt;

&lt;p&gt;CI runs on Windows with Temurin 8, 21 and 25 and starts real JVMs in the integration tests. Releases are built on GitHub Actions and carry a CycloneDX SBOM and Sigstore provenance attestations, which you can check with &lt;code&gt;gh attestation verify&lt;/code&gt;. The executable is not Authenticode-signed yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;The current version is 0.3.2, so this is pre-1.0. The configuration format, command line, log format and supervision behaviour are meant for production; the Rust and Java APIs may still change between minor versions, and every incompatible change is listed in the changelog.&lt;/p&gt;

&lt;p&gt;If you have a &lt;code&gt;wrapper.conf&lt;/code&gt; that does not behave the same way under Java Service Steward, that is the most useful issue you can open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to get it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Releases (zip with &lt;code&gt;wrapper.exe&lt;/code&gt;, &lt;code&gt;wrapper.jar&lt;/code&gt;, licences and an example configuration): &lt;a href="https://github.com/jayyanez/java-service-steward/releases" rel="noopener noreferrer"&gt;https://github.com/jayyanez/java-service-steward/releases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;crates.io: &lt;a href="https://crates.io/crates/java-service-steward" rel="noopener noreferrer"&gt;https://crates.io/crates/java-service-steward&lt;/a&gt;. &lt;code&gt;cargo install java-service-steward&lt;/code&gt; builds &lt;code&gt;wrapper.exe&lt;/code&gt; from source; &lt;code&gt;wrapper.jar&lt;/code&gt; comes from the release zip or from &lt;code&gt;scripts/build-java-bridge.ps1&lt;/code&gt; with a JDK on &lt;code&gt;PATH&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;winget: the package &lt;code&gt;JayYanez.JavaServiceSteward&lt;/code&gt; has been submitted to the community repository and is waiting for moderator approval. Once it is merged, &lt;code&gt;winget install JayYanez.JavaServiceSteward&lt;/code&gt; unpacks the same two files; installing the service is still &lt;code&gt;wrapper.exe -i wrapper.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Documentation: &lt;a href="https://jayyanez.github.io/java-service-steward/" rel="noopener noreferrer"&gt;https://jayyanez.github.io/java-service-steward/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Repository: &lt;a href="https://github.com/jayyanez/java-service-steward" rel="noopener noreferrer"&gt;https://github.com/jayyanez/java-service-steward&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>opensource</category>
      <category>rust</category>
      <category>software</category>
    </item>
  </channel>
</rss>
