-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="shutDown" name="org.eclipse.jgit.internal.util.CleanupService"> | ||
<implementation class="org.eclipse.jgit.internal.util.CleanupService"/> | ||
</scr:component> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* Copyright (C) 2024, Thomas Wolf <twolf@apache.org> and others | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Distribution License v. 1.0 which is available at | ||
* https://www.eclipse.org/org/documents/edl-v10.php. | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
package org.eclipse.jgit.internal.util; | ||
|
||
/** | ||
* A class that is registered as an OSGi service via the manifest. If JGit runs | ||
* in OSGi, OSGi will instantiate a singleton as soon as the bundle is activated | ||
This comment has been minimized.
Sorry, something went wrong.
laeubi
|
||
* since this class is an immediate OSGi component with no dependencies. OSGi | ||
* will then call its {@link #start()} method. If JGit is not running in OSGi, | ||
* {@link #getInstance()} will lazily create an instance. | ||
* <p> | ||
* An OSGi-created {@link CleanupService} will run the registered cleanup when | ||
* the {@code org.eclipse.jgit} bundle is deactivated. A lazily created instance | ||
* will register the cleanup as a JVM shutdown hook. | ||
* </p> | ||
*/ | ||
public final class CleanupService { | ||
|
||
private static final Object LOCK = new Object(); | ||
|
||
private static CleanupService INSTANCE; | ||
|
||
private final boolean isOsgi; | ||
This comment has been minimized.
Sorry, something went wrong.
laeubi
|
||
|
||
private Runnable cleanup; | ||
|
||
/** | ||
* Public component constructor for OSGi DS. Do <em>not</em> call this | ||
* explicitly! (Unfortunately this constructor must be public because of | ||
* OSGi requirements.) | ||
*/ | ||
public CleanupService() { | ||
this.isOsgi = true; | ||
setInstance(this); | ||
} | ||
|
||
private CleanupService(boolean isOsgi) { | ||
this.isOsgi = isOsgi; | ||
} | ||
|
||
private static void setInstance(CleanupService service) { | ||
synchronized (LOCK) { | ||
INSTANCE = service; | ||
} | ||
} | ||
|
||
/** | ||
* Obtains the singleton instance of the {@link CleanupService} that knows | ||
* whether or not it is running on OSGi. | ||
* | ||
* @return the {@link CleanupService} singleton instance | ||
*/ | ||
public static CleanupService getInstance() { | ||
synchronized (LOCK) { | ||
if (INSTANCE == null) { | ||
INSTANCE = new CleanupService(false); | ||
} | ||
return INSTANCE; | ||
} | ||
} | ||
|
||
void start() { | ||
// Nothing to do | ||
} | ||
|
||
void register(Runnable cleanUp) { | ||
if (isOsgi) { | ||
cleanup = cleanUp; | ||
} else { | ||
try { | ||
Runtime.getRuntime().addShutdownHook(new Thread(cleanUp)); | ||
} catch (IllegalStateException e) { | ||
// Ignore -- the JVM is already shutting down. | ||
} | ||
} | ||
} | ||
|
||
void shutDown() { | ||
if (isOsgi && cleanup != null) { | ||
Runnable r = cleanup; | ||
cleanup = null; | ||
r.run(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,8 +24,12 @@ | |
import org.slf4j.LoggerFactory; | ||
|
||
/** | ||
* A hook registered as a JVM shutdown hook managing a set of objects needing | ||
* cleanup during JVM shutdown. See {@link Runtime#addShutdownHook}. | ||
* The singleton {@link ShutdownHook} provides a means to register | ||
* {@link Listener}s that are run when JGit is uninstalled, either | ||
* <ul> | ||
* <li>in an OSGi framework when this bundle is deactivated, or</li> | ||
* <li>otherwise, when the JVM as a whole shuts down.</li> | ||
* </ul> | ||
*/ | ||
@SuppressWarnings("ImmutableEnumChecker") | ||
public enum ShutdownHook { | ||
|
@@ -35,11 +39,11 @@ public enum ShutdownHook { | |
INSTANCE; | ||
|
||
/** | ||
* Object that needs to cleanup on JVM shutdown. | ||
* Object that needs to cleanup on shutdown. | ||
*/ | ||
public interface Listener { | ||
/** | ||
* Cleanup resources when JVM shuts down, called from JVM shutdown hook. | ||
* Cleanup resources when JGit is shut down. | ||
* <p> | ||
* Implementations should be coded defensively | ||
* <ul> | ||
|
@@ -65,11 +69,7 @@ public interface Listener { | |
private volatile boolean shutdownInProgress; | ||
|
||
private ShutdownHook() { | ||
try { | ||
Runtime.getRuntime().addShutdownHook(new Thread(this::cleanup)); | ||
} catch (IllegalStateException e) { | ||
// ignore - the VM is already shutting down | ||
} | ||
CleanupService.getInstance().register(this::cleanup); | ||
} | ||
|
||
private void cleanup() { | ||
|
@@ -82,9 +82,7 @@ private void cleanup() { | |
}).get(30L, TimeUnit.SECONDS); | ||
} catch (RejectedExecutionException | InterruptedException | ||
| ExecutionException | TimeoutException e) { | ||
// message isn't localized since during shutdown there's no | ||
// guarantee which classes are still loaded | ||
LOG.error("Cleanup during JVM shutdown failed", e); //$NON-NLS-1$ | ||
LOG.error(JGitText.get().shutdownCleanupFailed, e); | ||
This comment has been minimized.
Sorry, something went wrong.
laeubi
|
||
} | ||
runner.shutdownNow(); | ||
} | ||
|
@@ -104,12 +102,12 @@ private void notify(Listener l) { | |
} | ||
|
||
/** | ||
* Register object that needs cleanup during JVM shutdown if it is not | ||
* already registered. Registration is disabled when JVM shutdown is already | ||
* in progress. | ||
* Register object that needs cleanup during JGit shutdown if it is not | ||
* already registered. Registration is disabled when JGit shutdown is | ||
* already in progress. | ||
* | ||
* @param l | ||
* the object to call {@link Listener#onShutdown} on when JVM | ||
* the object to call {@link Listener#onShutdown} on when JGit | ||
* shuts down | ||
* @return {@code true} if this object has been registered | ||
*/ | ||
|
@@ -123,8 +121,8 @@ public boolean register(Listener l) { | |
} | ||
|
||
/** | ||
* Unregister object that no longer needs cleanup during JVM shutdown if it | ||
* is still registered. Unregistration is disabled when JVM shutdown is | ||
* Unregister object that no longer needs cleanup during JGit shutdown if it | ||
* is still registered. Unregistration is disabled when JGit shutdown is | ||
* already in progress. | ||
* | ||
* @param l | ||
|
@@ -142,9 +140,9 @@ public boolean unregister(Listener l) { | |
} | ||
|
||
/** | ||
* Whether a JVM shutdown is in progress | ||
* Whether a JGit shutdown is in progress | ||
* | ||
* @return {@code true} if a JVM shutdown is in progress | ||
* @return {@code true} if a JGit shutdown is in progress | ||
*/ | ||
public boolean isShutdownInProgress() { | ||
return shutdownInProgress; | ||
|
I think this is one of the cases where a
BundleActivator
would be more appropriate than a component: