View Javadoc
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 		// Chunk the source list to avoid resource starvation
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 }