Package org.cruxframework.crux.core.ioc

Source Code of org.cruxframework.crux.core.ioc.IocContainerManager

/*
* Copyright 2011 cruxframework.org.
*
* 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.cruxframework.crux.core.ioc;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cruxframework.crux.core.client.controller.Controller;
import org.cruxframework.crux.core.client.datasource.annotation.DataSource;
import org.cruxframework.crux.core.client.ioc.Inject;
import org.cruxframework.crux.core.client.ioc.IoCResource;
import org.cruxframework.crux.core.client.ioc.IoCResource.NoClass;
import org.cruxframework.crux.core.client.ioc.IoCResource.NoProvider;
import org.cruxframework.crux.core.client.screen.DeviceAdaptive.Device;
import org.cruxframework.crux.core.rebind.controller.ClientControllers;
import org.cruxframework.crux.core.rebind.datasource.DataSources;
import org.cruxframework.crux.core.rebind.screen.View;
import org.cruxframework.crux.core.utils.ClassUtils;
import org.cruxframework.crux.scanner.ClassScanner;

/**
* @author Thiago da Rosa de Bustamante
*
*/
public class IocContainerManager
{
  private static final Log logger = LogFactory.getLog(IocContainerManager.class);

  private static boolean initialized = false;
 
  public synchronized static void initialize()
  {
    if (!initialized)
    {
      initialized = true;
      try
      {
        Set<String> configurations =  ClassScanner.searchClassesByInterface(IocConfiguration.class);
        if (configurations != null)
        {
          for (String configurationClassName : configurations)
          {
            Class<?> configurationClass = Class.forName(configurationClassName);
            if (!Modifier.isAbstract(configurationClass.getModifiers()) && IocContainerConfigurations.class.isAssignableFrom(configurationClass))
            {
              IocContainerConfigurations configuration = (IocContainerConfigurations)configurationClass.newInstance();
              if (configuration.isEnabled())
              {
                if (logger.isInfoEnabled())
                {
                  logger.info("Configuring new ioc module ["+configurationClassName+"]...");
                }
                configuration.configure();
              }
            }
          }
        }
       
        configureAnnotatedClasses();
      }
      catch (Exception e)
      {
        logger.error("Error initializing ioc container.", e);
      }
    }
  }

  @SuppressWarnings({ "rawtypes", "unchecked" })
    private static void configureAnnotatedClasses() throws ClassNotFoundException
    {
    Map<String, IocConfig<?>> globalConfigurations = IocContainerConfigurations.getConfigurations();
    Set<String> configurations =  ClassScanner.searchClassesByAnnotation(IoCResource.class);
    if (configurations != null)
    {
      for (String resourceClassName : configurations)
      {
        if (!globalConfigurations.containsKey(resourceClassName))
        {
          Class<?> clazz = Class.forName(resourceClassName);
          IoCResource ioCResource = clazz.getAnnotation(IoCResource.class);
          bindTypeImplicitly(clazz, globalConfigurations);
          IocConfig<?> iocConfig = globalConfigurations.get(resourceClassName);
          if (!ioCResource.bindClass().equals(NoClass.class))
          {
            iocConfig.toClass((Class) ioCResource.bindClass());
          }
          if (!ioCResource.provider().equals(NoProvider.class))
          {
            iocConfig.toProvider((Class)ioCResource.provider());
          }
          iocConfig.runtimeAccessible(ioCResource.runtimeAccessible());
          iocConfig.scope(ioCResource.scope());
        }
      }
    }
    }

  /**
   *
   * @param view
   * @return
   */
  public static Map<String, IocConfig<?>> getConfigurationsForView(View view, Device device)
  {
    //TODO estudar a possibilidade de um cache para essass configuracoes.
   
    if (!initialized)
    {
      initialize();
    }
   
    Map<String, IocConfig<?>> globalConfigurations = IocContainerConfigurations.getConfigurations();
    Map<String, IocConfig<?>> viewConfigurations = new HashMap<String, IocConfig<?>>();
    viewConfigurations.putAll(globalConfigurations);
   
    if (view != null)
    {
      bindImplicityInjectcionsForControllers(view, viewConfigurations, device);
      bindImplicityInjectcionsForDatasources(view, viewConfigurations, device);
    }
   
    return viewConfigurations;
  }
 
  /**
   * @param viewConfigurations
   * @param view
   *
   */
  private static void bindImplicityInjectcionsForControllers(View view, Map<String, IocConfig<?>> viewConfigurations, Device device)
  {
    Iterator<String> controllers = view.iterateControllers();
    while (controllers.hasNext())
    {
      Class<?> controllerClass = ClientControllers.getControllerClass(controllers.next(), device);
      bindImplicityInjectcions(controllerClass, new HashSet<String>(), new HashSet<String>(), true, viewConfigurations);
    }
  }
 
  /**
   * @param viewConfigurations
   * @param view
   *
   */
  private static void bindImplicityInjectcionsForDatasources(View view, Map<String, IocConfig<?>> viewConfigurations, Device device)
  {
    Iterator<String> datasources = view.iterateDataSources();
    while (datasources.hasNext())
    {
      Class<?> controllerClass = DataSources.getDataSourceClass(datasources.next(), device);
      bindImplicityInjectcions(controllerClass, new HashSet<String>(), new HashSet<String>(), true, viewConfigurations);
    }
  }
 
  /**
   *
   * @param type
   * @param added
   * @param path
   */
  private static void bindImplicityInjectcions(Class<?> type, Set<String> added, Set<String> path, boolean iocRootType, Map<String, IocConfig<?>> configurations)
    {
        if (isBindable(type, iocRootType))
        {
          bindImplicityInjectionsForFields(type, added, path, configurations);
          bindImplicityInjectionsForMethods(type, added, path, configurations);
          if (type.getSuperclass() != null)
          {
            bindImplicityInjectcions(type.getSuperclass(), added, path, iocRootType, configurations);
          }
        }
    }

  /**
   *
   * @param type
   * @param added
   * @param path
   * @param configurations
   */
  private static void bindImplicityInjectionsForFields(Class<?> type, Set<String> added, Set<String> path, Map<String, IocConfig<?>> configurations)
    {
      for (Field field : type.getDeclaredFields())
      {
        String fieldName = field.getName();
        if (!added.contains(fieldName))
        {
          added.add(fieldName);
          Class<?> fieldType = field.getType();
          if (isBindable(fieldType, false))
          {
            Inject inject = field.getAnnotation(Inject.class);
            if (inject != null)
            {
              if (path.contains(fieldType.getCanonicalName()))
              {
                throw new IoCException("IoC Create Looping Error between classes ["+type.getCanonicalName()+"] and ["+fieldType.getCanonicalName()+"].");
              }
              Set<String> fieldPath = new HashSet<String>();
              fieldPath.addAll(path);
              fieldPath.add(fieldType.getCanonicalName());
              bindTypeImplicitly(fieldType, configurations);
              bindImplicityInjectcions(fieldType, new HashSet<String>(), fieldPath, false, configurations);
            }
          }
        }
      }
    }

  /**
   *
   * @param type
   * @param added
   * @param path
   * @param configurations
   */
  private static void bindImplicityInjectionsForMethods(Class<?> type, Set<String> added, Set<String> path, Map<String, IocConfig<?>> configurations)
    {
      for (Method method : type.getDeclaredMethods())
      {
        Inject inject = method.getAnnotation(Inject.class);
        Class<?>[] parameterTypes = method.getParameterTypes();
      if (inject != null && !Modifier.isAbstract(method.getModifiers()) && parameterTypes != null && parameterTypes.length > 0)
        {
          if (!added.contains(method.toString()))
          {
            added.add(method.toString());
            for (int i=0; i< parameterTypes.length; i++)
            {
              Class<?> parameterType = parameterTypes[i];
              if (isBindable(parameterType, false))
              {
                if (path.contains(parameterType.getCanonicalName()))
                {
                  throw new IoCException("IoC Create Looping Error between classes ["+type.getCanonicalName()+"] and ["+parameterType.getCanonicalName()+"].");
                }
                Set<String> methodPath = new HashSet<String>();
                methodPath.addAll(path);
                methodPath.add(parameterType.getCanonicalName());
                bindTypeImplicitly(parameterType, configurations);
                bindImplicityInjectcions(parameterType, new HashSet<String>(), methodPath, false, configurations);
              }
            }
          }
        }
      }
    }

  /**
   *
   * @param <T>
   * @param clazz
   * @param configurations
   */
  private static <T> void bindTypeImplicitly(Class<T> clazz, Map<String, IocConfig<?>> configurations)
  {
    String className = clazz.getCanonicalName();
    if (!configurations.containsKey(className))
    {
      IocConfig<T> iocConfig = new IocConfigImpl<T>(clazz);
      configurations.put(className, iocConfig);
    }
  }

 
  /**
   *
   * @param type
   * @return
   */
  private static boolean isBindable(Class<?> type, boolean iocRootType)
    {
      boolean bindable = !ClassUtils.isSimpleType(type);
     
      if (bindable && !iocRootType)
      {
        if (type.getAnnotation(Controller.class) != null || type.getAnnotation(DataSource.class) != null)
        {
          bindable = false;
        }
      }
     
    return bindable;
    }
}
TOP

Related Classes of org.cruxframework.crux.core.ioc.IocContainerManager

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.