1 package org.jadira.scanner.core.spi;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collections;
6 import java.util.List;
7
8 import org.jadira.scanner.core.api.Allocator;
9 import org.jadira.scanner.core.api.Filter;
10 import org.jadira.scanner.core.api.Locator;
11 import org.jadira.scanner.core.api.Projector;
12 import org.jadira.scanner.core.api.Resolver;
13 import org.jadira.scanner.core.concurrent.AllocatorTask;
14 import org.jadira.scanner.core.concurrent.FilterTask;
15 import org.jadira.scanner.core.concurrent.ProjectorTask;
16
17 public abstract class AbstractResolver<T, E, A> implements Resolver<T, E, A> {
18
19 private static final Integer ZERO = Integer.valueOf(0);
20
21 private static final int SEGMENT_SIZE = 500;
22
23 private final List<A> driverData;
24
25 protected AbstractResolver() {
26 this.driverData = new ArrayList<A>();
27 }
28
29 protected AbstractResolver(List<A> driverData) {
30 this.driverData = driverData;
31 }
32
33 protected List<A> getDriverData() {
34 return driverData;
35 }
36
37 protected List<A> locate(Locator<A> locator) {
38
39 final List<A> result = new ArrayList<A>();
40 if (driverData != null) {
41 result.addAll(driverData);
42 }
43 final List<A> located = locator == null ? null : locator.locate();
44 if (located != null) {
45 result.addAll(located);
46 }
47 return result;
48 }
49
50 protected List<E> allocate(List<A> driverData) {
51
52 AllocatorTask<E, A> task = new AllocatorTask<E, A>(getAllocator(), driverData);
53 final List<E> result = task.compute();
54
55 return result;
56 }
57
58 protected List<E> project(Projector<E> projector, List<E> sourceList) {
59
60 ProjectorTask<E> task = new ProjectorTask<E>(projector, sourceList);
61 List<E> result = task.compute();
62
63 return result;
64 }
65
66 protected List<T> assign(List<E> sourceList) {
67
68 AllocatorTask<T, E> task = new AllocatorTask<T, E>(getAssigner(), sourceList);
69 List<T> result = task.compute();
70
71 return result;
72 }
73
74 private <S> List<S> filter(Class<?> sourceType, Integer limit, List<Filter<?>> myFilters, List<S> sourceList) {
75
76 if (ZERO.equals(limit)) {
77 return Collections.emptyList();
78 }
79
80 List<S> result = sourceList;
81 for (Filter<?> nextFilter : myFilters) {
82 if (nextFilter.targetType().isAssignableFrom(sourceType)) {
83
84 @SuppressWarnings("unchecked")
85 Filter<S> theFilter = (Filter<S>) nextFilter;
86
87 FilterTask<S> task = new FilterTask<S>(limit, theFilter, result);
88 result = task.compute();
89 }
90 }
91 return result;
92 }
93
94 protected abstract Allocator<E,A> getAllocator();
95
96 protected abstract Allocator<T,E> getAssigner();
97
98 @Override
99 public T resolveFirst(Locator<A> locator, Projector<E> projector, Filter<?>... filters) {
100 List<? extends T> result = resolve(Integer.valueOf(1), locator, projector, filters);
101 return result.isEmpty() ? null : result.get(0);
102 }
103
104 @Override
105 public List<? extends T> resolve(Integer limit, Locator<A> locator, Projector<E> projector, Filter<?>... filters) {
106
107 final List<Filter<?>> myFilters = Arrays.asList(filters);
108
109 final List<A> locatedList = locate(locator);
110 List<E> sourceList = allocate(locatedList);
111
112
113 final List<T> output = new ArrayList<T>();
114
115 sourceList = project(projector, sourceList);
116
117 while (!sourceList.isEmpty()
118 && (limit == null || (output.size() < limit))) {
119
120 List<E> nextSegmentList;
121 if (sourceList.size() <= SEGMENT_SIZE) {
122 nextSegmentList = sourceList;
123 sourceList = Collections.emptyList();
124 } else {
125 nextSegmentList = sourceList.subList(0, SEGMENT_SIZE);
126 sourceList = sourceList.subList(SEGMENT_SIZE, sourceList.size());
127 }
128
129 nextSegmentList = filter(getSourceType(), null, myFilters, nextSegmentList);
130
131 if (!nextSegmentList.isEmpty()) {
132 List<T> targetList = assign(nextSegmentList);
133 targetList = filter(getTargetType(), limit, myFilters, targetList);
134 output.addAll(targetList);
135 }
136 }
137 if (limit == null) {
138 return output;
139 } else {
140 return output.subList(0, output.size() < limit ? output.size() : limit);
141 }
142 }
143
144 @Override
145 public List<? extends T> resolveAll(Locator<A> locator, Projector<E> projector, Filter<?>... filters) {
146 return resolve(null, locator, projector, filters);
147 }
148
149 protected Class<?> getSourceType() {
150 return TypeHelper.getTypeArguments(AbstractResolver.class, this.getClass()).get(1);
151 }
152
153 protected Class<?> getTargetType() {
154 return TypeHelper.getTypeArguments(AbstractResolver.class, this.getClass()).get(0);
155 }
156 }