Skip to content

Commit

Permalink
Fixes #10 by reverting the change from native Unix Domain Sockets to …
Browse files Browse the repository at this point in the history
…libsysted over JNA.
  • Loading branch information
jpmsilva committed Jul 17, 2023
1 parent cb3dc4b commit abf6f77
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 79 deletions.
4 changes: 2 additions & 2 deletions do-release
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ git checkout master && \
git pull && \
git checkout development && \
git pull && \
"${SCRIPTPATH}"/mvnw jgitflow:release-start -am -pl :jsystemd-core,:jsystemd-spring-boot-starter && \
"${SCRIPTPATH}"/mvnw jgitflow:release-finish -am -pl :jsystemd-core,:jsystemd-spring-boot-starter
"${SCRIPTPATH}"/mvnw jgitflow:release-start -P !sample -am -pl :jsystemd-core,:jsystemd-spring-boot-starter && \
"${SCRIPTPATH}"/mvnw jgitflow:release-finish -P !sample -am -pl :jsystemd-core,:jsystemd-spring-boot-starter
2 changes: 1 addition & 1 deletion do-site-release
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ SCRIPTPATH=$(dirname "$SCRIPT")

set -e

"${SCRIPTPATH}"/mvnw clean package site site:site -am -pl :jsystemd-core,:jsystemd-spring-boot-starter --debug
"${SCRIPTPATH}"/mvnw clean package site site:site -P !sample -am -pl :jsystemd-core,:jsystemd-spring-boot-starter --debug
4 changes: 4 additions & 0 deletions jsystemd-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ limitations under the License.
</description>

<dependencies>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,12 @@

package com.github.jpmsilva.jsystemd;

import static com.github.jpmsilva.jsystemd.SystemdUtilities.hasNotifySocket;
import static com.github.jpmsilva.jsystemd.SystemdUtilities.isLinux;
import static java.lang.invoke.MethodHandles.lookup;
import static java.util.Objects.requireNonNull;
import static org.slf4j.LoggerFactory.getLogger;

import java.io.IOException;
import java.net.StandardProtocolFamily;
import com.sun.jna.Native;
import java.net.UnixDomainSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;

Expand All @@ -41,47 +35,13 @@ public class SystemdNotify {

private static final Logger logger = getLogger(lookup().lookupClass());

private static final SocketChannel channel = createSocketChannel();

private static SocketChannel createSocketChannel() {
if (isLinux() && hasNotifySocket()) {
SocketChannel channel = null;
try {
Path socketPath = SystemdUtilities.notifySocketPath();
if (socketPath.toFile().exists()) {
channel = SocketChannel.open(StandardProtocolFamily.UNIX);
channel.configureBlocking(true);
channel.connect(UnixDomainSocketAddress.of(socketPath));
channel.shutdownInput();
return channel;
} else {
logger.warn("Specified socket path does not exist - systemd integration disabled: " + socketPath);
}
} catch (IOException e) {
if (channel != null) {
try {
channel.close();
} catch (IOException ex) {
e.addSuppressed(ex);
}
}
if (logger.isDebugEnabled()) {
logger.warn("Could not connect to systemd socket", e);
} else {
logger.warn("Could not connect to systemd socket: " + e.getMessage());
}
}
}
return null;
}

/**
* Allows knowing if this library is usable under current execution conditions (operating system type, systemd available, etc...).
*
* @return {@code true} if and only if the library can be used
*/
static boolean usable() {
return channel != null && channel.isConnected();
return Library.initialized;
}

/**
Expand Down Expand Up @@ -151,34 +111,13 @@ static void stopping() {
* @param message the message to send, according to <a href="https://www.freedesktop.org/software/systemd/man/sd_notify.html#Description">specification</a>
*/
private static void invoke(String message) {
requireNonNull(message);
if (usable() && !message.isEmpty()) {
try {
synchronized (requireNonNull(channel)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.clear();
if (message.endsWith("\n")) {
buffer.put(message.getBytes());
} else {
buffer.put((message + "\n").getBytes());
}
buffer.flip();
while (buffer.hasRemaining()) {
channel.write(buffer);
}
}
} catch (IOException e) {
if (logger.isDebugEnabled()) {
logger.warn("Failed to send systemd message " + message, e);
} else {
logger.warn("Failed to send systemd message " + message + ": " + e.getMessage());
}
}
if (usable() && message != null && !message.isEmpty()) {
Library.sd_notify(0, message);
}
}

/**
* Registers a JVM shutdown hook that closes the system integration channel.
* Registers a JVM shutdown hook that closes the systemd integration channel.
*
* @see Runtime#addShutdownHook(Thread)
* @see #close()
Expand All @@ -193,14 +132,25 @@ public static void registerShutdownHook() {
* <p>Normally, the integration channel will be closed when the JVM shuts down.<br>
* However, you may wish of explicitly close the integration channel, to ensure that all closeable resources are effectively closed.<br> As such, this method
* should only be called at most once during the lifecycle of the JVM.
*
* <p>Currenty this does nothing, as currently the only supported integration channel is the native libsystemd library, which does not need any cleanup.
*/
public static void close() {
if (channel != null) {
}

private static class Library {

private static boolean initialized = false;

static {
try {
channel.close();
} catch (IOException ignored) {
// This is a best effort at this point
Native.register("systemd");
initialized = true;
} catch (UnsatisfiedLinkError ignored) {
}
}

@SuppressWarnings({"UnusedReturnValue", "checkstyle:ParameterName"})
public static native int sd_notify(int unset_environment, String state);
}
}
8 changes: 8 additions & 0 deletions jsystemd-spring-boot-sample/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ limitations under the License.

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
Expand Down Expand Up @@ -64,13 +65,17 @@ public class SystemdAutoConfiguration {
}

/**
* Event listener for the {@link ApplicationReadyEvent} event to report to systemd that the service is ready.
* Event listener for the {@link AvailabilityChangeEvent} event to report to systemd that the service is ready.
*
* @param event the {@link ApplicationReadyEvent} received
* <p>The application is considered ready when the event is a {@link ReadinessState} with the state {@link ReadinessState#ACCEPTING_TRAFFIC}.
*
* @param event the {@link AvailabilityChangeEvent} received
*/
@EventListener
public void started(@SuppressWarnings("unused") ApplicationReadyEvent event) {
systemd.ready();
public void started(@SuppressWarnings("unused") AvailabilityChangeEvent<ReadinessState> event) {
if(event.getState() == ReadinessState.ACCEPTING_TRAFFIC) {
systemd.ready();
}
}

@Bean
Expand Down
28 changes: 27 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ limitations under the License.

<dependencyManagement>
<dependencies>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.13.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down Expand Up @@ -268,6 +273,16 @@ limitations under the License.
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${plugin.javadoc.version}</version>
<configuration>
<links>
<link>https://docs.oracle.com/en/java/javase/17/docs/api/</link>
<link>https://docs.spring.io/spring-boot/docs/3.0.0/api/</link>
<link>https://docs.spring.io/spring-framework/docs/6.0.2/javadoc-api/</link>
<link>https://java-native-access.github.io/jna/5.13.0/javadoc/</link>
</links>
<doctitle>${project.name} ${project.version}</doctitle>
<windowtitle>${project.artifactId} ${project.version}</windowtitle>
</configuration>
</plugin>

<plugin>
Expand Down Expand Up @@ -305,6 +320,9 @@ limitations under the License.
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>${plugin.pmd.version}</version>
<configuration>
<xrefLocation></xrefLocation>
</configuration>
</plugin>

<plugin>
Expand Down Expand Up @@ -390,6 +408,15 @@ limitations under the License.
</build>

<profiles>
<profile>
<id>sample</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<modules>
<module>jsystemd-spring-boot-sample</module>
</modules>
</profile>
<profile>
<id>release-profile</id>
<activation>
Expand Down Expand Up @@ -564,7 +591,6 @@ limitations under the License.

<modules>
<module>jsystemd-core</module>
<module>jsystemd-spring-boot-sample</module>
<module>jsystemd-spring-boot-starter</module>
</modules>
</project>
14 changes: 14 additions & 0 deletions src/site/markdown/native-library.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Native library

The integration uses [JNA](https://github.com/java-native-access/jna) (`net.java.dev.jna:jna`) to interface
with [libsystemd](https://github.com/systemd/systemd/tree/master/src/libsystemd) natively.

## Running without JNA

It used to be possible to switch the implementation from JNA with an executable call to the
[systemd-notify](https://www.freedesktop.org/software/systemd/man/systemd-notify.html) program that is bundled with systemd.

However, that method is no longer supported.

For the time being, JNA is the only reliable way to interface with systemd via libsystemd, as the JVM does not
yet [implement proper support for Datagram Channels (SOCK_DGRAM) over Unix Domain Sockets (AF_UNIX)](https://bugs.openjdk.org/browse/JDK-8297837).
1 change: 1 addition & 0 deletions src/site/site.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<item name="Startup progress" href="startup-progress.html"/>
<item name="Startup timeout" href="startup-timeout.html"/>
<item name="Tomcat status" href="tomcat-status.html"/>
<item name="Native library" href="native-library.html"/>
<item name="Conditionals" href="conditionals.html"/>
<item name="API (Javadocs)" href="apidocs/index.html"/>
</menu>
Expand Down

0 comments on commit abf6f77

Please sign in to comment.