001package org.jadira.scanner.core.spi; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.Collections; 006import java.util.List; 007 008import org.jadira.scanner.core.api.Allocator; 009import org.jadira.scanner.core.api.Filter; 010import org.jadira.scanner.core.api.Locator; 011import org.jadira.scanner.core.api.Projector; 012import org.jadira.scanner.core.api.Resolver; 013import org.jadira.scanner.core.concurrent.AllocatorTask; 014import org.jadira.scanner.core.concurrent.FilterTask; 015import org.jadira.scanner.core.concurrent.ProjectorTask; 016 017public abstract class AbstractResolver<T, E, A> implements Resolver<T, E, A> { 018 019 private static final Integer ZERO = Integer.valueOf(0); 020 021 private static final int SEGMENT_SIZE = 500; 022 023 private final List<A> driverData; 024 025 protected AbstractResolver() { 026 this.driverData = new ArrayList<A>(); 027 } 028 029 protected AbstractResolver(List<A> driverData) { 030 this.driverData = driverData; 031 } 032 033 protected List<A> getDriverData() { 034 return driverData; 035 } 036 037 protected List<A> locate(Locator<A> locator) { 038 039 final List<A> result = new ArrayList<A>(); 040 if (driverData != null) { 041 result.addAll(driverData); 042 } 043 final List<A> located = locator == null ? null : locator.locate(); 044 if (located != null) { 045 result.addAll(located); 046 } 047 return result; 048 } 049 050 protected List<E> allocate(List<A> driverData) { 051 052 AllocatorTask<E, A> task = new AllocatorTask<E, A>(getAllocator(), driverData); 053 final List<E> result = task.compute(); 054 055 return result; 056 } 057 058 protected List<E> project(Projector<E> projector, List<E> sourceList) { 059 060 ProjectorTask<E> task = new ProjectorTask<E>(projector, sourceList); 061 List<E> result = task.compute(); 062 063 return result; 064 } 065 066 protected List<T> assign(List<E> sourceList) { 067 068 AllocatorTask<T, E> task = new AllocatorTask<T, E>(getAssigner(), sourceList); 069 List<T> result = task.compute(); 070 071 return result; 072 } 073 074 private <S> List<S> filter(Class<?> sourceType, Integer limit, List<Filter<?>> myFilters, List<S> sourceList) { 075 076 if (ZERO.equals(limit)) { 077 return Collections.emptyList(); 078 } 079 080 List<S> result = sourceList; 081 for (Filter<?> nextFilter : myFilters) { 082 if (nextFilter.targetType().isAssignableFrom(sourceType)) { 083 084 @SuppressWarnings("unchecked") 085 Filter<S> theFilter = (Filter<S>) nextFilter; 086 087 FilterTask<S> task = new FilterTask<S>(limit, theFilter, result); 088 result = task.compute(); 089 } 090 } 091 return result; 092 } 093 094 protected abstract Allocator<E,A> getAllocator(); 095 096 protected abstract Allocator<T,E> getAssigner(); 097 098 @Override 099 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}