CleanableMessagingService.java

1
package fr.sii.ogham.core.service;
2
3
import java.io.Closeable;
4
import java.io.IOException;
5
6
import org.slf4j.Logger;
7
import org.slf4j.LoggerFactory;
8
9
import fr.sii.ogham.core.builder.registry.CleanableRegistry;
10
import fr.sii.ogham.core.clean.Cleanable;
11
import fr.sii.ogham.core.exception.MessagingException;
12
import fr.sii.ogham.core.exception.clean.CleanException;
13
import fr.sii.ogham.core.exception.clean.CloseException;
14
import fr.sii.ogham.core.message.Message;
15
16
/**
17
 * Service that decorated the regular service to also provide the possibility to
18
 * clean resources.
19
 * 
20
 * <p>
21
 * Usually, the {@link MessagingService} in instantiated once per application
22
 * and is closed when the application exists. But for any reason, a developer
23
 * may want to create a new service several times. For example, he may create a
24
 * new service everytime a message has to be sent (even if it is less efficient,
25
 * we are not here to make judgments). In this case, the previously created
26
 * service may need to be destroyed and all associated resources should be
27
 * cleaned up.
28
 * 
29
 * This service provides three ways to do some cleanup: manually, using
30
 * auto-close behavior using try-with-resource or automatically before garbage
31
 * collection (<strong>/!\ Read information below to understand the
32
 * risks</strong>).
33
 * 
34
 * <p>
35
 * This service implements {@link Cleanable} interface to provide a way to
36
 * manually clean resources (by explicitly calling {@link #clean()} method).
37
 * 
38
 * <p>
39
 * This service also implements {@link Closeable} interface to automatically
40
 * cleanup resources using the try-with-resource capabilities:
41
 * 
42
 * <pre>
43
 * {@code
44
 *  try (CleanableMessagingService service = (CleanableMessagingService) builder.build()) {
45
 *  	service.send(new Email());
46
 *  } 
47
 * }
48
 * </pre>
49
 * 
50
 * In Spring environment, the {@link #close()} is automatically called when the
51
 * enclosing ApplicationContext is closed.
52
 * 
53
 * <p>
54
 * This service also overrides the {@code finalize()} method so that if the
55
 * service is garbage collected (no more references on the service instance),
56
 * all resources are automatically cleaned. The purpose is to provide an easy to
57
 * use service that tries to do some cleanup even if the developer forgets to do
58
 * so.
59
 * 
60
 * <strong>However, be careful as stated by Sonar: The {@code Object.finalize()}
61
 * method is called on an object by the garbage collector when it determines
62
 * that there are no more references to the object. But there is absolutely no
63
 * warranty that this method will be called AS SOON AS the last references to
64
 * the object are removed. It can be few microseconds to few minutes later. So
65
 * when system resources need to be disposed by an object, it's better to not
66
 * rely on this asynchronous mechanism to dispose them.</strong>
67
 * 
68
 * <p>
69
 * The cleanup of resources happens only once per {@link Cleanable}. It means
70
 * that if the developer explicitly calls {@link #clean()}, all resources are
71
 * cleaned up and then if service is garbage collected, the resources are not
72
 * cleaned a second time.
73
 * 
74
 * 
75
 * @author Aurélien Baudet
76
 * @see Cleanable
77
 * @see CleanableRegistry
78
 * @see AutoCloseable
79
 * @see "https://www.javaworld.com/article/2076697/object-finalization-and-cleanup.html"
80
 *
81
 */
82
public class CleanableMessagingService implements MessagingService, Cleanable, Closeable {
83
	private static final Logger LOG = LoggerFactory.getLogger(CleanableMessagingService.class);
84
85
	private final MessagingService delegate;
86
	private final Cleanable cleaner;
87
88
	/**
89
	 * Wraps the service and delegates cleaning operations to a dedicated
90
	 * implementation.
91
	 * 
92
	 * @param delegate
93
	 *            the wrapped service
94
	 * @param cleaner
95
	 *            the implementation that will really do some cleanup
96
	 */
97
	public CleanableMessagingService(MessagingService delegate, Cleanable cleaner) {
98
		super();
99
		this.delegate = delegate;
100
		this.cleaner = cleaner;
101
	}
102
103
	@Override
104
	public void send(Message message) throws MessagingException {
105 7 1. send : removed call to fr/sii/ogham/core/service/MessagingService::send → NO_COVERAGE
2. send : removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED
3. send : removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED
4. send : removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED
5. send : removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED
6. send : removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED
7. send : removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED
		delegate.send(message);
106
	}
107
108
	@Override
109
	public void clean() throws CleanException {
110
		LOG.info("Manually cleaning all resources...");
111 2 1. clean : removed call to fr/sii/ogham/core/clean/Cleanable::clean → NO_COVERAGE
2. clean : removed call to fr/sii/ogham/core/clean/Cleanable::clean → KILLED
		cleaner.clean();
112
		LOG.info("Manually cleaned");
113
	}
114
115
	@Override
116
	public void close() throws IOException {
117
		try {
118
			LOG.info("Automatically closing all resources...");
119 3 1. close : removed call to fr/sii/ogham/core/clean/Cleanable::clean → SURVIVED
2. close : removed call to fr/sii/ogham/core/clean/Cleanable::clean → NO_COVERAGE
3. close : removed call to fr/sii/ogham/core/clean/Cleanable::clean → KILLED
			cleaner.clean();
120
			LOG.info("Automatically closed");
121
		} catch (CleanException e) {
122
			throw new CloseException("Failed to close resources", e);
123
		}
124
	}
125
126
	@Override
127
	@SuppressWarnings("squid:ObjectFinalizeOverridenCheck") // This is
128
															// intentional for
129
															// automatic cleanup
130
															// if developer
131
															// forgets it
132
	protected void finalize() throws Throwable {
133
		try {
134
			LOG.info("Automatically cleaning all resources...");
135 3 1. finalize : removed call to fr/sii/ogham/core/clean/Cleanable::clean → SURVIVED
2. finalize : removed call to fr/sii/ogham/core/clean/Cleanable::clean → NO_COVERAGE
3. finalize : removed call to fr/sii/ogham/core/clean/Cleanable::clean → SURVIVED
			cleaner.clean();
136
			LOG.info("Automatically cleaned");
137
		} finally {
138 3 1. finalize : removed call to java/lang/Object::finalize → SURVIVED
2. finalize : removed call to java/lang/Object::finalize → NO_COVERAGE
3. finalize : removed call to java/lang/Object::finalize → SURVIVED
			super.finalize();
139
		}
140
	}
141
142
}

Mutations

105

1.1
Location : send
Killed by : oghamall.it.configuration.EmptyBuilderTest.unconfiguredServiceCantSendSms(oghamall.it.configuration.EmptyBuilderTest)
removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED

2.2
Location : send
Killed by : oghamspringbootv1autoconfigure.it.SpringWebBeanResolutionTest.smsUsingThymeleafTemplateShouldResolveBeansAndUrls(oghamspringbootv1autoconfigure.it.SpringWebBeanResolutionTest)
removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED

3.3
Location : send
Killed by : oghamcore.it.core.sender.AutoRetryTest.smsSentSuccessfullyOnFirstExecution(oghamcore.it.core.sender.AutoRetryTest)
removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED

4.4
Location : send
Killed by : oghamjavamail.it.builder.JavaMailCustomConfigurationTest.noHostDefinedShouldFail(oghamjavamail.it.builder.JavaMailCustomConfigurationTest)
removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED

5.5
Location : send
Killed by : none
removed call to fr/sii/ogham/core/service/MessagingService::send → NO_COVERAGE

6.6
Location : send
Killed by : oghamcloudhopper.it.AutoRetryExtensionTest.smsNotRetriedDueToCloudhopperError(oghamcloudhopper.it.AutoRetryExtensionTest)
removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED

7.7
Location : send
Killed by : oghamspringbootv2autoconfigure.it.SpringWebBeanResolutionTest.smsUsingThymeleafTemplateShouldResolveBeansAndUrls(oghamspringbootv2autoconfigure.it.SpringWebBeanResolutionTest)
removed call to fr/sii/ogham/core/service/MessagingService::send → KILLED

111

1.1
Location : clean
Killed by : none
removed call to fr/sii/ogham/core/clean/Cleanable::clean → NO_COVERAGE

2.2
Location : clean
Killed by : oghamcore.it.core.service.CleanupTest.manualCleanupShouldAutomaticallyCleanTheSenders(oghamcore.it.core.service.CleanupTest)
removed call to fr/sii/ogham/core/clean/Cleanable::clean → KILLED

119

1.1
Location : close
Killed by : none
removed call to fr/sii/ogham/core/clean/Cleanable::clean → SURVIVED

2.2
Location : close
Killed by : oghamcore.it.core.service.CleanupTest.tryWithResourceShouldAutomaticallyCleanTheSenders(oghamcore.it.core.service.CleanupTest)
removed call to fr/sii/ogham/core/clean/Cleanable::clean → KILLED

3.3
Location : close
Killed by : none
removed call to fr/sii/ogham/core/clean/Cleanable::clean → NO_COVERAGE

135

1.1
Location : finalize
Killed by : none
removed call to fr/sii/ogham/core/clean/Cleanable::clean → SURVIVED

2.2
Location : finalize
Killed by : none
removed call to fr/sii/ogham/core/clean/Cleanable::clean → NO_COVERAGE

3.3
Location : finalize
Killed by : none
removed call to fr/sii/ogham/core/clean/Cleanable::clean → SURVIVED

138

1.1
Location : finalize
Killed by : none
removed call to java/lang/Object::finalize → SURVIVED

2.2
Location : finalize
Killed by : none
removed call to java/lang/Object::finalize → NO_COVERAGE

3.3
Location : finalize
Killed by : none
removed call to java/lang/Object::finalize → SURVIVED

Active mutators

Tests examined


Report generated by PIT OGHAM