Package org.jibeframework.core.service.impl

Source Code of org.jibeframework.core.service.impl.MethodServiceImpl

package org.jibeframework.core.service.impl;

import groovy.lang.GroovyObject;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jibeframework.core.Context;
import org.jibeframework.core.JibeRuntimeException;
import org.jibeframework.core.annotation.UIComponent;
import org.jibeframework.core.annotation.UIController;
import org.jibeframework.core.app.ApplicationInitializedListener;
import org.jibeframework.core.app.config.ConfigMap;
import org.jibeframework.core.app.method.ArgumentsResolver;
import org.jibeframework.core.app.method.BootstrapedMethodNotFoundException;
import org.jibeframework.core.app.method.MethodHolder;
import org.jibeframework.core.service.ConfigService;
import org.jibeframework.core.service.MethodService;
import org.jibeframework.core.ui.Event;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

@Service("jibe.MethodService")
public class MethodServiceImpl implements MethodService, ApplicationInitializedListener, ApplicationContextAware {

  public Map<Class<? extends Annotation>, Map<String, String>> holders = new HashMap<Class<? extends Annotation>, Map<String, String>>();

  @Autowired
  private ArgumentsResolver argumentsResolver;
  @Autowired
  private ConfigService configService;

  public ApplicationContext applicationContext;

  private List<String> annotationClasses = new ArrayList<String>();

  private static final Log logger = LogFactory.getLog(MethodHolder.class);

  public boolean annotatedMethodExists(Class<? extends Annotation> annotation, String id) {
    return holders.get(annotation).containsKey(id);
  }

  public Object invoke(Class<? extends Annotation> annotationClass, String methodId, Object... args) {
    MethodHolder holder = resolveAnnotatedMethodHolder(annotationClass, methodId, args);
    Object retValue = holder.invoke();
    return retValue;
  }

  public Object invoke(String value, Object... args) {
    MethodHolder holder = resolveHolder(value, args);
    Object retValue = holder.invoke();
    return retValue;
  }

  public Collection<String> getAnnotatedMethodNames(Class<? extends Annotation> annotationClass) {
    return holders.get(annotationClass).keySet();
  }

  public Object invokeServiceMethod(String methodId, Object... args) {
    String beanName = StringUtils.substringBeforeLast(methodId, ".");
    String methodName = StringUtils.substringAfterLast(methodId, ".");
    Object bean = applicationContext.getBean(beanName);
    List<Method> candidates = new ArrayList<Method>();
    Method[] methods = bean.getClass().getMethods();
    for (int i = 0; i < methods.length; i++) {
      if (methods[i].getName().equals(methodName)) {
        candidates.add(methods[i]);
      }
    }
    if (candidates.isEmpty()) {
      throw new JibeRuntimeException("Method " + methodId + " could not be found");
    }
    if (candidates.size() == 1) {
      Method method = candidates.get(0);
      return ReflectionUtils.invokeMethod(method, bean, args);
    } else {
      throw new JibeRuntimeException("Overloaded methods are not supported yet");
    }
  }

  private MethodHolder resolveAnnotatedMethodHolder(Class<? extends Annotation> annotationClass, String methodId,
      Object... args) {
    if (holders.containsKey(annotationClass)) {
      if (holders.get(annotationClass).containsKey(methodId)) {
        String methodSignature = holders.get(annotationClass).get(methodId);
        return resolveHolder(methodSignature, args);
      }
    }
    throw new BootstrapedMethodNotFoundException("Boostraped method not found: " + methodId);
  }

  public MethodHolder resolveHolder(String methodId, Object... args) {
    List<MethodHolder> candidates = new ArrayList<MethodHolder>();
    String beanName = StringUtils.substringBeforeLast(methodId, ".");
    String methodName = StringUtils.substringAfterLast(methodId, ".");
    Class<?> userClass = null;
    Context context = Context.getCurrentContext();
    Object bean = null;
    if (context.containsViewBean(beanName)) {
      bean = context.getViewBean(beanName);
      userClass = ((GroovyObject) bean).getMetaClass().getTheClass();
    } else {
      bean = applicationContext.getBean(beanName);
      userClass = ClassUtils.getUserClass(bean.getClass());
    }
    if (AnnotationUtils.findAnnotation(userClass, Controller.class) != null
        || AnnotationUtils.findAnnotation(userClass, UIComponent.class) != null
        || AnnotationUtils.findAnnotation(userClass, UIController.class) != null) {
      Method[] methods = userClass.getMethods();
      for (int i = 0; i < methods.length; i++) {
        if (methods[i].getName().equals(methodName)) {
          Object[] resolvedArguments = argumentsResolver.resolveArguments(methods[i], args);
          candidates.add(new MethodHolder(methodId, bean, methods[i], resolvedArguments));
        }
      }
      if (candidates.isEmpty()) {
        throw new JibeRuntimeException("Method " + methodId + " could not be found");
      }
      Double bestGuess = null;
      MethodHolder bestCandidate = null;
      for (MethodHolder candidate : candidates) {
        double guess = candidate.getQuality();
        if (bestGuess == null || guess > bestGuess) {
          bestGuess = guess;
          bestCandidate = candidate;
        }
      }
      return bestCandidate;
    }
    throw new JibeRuntimeException(
        "It is only possible to invoke methods on classes annotated with @Controller  or @UIComponent annotations: "
            + methodId);
  }

  public void setAnnotationClasses(List<String> annotationClasses) {
    this.annotationClasses = annotationClasses;
  }

  public void onApplicationInitialized() {
    List<String> beanNames = Arrays.asList(applicationContext.getBeanDefinitionNames());
    for (String beanName : beanNames) {
      Object bean = null;
      try {
        bean = applicationContext.getBean(beanName);
      } catch (Exception e) {
        continue;
      }
      Controller controllerAnn = bean.getClass().getAnnotation(Controller.class);
      if (controllerAnn != null) {
        bootstrapObject(beanName, bean, annotationClasses);
      }

    }

  }

  @SuppressWarnings("unchecked")
  private void bootstrapObject(String beanName, Object bean, List<String> classes) {
    Method[] methods = ClassUtils.getUserClass(bean.getClass()).getMethods();
    for (String clazzName : classes) {
      for (Method method : methods) {
        Class<? extends Annotation> clazz;
        try {
          clazz = (Class<? extends Annotation>) Class.forName(clazzName);
        } catch (ClassNotFoundException e1) {
          throw new JibeRuntimeException("Annotation class could not be found: " + clazzName);
        }
        Annotation annotation = method.getAnnotation(clazz);
        if (annotation != null) {
          String id = null;
          try {
            id = (String) annotation.getClass().getMethod("value").invoke(annotation);
          } catch (Exception e) {
            throw new JibeRuntimeException("Annotation does not have value property: "
                + annotation.annotationType().getName());
          }

          if (StringUtils.isEmpty(id)) {
            id = String.format("%1$s.%2$s", beanName, method.getName());
          }
          String methodName = String.format("%1$s.%2$s", beanName, method.getName());
          if (!holders.containsKey(clazz)) {
            holders.put(clazz, new HashMap<String, String>());
          }
          holders.get(clazz).put(id, methodName);
        }
      }
    }
  }

  @SuppressWarnings("unchecked")
  public void fireEvent(Object source, String id, String event, Object... data) {
    ConfigMap handlers = (ConfigMap) configService.getConfig("core.binding");
    Event eventData = new Event(source, data);
    if (handlers.containsKey(id)) {
      Map map = (Map) handlers.get(id);
      if (map.containsKey(event)) {
        invoke((String) map.get(event), eventData);
      }
    }

  }

  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;

  }
}
TOP

Related Classes of org.jibeframework.core.service.impl.MethodServiceImpl

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.