Package org.jboss.errai.ioc.rebind.ioc.bootstrapper

Source Code of org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCConfigProcessor$ProcessingDelegate

/*
* Copyright 2013 JBoss, by Red Hat, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jboss.errai.ioc.rebind.ioc.bootstrapper;

import static org.jboss.errai.ioc.rebind.ioc.injector.api.InjectableInstance.getInjectedInstance;
import static org.jboss.errai.ioc.rebind.ioc.injector.api.InjectableInstance.getMethodInjectedInstance;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.util.*;

import javax.enterprise.context.Dependent;
import javax.enterprise.context.NormalScope;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.Stereotype;
import javax.inject.Provider;
import javax.inject.Scope;

import org.jboss.errai.codegen.meta.MetaClass;
import org.jboss.errai.codegen.meta.MetaClassFactory;
import org.jboss.errai.codegen.meta.MetaClassMember;
import org.jboss.errai.codegen.meta.MetaField;
import org.jboss.errai.codegen.meta.MetaMethod;
import org.jboss.errai.codegen.meta.MetaParameter;
import org.jboss.errai.codegen.meta.MetaParameterizedType;
import org.jboss.errai.codegen.meta.MetaType;
import org.jboss.errai.common.metadata.RebindUtils;
import org.jboss.errai.config.rebind.EnvUtil;
import org.jboss.errai.config.util.ClassScanner;
import org.jboss.errai.config.util.ThreadUtil;
import org.jboss.errai.ioc.client.api.ContextualTypeProvider;
import org.jboss.errai.ioc.client.api.EnabledByProperty;
import org.jboss.errai.ioc.client.api.TestMock;
import org.jboss.errai.ioc.client.api.TestOnly;
import org.jboss.errai.ioc.rebind.ioc.extension.AnnotationHandler;
import org.jboss.errai.ioc.rebind.ioc.extension.DependencyControl;
import org.jboss.errai.ioc.rebind.ioc.extension.JSR330AnnotationHandler;
import org.jboss.errai.ioc.rebind.ioc.extension.Rule;
import org.jboss.errai.ioc.rebind.ioc.extension.RuleDef;
import org.jboss.errai.ioc.rebind.ioc.graph.Dependency;
import org.jboss.errai.ioc.rebind.ioc.graph.GraphBuilder;
import org.jboss.errai.ioc.rebind.ioc.graph.GraphSort;
import org.jboss.errai.ioc.rebind.ioc.graph.SortUnit;
import org.jboss.errai.ioc.rebind.ioc.injector.Injector;
import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectableInstance;
import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectionContext;
import org.jboss.errai.ioc.rebind.ioc.injector.api.WiringElementType;

import com.google.gwt.core.ext.TreeLogger.Type;

/**
* The main IOC configuration processor. This class is responsible for scanning the classpath, finding beans,
* reading configuration, and then configuring the IOC code generator to emit the bootstrapper code.
*/
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public class IOCConfigProcessor {
  private final Stack<SortedSet<ProcessingEntry>> processingTasksStack = new Stack<SortedSet<ProcessingEntry>>();
  private final InjectionContext injectionContext;
  private final Set<String> visitedAutoDiscoveredDependentBeans = new HashSet<String>();

  public IOCConfigProcessor(final InjectionContext injectionContext) {
    this.injectionContext = injectionContext;
  }

  public void registerHandler(final Class<? extends Annotation> annotation,
                              final AnnotationHandler handler) {
    registerHandler(annotation, handler, null);
  }

  public void registerHandler(final Class<? extends Annotation> annotation,
                              final AnnotationHandler handler,
                              final List<RuleDef> rules) {

    getProcessingTasksSet().add(new ProcessingEntry(annotation, handler, rules));
  }

  protected SortedSet<ProcessingEntry> getProcessingTasksSet() {
    if (processingTasksStack.isEmpty()) {
      processingTasksStack.push(new TreeSet<ProcessingEntry>());
    }
    return processingTasksStack.peek();
  }

  class DependencyControlImpl implements DependencyControl {
    MetaClass masqueradeClass;
    Stack<SortedSet<ProcessingEntry>> tasksStack;

    DependencyControlImpl(final Stack<SortedSet<ProcessingEntry>> tasksStack) {
      this.tasksStack = tasksStack;
    }

    @Override
    public void masqueradeAs(final MetaClass clazz) {
      masqueradeClass = clazz;
    }

    @Override
    public void notifyDependency(final MetaClass dependentClazz) {
      if (injectionContext.isAnyKnownElementType(dependentClazz)) {
        injectionContext.getGraphBuilder().addDependency(masqueradeClass, Dependency.on(dependentClazz));
      }
      else {
        final DependencyControl control = new DependencyControl() {
          @Override
          public void masqueradeAs(final MetaClass clazz) {
            // can't masquerade.
          }

          @Override
          public void notifyDependency(final MetaClass clazz) {
            if (visitedAutoDiscoveredDependentBeans.contains(clazz.getFullyQualifiedName())) return;
            visitedAutoDiscoveredDependentBeans.add(clazz.getFullyQualifiedName());

            injectionContext.getGraphBuilder().addDependency(dependentClazz, Dependency.on(clazz));
          }

          @Override
          public void notifyDependencies(final Collection<MetaClass> classes) {
            for (final MetaClass clazz : classes) {
              notifyDependency(clazz);
            }
          }
        };

        injectionContext.getGraphBuilder().addDependency(masqueradeClass, Dependency.on(dependentClazz));
        JSR330AnnotationHandler.processDependencies(control, dependentClazz, injectionContext);
      }
    }

    @Override
    public void notifyDependencies(final Collection<MetaClass> classes) {
      for (final MetaClass clazz : classes) {
        notifyDependency(clazz);
      }
    }
  }

  private static boolean checkIfEnabled(MetaClass clazzType) {
    if (clazzType.isAnnotationPresent(EnabledByProperty.class)) {
      final EnabledByProperty enabledByProperty = clazzType.getAnnotation(EnabledByProperty.class);
      final String propertyValue = enabledByProperty.value();
      final boolean negatedTest = enabledByProperty.negated();

      boolean bool = Boolean.parseBoolean(EnvUtil.getEnvironmentConfig().getFrameworkOrSystemProperty(propertyValue));
      if (negatedTest) {
        bool = !bool;
      }
      if (!bool) {
        return false;
      }
    }
    return true;
  }

  @SuppressWarnings("unchecked")
  private void setupHandlers() {
    for (final Map.Entry<WiringElementType, Class<? extends Annotation>> entry
        : injectionContext.getAllElementMappings()) {
      switch (entry.getKey()) {
        case TopLevelProvider:
          registerHandler(entry.getValue(), new JSR330AnnotationHandler() {
            @SuppressWarnings("unchecked")
            @Override
            public void getDependencies(final DependencyControl control,
                                        final InjectableInstance instance,
                                        final Annotation annotation,
                                        final IOCProcessingContext context) {

              final MetaClass providerClassType = instance.getEnclosingType();

              if (!checkIfEnabled(providerClassType)) {
                return;
              }


              final MetaClass MC_Provider = MetaClassFactory.get(Provider.class);
              final MetaClass MC_ContextualTypeProvider = MetaClassFactory.get(ContextualTypeProvider.class);

              MetaClass providerInterface = null;
              final MetaClass providedType;

              if (MC_Provider.isAssignableFrom(providerClassType)) {
                for (final MetaClass interfaceType : providerClassType.getInterfaces()) {
                  if (MC_Provider.equals(interfaceType.getErased())) {
                    providerInterface = interfaceType;
                  }
                }

                if (providerInterface == null) {
                  throw new RuntimeException("top level provider " + providerClassType.getFullyQualifiedName()
                      + " must directly implement " + Provider.class.getName());
                }

                if (providerInterface.getParameterizedType() == null) {
                  throw new RuntimeException("top level provider " + providerClassType.getFullyQualifiedName()
                      + " must use a parameterized " + Provider.class.getName() + " interface type.");
                }

                final MetaType parmType = providerInterface.getParameterizedType().getTypeParameters()[0];
                if (parmType instanceof MetaParameterizedType) {
                  providedType = (MetaClass) ((MetaParameterizedType) parmType).getRawType();
                }
                else {
                  providedType = (MetaClass) parmType;
                }

                injectionContext.registerInjector(
                    injectionContext.getInjectorFactory().getProviderInjector(providedType, providerClassType, injectionContext)
                );
              }
              else if (MC_ContextualTypeProvider.isAssignableFrom(providerClassType)) {
                for (final MetaClass interfaceType : providerClassType.getInterfaces()) {
                  if (MC_ContextualTypeProvider.equals(interfaceType.getErased())) {
                    providerInterface = interfaceType;
                  }
                }

                if (providerInterface == null) {
                  throw new RuntimeException("top level provider " + providerClassType.getFullyQualifiedName()
                      + " must directly implement " + ContextualTypeProvider.class.getName());
                }

                if (providerInterface.getParameterizedType() == null) {
                  throw new RuntimeException("top level provider " + providerClassType.getFullyQualifiedName()
                      + " must use a parameterized " + ContextualTypeProvider.class.getName() + " interface type.");
                }

                final MetaType parmType = providerInterface.getParameterizedType().getTypeParameters()[0];
                if (parmType instanceof MetaParameterizedType) {
                  providedType = (MetaClass) ((MetaParameterizedType) parmType).getRawType();
                }
                else {
                  providedType = (MetaClass) parmType;
                }

                injectionContext.registerInjector(
                    injectionContext.getInjectorFactory()
                        .getContextualProviderInjector(providedType, providerClassType, injectionContext)
                );
              }
              else {
                throw new RuntimeException("top level provider " + providerClassType.getFullyQualifiedName()
                    + " does not implement: " + Provider.class.getName() + " or " + ContextualTypeProvider.class);
              }

              injectionContext.getGraphBuilder().addDependency(providedType, Dependency.on(providerClassType));

              control.masqueradeAs(providedType);
              super.getDependencies(control, instance, annotation, context);
            }

            @Override
            public boolean handle(final InjectableInstance instance,
                                  final Annotation annotation,
                                  final IOCProcessingContext context) {
              final List<Injector> injectors
                  = injectionContext.getInjectors(instance.getElementTypeOrMethodReturnType());
              for (final Injector injector : injectors) {
                if (injector.isEnabled() && injectionContext.isTypeInjectable(injector.getEnclosingType())) {
                  injector.renderProvider(instance);
                }
              }
              return true;
            }
          }, Rule.before(injectionContext.getAnnotationsForElementType(WiringElementType.SingletonBean),
              injectionContext.getAnnotationsForElementType(WiringElementType.DependentBean)));

          break;
      }
    }

    for (final Map.Entry<WiringElementType, Class<? extends Annotation>> entry
        : injectionContext.getAllElementMappings()) {
      switch (entry.getKey()) {
        case ProducerElement:
          registerHandler(entry.getValue(), new JSR330AnnotationHandler() {
            @Override
            public void getDependencies(final DependencyControl control,
                                        final InjectableInstance instance,
                                        final Annotation annotation,
                                        final IOCProcessingContext context) {

              if (!checkIfEnabled(instance.getEnclosingType())) {
                return;
              }

              final MetaClass injectedType = instance.getElementTypeOrMethodReturnType();
              injectionContext.addTopLevelType(injectedType);

              control.masqueradeAs(injectedType);

              final MetaClassMember producerMember;

              control.masqueradeAs(injectedType);

              switch (instance.getTaskType()) {
                case PrivateMethod:
                case Method:
                  producerMember = instance.getMethod();

                  for (final MetaParameter parm : instance.getMethod().getParameters()) {
                    control.notifyDependency(parm.getType());
                    final Set<MetaClass> interfaceTypes = fillInInterface(parm.getType(), context.getGeneratorContext());
                    control.notifyDependencies(interfaceTypes);

                    if (!producerMember.isStatic()) {
                      final GraphBuilder graphBuilder = injectionContext.getGraphBuilder();
                      graphBuilder.addDependency(producerMember.getDeclaringClass(), Dependency.on(parm.getType()));
                      for (MetaClass type : interfaceTypes) {
                        graphBuilder.addDependency(producerMember.getDeclaringClass(), Dependency.on(type));
                      }
                    }
                  }

                  break;
                case PrivateField:
                case Field:
                  producerMember = instance.getField();
                  break;
                default:
                  throw new RuntimeException("illegal producer type");
              }

              final Injector producerInjector = injectionContext.getInjectorFactory()
                  .getProducerInjector(injectedType, producerMember, instance);

              injectionContext.registerInjector(producerInjector);


              if (!producerMember.isStatic()) {
                // if this is a static producer, it does not have a dependency on its parent bean
                injectionContext.getGraphBuilder()
                    .addDependency(injectedType, Dependency.on(instance.getEnclosingType()));
              }
            }

            @Override
            public boolean handle(final InjectableInstance instance,
                                  final Annotation annotation,
                                  final IOCProcessingContext context) {
              final List<Injector> injectors
                  = injectionContext.getInjectors(instance.getElementTypeOrMethodReturnType());
              for (final Injector injector : injectors) {
                if (injector.isEnabled()) {
                  injector.renderProvider(instance);
                }
              }
              return true;
            }

          }, Rule.after(injectionContext.getAnnotationsForElementType(WiringElementType.SingletonBean),
              injectionContext.getAnnotationsForElementType(WiringElementType.DependentBean)));
          break;

        case DependentBean:
          registerHandler(entry.getValue(), new JSR330AnnotationHandler() {
            @Override
            public boolean handle(final InjectableInstance instance,
                                  final Annotation annotation,
                                  final IOCProcessingContext context) {

              final List<Injector> injectors
                  = new ArrayList<Injector>(injectionContext.getInjectors(instance.getEnclosingType()));
              final Injector injector;

              final Iterator<Injector> injectorIterator = injectors.iterator();
              boolean removed = false;
              while (injectorIterator.hasNext()) {
                if (!injectorIterator.next().isEnabled()) {
                  injectorIterator.remove();
                  removed = true;
                }
              }

              if (injectors.isEmpty() && removed) {
                return true;
              }

              if (injectors.size() == 1) {
                injector = injectors.get(0);
              }
              else {
                injector = injectionContext.getInjectorFactory()
                    .getTypeInjector(instance.getEnclosingType(), injectionContext);
              }

              if (injector.isEnabled() && injector.isRegularTypeInjector()) {
                injector.renderProvider(instance);
              }
              return true;
            }
          });
          break;

        case SingletonBean:
          registerHandler(entry.getValue(), new JSR330AnnotationHandler() {
            @Override
            public boolean handle(final InjectableInstance instance,
                                  final Annotation annotation,
                                  final IOCProcessingContext context) {
              final Injector injector = injectionContext.getInjector(instance.getEnclosingType());

              if (injector.isEnabled()) {
                injector.renderProvider(instance);
              }
              return true;
            }
          });
          break;
      }
    }
  }

  @SuppressWarnings({"unchecked"})
  public void process(final IOCProcessingContext context) {
    setupHandlers();

    /**
     * Let's accumulate all the processing tasks.
     */
    do {
      for (final ProcessingEntry entry : processingTasksStack.pop()) {
        final Class<? extends Annotation> annotationClass = entry.annotationClass;
        Target target = annotationClass.getAnnotation(Target.class);

        if (target == null) {
          target = new Target() {
            @Override
            public ElementType[] value() {
              return new ElementType[]
                  {ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD,
                      ElementType.METHOD, ElementType.FIELD};
            }

            @Override
            public Class<? extends Annotation> annotationType() {
              return Target.class;
            }
          };
        }

        for (final ElementType elementType : target.value()) {
          final DependencyControlImpl dependencyControl = new DependencyControlImpl(processingTasksStack);

          switch (elementType) {
            case TYPE: {
              Collection<MetaClass> classes;

              classes = ClassScanner.getTypesAnnotatedWith(annotationClass, context.getPackages(), context.getGeneratorContext());
             
              // Get producer classes which are implicitly dependent
              if (annotationClass.equals(Dependent.class)) {
                classes = new ArrayList<MetaClass>(classes);
                final Collection<MetaClass> toCheck = new ArrayList<MetaClass>();
                for (final MetaMethod method : ClassScanner.getMethodsAnnotatedWith(Produces.class, context.getPackages(),
                    context.getGeneratorContext())) {
                  toCheck.add(method.getDeclaringClass());
                }
                for (final MetaField field : ClassScanner.getFieldsAnnotatedWith(Produces.class, context.getPackages(),
                    context.getGeneratorContext())) {
                  toCheck.add(field.getDeclaringClass());
                }
               
                for (final MetaClass clazz : toCheck) {
                  boolean scoped = false;
                  for (final Annotation anno : clazz.getAnnotations()) {
                    if (anno.annotationType().isAnnotationPresent(Scope.class)
                            || anno.annotationType().isAnnotationPresent(NormalScope.class)) {
                      scoped = true;
                      break;
                    }
                  }
                  if (!scoped) {
                    classes.add(clazz);
                  }
                }
              }

              if (annotationClass.equals(Dependent.class)
                  && Boolean.getBoolean(IOCBootstrapGenerator.EXPERIMENTAL_INFER_DEPENDENT_BY_REACHABILITY)
                  && injectionContext.getAllReachableTypes() != null) {

                System.out.println("******************************************************************************");
                System.out.println("*** EXPERIMENTAL FEATURE ENABLED                                           ***");
                System.out.println("*** You have enabled support for inferred dependent scope by reachability. ***");
                System.out.println("***                                                                        ***");
                System.out.println("*** This feature is designed to allow the @Dependent scope to work         ***");
                System.out.println("*** as per the JSR-299 specification, without imposing the overhead of     ***");
                System.out.println("*** adding all translatable beans to the container -- but rather, just     ***");
                System.out.println("*** those which are reachable within your application.                     ***");
                System.out.println("***                                                                        ***");
                System.out.println("*** This feature is only experimental, and may be removed in a future      ***");
                System.out.println("*** version without notice.                                                ***");
                System.out.println("******************************************************************************");

                classes = new ArrayList<MetaClass>(classes);

                MetaClass metaClass;
                Scan:
                for (final String type : injectionContext.getAllReachableTypes()) {
                  if (type.indexOf('$') != -1) {
                    try {
                      metaClass = MetaClassFactory.get(type);
                    }
                    catch (Throwable t) {
                      continue;
                    }
                  }
                  else {
                    metaClass = MetaClassFactory.get(type);
                  }

                  if (metaClass.isDefaultInstantiable() && metaClass.isPublic() && metaClass.isConcrete()) {
                    for (final Annotation anno : metaClass.getAnnotations()) {
                      if (anno.annotationType().isAnnotationPresent(Scope.class)
                          || anno.annotationType().isAnnotationPresent(NormalScope.class)) {
                        continue Scan;
                      }
                    }

                    classes.add(metaClass);
                  }
                }

                classes = Collections.unmodifiableCollection(classes);
              }

              injectionContext.addTopLevelTypes(classes);

              for (final MetaClass clazz : classes) {
                if (clazz.isAnnotation()) {
                  if (clazz.isAnnotationPresent(Stereotype.class)) {
                    final Class<? extends Annotation> stereoType = clazz.asClass().asSubclass(Annotation.class);
                    for (final MetaClass stereoTypedClass :
                        ClassScanner.getTypesAnnotatedWith(stereoType, context.getGeneratorContext())) {
                      handleType(entry, dependencyControl, stereoTypedClass, annotationClass, context);
                    }
                  }

                  //TODO: recurse and handle stereotypes
                  continue;
                }

                handleType(entry, dependencyControl, clazz, annotationClass, context);
              }
            }
            break;

            case METHOD: {
              for (final MetaMethod method : ClassScanner.getMethodsAnnotatedWith(annotationClass, context.getPackages(),
                  context.getGeneratorContext())) {
                handleMethod(entry, dependencyControl, method, annotationClass, context);
              }
            }
            break;

            case FIELD: {
              for (final MetaField field : ClassScanner.getFieldsAnnotatedWith(annotationClass, context.getPackages(),
                  context.getGeneratorContext())) {
                handleField(entry, dependencyControl, field, annotationClass, context);
              }
            }
          }
        }
      }
    }
    while (!processingTasksStack.isEmpty());

    final List<SortUnit> toSort = injectionContext.getGraphBuilder().build();
    final List<SortUnit> list = GraphSort.sortGraph(toSort);

    ThreadUtil.execute(new Runnable() {
      @Override
      public void run() {
        final File dotFile = new File(RebindUtils.getErraiCacheDir().getAbsolutePath() + "/beangraph.gv");
        RebindUtils.writeStringToFile(dotFile,
            "//\n" +
                "// Generated IOC bean dependency graph in GraphViz DOT format.\n" +
                "//\n\n" +
                GraphBuilder.toDOTRepresentation(list));
      }
    });


    for (final SortUnit unit : list) {
      if (unit.isCyclicGraph()) {
        final Set<String> knownCycles = new HashSet<String>();
        knownCycles.add(unit.getType().getFullyQualifiedName());

        for (final SortUnit dep : unit.getDependencies()) {
          if (dep.isCyclicGraph()) {
            knownCycles.add(dep.getType().getFullyQualifiedName());
          }
        }

        injectionContext.addKnownTypesWithCycles(knownCycles);
      }
    }

    for (final SortUnit unit : list) {
      for (final Object item : unit.getItems()) {
        if (item instanceof ProcessingDelegate) {
          ((ProcessingDelegate) item).process();
        }
      }
    }
  }

  @SuppressWarnings("unchecked")
  private void handleType(final ProcessingEntry entry,
                          final DependencyControl dependencyControl,
                          final MetaClass type,
                          final Class<? extends Annotation> aClass,
                          final IOCProcessingContext context) {

    if (type.getFullyQualifiedName().equals(Object.class.getName())) {
      return;
    }

    final Annotation annotation = type.getAnnotation(aClass);

    dependencyControl.masqueradeAs(type);

    if (!IOCGenerator.isTestMode) {
      if (type.isAnnotationPresent(TestOnly.class) || type.isAnnotationPresent(TestMock.class)) {
        context.treeLogger.log(Type.DEBUG, "Skipping test-only type " + type.getFullyQualifiedName());
        return;
      }
    }
    final InjectableInstance injectableInstance
        = getInjectedInstance(annotation, type, null, injectionContext);

    final ProcessingDelegate del = new ProcessingDelegate() {
      @Override
      public void processDependencies() {
        entry.handler.getDependencies(dependencyControl, injectableInstance, annotation, context);
      }

      @Override
      public boolean process() {
        if (!checkIfEnabled(type)) {
          return false;
        }

        injectionContext.addType(type);

        final List<Injector> injectors = injectionContext.getInjectors(type);
        final Injector injector;

        if (injectors.size() == 1) {
          injector = injectors.get(0);
        }
        else {
          injector = injectionContext.getInjectorFactory().getTypeInjector(type, injectionContext);
        }

        return entry.handler
            .handle(getInjectedInstance(annotation, type, injector, injectionContext), annotation, context);
      }

      @Override
      public String toString() {
        return type.getFullyQualifiedName();
      }
    };

    entry.handler.registerMetadata(injectableInstance, annotation, context);

    del.processDependencies();

    final MetaClass masqueradeClass = ((DependencyControlImpl) dependencyControl).masqueradeClass;

    injectionContext.getGraphBuilder().addItem(masqueradeClass, del);
  }

  @SuppressWarnings("unchecked")
  private void handleMethod(final ProcessingEntry entry,
                            final DependencyControl dependencyControl,
                            final MetaMethod metaMethod,
                            final Class<? extends Annotation> annotationClass,
                            final IOCProcessingContext context) {

    final Annotation annotation = metaMethod.getAnnotation(annotationClass);
    final MetaClass type = metaMethod.getDeclaringClass();

    //final MetaMethod metaMethod = MetaClassFactory.get(method);

    dependencyControl.masqueradeAs(type);

    final InjectableInstance injectableInstance
        = getMethodInjectedInstance(metaMethod, null,
        injectionContext);

    final ProcessingDelegate del = new ProcessingDelegate() {
      @Override
      public void processDependencies() {
        entry.handler.getDependencies(dependencyControl, injectableInstance, annotation, context);
      }

      @Override
      public boolean process() {
        if (!checkIfEnabled(type)) {
          return false;
        }

        injectionContext.addType(type);

        final Injector injector = injectionContext.getInjector(type);
        final InjectableInstance injectableInstance
            = getMethodInjectedInstance(metaMethod, injector,
            injectionContext);

        return entry.handler.handle(injectableInstance, annotation, context);
      }

      @Override
      public String toString() {
        return type.getFullyQualifiedName();
      }
    };

    entry.handler.registerMetadata(injectableInstance, annotation, context);

    del.processDependencies();

    final MetaClass masqueradeClass = ((DependencyControlImpl) dependencyControl).masqueradeClass;

    injectionContext.getGraphBuilder().addItem(masqueradeClass, del);
  }

  private void handleField(final ProcessingEntry entry,
                           final DependencyControl dependencyControl,
                           final MetaField metaField,
                           final Class<? extends Annotation> annotationClass,
                           final IOCProcessingContext context) {

    final Annotation annotation = metaField.getAnnotation(annotationClass);
    final MetaClass type = metaField.getDeclaringClass();

    dependencyControl.masqueradeAs(type);

    final ProcessingDelegate del = new ProcessingDelegate() {
      @SuppressWarnings("unchecked")
      @Override
      public void processDependencies() {

        entry.handler.getDependencies(dependencyControl, InjectableInstance.getFieldInjectedInstance(metaField, null,
            injectionContext), annotation, context);
      }

      @SuppressWarnings("unchecked")
      @Override
      public boolean process() {
        if (!checkIfEnabled(type)) {
          return false;
        }

        injectionContext.addType(type);

        final InjectableInstance injectableInstance
            = InjectableInstance.getFieldInjectedInstance(metaField, injectionContext.getInjector(type),
            injectionContext);

        entry.handler.registerMetadata(injectableInstance, annotation, context);

        return entry.handler.handle(injectableInstance, annotation, context);
      }

      @Override
      public String toString() {
        return type.getFullyQualifiedName();
      }
    };

    del.processDependencies();

    injectionContext.getGraphBuilder().addItem(((DependencyControlImpl) dependencyControl).masqueradeClass, del);
  }

  private class ProcessingEntry implements Comparable<ProcessingEntry> {
    private final Class<? extends Annotation> annotationClass;
    private final AnnotationHandler handler;
    private Set<RuleDef> rules;

    private ProcessingEntry(final Class<? extends Annotation> annotationClass,
                            final AnnotationHandler handler,
                            final List<RuleDef> rule) {

      this.annotationClass = annotationClass;
      this.handler = handler;
      if (rule != null) {
        this.rules = new HashSet<RuleDef>(rule);
      }
    }

    @Override
    public int compareTo(final ProcessingEntry processingEntry) {
      if (rules != null) {
        for (final RuleDef def : rules) {
          if (!def.getRelAnnotation().equals(annotationClass)) {
            continue;
          }

          switch (def.getOrder()) {
            case After:
              return 1;
            case Before:
              return -1;
          }
        }
      }
      else if (processingEntry.rules != null) {
        //noinspection unchecked
        for (final RuleDef def : processingEntry.rules) {
          if (!def.getRelAnnotation().equals(annotationClass)) {
            continue;
          }

          switch (def.getOrder()) {
            case After:
              return -1;
            case Before:
              return 1;
          }
        }
      }

      return -1;
    }

    @Override
    public String toString() {
      return "Scope:" + annotationClass.getName();
    }
  }

  private static interface ProcessingDelegate {
    public boolean process();

    public void processDependencies();
  }
}
TOP

Related Classes of org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCConfigProcessor$ProcessingDelegate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.