Skip to content

Commit 05ae936

Browse files
committed
Refactor out lazy initialization logic into own helper classes
1 parent 6ca0a1e commit 05ae936

15 files changed

Lines changed: 1441 additions & 481 deletions

config/codenarc/codenarc.groovy

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ ruleset {
3232
ComparisonOfTwoConstants
3333
ComparisonWithSelf {
3434
doNotApplyToClassNames = [
35-
'net.kautler.command.api.AliasAndParameterStringTest'
35+
'net.kautler.command.api.AliasAndParameterStringTest',
36+
'net.kautler.command.util.lazy.LazyReferenceByFunctionTest',
37+
'net.kautler.command.util.lazy.LazyReferenceBySupplierTest',
38+
'net.kautler.command.util.lazy.LazyReferenceTest'
3639
].join(', ')
3740
}
3841
ConstantAssertExpression
@@ -251,7 +254,12 @@ ruleset {
251254
}
252255
SpaceAroundOperator
253256
SpaceBeforeClosingBrace
254-
SpaceBeforeOpeningBrace
257+
SpaceBeforeOpeningBrace {
258+
doNotApplyToClassNames = [
259+
'net.kautler.command.util.lazy.LazyReferenceByFunctionTest$1',
260+
'net.kautler.command.util.lazy.LazyReferenceBySupplierTest$1'
261+
].join(', ')
262+
}
255263
TrailingWhitespace
256264

257265
// rulesets/generic.xml
@@ -295,7 +303,10 @@ ruleset {
295303
ExplicitCallToDivMethod
296304
ExplicitCallToEqualsMethod {
297305
doNotApplyToClassNames = [
298-
'net.kautler.command.api.AliasAndParameterStringTest'
306+
'net.kautler.command.api.AliasAndParameterStringTest',
307+
'net.kautler.command.util.lazy.LazyReferenceByFunctionTest',
308+
'net.kautler.command.util.lazy.LazyReferenceBySupplierTest',
309+
'net.kautler.command.util.lazy.LazyReferenceTest'
299310
].join(', ')
300311
}
301312
ExplicitCallToGetAtMethod

config/spotbugs/spotbugs-exclude.xml

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,21 +91,18 @@
9191
</Match>
9292

9393
<Match>
94+
<Class name="net.kautler.command.util.lazy.LazyReference"/>
95+
<Method name="get" params="java.util.function.Supplier" returns="java.lang.Object"/>
96+
<Bug pattern="MDM_WAIT_WITHOUT_TIMEOUT"/>
97+
</Match>
98+
99+
<Match>
100+
<Class name="net.kautler.command.util.lazy.LazyReference"/>
94101
<Or>
95-
<And>
96-
<Class name="net.kautler.command.api.CommandHandler"/>
97-
<Method name="getExecutorService" params="" returns="java.util.concurrent.ExecutorService"/>
98-
</And>
99-
<And>
100-
<Class name="net.kautler.command.api.prefix.javacord.MentionPrefixProviderJavacord"/>
101-
<Method name="getCommandPrefix" params="org.javacord.api.entity.message.Message" returns="java.lang.String"/>
102-
</And>
103-
<And>
104-
<Class name="net.kautler.command.api.prefix.jda.MentionPrefixProviderJda"/>
105-
<Method name="getCommandPrefix" params="net.dv8tion.jda.api.entities.Message" returns="java.lang.String"/>
106-
</And>
102+
<Method name="equals" params="java.lang.Object" returns="boolean"/>
103+
<Method name="isSet" params="" returns="boolean"/>
107104
</Or>
108-
<Bug pattern="MDM_WAIT_WITHOUT_TIMEOUT"/>
105+
<Bug pattern="OPM_OVERLY_PERMISSIVE_METHOD"/>
109106
</Match>
110107

111108
<Match>

src/main/java/net/kautler/command/api/CommandHandler.java

Lines changed: 8 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019 Björn Kautler
2+
* Copyright 2020 Björn Kautler
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222
import net.kautler.command.api.prefix.PrefixProvider;
2323
import net.kautler.command.api.restriction.Restriction;
2424
import net.kautler.command.restriction.RestrictionLookup;
25+
import net.kautler.command.util.lazy.LazyReferenceBySupplier;
2526
import org.apache.logging.log4j.Logger;
2627

2728
import javax.annotation.PostConstruct;
@@ -38,15 +39,12 @@
3839
import java.util.Map;
3940
import java.util.concurrent.ConcurrentHashMap;
4041
import java.util.concurrent.ExecutorService;
41-
import java.util.concurrent.locks.Lock;
42-
import java.util.concurrent.locks.ReadWriteLock;
43-
import java.util.concurrent.locks.ReentrantReadWriteLock;
42+
import java.util.concurrent.Executors;
4443
import java.util.regex.Matcher;
4544
import java.util.regex.Pattern;
4645

4746
import static java.lang.String.format;
4847
import static java.util.concurrent.CompletableFuture.runAsync;
49-
import static java.util.concurrent.Executors.newCachedThreadPool;
5048
import static java.util.stream.Collectors.joining;
5149
import static java.util.stream.Collectors.toList;
5250
import static java.util.stream.Collectors.toMap;
@@ -118,29 +116,11 @@ public abstract class CommandHandler<M> {
118116
*/
119117
private final RestrictionLookup<M> availableRestrictions = new RestrictionLookup<>();
120118

121-
/**
122-
* A read lock for lazy initialization of the executor service.
123-
*/
124-
private final Lock readLock;
125-
126-
/**
127-
* A write lock for lazy initialization of the executor service.
128-
*/
129-
private final Lock writeLock;
130-
131119
/**
132120
* An executor service for asynchronous command execution.
133121
*/
134-
private ExecutorService executorService;
135-
136-
/**
137-
* Constructs a new command handler.
138-
*/
139-
public CommandHandler() {
140-
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
141-
readLock = readWriteLock.readLock();
142-
writeLock = readWriteLock.writeLock();
143-
}
122+
private final LazyReferenceBySupplier<ExecutorService> executorService =
123+
new LazyReferenceBySupplier<>(Executors::newCachedThreadPool);
144124

145125
/**
146126
* Ensures the implementing command handlers are initialized on startup.
@@ -295,8 +275,8 @@ private void determineProcessors() {
295275
*/
296276
@PreDestroy
297277
private void shutdownExecutorService() {
298-
if (executorService != null) {
299-
executorService.shutdown();
278+
if (executorService.isSet()) {
279+
executorService.get().shutdown();
300280
}
301281
}
302282

@@ -434,40 +414,11 @@ private boolean isCommandAllowed(M message, Command<? super M> command) {
434414
* @param commandExecutor the executor that runs the actual command implementation
435415
*/
436416
protected void executeAsync(M message, Runnable commandExecutor) {
437-
runAsync(commandExecutor, getExecutorService())
417+
runAsync(commandExecutor, executorService.get())
438418
.whenComplete((nothing, throwable) -> {
439419
if (throwable != null) {
440420
logger.error("Exception while executing command asynchronously", throwable);
441421
}
442422
});
443423
}
444-
445-
/**
446-
* Returns the executor service that is used for asynchronous command execution.
447-
*
448-
* @return the executor service that is used for asynchronous command execution
449-
*/
450-
private ExecutorService getExecutorService() {
451-
readLock.lock();
452-
try {
453-
if (executorService == null) {
454-
readLock.unlock();
455-
try {
456-
writeLock.lock();
457-
try {
458-
if (executorService == null) {
459-
executorService = newCachedThreadPool();
460-
}
461-
} finally {
462-
writeLock.unlock();
463-
}
464-
} finally {
465-
readLock.lock();
466-
}
467-
}
468-
return executorService;
469-
} finally {
470-
readLock.unlock();
471-
}
472-
}
473424
}
Lines changed: 6 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019 Björn Kautler
2+
* Copyright 2020 Björn Kautler
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,13 +17,11 @@
1717
package net.kautler.command.api.prefix.javacord;
1818

1919
import net.kautler.command.api.prefix.PrefixProvider;
20+
import net.kautler.command.util.lazy.LazyReferenceByFunction;
2021
import org.javacord.api.entity.message.Message;
2122

2223
import javax.enterprise.context.ApplicationScoped;
2324
import java.util.StringJoiner;
24-
import java.util.concurrent.locks.Lock;
25-
import java.util.concurrent.locks.ReadWriteLock;
26-
import java.util.concurrent.locks.ReentrantReadWriteLock;
2725

2826
import static java.lang.String.format;
2927

@@ -33,53 +31,15 @@
3331
* for example by annotating it with {@link ApplicationScoped @ApplicationScoped}.
3432
*/
3533
public abstract class MentionPrefixProviderJavacord implements PrefixProvider<Message> {
36-
/**
37-
* A read lock for lazy initialization of the prefix string from a message.
38-
*/
39-
private final Lock readLock;
40-
41-
/**
42-
* A write lock for lazy initialization of the prefix string from a message.
43-
*/
44-
private final Lock writeLock;
45-
4634
/**
4735
* The mention string that is used as prefix.
4836
*/
49-
private String prefix;
50-
51-
/**
52-
* Constructs a new mention prefix provider for Javacord.
53-
*/
54-
public MentionPrefixProviderJavacord() {
55-
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
56-
readLock = readWriteLock.readLock();
57-
writeLock = readWriteLock.writeLock();
58-
}
37+
private final LazyReferenceByFunction<Message, String> prefix =
38+
new LazyReferenceByFunction<>(message -> format("%s ", message.getApi().getYourself().getMentionTag()));
5939

6040
@Override
6141
public String getCommandPrefix(Message message) {
62-
readLock.lock();
63-
try {
64-
if (prefix == null) {
65-
readLock.unlock();
66-
try {
67-
writeLock.lock();
68-
try {
69-
if (prefix == null) {
70-
prefix = format("%s ", message.getApi().getYourself().getMentionTag());
71-
}
72-
} finally {
73-
writeLock.unlock();
74-
}
75-
} finally {
76-
readLock.lock();
77-
}
78-
}
79-
return prefix;
80-
} finally {
81-
readLock.unlock();
82-
}
42+
return prefix.get(message);
8343
}
8444

8545
@Override
@@ -90,7 +50,7 @@ public String toString() {
9050
className = clazz.getTypeName().substring(clazz.getPackage().getName().length() + 1);
9151
}
9252
return new StringJoiner(", ", className + "[", "]")
93-
.add("prefix='" + prefix + "'")
53+
.add("prefix=" + prefix)
9454
.toString();
9555
}
9656
}
Lines changed: 6 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019 Björn Kautler
2+
* Copyright 2020 Björn Kautler
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,12 +18,10 @@
1818

1919
import net.dv8tion.jda.api.entities.Message;
2020
import net.kautler.command.api.prefix.PrefixProvider;
21+
import net.kautler.command.util.lazy.LazyReferenceByFunction;
2122

2223
import javax.enterprise.context.ApplicationScoped;
2324
import java.util.StringJoiner;
24-
import java.util.concurrent.locks.Lock;
25-
import java.util.concurrent.locks.ReadWriteLock;
26-
import java.util.concurrent.locks.ReentrantReadWriteLock;
2725

2826
import static java.lang.String.format;
2927

@@ -33,53 +31,15 @@
3331
* for example by annotating it with {@link ApplicationScoped @ApplicationScoped}.
3432
*/
3533
public abstract class MentionPrefixProviderJda implements PrefixProvider<Message> {
36-
/**
37-
* A read lock for lazy initialization of the prefix string from a message.
38-
*/
39-
private final Lock readLock;
40-
41-
/**
42-
* A write lock for lazy initialization of the prefix string from a message.
43-
*/
44-
private final Lock writeLock;
45-
4634
/**
4735
* The mention string that is used as prefix.
4836
*/
49-
private String prefix;
50-
51-
/**
52-
* Constructs a new mention prefix provider for JDA.
53-
*/
54-
public MentionPrefixProviderJda() {
55-
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
56-
readLock = readWriteLock.readLock();
57-
writeLock = readWriteLock.writeLock();
58-
}
37+
private final LazyReferenceByFunction<Message, String> prefix =
38+
new LazyReferenceByFunction<>(message -> format("%s ", message.getJDA().getSelfUser().getAsMention()));
5939

6040
@Override
6141
public String getCommandPrefix(Message message) {
62-
readLock.lock();
63-
try {
64-
if (prefix == null) {
65-
readLock.unlock();
66-
try {
67-
writeLock.lock();
68-
try {
69-
if (prefix == null) {
70-
prefix = format("%s ", message.getJDA().getSelfUser().getAsMention());
71-
}
72-
} finally {
73-
writeLock.unlock();
74-
}
75-
} finally {
76-
readLock.lock();
77-
}
78-
}
79-
return prefix;
80-
} finally {
81-
readLock.unlock();
82-
}
42+
return prefix.get(message);
8343
}
8444

8545
@Override
@@ -90,7 +50,7 @@ public String toString() {
9050
className = clazz.getTypeName().substring(clazz.getPackage().getName().length() + 1);
9151
}
9252
return new StringJoiner(", ", className + "[", "]")
93-
.add("prefix='" + prefix + "'")
53+
.add("prefix=" + prefix)
9454
.toString();
9555
}
9656
}

0 commit comments

Comments
 (0)