Implementation.java

1
package io.github.gipo999.smispi;
2
3
import java.util.ArrayList;
4
import java.util.Collections;
5
import java.util.HashMap;
6
import java.util.List;
7
import java.util.Map;
8
import java.util.Optional;
9
import java.util.ServiceLoader;
10
import org.slf4j.Logger;
11
12
/** Utility class for loading implementations of services. */
13
public final class Implementation {
14
15
  /** The logger for this class. */
16
  private static final Logger LOGGER = SmiSpi.LOGGER;
17
18
  /** The cache for implementations. */
19
  private static final Map<String, NamedService> CACHE = new HashMap<>();
20
21
  /** The cache for implementations with parameters. */
22
  private static final Map<String, Map<String, NamedService>> PARAMS_CACHE = new HashMap<>();
23
24
  /** The global implementation selector. */
25
  private static ImplementationSelector globalSelector;
26
27
  /** Prevents instantiation of this utility class. */
28
  private Implementation() {}
29
30
  /**
31
   * Sets the global implementation selector.
32
   *
33
   * @param selector the global implementation selector
34
   */
35
  public static void setGlobalSelector(ImplementationSelector selector) {
36
    Implementation.globalSelector = selector;
37
  }
38
39
  /**
40
   * Returns the global implementation selector.
41
   *
42
   * @return the global implementation selector
43
   */
44
  private static ImplementationSelector getGlobalSelector() {
45 1 1. getGlobalSelector : negated conditional → KILLED
    if (globalSelector == null) {
46
      globalSelector = new DefaultImplementationSelector();
47
    }
48
49 1 1. getGlobalSelector : replaced return value with null for io/github/gipo999/smispi/Implementation::getGlobalSelector → KILLED
    return globalSelector;
50
  }
51
52
  /**
53
   * Returns the implementation selector.
54
   *
55
   * @param selector the implementation selector
56
   * @return the implementation selector
57
   */
58
  private static ImplementationSelector getSelector(ImplementationSelector selector) {
59 1 1. getSelector : negated conditional → KILLED
    if (selector != null) {
60 1 1. getSelector : replaced return value with null for io/github/gipo999/smispi/Implementation::getSelector → KILLED
      return selector;
61
    }
62
63 1 1. getSelector : replaced return value with null for io/github/gipo999/smispi/Implementation::getSelector → KILLED
    return getGlobalSelector();
64
  }
65
66
  /**
67
   * Returns the implementation of a service.
68
   *
69
   * @param clazz the class of the service
70
   * @param <T> the type of the service
71
   * @return the implementation of the service
72
   */
73
  public static <T extends NamedService> Optional<T> of(Class<T> clazz) {
74
75 1 1. of : replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::of → KILLED
    return of(clazz, null);
76
  }
77
78
  /**
79
   * Returns the implementation of a service.
80
   *
81
   * @param clazz the class of the service
82
   * @param selector the selector for the implementation
83
   * @param <T> the type of the service
84
   * @return the implementation of the service
85
   */
86
  public static <T extends NamedService> Optional<T> of(
87
      Class<T> clazz, ImplementationSelector selector) {
88
89 1 1. of : replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::of → KILLED
    return of(clazz, selector, null);
90
  }
91
92
  /**
93
   * Returns the implementation of a service.
94
   *
95
   * @param clazz the class of the service
96
   * @param selector the selector for the implementation
97
   * @param params the parameters for the implementation
98
   * @param <T> the type of the service
99
   * @return the implementation of the service
100
   */
101
  @SuppressWarnings("unchecked")
102
  public static <T extends NamedService> Optional<T> of(
103
      Class<T> clazz, ImplementationSelector selector, ImplementationParams params) {
104
105
    Map<String, NamedService> cacheObject;
106
107
    String cacheKey;
108
109
    String className = getClassName(clazz);
110
111 1 1. of : negated conditional → KILLED
    if (params == null) {
112
      cacheObject = CACHE;
113
114
      cacheKey = className;
115
    } else {
116
      cacheKey = params.getCacheKey();
117
118 1 1. lambda$of$0 : replaced return value with Collections.emptyMap for io/github/gipo999/smispi/Implementation::lambda$of$0 → SURVIVED
      cacheObject = PARAMS_CACHE.computeIfAbsent(className, k -> new HashMap<>());
119
    }
120
121 1 1. of : negated conditional → KILLED
    if (cacheObject.containsKey(cacheKey)) {
122
123 1 1. of : replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::of → KILLED
      return Optional.of((T) cacheObject.get(cacheKey));
124
    }
125
126
    Optional<T> selected = ofNew(clazz, selector, params);
127
128 1 1. of : removed call to java/util/Optional::ifPresent → KILLED
    selected.ifPresent(t -> cacheObject.put(cacheKey, t));
129
130 1 1. of : replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::of → KILLED
    return selected;
131
  }
132
133
  /**
134
   * Returns the class name of a service.
135
   *
136
   * @param clazz the class of the service
137
   * @param <T> the type of the service
138
   * @return the class name of the service
139
   */
140
  private static <T extends NamedService> String getClassName(Class<T> clazz) {
141
142 1 1. getClassName : replaced return value with "" for io/github/gipo999/smispi/Implementation::getClassName → KILLED
    return clazz.getCanonicalName();
143
  }
144
145
  /**
146
   * Returns a new implementation of a service.
147
   *
148
   * @param clazz the class of the service
149
   * @param <T> the type of the service
150
   * @return the new implementation of the service
151
   */
152
  public static <T extends NamedService> Optional<T> ofNew(Class<T> clazz) {
153
154 1 1. ofNew : replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::ofNew → KILLED
    return ofNew(clazz, null);
155
  }
156
157
  /**
158
   * Returns a new implementation of a service.
159
   *
160
   * @param clazz the class of the service
161
   * @param selector the selector for the implementation
162
   * @param <T> the type of the service
163
   * @return the new implementation of the service
164
   */
165
  public static <T extends NamedService> Optional<T> ofNew(
166
      Class<T> clazz, ImplementationSelector selector) {
167 1 1. ofNew : replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::ofNew → KILLED
    return ofNew(clazz, selector, null);
168
  }
169
170
  /**
171
   * Returns a new implementation of a service.
172
   *
173
   * @param clazz the class of the service
174
   * @param selector the selector for the implementation
175
   * @param params the parameters for the implementation
176
   * @param <T> the type of the service
177
   * @return the new implementation of the service
178
   */
179
  public static <T extends NamedService> Optional<T> ofNew(
180
      Class<T> clazz, ImplementationSelector selector, ImplementationParams params) {
181
182
    List<T> list = loadList(clazz);
183
184
    Optional<T> selected;
185
186 1 1. ofNew : negated conditional → KILLED
    if (list.isEmpty()) {
187
188
      selected = Optional.empty();
189
    } else {
190
191
      selected = getSelector(selector).choose(clazz, list, Optional.ofNullable(params));
192
    }
193
194
    if (LOGGER.isDebugEnabled()) {
195
196 1 1. ofNew : negated conditional → NO_COVERAGE
      if (selected.isPresent()) {
197
198
        LOGGER.debug(
199
            "Selected implementation is : {}", selected.get().getServiceImplementationName());
200
      } else {
201
202
        LOGGER.warn("No implementation selected for : {}", getClassName(clazz));
203
      }
204
    }
205
206 1 1. ofNew : replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::ofNew → KILLED
    return selected;
207
  }
208
209
  /**
210
   * Loads the implementations of a service.
211
   *
212
   * @param clazz the class of the service
213
   * @param <T> the type of the service
214
   * @return the implementations of the service
215
   */
216
  private static <T extends NamedService> List<T> loadList(Class<T> clazz) {
217
218
    if (LOGGER.isDebugEnabled()) {
219
220
      LOGGER.debug("Loading implementations for class <{}> :", getClassName(clazz));
221
    }
222
223
    final List<T> implementations = new ArrayList<>();
224
225
    final ServiceLoader<? extends T> implementationsLoader = ServiceLoader.load(clazz);
226
227
    for (T impl : implementationsLoader) {
228
229
      implementations.add(impl);
230
231
      if (LOGGER.isDebugEnabled()) {
232
233
        LOGGER.debug("\t{} : {}", impl.getServiceImplementationName(), impl.getClass().getName());
234
      }
235
    }
236
237
    if (LOGGER.isDebugEnabled() && implementations.isEmpty()) {
238
239
      LOGGER.debug("\tNo implementations found.");
240
    }
241
242 1 1. loadList : replaced return value with Collections.emptyList for io/github/gipo999/smispi/Implementation::loadList → KILLED
    return Collections.unmodifiableList(implementations);
243
  }
244
}

Mutations

45

1.1
Location : getGlobalSelector
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testGlobalEmptySelectorWithCache()]
negated conditional → KILLED

49

1.1
Location : getGlobalSelector
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testGlobalEmptySelectorWithCache()]
replaced return value with null for io/github/gipo999/smispi/Implementation::getGlobalSelector → KILLED

59

1.1
Location : getSelector
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testEmptySelectorWithCache()]
negated conditional → KILLED

60

1.1
Location : getSelector
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testEmptySelectorNoCache()]
replaced return value with null for io/github/gipo999/smispi/Implementation::getSelector → KILLED

63

1.1
Location : getSelector
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testGlobalEmptySelectorWithCache()]
replaced return value with null for io/github/gipo999/smispi/Implementation::getSelector → KILLED

75

1.1
Location : of
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testStandardOnlyWithCache()]
replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::of → KILLED

89

1.1
Location : of
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testStandardOnlyWithCache()]
replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::of → KILLED

111

1.1
Location : of
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testNoPresenceWithCache()]
negated conditional → KILLED

118

1.1
Location : lambda$of$0
Killed by : none
replaced return value with Collections.emptyMap for io/github/gipo999/smispi/Implementation::lambda$of$0 → SURVIVED

121

1.1
Location : of
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testNoPresenceWithCache()]
negated conditional → KILLED

123

1.1
Location : of
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testStandardOnlyWithCache()]
replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::of → KILLED

128

1.1
Location : of
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testEmptySelectorWithCache()]
removed call to java/util/Optional::ifPresent → KILLED

130

1.1
Location : of
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testEmptySelectorWithCache()]
replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::of → KILLED

142

1.1
Location : getClassName
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testBothOnlyWithCache()]
replaced return value with "" for io/github/gipo999/smispi/Implementation::getClassName → KILLED

154

1.1
Location : ofNew
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testStandardOnlyNoCache()]
replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::ofNew → KILLED

167

1.1
Location : ofNew
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testStandardOnlyNoCache()]
replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::ofNew → KILLED

186

1.1
Location : ofNew
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testEmptySelectorWithCache()]
negated conditional → KILLED

196

1.1
Location : ofNew
Killed by : none
negated conditional → NO_COVERAGE

206

1.1
Location : ofNew
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testEmptySelectorWithCache()]
replaced return value with Optional.empty for io/github/gipo999/smispi/Implementation::ofNew → KILLED

242

1.1
Location : loadList
Killed by : io.github.gipo999.smispi.ImplementationTest.[engine:junit-jupiter]/[class:io.github.gipo999.smispi.ImplementationTest]/[method:testEmptySelectorWithCache()]
replaced return value with Collections.emptyList for io/github/gipo999/smispi/Implementation::loadList → KILLED

Active mutators

Tests examined


Report generated by PIT 1.15.2