blob: 29ed7564d382dd73e3b33d75e7bc92eb6cf2cbdd (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/*
* 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;
import org.eclipse.jgit.internal.JGitText;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 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
* 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 Logger LOG = LoggerFactory
.getLogger(CleanupService.class);
private static final Object LOCK = new Object();
private static CleanupService INSTANCE;
private final boolean isOsgi;
private JGitText jgitText;
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 {
// Ensure the JGitText class is loaded. Depending on the framework
// JGit runs in, it may not be possible anymore to load classes when
// the hook runs. For instance when run in a maven plug-in: the
// Plexus class world that loaded JGit may already have been
// disposed by the time the JVM shutdown hook runs when the whole
// maven build terminates.
jgitText = JGitText.get();
assert jgitText != null;
try {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
cleanUp.run();
// Don't catch exceptions; let the JVM do the problem
// reporting.
} finally {
jgitText = null;
}
}));
} catch (IllegalStateException e) {
// Ignore -- the JVM is already shutting down.
}
}
}
void shutDown() {
if (isOsgi && cleanup != null) {
Runnable r = cleanup;
cleanup = null;
try {
r.run();
} catch (RuntimeException e) {
LOG.error(JGitText.get().shutdownCleanupFailed, e);
}
}
}
}
|