package com.noga.njexl.testing.api; import java.lang.reflect.Constructor; import com.noga.njexl.lang.JexlContext; import com.noga.njexl.lang.JexlEngine; import com.noga.njexl.lang.Main; import com.noga.njexl.lang.Script; import com.noga.njexl.lang.internal.logging.Log; import com.noga.njexl.lang.internal.logging.LogFactory; import com.noga.njexl.testing.api.Annotations.*; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * A factory to create service creators */ public final class ServiceCreatorFactory { public static final Log LOG = LogFactory.getLog( ServiceCreatorFactory.class ); /** * A template service creator */ public static abstract class ServiceCreator{ /** * Tries to create an instance of a class * @param clazz the class * @param init a @{NApiServiceInit} metadata * @return one instance if possible * @throws Exception in case fails */ protected abstract Object instantiate(Class clazz, NApiServiceInit init) throws Exception; protected Constructor constructor ; protected NApiServiceInit init ; public ServiceCreator(){ constructor = null; init = null; } protected void findInit(Class clazz){ Constructor[] constructors = clazz.getConstructors(); for ( int i = 0 ; i < constructors.length ; i++ ){ init = Annotations.NApiServiceInit(constructors[i]); if ( init != null ){ constructor = constructors[i]; break; } } } /** * Given a class, creates instance of the class * @param clazz the class * @return one instance of the class, if possible * @throws Exception if fails to do so */ public Object create(Class clazz) throws Exception { findInit(clazz); if ( constructor == null ) throw new Exception("No Constructor with Init Property!"); Object o = instantiate( clazz, init); return o; } } /** * A simple class instance creator - args converted from string */ public static class SimpleCreator extends ServiceCreator{ public SimpleCreator(){} @Override protected Object instantiate(Class clazz, NApiServiceInit init) throws Exception { return createInstance( clazz , init.args() ); } } /** * Create class instance using the spring context */ public static class SpringContextCreator extends ServiceCreator{ protected AutowireCapableBeanFactory beanFactory ; public SpringContextCreator(String[] args) { try { ApplicationContext ctx = new ClassPathXmlApplicationContext(args,true); beanFactory = ctx.getAutowireCapableBeanFactory(); LOG.info(String.format("Bean factory is : %s", beanFactory)); }catch (Exception e){ LOG.error(" No application context found! Thus, I can not use spring context!", e); } } @Override protected Object instantiate(Class clazz, NApiServiceInit init) throws Exception { Object object = null; try { object = beanFactory.getBean(init.bean()); }catch (Exception e){ LOG.info(String.format("No bean [%s] , creating one fully, pray to Spring God!", clazz)); object = beanFactory.createBean(clazz); } LOG.info(String.format("Object is [%s]", object)); return object ; } } /** * Converts the arguments string array into object array * using nJexl - thus every string gets executed as script * @param args the string array * @return an object array */ public static Object[] params(String[] args){ JexlContext context = Main.getContext() ; JexlEngine engine = Main.getJexl(context); Object[] params = new Object[args.length ]; for ( int i = 0 ; i < args.length ; i++ ){ Script s = engine.createScript( args[i]); params[i] = s.execute(context); } return params; } /** * Create instance of a class * @param clazz the class * @param args as strings, nJexl will be used to covert each one to object * @return one instance * @throws Exception if fails */ public static Object createInstance(Class clazz, String[] args) throws Exception { if ( args.length == 0 ){ return clazz.newInstance() ; } Constructor[] constructors = clazz.getConstructors(); for (int i = 0; i < constructors.length; i++) { int c = constructors[i].getParameterCount(); if (c == args.length) { Object[] params = params( args); Object o = constructors[i].newInstance( params ); return o; } } return null; } /** * Gets a service creator from metadata * @param nApiServiceCreator the metadata * @return the service creator */ public static ServiceCreator creator(NApiServiceCreator nApiServiceCreator){ Class type = nApiServiceCreator.type() ; ServiceCreator sc = null; try { sc = (ServiceCreator)createInstance( type, nApiServiceCreator.args() ); }catch (Exception e){ LOG.error( String.format("Error at creating Service Creator!"), e ); } return sc ; } }