Skip to content

Package: FinderSupport

FinderSupport

nameinstructionbranchcomplexitylinemethod
FinderSupport()
M: 0 C: 24
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 8
100%
M: 0 C: 1
100%
FinderSupport(FinderSupport, Object)
M: 0 C: 34
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
FinderSupport(String)
M: 22 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
FinderSupport(String, int, int, List, List)
M: 15 C: 24
62%
M: 3 C: 3
50%
M: 3 C: 1
25%
M: 0 C: 1
100%
M: 0 C: 1
100%
checkSubClass()
M: 14 C: 5
26%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 2 C: 3
60%
M: 0 C: 1
100%
clone()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
clone(Object)
M: 6 C: 20
77%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 2 C: 3
60%
M: 0 C: 1
100%
computeNeededResults()
M: 0 C: 55
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 11
100%
M: 0 C: 1
100%
computeResults()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
concat(List, Object)
M: 0 C: 12
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
count()
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
emptyFinder()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
firstResult()
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
from(int)
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getCloneConstructor()
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getContexts()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getSource(Class, Object, Object)
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
max(int)
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
ofType(Class)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
result()
M: 33 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
results()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
sort(Finder.SortCriterion)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
sort(Finder.SortCriterion, Finder.SortDirection)
M: 20 C: 28
58%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 3 C: 3
50%
M: 0 C: 1
100%
static {...}
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
toString()
M: 0 C: 32
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
withContext(Object)
M: 20 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * #%L
3: * *********************************************************************************************************************
4: *
5: * These Foolish Things - Miscellaneous utilities
6: * http://thesefoolishthings.tidalwave.it - git clone git@bitbucket.org:tidalwave/thesefoolishthings-src.git
7: * %%
8: * Copyright (C) 2009 - 2018 Tidalwave s.a.s. (http://tidalwave.it)
9: * %%
10: * *********************************************************************************************************************
11: *
12: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
13: * the License. You may obtain a copy of the License at
14: *
15: * http://www.apache.org/licenses/LICENSE-2.0
16: *
17: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
18: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
19: * specific language governing permissions and limitations under the License.
20: *
21: * *********************************************************************************************************************
22: *
23: * $Id$
24: *
25: * *********************************************************************************************************************
26: * #L%
27: */
28: package it.tidalwave.util.spi;
29:
30: import javax.annotation.Nonnegative;
31: import javax.annotation.Nonnull;
32: import java.lang.reflect.Constructor;
33: import java.util.ArrayList;
34: import java.util.Collections;
35: import java.util.List;
36: import java.util.concurrent.CopyOnWriteArrayList;
37: import it.tidalwave.util.Finder;
38: import it.tidalwave.util.Finder.FilterSortCriterion;
39: import it.tidalwave.util.Finder.SortCriterion;
40: import it.tidalwave.util.Finder.SortDirection;
41: import it.tidalwave.util.NotFoundException;
42: import lombok.AccessLevel;
43: import lombok.AllArgsConstructor;
44: import lombok.Getter;
45: import lombok.ToString;
46: import lombok.extern.slf4j.Slf4j;
47:
48: /***********************************************************************************************************************
49: *
50: * A support class for implementing a {@link Finder}. Subclasses only need to implement the {@link #computeResults()}
51: * method where <i>raw</i> results are retrieved (with raw we mean that they shouldn't be filtered or sorted, as
52: * post-processing will be performed by this class) and a clone constructor.
53: *
54: * If you don't need to extend the {@link Finder} with extra methods, please use the simplified
55: * {@link SimpleFinderSupport}.
56: *
57: * @author Fabrizio Giudici
58: * @version $Id$
59: * @it.tidalwave.javadoc.draft
60: *
61: **********************************************************************************************************************/
62:•@Slf4j @AllArgsConstructor(access = AccessLevel.PRIVATE) @ToString
63: public class FinderSupport<TYPE, EXTENDED_FINDER extends Finder<TYPE>> implements Finder<TYPE>, Cloneable
64: {
65: static class Sorter<Type>
66: {
67: private final FilterSortCriterion<Type> sortCriterion;
68: private final SortDirection sortDirection;
69:
70: public Sorter (final @Nonnull FilterSortCriterion<Type> sortCriterion,
71: final @Nonnull SortDirection sortDirection)
72: {
73: this.sortCriterion = sortCriterion;
74: this.sortDirection = sortDirection;
75: }
76:
77: public void sort (final @Nonnull List<? extends Type> results)
78: {
79: sortCriterion.sort(results, sortDirection);
80: }
81: }
82:
83: private final static String MESSAGE =
84: "Since version 2.0, Implementations of Finder must have a clone constructor such as "
85: + "MyFinder(MyFinder other, Object override). This means that they can't be implemented by anonymous or inner, "
86: + "non static classes. See the javadoc for further information. Could not find constructor: ";
87:
88: @Nonnull
89: private final String name;
90:
91: @Nonnegative
92: private final int firstResult;
93:
94: @Nonnegative
95: private final int maxResults;
96:
97: @Nonnull @Getter(AccessLevel.PROTECTED)
98: private final List<Object> contexts;
99:
100: @Nonnull
101: private final List<Sorter<TYPE>> sorters;
102:
103: private static final int DEFAULT_MAX_RESULTS = Integer.MAX_VALUE;
104:
105: /*******************************************************************************************************************
106: *
107: * Returns an empty {@code Finder}.
108: *
109: * @param <T> the type of the {@code Finder}
110: * @return the empty {@code Finder}
111: *
112: ******************************************************************************************************************/
113: @Nonnull
114: public static <T> Finder<T> emptyFinder()
115: {
116: return new ArrayListFinder<>(Collections.<T>emptyList());
117: }
118:
119: /*******************************************************************************************************************
120: *
121: * Creates an instance with the given name (that will be used for diagnostics).
122: *
123: * @param name the name
124: *
125: ******************************************************************************************************************/
126: protected FinderSupport (final @Nonnull String name)
127: {
128: this.name = name;
129: this.firstResult = 0;
130: this.maxResults = DEFAULT_MAX_RESULTS;
131: this.sorters = new ArrayList<Sorter<TYPE>>();
132: this.contexts = Collections.emptyList();
133: checkSubClass();
134: }
135:
136: /*******************************************************************************************************************
137: *
138: * Default constructor.
139: *
140: ******************************************************************************************************************/
141: protected FinderSupport()
142: {
143: this.name = getClass().getName();
144: this.firstResult = 0;
145: this.maxResults = DEFAULT_MAX_RESULTS;
146: this.sorters = new ArrayList<Sorter<TYPE>>();
147: this.contexts = Collections.emptyList();
148: checkSubClass();
149: }
150:
151: /*******************************************************************************************************************
152: *
153: * Clone constructor for subclasses.
154: *
155: ******************************************************************************************************************/
156: protected FinderSupport (final @Nonnull FinderSupport<TYPE, EXTENDED_FINDER> other, final @Nonnull Object override)
157: {
158: log.trace("FinderSupport({}, {})", other, override);
159: final FinderSupport<TYPE, EXTENDED_FINDER> source = getSource(FinderSupport.class, other, override);
160: this.name = source.name;
161: this.firstResult = source.firstResult;
162: this.maxResults = source.maxResults;
163: this.sorters = source.sorters;
164: this.contexts = source.contexts; // it's always unmodifiable
165: }
166:
167: /*******************************************************************************************************************
168: *
169: *
170: ******************************************************************************************************************/
171: @Nonnull
172: protected static <T> T getSource (final Class<T> clazz, final @Nonnull T other, final @Nonnull Object override)
173: {
174:• return override.getClass().equals(clazz) ? (T)override : other;
175: }
176:
177: /*******************************************************************************************************************
178: *
179: * @deprecated
180: *
181: ******************************************************************************************************************/
182: @Override @Nonnull
183: public final FinderSupport<TYPE, EXTENDED_FINDER> clone()
184: {
185: throw new UnsupportedOperationException("\"FinderSupport.clone() no more supported");
186: }
187:
188: /*******************************************************************************************************************
189: *
190: *
191: ******************************************************************************************************************/
192: @Nonnull
193: protected EXTENDED_FINDER clone (final @Nonnull Object override)
194: {
195: try
196: {
197: final Constructor<? extends FinderSupport> constructor = getCloneConstructor();
198: constructor.setAccessible(true);
199: return (EXTENDED_FINDER)constructor.newInstance(this, override);
200: }
201: catch (Exception e)
202: {
203: throw new RuntimeException(e);
204: }
205: }
206:
207: /*******************************************************************************************************************
208: *
209: * {@inheritDoc}
210: *
211: ******************************************************************************************************************/
212: @Override @Nonnull
213: public EXTENDED_FINDER from (final @Nonnegative int firstResult)
214: {
215: return clone(new FinderSupport<TYPE, EXTENDED_FINDER>(name, firstResult, maxResults, contexts, sorters));
216: }
217:
218: /*******************************************************************************************************************
219: *
220: * {@inheritDoc}
221: *
222: ******************************************************************************************************************/
223: @Override @Nonnull
224: public EXTENDED_FINDER max (final @Nonnegative int maxResults)
225: {
226: return clone(new FinderSupport<TYPE, EXTENDED_FINDER>(name, firstResult, maxResults, contexts, sorters));
227: }
228:
229: /*******************************************************************************************************************
230: *
231: * {@inheritDoc}
232: *
233: ******************************************************************************************************************/
234: @Override @Nonnull
235: public EXTENDED_FINDER withContext (final @Nonnull Object context)
236: {
237: final List<Object> contexts = concat(this.contexts, context);
238: return clone(new FinderSupport<TYPE, EXTENDED_FINDER>(name, firstResult, maxResults, contexts, sorters));
239: }
240:
241: /*******************************************************************************************************************
242: *
243: * {@inheritDoc}
244: *
245: ******************************************************************************************************************/
246: @Override @Nonnull
247: public <ANOTHER_TYPE> Finder<ANOTHER_TYPE> ofType (final @Nonnull Class<ANOTHER_TYPE> type)
248: {
249: throw new UnsupportedOperationException("Must be eventually implemented by subclasses.");
250: }
251:
252: /*******************************************************************************************************************
253: *
254: * {@inheritDoc}
255: *
256: ******************************************************************************************************************/
257: @Override @Nonnull
258: public EXTENDED_FINDER sort (final @Nonnull SortCriterion criterion,
259: final @Nonnull SortDirection direction)
260: {
261:• if (criterion instanceof FilterSortCriterion)
262: {
263: final List<Sorter<TYPE>> sorters = concat(this.sorters,
264: new Sorter<TYPE>((FilterSortCriterion<TYPE>)criterion, direction));
265: return clone(new FinderSupport<TYPE, EXTENDED_FINDER>(name, firstResult, maxResults, contexts, sorters));
266: }
267:
268: final String template = "%s does not implement %s - you need to subclass Finder and override sort()";
269: final String message = String.format(template, criterion, FilterSortCriterion.class);
270: throw new UnsupportedOperationException(message);
271: }
272:
273: /*******************************************************************************************************************
274: *
275: * {@inheritDoc}
276: *
277: ******************************************************************************************************************/
278: @Override @Nonnull
279: public final EXTENDED_FINDER sort (final @Nonnull SortCriterion criterion)
280: {
281: return sort(criterion, SortDirection.ASCENDING);
282: }
283:
284: /*******************************************************************************************************************
285: *
286: * {@inheritDoc}
287: *
288: ******************************************************************************************************************/
289: @Override @Nonnull
290: public TYPE result()
291: throws NotFoundException
292: {
293: final List<? extends TYPE> result = computeNeededResults();
294:
295:• switch (result.size())
296: {
297: case 0:
298: throw new NotFoundException(name);
299:
300: case 1:
301: return result.get(0);
302:
303: default:
304: throw new RuntimeException("More than one result, " + name + ": " + result);
305: }
306: }
307:
308: /*******************************************************************************************************************
309: *
310: * {@inheritDoc}
311: *
312: ******************************************************************************************************************/
313: @Override @Nonnull
314: public TYPE firstResult()
315: throws NotFoundException
316: {
317: return NotFoundException.throwWhenEmpty(computeNeededResults(), "Empty result").get(0);
318: }
319:
320: /*******************************************************************************************************************
321: *
322: * {@inheritDoc}
323: *
324: ******************************************************************************************************************/
325: @Override @Nonnull
326: public List<? extends TYPE> results()
327: {
328: return computeNeededResults();
329: }
330:
331: /*******************************************************************************************************************
332: *
333: * {@inheritDoc}
334: *
335: ******************************************************************************************************************/
336: @Override @Nonnegative
337: public int count()
338: {
339: return computeNeededResults().size();
340: }
341:
342: /*******************************************************************************************************************
343: *
344: * Subclasses can implement this method where *all* the raw results must be actually retrieved.
345: *
346: * @return the unprocessed results
347: *
348: ******************************************************************************************************************/
349: @Nonnull
350: protected List<? extends TYPE> computeResults()
351: {
352: throw new UnsupportedOperationException("You must implement me!");
353: }
354:
355: /*******************************************************************************************************************
356: *
357: * Subclasses can implement this method where *only the requested* raw results must be retrieved.
358: *
359: * @return the unprocessed results
360: *
361: ******************************************************************************************************************/
362: @Nonnull
363: protected List<? extends TYPE> computeNeededResults()
364: {
365: log.trace("computeNeededResults() - {}", this);
366: List<? extends TYPE> results = computeResults();
367:
368: // First sort and then extract the sublist
369:• for (final Sorter<TYPE> sorter : sorters)
370: {
371: log.trace(">>>> sorting with {}...", sorter);
372: sorter.sort(results);
373: }
374:
375: final int toIndex = (int)Math.min(results.size(), (long)firstResult + (long)maxResults);
376:
377:• if (firstResult > toIndex)
378: {
379: return new CopyOnWriteArrayList();
380: }
381:
382: results = results.subList(firstResult, toIndex);
383:
384: return results;
385: }
386:
387: /*******************************************************************************************************************
388: *
389: *
390: ******************************************************************************************************************/
391: @Nonnull
392: private static <T> List<T> concat (final @Nonnull List<T> list, final @Nonnull T item)
393: {
394: final List<T> result = new ArrayList<T>(list);
395: result.add(item);
396: return Collections.unmodifiableList(result);
397: }
398:
399: /*******************************************************************************************************************
400: *
401: *
402: ******************************************************************************************************************/
403: @Nonnull
404: private Constructor<? extends FinderSupport> getCloneConstructor()
405: throws SecurityException, NoSuchMethodException
406: {
407: return getClass().getConstructor(new Class<?>[] { getClass(), Object.class });
408: }
409:
410: /*******************************************************************************************************************
411: *
412: *
413: ******************************************************************************************************************/
414: private void checkSubClass()
415: {
416: try
417: {
418: getCloneConstructor();
419: }
420: catch (SecurityException | NoSuchMethodException e)
421: {
422: throw new ExceptionInInitializerError(MESSAGE + e.getMessage());
423: }
424: }
425: }