package org.jvalue.ods.processor; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.inject.Inject; import org.jvalue.commons.utils.Assert; import org.jvalue.ods.api.processors.ProcessorReference; import org.jvalue.ods.api.processors.ProcessorReferenceChain; import org.jvalue.ods.api.sources.DataSource; import org.jvalue.ods.db.DataRepository; import org.jvalue.ods.processor.adapter.SourceAdapter; import org.jvalue.ods.processor.adapter.SourceAdapterFactory; import org.jvalue.ods.processor.filter.Filter; import org.jvalue.ods.processor.filter.FilterFactory; import org.jvalue.ods.processor.specification.Argument; import org.jvalue.ods.processor.specification.CreationMethod; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public final class ProcessorChainFactory { private final SourceAdapterFactory adapterFactory; private final FilterFactory filterFactory; @Inject public ProcessorChainFactory( SourceAdapterFactory adapterFactory, FilterFactory filterFactory) { this.adapterFactory = adapterFactory; this.filterFactory = filterFactory; } @SuppressWarnings("unchecked") public ProcessorChain createProcessorChain( ProcessorReferenceChain chainReference, DataSource source, DataRepository dataRepository) { Assert.assertNotNull(chainReference, source, dataRepository); SourceAdapter adapter; Filter<ObjectNode, ?> firstFilter = null; Filter<?, ObjectNode> lastFilter = null; Iterator<ProcessorReference> iterator = chainReference.getProcessors().iterator(); adapter = (SourceAdapter) createProcessorFromAnnotation(adapterFactory, SourceAdapterFactory.class, iterator.next(), source, dataRepository); while (iterator.hasNext()) { Filter filter = (Filter) createProcessorFromAnnotation(filterFactory, FilterFactory.class, iterator.next(), source, dataRepository); if (firstFilter == null) { firstFilter = (Filter<ObjectNode, ObjectNode>) filter; lastFilter = (Filter<ObjectNode, ObjectNode>) filter; } else { lastFilter = (Filter<ObjectNode, ObjectNode>) lastFilter.setNextFilter(filter); } } return new ProcessorChain(adapter, firstFilter); } private Object createProcessorFromAnnotation( Object factory, Class<?> factoryClass, // hack as jmockit removed annotations from methods ProcessorReference reference, DataSource dataSource, DataRepository dataRepository) { for (Method method : factoryClass.getDeclaredMethods()) { CreationMethod creationAnnotation = method.getAnnotation(CreationMethod.class); if (creationAnnotation == null) throw new IllegalArgumentException("creation annotation not found"); if (!reference.getName().equals(creationAnnotation.name())) continue; List<Object> arguments = new LinkedList<>(); // add source and repository arguments for (Class<?> parameterType : method.getParameterTypes()) { if (parameterType.equals(DataSource.class)) arguments.add(dataSource); else if (parameterType.equals(DataRepository.class)) arguments.add(dataRepository); } // add custom arguments Annotation[][] allParamAnnotations = method.getParameterAnnotations(); for (Annotation[] paramAnnotations : allParamAnnotations) { for (Annotation annotation : paramAnnotations) { if (annotation instanceof Argument) { Argument arg = (Argument) annotation; arguments.add(reference.getArguments().get(arg.value())); } } } try { return method.invoke(factory, arguments.toArray()); } catch (IllegalAccessException | InvocationTargetException ie) { throw new IllegalStateException(ie); } } throw new IllegalStateException("failed to find creation method for name " + reference.getName()); } }