├── src ├── test │ └── java │ │ └── com │ │ └── jenkov │ │ └── container │ │ ├── SingletonTestProduct.java │ │ ├── ISomeInterface.java │ │ ├── MyOtherFactory.java │ │ ├── TestSwitch.java │ │ ├── ICustomFactory.java │ │ ├── script │ │ ├── MathMaxTest.java │ │ ├── CharsetTest.java │ │ ├── SomeFactoryProduct.java │ │ ├── TestThread.java │ │ ├── LocalizedResourceFactoryTest.java │ │ ├── FieldGenericTypeTest.java │ │ ├── GlobalNewInstanceTest.java │ │ ├── InjectThreadLocalTest.java │ │ ├── ParameterCastingTest.java │ │ ├── PropertyStyleConfigTest.java │ │ ├── Bugs.java │ │ ├── ResourceTest.java │ │ ├── MapFactoryTest.java │ │ ├── GlobalSingletonTest.java │ │ ├── ScriptTokenizerInputBufferTest.java │ │ ├── FactoryFactoryTest.java │ │ ├── ParserInput2Test.java │ │ ├── GlobalFlyweightTest.java │ │ ├── MethodFactoryTest.java │ │ ├── ScriptTokenizer2Test.java │ │ ├── GlobalThreadSingletonTest.java │ │ └── CollectionFactoryTest.java │ │ ├── TestProductCasting.java │ │ ├── UnitTestExamples.java │ │ ├── performance │ │ ├── PerformanceTest.java │ │ └── PerformanceTest2.java │ │ ├── java │ │ └── JavaFactoryBuilderTest.java │ │ ├── ContainerTest.java │ │ └── TestProduct.java └── main │ └── java │ └── com │ └── jenkov │ └── container │ ├── script │ ├── ParserMark.java │ ├── ParserException.java │ ├── ObjectPool.java │ ├── ParserError.java │ ├── TokenPool.java │ ├── ParserInput.java │ ├── ScriptTokenizerInputBuffer.java │ └── Token.java │ ├── java │ ├── Factory.java │ ├── JavaFactory.java │ └── JavaFactoryBuilder.java │ ├── itf │ └── factory │ │ ├── FactoryException.java │ │ ├── ILocalFactory.java │ │ └── IGlobalFactory.java │ ├── impl │ └── factory │ │ ├── LocalFactoryBase.java │ │ ├── convert │ │ ├── IntegerFactory.java │ │ ├── CharFactory.java │ │ ├── ByteFactory.java │ │ ├── IntFactory.java │ │ ├── LongFactory.java │ │ ├── FloatFactory.java │ │ ├── ShortFactory.java │ │ ├── ByteObjectFactory.java │ │ ├── DoubleFactory.java │ │ ├── LongObjectFactory.java │ │ ├── FloatObjectFactory.java │ │ ├── ShortObjectFactory.java │ │ ├── BooleanFactory.java │ │ ├── CharacterFactory.java │ │ ├── BooleanObjectFactory.java │ │ ├── DoubleObjectFactory.java │ │ └── UrlFactory.java │ │ ├── LocalProductConsumerFactory.java │ │ ├── ValueFactory.java │ │ ├── GlobalSingletonFactory.java │ │ ├── GlobalNewInstanceFactory.java │ │ ├── LocalProductProducerFactory.java │ │ ├── LocalSingletonFactory.java │ │ ├── LocalFlyweightFactory.java │ │ ├── LocalThreadSingletonFactory.java │ │ ├── LocalizedResourceFactory.java │ │ ├── GlobalFactoryProxy.java │ │ ├── FlyweightKey.java │ │ ├── InputAdaptingFactory.java │ │ ├── FactoryInterfaceAdapter.java │ │ ├── GlobalThreadSingletonFactory.java │ │ ├── FieldFactory.java │ │ ├── GlobalFlyweightFactory.java │ │ ├── InputConsumerFactory.java │ │ ├── MapFactory.java │ │ ├── ConstructorFactory.java │ │ ├── FactoryFactory.java │ │ ├── StaticMethodFactory.java │ │ ├── FieldAssignmentFactory.java │ │ ├── InstanceMethodFactory.java │ │ ├── CollectionFactory.java │ │ ├── GlobalFactoryBase.java │ │ └── MethodFactory.java │ ├── resources │ └── Resources.java │ ├── Container.java │ ├── ContainerException.java │ └── IContainer.java ├── README.md ├── pom.xml └── test-config.script /src/test/java/com/jenkov/container/SingletonTestProduct.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | /** 4 | 5 | */ 6 | public class SingletonTestProduct { 7 | 8 | 9 | public static void doInit(){ 10 | System.out.println("Init executed"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/script/ParserMark.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | /** 4 | 5 | */ 6 | public class ParserMark { 7 | public int markIndex = 0; // relative to factory start index 8 | public int lineNo = 0; 9 | public int charNo = 0; 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/ISomeInterface.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | /** 4 | This interface is used to test mock testing inside the container, to see if a mock 5 | can be created from this interface. 6 | */ 7 | public interface ISomeInterface { 8 | 9 | public String sayHello(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # butterfly-di-container 2 | Butterfly Dependency Injection Container 3 | 4 | Butterly Container is a lightweight DI container for Java. It is mature, 5 | well tested, flexible, feature rich and fast. 6 | 7 | The documentation for Butterfly Container is available here: 8 | 9 | http://tutorials.jenkov.com/butterfly-container/index.html 10 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/java/Factory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.java; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.FIELD) 13 | public @interface Factory { 14 | String value(); 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/MyOtherFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | import com.jenkov.container.java.JavaFactory; 4 | import com.jenkov.container.itf.factory.IGlobalFactory; 5 | 6 | /** 7 | 8 | */ 9 | public class MyOtherFactory extends JavaFactory { 10 | 11 | public IGlobalFactory test = null; 12 | public String instance(Object ... parameters) { 13 | return "test2" + test.instance(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/TestSwitch.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | /** 4 | 5 | */ 6 | public class TestSwitch { 7 | 8 | public static void main(String[] args) { 9 | char aChar = '{'; 10 | 11 | switch(aChar){ 12 | case '&' : case '5' : System.out.println("Yes!"); break; 13 | case 'b' : case '}' :System.out.println("No!"); break; 14 | default : System.out.println("default"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/ICustomFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | /** 4 | This interface is used to test custom factory interface adaptation. 5 | */ 6 | public interface ICustomFactory { 7 | 8 | public String instance(); 9 | public String instance(String parameter); 10 | 11 | public String bean(); 12 | public String bean(String parameter); 13 | 14 | public String beanInstance(); 15 | public String beanInstance(String parameter); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/itf/factory/FactoryException.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.itf.factory; 2 | 3 | import com.jenkov.container.ContainerException; 4 | 5 | /** 6 | 7 | */ 8 | public class FactoryException extends ContainerException { 9 | public FactoryException(String errorContext, String errorCode, String errorMessage) { 10 | super(errorContext, errorCode, errorMessage); 11 | } 12 | 13 | public FactoryException(String errorContext, String errorCode, String errorMessage, Throwable cause) { 14 | super(errorContext, errorCode, errorMessage, cause); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/LocalFactoryBase.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | /** 6 | Extend this factory when implementing custom factories. Extending this class will reduce the risk of 7 | a faulty implementation. Since the class is abstract the compiler will help spotting wrong 8 | implementations. 9 | */ 10 | public abstract class LocalFactoryBase implements ILocalFactory { 11 | 12 | public abstract Class getReturnType(); 13 | 14 | public abstract Object instance(Object[] parameters, Object[] localProducts); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/script/ParserException.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import com.jenkov.container.ContainerException; 4 | 5 | /** 6 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 7 | */ 8 | public class ParserException extends ContainerException { 9 | 10 | public ParserException(String errorContext, String errorCode, String errorMessage) { 11 | super(errorContext, errorCode, errorMessage); 12 | } 13 | 14 | public ParserException(String errorContext, String errorCode, String errorMessage, Throwable cause) { 15 | super(errorContext, errorCode, errorMessage, cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/MathMaxTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | 7 | /** 8 | 9 | */ 10 | public class MathMaxTest extends TestCase{ 11 | 12 | public void test(){ 13 | IContainer container = new Container(); 14 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 15 | 16 | builder.addFactory("max = java.lang.Math.max((int)$0,(int)$1);"); 17 | 18 | int max = (Integer) container.instance("max", 2,4); 19 | assertEquals(4, max); 20 | 21 | 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/java/JavaFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.java; 2 | 3 | import com.jenkov.container.IContainer; 4 | import com.jenkov.container.itf.factory.IGlobalFactory; 5 | 6 | /** 7 | 8 | */ 9 | public class JavaFactory implements IGlobalFactory { 10 | 11 | protected Class returnType = null; 12 | 13 | public Class getReturnType() { 14 | return returnType; 15 | } 16 | 17 | public void setReturnType(Class returnType) { 18 | this.returnType = returnType; 19 | } 20 | 21 | public Object instance(Object... parameters) { 22 | return null; 23 | } 24 | 25 | public Object[] execPhase(String phase, Object... parameters) { 26 | return new Object[0]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/TestProductCasting.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | import java.net.URL; 4 | 5 | /** 6 | 7 | */ 8 | public class TestProductCasting { 9 | 10 | protected String value1 = null; 11 | protected URL value2 = null; 12 | protected int value3 = -1; 13 | 14 | 15 | public void setValue(String value){ 16 | this.value1 = value; 17 | } 18 | 19 | 20 | public void setValue(URL url){ 21 | this.value2 = url; 22 | } 23 | 24 | public void setValue(int value){ 25 | this.value3 = value; 26 | } 27 | 28 | public String getValue1() { 29 | return value1; 30 | } 31 | 32 | public URL getValue2() { 33 | return value2; 34 | } 35 | 36 | public int getValue3() { 37 | return value3; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/IntegerFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | 8 | */ 9 | public class IntegerFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public IntegerFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return Integer.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return new Integer(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/CharsetTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | 5 | import java.nio.charset.Charset; 6 | import java.util.SortedMap; 7 | import java.io.Reader; 8 | import java.io.InputStreamReader; 9 | 10 | /** 11 | 12 | */ 13 | public class CharsetTest extends TestCase { 14 | 15 | public void testCharset(){ 16 | 17 | SortedMap charsetSortedMap = Charset.availableCharsets(); 18 | 19 | for(Charset charset : charsetSortedMap.values()){ 20 | System.out.println("charset.aliases() = " + charset.aliases()); 21 | } 22 | 23 | Charset charset = Charset.forName("UTF-16"); 24 | assertNotNull(charset); 25 | 26 | //Reader reader = new InputStreamReader(null, Charset.forName("UTF-16")); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/CharFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class CharFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public CharFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return char.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return this.sourceFactory.instance(parameters, localProducts).toString().charAt(0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/ByteFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class ByteFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public ByteFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return byte.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return Byte.parseByte(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/IntFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class IntFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public IntFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return int.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return Integer.parseInt(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/LongFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class LongFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public LongFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return long.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return Long.parseLong(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/FloatFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class FloatFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public FloatFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return float.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return Float.parseFloat(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/ShortFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class ShortFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public ShortFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return short.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return Short.parseShort(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/ByteObjectFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class ByteObjectFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public ByteObjectFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return Byte.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return new Byte(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/DoubleFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class DoubleFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public DoubleFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return double.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return Double.parseDouble(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/LongObjectFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class LongObjectFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public LongObjectFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return Long.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return new Long(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/FloatObjectFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class FloatObjectFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public FloatObjectFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return Float.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return new Float(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/ShortObjectFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class ShortObjectFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public ShortObjectFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return Short.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return new Short(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/BooleanFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class BooleanFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public BooleanFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return boolean.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return Boolean.parseBoolean(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/CharacterFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class CharacterFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public CharacterFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return Character.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return new Character(this.sourceFactory.instance(parameters, localProducts).toString().charAt(0)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/BooleanObjectFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class BooleanObjectFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public BooleanObjectFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return Boolean.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return new Boolean(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/DoubleObjectFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 8 | */ 9 | public class DoubleObjectFactory extends LocalFactoryBase implements ILocalFactory { 10 | 11 | protected ILocalFactory sourceFactory = null; 12 | 13 | public DoubleObjectFactory(ILocalFactory sourceFactory) { 14 | this.sourceFactory = sourceFactory; 15 | } 16 | 17 | public Class getReturnType() { 18 | return Double.class; 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return new Double(this.sourceFactory.instance(parameters, localProducts).toString()); 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/SomeFactoryProduct.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | /** 4 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 5 | */ 6 | public class SomeFactoryProduct { 7 | 8 | protected String arg1 = null; 9 | protected String arg2 = null; 10 | 11 | public SomeFactoryProduct(String arg1){ 12 | this.arg1 = arg1; 13 | } 14 | 15 | public SomeFactoryProduct(String arg1, String arg2) { 16 | this.arg1 = arg1; 17 | this.arg2 = arg2; 18 | } 19 | 20 | public String getArg1() { 21 | return arg1; 22 | } 23 | 24 | public void setArg1(String arg1) { 25 | this.arg1 = arg1; 26 | } 27 | 28 | public String getArg2() { 29 | return arg2; 30 | } 31 | 32 | public void setArg2(String arg2) { 33 | this.arg2 = arg2; 34 | } 35 | 36 | public void dispose(){ 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/TestThread.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import com.jenkov.container.IContainer; 4 | 5 | /** 6 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 7 | */ 8 | public class TestThread extends Thread{ 9 | 10 | protected Object instance1 = null; 11 | protected Object instance2 = null; 12 | 13 | protected String string1 = null; 14 | protected String string2 = null; 15 | 16 | protected IContainer container = null; 17 | 18 | public TestThread(IContainer container) { 19 | this.container = container; 20 | } 21 | 22 | public Object getInstance1() { 23 | return instance1; 24 | } 25 | 26 | public Object getInstance2() { 27 | return instance2; 28 | } 29 | 30 | public String getString1() { 31 | return string1; 32 | } 33 | 34 | public String getString2() { 35 | return string2; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/LocalProductConsumerFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | /** 6 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 7 | */ 8 | public class LocalProductConsumerFactory extends LocalFactoryBase implements ILocalFactory { 9 | 10 | protected int index = 0; 11 | protected Class returnType = null; 12 | 13 | public LocalProductConsumerFactory(Class returnType, int index) { 14 | this.returnType = returnType; 15 | this.index = index; 16 | } 17 | 18 | public int getIndex() { 19 | return index; 20 | } 21 | 22 | public Class getReturnType() { 23 | return returnType; 24 | } 25 | 26 | public void setReturnType(Class returnType) { 27 | this.returnType = returnType; 28 | } 29 | 30 | public Object instance(Object[] parameters, Object[] localProducts) { 31 | return localProducts[this.index]; 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/ValueFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | /** 6 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 7 | */ 8 | public class ValueFactory extends LocalFactoryBase implements ILocalFactory { 9 | 10 | public Object value = null; 11 | 12 | public ValueFactory(Object value) { 13 | this.value = value; 14 | } 15 | 16 | public Class getReturnType() { 17 | if(this.value == null) return null; 18 | return this.value.getClass(); 19 | } 20 | 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | return this.value; 23 | } 24 | 25 | public String toString() { 26 | StringBuilder builder = new StringBuilder(); 27 | builder .append(" --> <") 30 | .append(this.value) 31 | .append(">"); 32 | 33 | return builder.toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 5 | 4.0.0 6 | 7 | com.jenkov 8 | butterfly-di-container 9 | 3.2.0 10 | 11 | 12 | 13 | 14 | 15 | junit 16 | junit 17 | 4.11 18 | test 19 | 20 | 21 | 22 | 23 | 24 | 25 | org.apache.maven.plugins 26 | maven-compiler-plugin 27 | 3.3 28 | 29 | 1.8 30 | 1.8 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/LocalizedResourceFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | 7 | import java.util.Locale; 8 | 9 | /** 10 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 11 | */ 12 | public class LocalizedResourceFactoryTest extends TestCase { 13 | 14 | public static Locale getLocale(){ 15 | return new Locale("da", "dk"); 16 | } 17 | 18 | public void test(){ 19 | IContainer container = new Container(); 20 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 21 | 22 | builder.addFactory("UK = 1 java.util.Locale.UK;"); 23 | builder.addFactory("DK = 1 java.util.Locale('da', 'dk');"); 24 | builder.addFactory("locale = * com.jenkov.container.script.LocalizedResourceFactoryTest.getLocale(); "); 25 | builder.addFactory("aText = L ;"); 26 | 27 | String aText = (String) container.instance("aText"); 28 | assertEquals("hej", aText); 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/FieldGenericTypeTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.TestProduct; 5 | 6 | import java.lang.reflect.Field; 7 | import java.lang.reflect.Type; 8 | import java.lang.reflect.ParameterizedType; 9 | 10 | /** 11 | 12 | */ 13 | public class FieldGenericTypeTest extends TestCase { 14 | 15 | public void testGenericType() throws NoSuchFieldException { 16 | 17 | Field listField = TestProduct.class.getField("normalList"); 18 | // System.out.println(listField.getType()); 19 | 20 | Field genericListField = TestProduct.class.getField("genericListInt"); 21 | // System.out.println(genericListField.getType()); 22 | 23 | ParameterizedType type = (ParameterizedType) genericListField.getGenericType(); 24 | // System.out.println(type.getClass()); 25 | // System.out.println(type.getRawType()); 26 | 27 | Type[] typeArguments = type.getActualTypeArguments(); 28 | for(Type typeArgument : typeArguments){ 29 | Class typeArgumentClass = (Class) typeArgument; 30 | // System.out.println(typeArgumentClass); 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/GlobalSingletonFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.IGlobalFactory; 4 | 5 | /** 6 | todo fix phase execution on local products 7 | */ 8 | public class GlobalSingletonFactory extends GlobalFactoryBase implements IGlobalFactory { 9 | 10 | public Object[] localProducts = null; 11 | 12 | public Class getReturnType() { 13 | return getLocalInstantiationFactory().getReturnType(); 14 | } 15 | 16 | public synchronized Object instance(Object ... parameters) { 17 | if(this.localProducts == null){ 18 | this.localProducts = new Object[getLocalProductCount()]; 19 | this.localProducts[0] = getLocalInstantiationFactory().instance(parameters, localProducts); 20 | execPhase("config", parameters, localProducts); 21 | } 22 | return this.localProducts[0]; 23 | } 24 | 25 | public Object[] execPhase(String phase, Object ... parameters) { 26 | return execPhase(phase, parameters, this.localProducts); 27 | } 28 | 29 | public String toString() { 30 | return " --> "+ getLocalInstantiationFactory().toString(); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/script/ObjectPool.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import java.util.List; 4 | import java.util.ArrayList; 5 | 6 | /** 7 | 8 | */ 9 | public class ObjectPool { 10 | 11 | protected List free = new ArrayList(); 12 | protected List taken = new ArrayList(); 13 | 14 | protected int tokensTaken = 0; 15 | protected int maxSize = 0; 16 | 17 | 18 | 19 | public T take(){ 20 | this.tokensTaken++; 21 | T token = null; 22 | if(free.size() > 0) { 23 | token = free.remove(0); 24 | } else { 25 | // token = 26 | } 27 | taken.add(token); 28 | 29 | if(size() > maxSize){ 30 | maxSize = size(); 31 | } 32 | 33 | return token; 34 | } 35 | 36 | public void freeAll(){ 37 | free.addAll(taken); 38 | taken.clear(); 39 | } 40 | 41 | public void correctIndexOfTakenTokens(int valueToSubstract){ 42 | // for(T token : this.taken){ 43 | // if(token.length > 0){ 44 | // token.from -= valueToSubstract; 45 | // } 46 | // } 47 | } 48 | 49 | public int size() { 50 | return free.size() + taken.size(); 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/GlobalNewInstanceFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.IGlobalFactory; 4 | 5 | /** 6 | * 7 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 8 | */ 9 | public class GlobalNewInstanceFactory extends GlobalFactoryBase implements IGlobalFactory { 10 | 11 | public Class getReturnType() { 12 | return getLocalInstantiationFactory().getReturnType(); 13 | } 14 | 15 | public Object instance(Object ... parameters) { 16 | Object[] localProducts = getLocalProductCount() > 0 ? new Object[getLocalProductCount()] : null; 17 | return instance(parameters, localProducts); 18 | } 19 | 20 | /* todo remove this method, because it will only be called from the instance() method above */ 21 | public Object instance(Object[] parameters, Object[] localProducts) { 22 | Object instance = getLocalInstantiationFactory().instance(parameters, localProducts); 23 | if(localProducts != null) localProducts[0] = instance; 24 | 25 | execPhase("config", parameters, localProducts); 26 | 27 | return instance; 28 | } 29 | 30 | public Object[] execPhase(String phase, Object ... parameters) { 31 | return null; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/convert/UrlFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory.convert; 2 | 3 | import com.jenkov.container.impl.factory.LocalFactoryBase; 4 | import com.jenkov.container.itf.factory.FactoryException; 5 | import com.jenkov.container.itf.factory.ILocalFactory; 6 | 7 | import java.net.MalformedURLException; 8 | import java.net.URL; 9 | 10 | /** 11 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 12 | */ 13 | public class UrlFactory extends LocalFactoryBase implements ILocalFactory { 14 | 15 | protected ILocalFactory sourceFactory = null; 16 | 17 | public UrlFactory(ILocalFactory sourceFactory) { 18 | this.sourceFactory = sourceFactory; 19 | } 20 | 21 | public Class getReturnType() { 22 | return URL.class; 23 | } 24 | 25 | public Object instance(Object[] parameters, Object[] localProducts) { 26 | Object urlSource = null; 27 | try { 28 | urlSource = this.sourceFactory.instance(parameters, localProducts); 29 | return new URL(urlSource.toString()); 30 | } catch (MalformedURLException e) { 31 | throw new FactoryException( 32 | "UrlFactory", "INVALID_URL", 33 | "Error creating URL from object: " + urlSource, e); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/GlobalNewInstanceTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import com.jenkov.container.Container; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.TestProduct; 6 | import junit.framework.TestCase; 7 | 8 | /** 9 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 10 | */ 11 | public class GlobalNewInstanceTest extends TestCase { 12 | 13 | public void testInstance(){ 14 | IContainer container = new Container(); 15 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 16 | 17 | builder.addFactory("bean = * com.jenkov.container.TestProduct();"); 18 | TestProduct product1 = (TestProduct) container.instance("bean"); 19 | assertNotNull(product1); 20 | assertNull(product1.getValue1()); 21 | assertNull(product1.getValue2()); 22 | TestProduct product1_1 = (TestProduct) container.instance("bean"); 23 | assertNotSame(product1, product1_1); 24 | 25 | 26 | builder.addFactory( 27 | "bean2 = * com.jenkov.container.TestProduct();" + 28 | " config{ $bean2.setValue1(\"value1\"); }"); 29 | 30 | TestProduct product2 = (TestProduct) container.instance("bean2"); 31 | assertEquals("value1", product2.getValue1()); 32 | assertNull(product2.getValue2()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/LocalProductProducerFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | /** 6 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 7 | */ 8 | public class LocalProductProducerFactory extends LocalFactoryBase implements ILocalFactory { 9 | 10 | protected ILocalFactory instantiationFactory = null; 11 | protected int index = 0; 12 | 13 | public LocalProductProducerFactory(ILocalFactory localProductFactory, int index) { 14 | if(localProductFactory == null){ 15 | throw new IllegalArgumentException("Local product factory cannot be null"); 16 | } 17 | this.instantiationFactory = localProductFactory; 18 | this.index = index; 19 | } 20 | 21 | public ILocalFactory getInstantiationFactory() { 22 | return instantiationFactory; 23 | } 24 | 25 | public int getIndex() { 26 | return index; 27 | } 28 | 29 | public Class getReturnType() { 30 | return this.instantiationFactory.getReturnType(); 31 | } 32 | 33 | public Object instance(Object[] parameters, Object[] localProducts) { 34 | Object product = this.instantiationFactory.instance(parameters, localProducts); 35 | localProducts[this.index] = product; 36 | return product; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/LocalSingletonFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | /** 6 | * This class is a local singleton factory. 7 | * 8 | * Local singletons do not have their own life cycle phases. The products managed by a local singleton 9 | * will share life cycle phases with the global factory they are part of. If you need to manage the 10 | * life cycle of a local singleton, make it a named local factory, and reference the named local product 11 | * (the singleton instance) from the global factory's life cycle phases. 12 | * 13 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 14 | */ 15 | public class LocalSingletonFactory extends LocalFactoryBase implements ILocalFactory { 16 | 17 | protected ILocalFactory sourceFactory = null; 18 | protected Object instance = null; 19 | 20 | public LocalSingletonFactory(ILocalFactory sourceFactory) { 21 | this.sourceFactory = sourceFactory; 22 | } 23 | 24 | public Class getReturnType() { 25 | return this.sourceFactory.getReturnType(); 26 | } 27 | 28 | public synchronized Object instance(Object[] parameters, Object[] localProducts) { 29 | if(this.instance == null){ 30 | this.instance = this.sourceFactory.instance(parameters, localProducts); 31 | } 32 | return this.instance; 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/InjectThreadLocalTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | 7 | /** 8 | 9 | */ 10 | public class InjectThreadLocalTest extends TestCase { 11 | 12 | public static final ThreadLocal threadLocal = new ThreadLocal(); 13 | 14 | protected String local3 = null; 15 | 16 | public void testInjectThreadLocal() throws InterruptedException { 17 | final IContainer container = new Container(); 18 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 19 | 20 | builder.addFactory("local = * com.jenkov.container.script.InjectThreadLocalTest.threadLocal.get(); "); 21 | 22 | String local1 = (String) container.instance("local"); 23 | assertNull(local1); 24 | threadLocal.set("value"); 25 | 26 | String local2 = (String) container.instance("local"); 27 | assertEquals("value", local2); 28 | 29 | Thread thread = new Thread(){ 30 | public void run(){ 31 | threadLocal.set("value3"); 32 | 33 | local3 = (String) container.instance("local"); 34 | } 35 | }; 36 | thread.start(); 37 | 38 | thread.join(); 39 | 40 | // System.out.println(local3); 41 | assertEquals("value3", local3); 42 | 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/LocalFlyweightFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 10 | */ 11 | public class LocalFlyweightFactory extends LocalFactoryBase implements ILocalFactory { 12 | 13 | public ILocalFactory sourceFactory = null; 14 | public Map instances = new HashMap(); 15 | 16 | 17 | public LocalFlyweightFactory(ILocalFactory sourceFactory) { 18 | this.sourceFactory = sourceFactory; 19 | } 20 | 21 | public ILocalFactory getSourceFactory() { 22 | return sourceFactory; 23 | } 24 | 25 | public Class getReturnType() { 26 | return this.sourceFactory.getReturnType(); 27 | } 28 | 29 | public synchronized Object instance(Object[] parameters, Object[] localProducts) { 30 | FlyweightKey key = new FlyweightKey(parameters); 31 | Object instance = this.instances.get(key); 32 | if(instance == null){ 33 | instance = this.sourceFactory.instance(parameters, localProducts); 34 | this.instances.put(key, instance); 35 | } 36 | return instance; 37 | } 38 | 39 | public String toString() { 40 | return " --> "+ this.sourceFactory.toString(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test-config.script: -------------------------------------------------------------------------------- 1 | 2 | bean1 = * com.jenkov.container.TestProduct(); 3 | 4 | bean2 = * com.jenkov.container.script.SomeFactoryProduct("test"); 5 | 6 | bean3 = bean1.setValue1("bean3Value"); 7 | 8 | bean4 = bean1.setIntValue("beanValue".length()); 9 | 10 | bean5 = bean1.setValue1(com.jenkov.container.TestProduct.FIELD_VALUE); 11 | 12 | 13 | 14 | /* bean5 = * com.jenkov.NonExistingClass(); */ 15 | 16 | 17 | 18 | 19 | 20 | /* 21 | bean10 = * com.jenkov.NonExistingClass(); 22 | config{ 23 | local1 = bean10.get(); 24 | local2 = bean10.getOther(); 25 | $bean.set($0); 26 | } 27 | start{ 28 | thread = $bean10.getThread(); 29 | } 30 | stop{ 31 | $bean10.stop(); 32 | $thread.interrupt(); 33 | } 34 | dispose { 35 | $bean10.getConnection().close(); 36 | $local1.close(); 37 | } 38 | 39 | 40 | bean20 = 1 com.jenkov.NonExisitingClass(); 41 | bean21 = T com.jenkov.NonExisitingClass(); 42 | bean22 = F com.jenkov.NonExisitingClass(); 43 | bean22 = S com.jenkov.NonExisitingClass(); 44 | bean22 = R com.jenkov.NonExisitingClass(); 45 | 46 | bean20 = 1 com.jenkov.NonExisitingClass(); 47 | bean21 = 1T com.jenkov.NonExisitingClass(); 48 | bean22 = 1F com.jenkov.NonExisitingClass(); 49 | bean22 = 1S com.jenkov.NonExisitingClass(); 50 | bean22 = 1R com.jenkov.NonExisitingClass(); 51 | 52 | bean22 = 5 com.jenkov.NonExisitingClass(); 53 | bean22 = 5,10 com.jenkov.NonExisitingClass(); 54 | 55 | 56 | 57 | */ 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/LocalThreadSingletonFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 10 | */ 11 | public class LocalThreadSingletonFactory extends LocalFactoryBase implements ILocalFactory { 12 | public ILocalFactory sourceFactory = null; 13 | public Map instances = new HashMap(); 14 | 15 | 16 | public LocalThreadSingletonFactory(ILocalFactory sourceFactory) { 17 | this.sourceFactory = sourceFactory; 18 | } 19 | 20 | public ILocalFactory getSourceFactory() { 21 | return sourceFactory; 22 | } 23 | 24 | public Class getReturnType() { 25 | return this.sourceFactory.getReturnType(); 26 | } 27 | 28 | public synchronized Object instance(Object[] parameters, Object[] localProducts) { 29 | Thread callingThread = Thread.currentThread(); 30 | Object instance = this.instances.get(callingThread); 31 | if(instance == null){ 32 | instance = this.sourceFactory.instance(parameters, localProducts); 33 | this.instances.put(callingThread, instance); 34 | } 35 | return instance; 36 | } 37 | 38 | public String toString() { 39 | return " --> "+ this.sourceFactory.toString(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/LocalizedResourceFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | import com.jenkov.container.itf.factory.IGlobalFactory; 5 | 6 | import java.util.Map; 7 | import java.util.Locale; 8 | 9 | /** 10 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 11 | */ 12 | public class LocalizedResourceFactory extends LocalFactoryBase implements ILocalFactory { 13 | 14 | protected ILocalFactory resourceMapFactory = null; 15 | protected IGlobalFactory localeFactory = null; 16 | 17 | public LocalizedResourceFactory(ILocalFactory resourceMapFactory, IGlobalFactory localeFactory) { 18 | this.resourceMapFactory = resourceMapFactory; 19 | this.localeFactory = localeFactory; 20 | } 21 | 22 | public Class getReturnType() { 23 | return Object.class; 24 | } 25 | 26 | public Object instance(Object[] parameters, Object[] localProducts) { 27 | Map resourceMap = (Map ) this.resourceMapFactory.instance(parameters, localProducts); 28 | Locale locale = (Locale) this.localeFactory.instance(parameters, localProducts); 29 | if(locale == null){ 30 | throw new NullPointerException("The 'locale' factory returned null. It must always return a valid Locale instance."); 31 | } 32 | // return resourceMap.get(locale); 33 | return resourceMap.get(locale).instance(parameters, localProducts); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/script/ParserError.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | /** 4 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 5 | */ 6 | public class ParserError implements Comparable{ 7 | 8 | int lineNo = 0; 9 | int charNo = 0; 10 | 11 | String errorText = null; 12 | 13 | public ParserError(int lineNo, int charNo, String errorText) { 14 | this.lineNo = lineNo; 15 | this.charNo = charNo; 16 | this.errorText = errorText; 17 | } 18 | 19 | public int getLineNo() { 20 | return lineNo; 21 | } 22 | 23 | public int getCharNo() { 24 | return charNo; 25 | } 26 | 27 | public String getErrorText() { 28 | return errorText; 29 | } 30 | 31 | public String toString() { 32 | return "(" + lineNo + ":" + charNo + ") " + errorText; 33 | } 34 | 35 | public int compareTo(Object o) { 36 | if(o == null ) throw new NullPointerException("Cannot compare a ParserError instance to null!"); 37 | if(! (o instanceof ParserError)){ 38 | throw new IllegalArgumentException("Cannot compare ParserError instances to " + o.getClass().getName()); 39 | } 40 | 41 | ParserError other = (ParserError) o; 42 | if(this.lineNo > other.getLineNo()) return 1; 43 | if(this.lineNo < other.getLineNo()) return -1; 44 | if(this.charNo > other.getCharNo()) return 1; 45 | if(this.charNo < other.getCharNo()) return -1; 46 | 47 | return 0; 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/GlobalFactoryProxy.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.IGlobalFactory; 4 | 5 | /** 6 | 7 | */ 8 | public class GlobalFactoryProxy implements IGlobalFactory { 9 | 10 | protected IGlobalFactory delegateFactory = null; 11 | 12 | public GlobalFactoryProxy(IGlobalFactory delegateFactory) { 13 | this.delegateFactory = delegateFactory; 14 | } 15 | 16 | public synchronized IGlobalFactory getDelegateFactory() { 17 | return delegateFactory; 18 | } 19 | 20 | public synchronized IGlobalFactory setDelegateFactory(IGlobalFactory delegateFactory) { 21 | IGlobalFactory oldFactory = this.delegateFactory; 22 | this.delegateFactory = delegateFactory; 23 | return oldFactory; 24 | } 25 | 26 | public synchronized Class getReturnType() { 27 | return this.delegateFactory.getReturnType(); 28 | } 29 | 30 | public Object instance(Object ... parameters) { 31 | IGlobalFactory localDelegateFactory = null; 32 | synchronized(this){ 33 | localDelegateFactory = this.delegateFactory; 34 | } 35 | return localDelegateFactory.instance(parameters); 36 | } 37 | 38 | public Object[] execPhase(String phase, Object ... parameters) { 39 | IGlobalFactory localDelegateFactory = null; 40 | synchronized(this){ 41 | localDelegateFactory = this.delegateFactory; 42 | } 43 | return localDelegateFactory.execPhase(phase, parameters); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/FlyweightKey.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.FactoryException; 4 | 5 | /** 6 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 7 | */ 8 | public class FlyweightKey { 9 | Object[] parameters = null; 10 | int hashCode = 0; 11 | 12 | public FlyweightKey(Object[] parameters) { 13 | this.parameters = parameters; 14 | for(int i=0; i< parameters.length; i++){ 15 | if(parameters[i] == null) throw new FactoryException( 16 | "FlyweightKey", "ERROR_FLYWEIGHT_KEY_PARAMETER", 17 | "Flyweight parameter " + i + " was null. You cannot use null parameters with flyweight factories"); 18 | this.hashCode *= parameters[i].hashCode(); 19 | } 20 | } 21 | 22 | public Object[] getParameters() { 23 | return parameters; 24 | } 25 | 26 | public boolean equals(Object otherKeyObj){ 27 | FlyweightKey otherKey = (FlyweightKey) otherKeyObj; 28 | if(otherKey == null) return false; 29 | 30 | if(parameters.length != otherKey.getParameters().length) return false; 31 | 32 | for(int i=0; i inputFactories = null; 15 | 16 | public InputAdaptingFactory(IGlobalFactory targetFactory, List inputFactories) { 17 | this.targetFactory = targetFactory; 18 | this.inputFactories = inputFactories; 19 | } 20 | 21 | public Class getReturnType() { 22 | return this.targetFactory.getReturnType(); 23 | } 24 | 25 | public Object instance(Object[] parameters, Object[] localProducts) { 26 | Object[] adaptedParameters = new Object[inputFactories.size()]; 27 | for(int i=0; i free = new ArrayList(); 15 | protected List taken = new ArrayList(); 16 | 17 | protected int tokensTaken = 0; 18 | protected int maxSize = 0; 19 | 20 | 21 | public Token take(){ 22 | this.tokensTaken++; 23 | Token token = null; 24 | if(free.size() > 0) { 25 | token = free.remove(0); 26 | token.reset(); 27 | } else { 28 | token = new Token(); 29 | } 30 | taken.add(token); 31 | 32 | if(size() > maxSize){ 33 | maxSize = size(); 34 | } 35 | 36 | return token; 37 | } 38 | 39 | public void freeAll(){ 40 | free.addAll(taken); 41 | taken.clear(); 42 | } 43 | 44 | public void correctIndexOfTakenTokens(int valueToSubstract){ 45 | for(Token token : this.taken){ 46 | if(token.length > 0){ 47 | token.from -= valueToSubstract; 48 | } 49 | } 50 | } 51 | 52 | public int size() { 53 | return free.size() + taken.size(); 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/UnitTestExamples.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.script.ScriptFactoryBuilder; 5 | //import com.jenkov.testing.mock.impl.MockFactory; 6 | //import com.jenkov.testing.mock.itf.IMock; 7 | 8 | /** 9 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 10 | */ 11 | public class UnitTestExamples extends TestCase { 12 | public void test(){ 13 | IContainer container = new Container(); 14 | ScriptFactoryBuilder scriptBuilder = new ScriptFactoryBuilder(container); 15 | 16 | scriptBuilder.addFactory("test = * com.jenkov.container.TestProduct().setValue1('value1');"); 17 | TestProduct product = (TestProduct) container.instance("test"); 18 | assertEquals("value1", product.getValue1()); 19 | } 20 | 21 | public void test2(){ 22 | 23 | /* 24 | IContainer container = new Container(); 25 | ScriptFactoryBuilder scriptBuilder = new ScriptFactoryBuilder(container); 26 | 27 | scriptBuilder.addFactory("itfProxy = * com.jenkov.testing.mock.impl.MockFactory.createProxy((java.lang.Class) $0);"); 28 | scriptBuilder.addFactory("colProxy = * com.jenkov.testing.mock.impl.MockFactory.createProxy((java.lang.Object) $0);"); 29 | scriptBuilder.addFactory("test = * itfProxy(com.jenkov.container.ISomeInterface.class); "); 30 | 31 | Object test = container.instance("test"); 32 | ISomeInterface testInterface = (ISomeInterface) test; 33 | assertTrue(test instanceof ISomeInterface); 34 | */ 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/ParameterCastingTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | import com.jenkov.container.TestProductCasting; 7 | 8 | import java.net.URL; 9 | import java.net.MalformedURLException; 10 | 11 | /** 12 | 13 | */ 14 | public class ParameterCastingTest extends TestCase { 15 | 16 | public void test() throws MalformedURLException { 17 | IContainer container = new Container(); 18 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 19 | 20 | builder.addFactory("bean = * com.jenkov.container.TestProductCasting().setValue((int) 2);"); 21 | TestProductCasting product = (TestProductCasting) container.instance("bean"); 22 | 23 | assertNull(product.getValue1()); 24 | assertNull(product.getValue2()); 25 | assertEquals(2, product.getValue3()); 26 | 27 | 28 | builder.addFactory("bean2 = * com.jenkov.container.TestProductCasting().setValue((String) 2);"); 29 | product = (TestProductCasting) container.instance("bean2"); 30 | 31 | assertEquals("2", product.getValue1()); 32 | assertNull(product.getValue2()); 33 | assertEquals(-1, product.getValue3()); 34 | 35 | 36 | builder.addFactory("bean3 = * com.jenkov.container.TestProductCasting().setValue((URL) 'http://jenkov.com');"); 37 | product = (TestProductCasting) container.instance("bean3"); 38 | 39 | assertNull(product.getValue1()); 40 | assertEquals(new URL("http://jenkov.com"), product.getValue2()); 41 | assertEquals(-1, product.getValue3()); 42 | 43 | 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/FactoryInterfaceAdapter.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.IContainer; 4 | 5 | import java.lang.reflect.InvocationHandler; 6 | import java.lang.reflect.Method; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | 12 | */ 13 | public class FactoryInterfaceAdapter implements InvocationHandler { 14 | 15 | IContainer container = null; 16 | Map instanceMethodFactoryNameMap = new HashMap(); 17 | String defaultFactoryName = null; 18 | 19 | public FactoryInterfaceAdapter(IContainer container, String defaultFactoryName) { 20 | this.container = container; 21 | this.defaultFactoryName = defaultFactoryName; 22 | } 23 | 24 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 25 | String factoryName = null; 26 | synchronized(this.instanceMethodFactoryNameMap){ 27 | factoryName = this.instanceMethodFactoryNameMap.get(method); 28 | if(factoryName == null){ 29 | String methodName = method.getName(); 30 | if(methodName.endsWith("Instance") || methodName.endsWith("instance")){ 31 | factoryName = methodName.substring(0, methodName.length() - "Instance".length()); 32 | } else { 33 | factoryName = methodName; 34 | } 35 | if(factoryName.length() == 0) factoryName = defaultFactoryName; 36 | this.instanceMethodFactoryNameMap.put(method, factoryName); 37 | } 38 | } 39 | return this.container.instance(factoryName, args); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/PropertyStyleConfigTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | 7 | /** 8 | Tests if the container can be used for property file style application configuration, for instance 9 | 10 | noOfThreads = 10; 11 | cacheSize = 1024; 12 | dbUrl = "jdbc:tcp..."; 13 | 14 | */ 15 | public class PropertyStyleConfigTest extends TestCase { 16 | 17 | public void test (){ 18 | IContainer container = new Container(); 19 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 20 | 21 | builder.addFactory("noOfThreads = 10;"); 22 | String noOfThreads = (String) container.instance("noOfThreads"); 23 | assertEquals("10", noOfThreads); 24 | String noOfThreads2 = (String) container.instance("noOfThreads"); 25 | assertSame(noOfThreads, noOfThreads2); 26 | 27 | 28 | builder.addFactory("dbUrl = 'jdbc:tcp';"); 29 | String dbUrl = (String) container.instance("dbUrl"); 30 | assertEquals("jdbc:tcp", dbUrl); 31 | 32 | builder.addFactory("defaultSize = 1;"); 33 | String defaultSize = (String) container.instance("defaultSize"); 34 | assertEquals("1", defaultSize); 35 | String defaultSize2 = (String) container.instance("defaultSize"); 36 | assertSame(defaultSize, defaultSize2); 37 | 38 | builder.addFactory("aValue = 1 1;"); 39 | String aValue = (String) container.instance("aValue"); 40 | assertEquals("1", aValue); 41 | String aValue2 = (String) container.instance("aValue"); 42 | assertSame(aValue, aValue2); 43 | 44 | 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/Bugs.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | 7 | import java.io.BufferedInputStream; 8 | import java.io.ByteArrayInputStream; 9 | 10 | /** 11 | 12 | */ 13 | public class Bugs extends TestCase { 14 | 15 | public void testExtraParanthesesErrorMessage(){ 16 | IContainer container = new Container(); 17 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 18 | 19 | String script = "test1 = * com.jenkov.container.TestProduct()); \n" + 20 | "test2 = * com.jenkov.container.TestProduct(); " ; 21 | 22 | ByteArrayInputStream input = new ByteArrayInputStream(script.getBytes()); 23 | 24 | try{ 25 | builder.addFactories(input); 26 | fail("should throw exception because of extra parantheses in script"); 27 | } catch(ParserException e){ 28 | assertTrue(e.getMessage().indexOf("Expected token ; but found )") > -1); 29 | } 30 | 31 | 32 | } 33 | 34 | public void testFactoryTailErrorMessage(){ 35 | IContainer container = new Container(); 36 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 37 | 38 | String script = "test1 = * com.jenkov.container.TestProduct().setValue1('A value')); "; 39 | 40 | ByteArrayInputStream input = new ByteArrayInputStream(script.getBytes()); 41 | 42 | try{ 43 | builder.addFactories(input); 44 | fail("should throw exception because of extra parantheses in script"); 45 | } catch (ParserException e){ 46 | assertTrue(e.getMessage().indexOf("Expected token ; but found )") > -1); 47 | } 48 | 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/GlobalThreadSingletonFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.IGlobalFactory; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * todo fix phase execution on local products 10 | * 11 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 12 | */ 13 | public class GlobalThreadSingletonFactory extends GlobalFactoryBase implements IGlobalFactory { 14 | 15 | public Map localProductMap = new HashMap(); 16 | 17 | public Class getReturnType() { 18 | return getLocalInstantiationFactory().getReturnType(); 19 | } 20 | 21 | public synchronized Object instance(Object ... parameters) { 22 | Thread callingThread = Thread.currentThread(); 23 | Object[] threadLocalProducts = this.localProductMap.get(callingThread); 24 | if(threadLocalProducts != null) return threadLocalProducts[0]; 25 | 26 | threadLocalProducts = new Object[getLocalProductCount()]; 27 | threadLocalProducts[0] = getLocalInstantiationFactory().instance(parameters, threadLocalProducts); 28 | execPhase("config", parameters, threadLocalProducts); 29 | this.localProductMap.put(callingThread, threadLocalProducts); 30 | 31 | return threadLocalProducts[0]; 32 | } 33 | 34 | 35 | public Object[] execPhase(String phase, Object ... parameters) { 36 | for(Thread thread : this.localProductMap.keySet()){ 37 | Object[] threadLocalProducts = this.localProductMap.get(thread); 38 | execPhase(phase, parameters, threadLocalProducts); 39 | } 40 | return null; 41 | } 42 | 43 | public String toString() { 44 | return " --> "+ getLocalInstantiationFactory().toString(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/itf/factory/ILocalFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.itf.factory; 2 | 3 | /** 4 | A Local Factory is a factory that is used inside the container. Local factories are typically chained into 5 | factory chains. You cannot plug a local factory into a container. Local factories and chains are typically 6 | called from within a global factory. Local factories are mostly used in global factories when the global 7 | factories are created from a Butterfly Container Script. If you plugin custom IGlobalFactory implementations 8 | you will typically not need ILocalFactory instances inside it. You would just use plain Java. 9 | */ 10 | public interface ILocalFactory { 11 | 12 | public Class getReturnType(); 13 | 14 | /** 15 | * This method is intended to be called *internally between* factories when creating 16 | * an instance of some class. It is not intended to be called directly by client code, 17 | * or from the Container. For that purpose use the instance(Object ... parameters) 18 | * method. If you do call this method directly, a null will suffice for the localProducts 19 | * array. 20 | * 21 | * NOTE: Only called on local factories. Never on global factories. 22 | * 23 | *

24 | * If you develop a custom IFactory implementation you should 25 | * extend LocalFactoryBase and override this method, not the instance(Object ... parameters) 26 | * method. If your factory implementation calls any other factories it should pass on 27 | * both the parameters and localProducts object arrays!! 28 | * ... as in factory.instance(parameters, localProducts); . 29 | * Do not just call the instance() or instance(parameters) method. 30 | * 31 | * @param parameters 32 | * @param localProducts 33 | * @return The created object. 34 | */ 35 | public Object instance(Object[] parameters, Object[] localProducts); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/resources/Resources.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.resources; 2 | 3 | import com.jenkov.container.Container; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.script.ScriptFactoryBuilder; 6 | 7 | import java.util.Locale; 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | public class Resources { 12 | 13 | public static final ThreadLocal locale = new ThreadLocal(); 14 | 15 | 16 | public static Locale getThreadLocale(){ 17 | return locale.get(); 18 | } 19 | 20 | public static String getString(Map texts, Locale paramLocale, Locale threadLocale, Locale defaultLocale){ 21 | if(texts == null) throw new NullPointerException("texts parameter (Map) was null"); 22 | Locale actualLocale = paramLocale; 23 | if(actualLocale == null) actualLocale = threadLocale; 24 | if(actualLocale == null) actualLocale = defaultLocale; 25 | 26 | return texts.get(actualLocale); 27 | } 28 | 29 | 30 | public static void main(String[] args) throws NoSuchMethodException { 31 | 32 | IContainer container = new Container(); 33 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 34 | 35 | builder.addFactory("UK = java.util.Locale('en', 'gb'); "); 36 | builder.addFactory("DK = java.util.Locale('da', 'dk'); "); 37 | builder.addFactory("threadLocale = com.jenkov.container.resources.Resources.getThreadLocale(); "); 38 | builder.addFactory("localize = * com.jenkov.container.resources.Resources.getString($1, $0, threadLocale, UK);"); 39 | builder.addFactory("astring = * localize($0, } " 40 | ); 41 | 42 | String astring = (String) container.instance("astring"); 43 | 44 | System.out.println("astring = " + astring); 45 | 46 | 47 | 48 | } 49 | 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/FieldFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.FactoryException; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | import java.lang.reflect.Field; 7 | import java.lang.reflect.Type; 8 | import java.lang.reflect.ParameterizedType; 9 | 10 | /** 11 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 12 | */ 13 | public class FieldFactory extends LocalFactoryBase implements ILocalFactory { 14 | protected Field field = null; 15 | protected Object fieldOwner = null; 16 | protected ILocalFactory fieldOwnerFactory = null; 17 | 18 | 19 | public FieldFactory(Field method) { 20 | this.field = method; 21 | } 22 | 23 | public FieldFactory(Field field, Object fieldOwner) { 24 | this.field = field; 25 | this.fieldOwner = fieldOwner; 26 | } 27 | 28 | public FieldFactory(Field field, ILocalFactory fieldOwnerFactory) { 29 | this.field = field; 30 | this.fieldOwnerFactory = fieldOwnerFactory; 31 | } 32 | 33 | 34 | public Class getReturnType() { 35 | return this.field.getType(); 36 | } 37 | 38 | public Object instance(Object[] parameters, Object[] localProducts) { 39 | try { 40 | if(this.fieldOwnerFactory != null){ 41 | return this.field.get(this.fieldOwnerFactory.instance(parameters, localProducts)); 42 | } 43 | return this.field.get(this.fieldOwner); 44 | } catch (IllegalAccessException e) { 45 | throw new FactoryException( 46 | "FieldFactory", "ERROR_ACCESSING_FIELD", 47 | "Error accessing field " + field, e); 48 | } 49 | } 50 | 51 | public String toString() { 52 | StringBuilder builder = new StringBuilder(); 53 | builder.append("field: "); 54 | builder.append(field); 55 | 56 | return builder.toString(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/GlobalFlyweightFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.IGlobalFactory; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * todo fix phase execution for local products 10 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 11 | */ 12 | public class GlobalFlyweightFactory extends GlobalFactoryBase implements IGlobalFactory { 13 | 14 | public Map localProducts = new HashMap(); 15 | 16 | public Class getReturnType() { 17 | return getLocalInstantiationFactory().getReturnType(); 18 | } 19 | 20 | public Object instance(Object ... parameters) { 21 | FlyweightKey key = new FlyweightKey(parameters); 22 | Object[] keyLocalProducts = this.localProducts.get(key); 23 | 24 | if(keyLocalProducts != null) return keyLocalProducts[0]; 25 | keyLocalProducts = new Object[getLocalProductCount()]; 26 | return instance(parameters, keyLocalProducts); 27 | } 28 | 29 | public synchronized Object instance(Object[] parameters, Object[] localProducts) { 30 | FlyweightKey key = new FlyweightKey(parameters); 31 | Object[] keyLocalProducts = this.localProducts.get(key); 32 | if(keyLocalProducts == null){ 33 | keyLocalProducts = localProducts; 34 | keyLocalProducts[0] = getLocalInstantiationFactory().instance(parameters, localProducts); 35 | this.localProducts.put(key, keyLocalProducts); 36 | execPhase("config", parameters, keyLocalProducts); 37 | } 38 | return keyLocalProducts[0]; 39 | } 40 | 41 | public Object[] execPhase(String phase, Object ... parameters) { 42 | for(FlyweightKey key : localProducts.keySet()){ 43 | Object[] keyLocalProducts = localProducts.get(key); 44 | execPhase(phase, parameters, keyLocalProducts); 45 | } 46 | return null; 47 | } 48 | 49 | public String toString() { 50 | return " --> "+ getLocalInstantiationFactory().toString(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/ResourceTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import com.jenkov.container.Container; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.resources.Resources; 6 | import junit.framework.TestCase; 7 | 8 | import java.util.Locale; 9 | 10 | /** 11 | 12 | */ 13 | public class ResourceTest extends TestCase { 14 | 15 | public static final ThreadLocal threadLocal = new ThreadLocal(); 16 | 17 | public static Locale getThreadLocale(){ 18 | return threadLocal.get(); 19 | } 20 | 21 | 22 | public void testLocalization(){ 23 | IContainer container = new Container(); 24 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 25 | 26 | builder.addFactory("UK = java.util.Locale('en', 'gb'); "); 27 | builder.addFactory("DK = java.util.Locale('da', 'dk'); "); 28 | builder.addFactory("ES = java.util.Locale('es', 'es'); "); 29 | builder.addFactory("threadLocale = * com.jenkov.container.resources.Resources.getThreadLocale(); "); 30 | builder.addFactory("localize = * com.jenkov.container.resources.Resources.getString($1, $0, threadLocale, UK);"); 31 | builder.addFactory("astring = * localize($0, ); " ); 32 | 33 | assertNull(container.instance("threadLocale")); 34 | 35 | 36 | String astring = (String) container.instance("astring"); 37 | assertEquals("hello", astring); 38 | 39 | astring = (String) container.instance("astring", new Locale("da", "dk")); 40 | assertEquals("hej", astring); 41 | 42 | 43 | Resources.locale.set(new Locale("da", "dk")); 44 | assertNotNull(container.instance("threadLocale")); 45 | astring = (String) container.instance("astring"); 46 | assertEquals("hej", astring); 47 | 48 | assertEquals("hola", container.instance("astring", new Locale("es", "es"))); 49 | 50 | 51 | // Locale[] locales = Locale.getAvailableLocales(); 52 | // for(Locale alocale : locales){ 53 | // System.out.println("locale.getCountry() = " + alocale.getCountry() + " - " + alocale.getLanguage()); 54 | // } 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/InputConsumerFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | /** 6 | This factory returns one of the input parameters given to the instance call as its product. 7 | This is handy when another factory needs one of the input parameters. Rather than having to know 8 | that one of the objects needed comes from the input array, the given factory only calls the factories 9 | it depends upon, some of which may return object obtained from the input parameter array. This 10 | gives a more uniform way of using other factories and input parameters. No factory except this factory 11 | need be aware of the input parameters. They just need to pass them on, that's all. 12 | */ 13 | 14 | public class InputConsumerFactory extends LocalFactoryBase implements ILocalFactory { 15 | 16 | protected int inputParameterIndex = 0; 17 | protected Class returnType = null; //if changed to other than null as default, remember to change 18 | //the FactoryBuilder allArgumentsMatch and wrapInConversionFactoriesIfNecessary 19 | //to check for the new default value instead of null. 20 | 21 | public InputConsumerFactory(int inputParameterIndex) { 22 | this.inputParameterIndex = inputParameterIndex; 23 | } 24 | 25 | public int getInputParameterIndex() { 26 | return inputParameterIndex; 27 | } 28 | 29 | // todo check if the return type can be specified more precisely? Perhaps by forcing it (casting it in the script). 30 | public Class getReturnType() { 31 | return returnType; 32 | } 33 | 34 | public void setReturnType(Class returnType) { 35 | this.returnType = returnType; 36 | } 37 | 38 | public Object instance(Object[] parameters, Object[] localProducts) { 39 | if(parameters == null) return null; 40 | //if no input parameter was given matching this index, return null. 41 | if(this.inputParameterIndex >= parameters.length) return null; 42 | return parameters[this.inputParameterIndex]; 43 | } 44 | 45 | public String toString() { 46 | return "$" + this.inputParameterIndex; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/MapFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | import java.lang.reflect.Array; 6 | import java.lang.reflect.ParameterizedType; 7 | import java.lang.reflect.Type; 8 | import java.util.*; 9 | 10 | /** 11 | 12 | */ 13 | public class MapFactory extends LocalFactoryBase implements ILocalFactory { 14 | 15 | 16 | protected List keyFactories = null; 17 | protected List valueFactories = null; 18 | 19 | /** If true, produces a map of the product factories instead of the products. */ 20 | protected boolean isFactoryMap = false; 21 | 22 | public MapFactory(List keyFactories, List valueFactories) { 23 | this.keyFactories = keyFactories; 24 | this.valueFactories = valueFactories; 25 | } 26 | 27 | public Class getReturnType() { 28 | return Map.class; 29 | } 30 | 31 | public synchronized boolean isFactoryMap() { 32 | return isFactoryMap; 33 | } 34 | 35 | public synchronized void setFactoryMap(boolean factoryMap) { 36 | isFactoryMap = factoryMap; 37 | } 38 | 39 | public Object instance(Object[] parameters, Object[] localProducts) { 40 | Map map = new HashMap(); 41 | 42 | Iterator keyFactoryIterator = keyFactories.iterator(); 43 | Iterator valueFactoryIterator = valueFactories.iterator(); 44 | if(!isFactoryMap()){ 45 | while(keyFactoryIterator.hasNext()){ 46 | ILocalFactory keyFactory = keyFactoryIterator.next(); 47 | ILocalFactory valueFactory = valueFactoryIterator.next(); 48 | map.put(keyFactory.instance(parameters, localProducts), 49 | valueFactory.instance(parameters, localProducts)); 50 | } 51 | } else { 52 | while(keyFactoryIterator.hasNext()){ 53 | ILocalFactory keyFactory = keyFactoryIterator.next(); 54 | ILocalFactory valueFactory = valueFactoryIterator.next(); 55 | map.put(keyFactory.instance(parameters, localProducts), valueFactory); 56 | } 57 | } 58 | return map; 59 | } 60 | } -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/MapFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | import com.jenkov.container.itf.factory.IGlobalFactory; 7 | 8 | import java.util.Map; 9 | 10 | /** 11 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 12 | */ 13 | public class MapFactoryTest extends TestCase { 14 | 15 | public void test(){ 16 | IContainer container = new Container(); 17 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 18 | 19 | builder.addFactory("map = * <'key':'value'>; "); 20 | 21 | Map map = (Map) container.instance("map"); 22 | assertEquals(1, map.size()); 23 | assertEquals("value", map.get("key")); 24 | } 25 | 26 | public void testFactoryAsValue() { 27 | IContainer container = new Container(); 28 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 29 | 30 | builder.addFactory("index = 'index value';"); 31 | 32 | String indexValue = (String) container.instance("index"); 33 | assertEquals("index value", indexValue); 34 | 35 | 36 | builder.addFactory("uriMap = 1 < '/index3.html' : #index >;"); 37 | 38 | Map map = (Map) container.instance("uriMap"); 39 | assertEquals(1, map.size()); 40 | assertTrue(map.get("/index3.html") instanceof IGlobalFactory); 41 | 42 | IGlobalFactory indexFactory = (IGlobalFactory) map.get("/index3.html"); 43 | indexValue = (String) indexFactory.instance(); 44 | assertEquals("index value", indexValue); 45 | } 46 | 47 | public void testNewInstanceAndSingleonMaps() { 48 | IContainer container = new Container(); 49 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 50 | 51 | builder.addFactory("index = 'index value';"); 52 | 53 | String indexValue = (String) container.instance("index"); 54 | assertEquals("index value", indexValue); 55 | 56 | builder.addFactory("uriMap = * < '/index3.html' : #index >;"); 57 | Map map1 = (Map) container.instance("uriMap"); 58 | Map map2 = (Map) container.instance("uriMap"); 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/GlobalSingletonTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | import com.jenkov.container.TestProduct; 7 | 8 | /** 9 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 10 | */ 11 | public class GlobalSingletonTest extends TestCase { 12 | 13 | public void testInstance(){ 14 | IContainer container = new Container(); 15 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 16 | 17 | builder.addFactory("bean = 1 com.jenkov.container.TestProduct();"); 18 | TestProduct product1 = (TestProduct) container.instance("bean"); 19 | assertNotNull(product1); 20 | assertNull(product1.getValue1()); 21 | assertNull(product1.getValue2()); 22 | TestProduct product1_1 = (TestProduct) container.instance("bean"); 23 | assertSame(product1, product1_1); 24 | 25 | 26 | builder.addFactory( 27 | "bean2 = 1 com.jenkov.container.TestProduct();" + 28 | " config{ $bean2.setValue1(\"value1\"); }"); 29 | 30 | TestProduct product2 = (TestProduct) container.instance("bean2"); 31 | assertEquals("value1", product2.getValue1()); 32 | assertNull(product2.getValue2()); 33 | TestProduct product2_1 = (TestProduct) container.instance("bean2"); 34 | assertSame(product2, product2_1); 35 | 36 | builder.addFactory( 37 | "bean3 = 1 com.jenkov.container.TestProduct();" + 38 | " config { $bean3.setValue1(\"value1\"); } " + 39 | " myPhase{ $bean3.setValue2(\"value2\"); } " + 40 | " dispose{ $bean3.setValue2(\"disposed\"); }"); 41 | 42 | TestProduct product3 = (TestProduct) container.instance("bean3"); 43 | assertEquals("value1", product2.getValue1()); 44 | assertNull(product3.getValue2()); 45 | TestProduct product3_1 = (TestProduct) container.instance("bean3"); 46 | assertSame(product3, product3_1); 47 | 48 | container.execPhase("myPhase"); 49 | assertEquals("value2", product3.getValue2()); 50 | 51 | container.dispose(); 52 | assertEquals("disposed", product3.getValue2()); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/itf/factory/IGlobalFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.itf.factory; 2 | 3 | /** 4 | * 5 | * An object factory that can be plugged into an IContainer instance. 6 | * A factory creates instances with a common interface or super class. 7 | * 8 | *

9 | * The factory 10 | * can create instances of many different classes as long as they 11 | * all either implement a common interface, or extend a common 12 | * super class. 13 | *

14 | * 15 | * 16 | * Copyright 2008 Jenkov Development 17 | */ 18 | public interface IGlobalFactory { 19 | 20 | public Class getReturnType(); 21 | 22 | 23 | /** 24 | * Returns an instance of whatever component this global factory produces 25 | * 26 | * @param parameters Any parameters needed by the factory to create its instance. 27 | * @return The object instance as created by the facttory. 28 | */ 29 | public T instance(Object ... parameters); 30 | 31 | /** 32 | * This method is called by the container when executing a phase in a factory that supports life cycle phases. 33 | * The container knows nothing about local products, therefore this method is called. Only the concrete 34 | * factory knows about cached local products (if any). 35 | * 36 | *

37 | * This is the method a global factory will override when implementing life cycle phase behaviour, e.g. for 38 | * cached objects. 39 | * 40 | * @param phase The name of the phase to execute. For instance, "config" or "dispose". 41 | * @param parameters The parameters passed to the container when the phase begins. For instance to 42 | * an instance() method call, or an execPhase(phase, factory, parameters) call. 43 | * @return Null, or the local products the phase ends up being executed on. If executed 44 | * for several local product arrays (e.g. in pools or flyweights), null will be returned, since it does not 45 | * make sense to return anything. Returning anything would only make sense for 46 | * the "create" phase, but currently this phase does not use the execPhase() method 47 | * to carry out its work. It uses the factory.instance() methods instead. 48 | */ 49 | public Object[] execPhase(String phase, Object ... parameters); 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/ConstructorFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.FactoryException; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | import java.lang.reflect.Constructor; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | 12 | */ 13 | public class ConstructorFactory extends LocalFactoryBase implements ILocalFactory { 14 | 15 | protected Constructor constructor = null; 16 | protected List constructorArgFactories = new ArrayList(); 17 | 18 | public ConstructorFactory(Constructor constructor){ 19 | this.constructor = constructor; 20 | } 21 | 22 | public ConstructorFactory(Constructor contructor, List contructorArgFactories) { 23 | this.constructor = contructor; 24 | this.constructorArgFactories = contructorArgFactories; 25 | } 26 | 27 | public ConstructorFactory(Constructor constructor, ILocalFactory[] constructorArgFactories){ 28 | this.constructor = constructor; 29 | for(ILocalFactory factory : constructorArgFactories){ 30 | this.constructorArgFactories.add(factory); 31 | } 32 | } 33 | 34 | public Constructor getConstructor() { 35 | return constructor; 36 | } 37 | 38 | public List getConstructorArgFactories() { 39 | return constructorArgFactories; 40 | } 41 | 42 | public Class getReturnType() { 43 | return this.constructor.getDeclaringClass(); 44 | } 45 | 46 | public Object instance(Object[] parameters, Object[] localProducts) { 47 | Object[] arguments = FactoryUtil.toArgumentArray(this.constructorArgFactories, parameters, localProducts); 48 | 49 | Object returnValue = null; 50 | try { 51 | returnValue = this.constructor.newInstance(arguments); 52 | } catch (Throwable t){ 53 | throw new FactoryException( 54 | "ConstructorFactory", "CONSTRUCTOR_EXCEPTION", 55 | "Error instantiating object from constructor " + this.constructor, t); 56 | } finally{ 57 | for(int j=0; j"; 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/performance/PerformanceTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.performance; 2 | 3 | import com.jenkov.container.Container; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.TestProduct; 6 | import com.jenkov.container.script.ScriptFactoryBuilder; 7 | 8 | import java.io.*; 9 | 10 | /** 11 | 12 | */ 13 | public class PerformanceTest { 14 | 15 | public static void main(String[] args) throws IOException, InterruptedException { 16 | int iterations = 100000; 17 | 18 | String fileName = "large-script.bcs"; 19 | writeLargeFile(iterations, fileName); 20 | 21 | 22 | long startTime = System.currentTimeMillis(); 23 | 24 | IContainer container = new Container(); 25 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 26 | BufferedInputStream input = new BufferedInputStream(new FileInputStream(fileName), 1024 * 1024 ); 27 | 28 | builder.addFactories(input); 29 | input.close(); 30 | 31 | long parseTime = System.currentTimeMillis(); 32 | 33 | for(int i=0; i --> ") 60 | .append(this.container); 61 | 62 | return builder.toString(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/performance/PerformanceTest2.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.performance; 2 | 3 | import com.jenkov.container.Container; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.TestProduct; 6 | import com.jenkov.container.script.ScriptFactoryBuilder; 7 | 8 | import java.io.*; 9 | 10 | /** 11 | 12 | */ 13 | public class PerformanceTest2 { 14 | 15 | public static void main(String[] args) throws IOException, InterruptedException { 16 | int iterations = 100; 17 | 18 | String fileName = "large-script.bcs"; 19 | 20 | writeLargeFile(iterations, fileName); 21 | System.out.println("Writing File Done"); 22 | 23 | 24 | long startTime = System.currentTimeMillis(); 25 | 26 | IContainer container = new Container(); 27 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 28 | BufferedInputStream input = new BufferedInputStream(new FileInputStream(fileName), 1024 * 1024 ); 29 | 30 | builder.addFactories(input); 31 | input.close(); 32 | 33 | System.out.println("Script Parsing Done"); 34 | 35 | long parseTime = System.currentTimeMillis(); 36 | 37 | for(int i=0; i methodArgFactories = new ArrayList(); 17 | 18 | 19 | public StaticMethodFactory(Method method, List methodArgFactories) { 20 | if(method == null) throw new IllegalArgumentException("Method cannot be null"); 21 | this.method = method; 22 | this.methodArgFactories = methodArgFactories; 23 | } 24 | 25 | 26 | public Class getReturnType() { 27 | //if a method returns void, it should return the invocation target instead, enabling method chaining on methods returning void. 28 | if(isVoidReturnType()){ 29 | return Class.class; 30 | } 31 | 32 | return this.method.getReturnType(); 33 | } 34 | 35 | public Object instance(Object[] parameters, Object[] localProducts) { 36 | Object[] arguments = FactoryUtil.toArgumentArray(this.methodArgFactories, parameters, localProducts); 37 | try { 38 | //if a method returns void, it should return the invocation target instead, enabling method chaining on methods returning void. 39 | Object returnValue = method.invoke(null, arguments); 40 | if(isVoidReturnType()){ 41 | return null; 42 | } 43 | 44 | return returnValue; 45 | } catch(NullPointerException e){ 46 | throw new FactoryException( 47 | "StaticMethodFactory", "INSTANTIATION_ERROR", 48 | "Error instantiating object from static method [" + this.method + 49 | "]. Are you sure the method is declared static?" 50 | , e); 51 | } catch (Throwable t){ 52 | throw new FactoryException( 53 | "StaticMethodFactory", "INSTANTIATION_ERROR", 54 | "Error instantiating object from static method [" + this.method + "]", t); 55 | }finally{ 56 | //for(int j=0; j --> "); 65 | 66 | return builder.toString(); 67 | } 68 | 69 | 70 | public Method getMethod() { 71 | return method; 72 | } 73 | 74 | private boolean isVoidReturnType() { 75 | return void.class.equals(this.method.getReturnType()) || this.method.getReturnType() == null; 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/FieldAssignmentFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.FactoryException; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | import java.lang.reflect.Field; 7 | 8 | /** 9 | 10 | */ 11 | public class FieldAssignmentFactory extends LocalFactoryBase implements ILocalFactory { 12 | 13 | protected Field field = null; 14 | protected Class fieldOwningClass = null; 15 | protected ILocalFactory fieldAssignmentTargetFactory = null; 16 | protected ILocalFactory assignmentValueFactory = null; 17 | 18 | public FieldAssignmentFactory(Field field, ILocalFactory assignmentTargetFactory, ILocalFactory assignmentValueFactory) { 19 | this.field = field; 20 | this.fieldAssignmentTargetFactory = assignmentTargetFactory; 21 | this.assignmentValueFactory = assignmentValueFactory; 22 | } 23 | 24 | public FieldAssignmentFactory(Field field, Class fieldOwningClass, ILocalFactory assignmentValueFactory) { 25 | this.field = field; 26 | this.fieldOwningClass = fieldOwningClass; 27 | this.assignmentValueFactory = assignmentValueFactory; 28 | } 29 | 30 | public Class getReturnType() { 31 | return this.field.getType(); 32 | } 33 | 34 | /* todo clean up this method. Field can never be void return types. Fields always have a type. */ 35 | public Object instance(Object[] parameters, Object[] localProducts) { 36 | Object value = this.assignmentValueFactory.instance(parameters, localProducts); 37 | try { 38 | if(isInstanceField()) { 39 | field.set(this.fieldAssignmentTargetFactory.instance(parameters, localProducts), value); 40 | return value; 41 | } 42 | 43 | field.set(null, value); 44 | return value; 45 | } catch (Throwable t){ 46 | throw new FactoryException( 47 | "FieldAssignmentFactory", "ERROR_FLYWEIGHT_KEY_PARAMETER", 48 | "Error setting field value " + value + " on field " + this.field, t); 49 | } 50 | } 51 | 52 | private boolean isInstanceField() { 53 | return this.fieldAssignmentTargetFactory != null; 54 | } 55 | 56 | public String toString() { 57 | StringBuilder builder = new StringBuilder(); 58 | builder.append(" --> "); 61 | if(isInstanceField()){ 62 | builder.append(this.fieldAssignmentTargetFactory); 63 | } else { 64 | builder.append("<"); 65 | builder.append(this.fieldOwningClass); 66 | builder.append(">"); 67 | } 68 | 69 | return builder.toString(); 70 | } 71 | 72 | //this method is added only for testability. It is not part of the IFactory interface. 73 | public ILocalFactory getFieldAssignmentTargetFactory() { 74 | return fieldAssignmentTargetFactory; 75 | } 76 | 77 | public Field getField() { 78 | return field; 79 | } 80 | 81 | private boolean isVoidReturnType() { 82 | return void.class.equals(this.field.getType()) || this.field.getType() == null; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/script/ParserInput.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import com.jenkov.container.script.ParserException; 4 | 5 | import java.io.*; 6 | import java.util.Stack; 7 | 8 | /** 9 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 10 | */ 11 | public class ParserInput { 12 | 13 | protected ScriptTokenizer scriptTokenizer = null; 14 | protected Stack marks = new Stack(); 15 | 16 | /** 17 | * @deprecated Use the constructor that takes a Reader instead. 18 | * @param input 19 | */ 20 | public ParserInput(InputStream input) { 21 | this.scriptTokenizer = new ScriptTokenizer(new ScriptTokenizerInputBuffer(new InputStreamReader(input))); 22 | } 23 | 24 | public ParserInput(Reader reader) { 25 | this.scriptTokenizer = new ScriptTokenizer(new ScriptTokenizerInputBuffer(reader)); 26 | } 27 | 28 | 29 | public ParserInput(String input){ 30 | this.scriptTokenizer = new ScriptTokenizer(new ScriptTokenizerInputBuffer(new StringReader(input))); 31 | } 32 | 33 | 34 | 35 | 36 | 37 | 38 | public void factoryStart(){ 39 | this.scriptTokenizer.factoryStart(); 40 | } 41 | 42 | public boolean isNextElseBacktrack(Token expectedToken){ 43 | mark(); 44 | Token nextToken = nextToken(); 45 | boolean matches = expectedToken.equals(nextToken); 46 | if(matches) clearMark(); 47 | else backtrack(); 48 | return matches; 49 | } 50 | 51 | public void assertNextToken(Token token){ 52 | Token nextToken = nextToken(); 53 | if(nextToken == null || !nextToken.equals(token)){ 54 | throw new ParserException( 55 | "ParserInput", "ASSERT_NEXT_TOKEN", 56 | "Error (" + this.scriptTokenizer.getLineNo() + ", " + this.scriptTokenizer.getCharNo() + 57 | "): Expected token " + token + " but found " + nextToken); 58 | } 59 | } 60 | 61 | public Token lookAhead() { 62 | mark(); 63 | Token nextToken = nextToken(); 64 | backtrack(); 65 | return nextToken; 66 | } 67 | 68 | public Token markAndNextToken(){ 69 | mark(); 70 | return nextToken(); 71 | } 72 | 73 | public Token nextToken() { 74 | Token nextToken = this.scriptTokenizer.nextToken(); 75 | if(nextToken == null) return null; 76 | return nextToken; 77 | } 78 | 79 | public void assertNoMarks(){ 80 | if(this.marks.size() > 0){ 81 | throw new ParserException( 82 | "ParserInput", "ASSERT_NO_MARKS", 83 | "There should have been no marks at the current parsing point"); 84 | } 85 | } 86 | 87 | public int mark(){ 88 | ParserMark mark = this.scriptTokenizer.mark(); 89 | this.marks.push(mark); 90 | return this.marks.size(); 91 | } 92 | 93 | public int backtrack(){ 94 | ParserMark mark = this.marks.pop(); 95 | this.scriptTokenizer.backtrackTo(mark); 96 | return this.marks.size() + 1; 97 | } 98 | 99 | public void clearMark(){ 100 | this.marks.pop(); 101 | } 102 | 103 | public boolean hasMark(){ 104 | return this.marks.size() > 0; 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/InstanceMethodFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | import com.jenkov.container.itf.factory.FactoryException; 5 | 6 | import java.lang.reflect.Method; 7 | import java.util.List; 8 | import java.util.ArrayList; 9 | 10 | /** 11 | 12 | */ 13 | public class InstanceMethodFactory extends LocalFactoryBase implements ILocalFactory { 14 | 15 | protected Method method = null; 16 | protected ILocalFactory methodInvocationTargetFactory = null; 17 | protected List methodArgFactories = new ArrayList(); 18 | 19 | 20 | public InstanceMethodFactory(Method method, ILocalFactory methodInvocationTargetFactory, List methodArgFactories) { 21 | if(method == null) throw new IllegalArgumentException("Method cannot be null"); 22 | if(methodInvocationTargetFactory == null) throw new IllegalArgumentException("Method invocation target cannot be null"); 23 | this.method = method; 24 | this.methodInvocationTargetFactory = methodInvocationTargetFactory; 25 | this.methodArgFactories = methodArgFactories; 26 | } 27 | 28 | 29 | public Class getReturnType() { 30 | //if a method returns void, it should return the invocation target instead, enabling method chaining on methods returning void. 31 | if(isVoidReturnType()){ 32 | return methodInvocationTargetFactory.getReturnType(); 33 | } 34 | 35 | return this.method.getReturnType(); 36 | } 37 | 38 | public Object instance(Object[] parameters, Object[] localProducts) { 39 | Object[] arguments = FactoryUtil.toArgumentArray(this.methodArgFactories, parameters, localProducts); 40 | try { 41 | Object target = this.methodInvocationTargetFactory.instance(parameters, localProducts); 42 | if(target == null){ 43 | throw new NullPointerException("The object call the method " + method.toString() + " on was null"); 44 | } 45 | Object returnValue = method.invoke(target, arguments); 46 | 47 | //if a method returns void, it should return the invocation target instead, enabling method chaining on methods returning void. 48 | if(isVoidReturnType()){ 49 | return target; 50 | } else { 51 | return returnValue; 52 | } 53 | 54 | } catch (Throwable t){ 55 | throw new FactoryException( 56 | "InstanceMethodFactory", "INSTANTIATION_ERROR", 57 | "Error instantiating object from instance method [" + this.method +"]", t); 58 | }finally{ 59 | for(int j=0; j --> "); 68 | 69 | builder.append(this.methodInvocationTargetFactory); 70 | 71 | return builder.toString(); 72 | } 73 | 74 | //this method is added only for testability. It is not part of the IFactory interface. 75 | public ILocalFactory getMethodInvocationTargetFactory() { 76 | return methodInvocationTargetFactory; 77 | } 78 | 79 | public Method getMethod() { 80 | return method; 81 | } 82 | 83 | private boolean isVoidReturnType() { 84 | return void.class.equals(this.method.getReturnType()) || this.method.getReturnType() == null; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/ScriptTokenizerInputBufferTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | 5 | import java.io.StringReader; 6 | import java.io.Reader; 7 | import java.io.IOException; 8 | 9 | /** 10 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 11 | */ 12 | public class ScriptTokenizerInputBufferTest extends TestCase { 13 | 14 | public void testFactoryStart_noCopy() throws IOException { 15 | 16 | Reader reader = new StringReader("0123456789ABCDEFGHIJ"); 17 | ScriptTokenizerInputBuffer buffer = new ScriptTokenizerInputBuffer(reader, 10); 18 | 19 | assertEquals( 0, buffer.index); 20 | assertEquals(10, buffer.endIndex); 21 | assertEquals( 0, buffer.factoryStartIndex); 22 | 23 | buffer.factoryStart(); 24 | assertEquals( 0, buffer.index); 25 | assertEquals(10, buffer.endIndex); 26 | assertEquals( 0, buffer.factoryStartIndex); 27 | 28 | assertEquals('0', buffer.read()); 29 | assertEquals('1', buffer.read()); 30 | assertEquals('2', buffer.read()); 31 | assertEquals('3', buffer.read()); 32 | assertEquals('4', buffer.read()); 33 | assertEquals('5', buffer.read()); 34 | assertEquals('6', buffer.read()); 35 | assertEquals('7', buffer.read()); 36 | assertEquals('8', buffer.read()); 37 | assertEquals('9', buffer.read()); 38 | 39 | buffer.factoryStart(); 40 | assertEquals(10, buffer.factoryStartIndex); 41 | assertEquals(10, buffer.index); 42 | assertEquals(10, buffer.endIndex); 43 | } 44 | 45 | public void testFactoryStart_copy() throws IOException { 46 | 47 | Reader reader = new StringReader("0123456789ABCDEFGHIJ"); 48 | ScriptTokenizerInputBuffer buffer = new ScriptTokenizerInputBuffer(reader, 1); 49 | 50 | assertEquals('0', buffer.read()); 51 | buffer.factoryStart(); 52 | assertEquals('1', buffer.read()); 53 | buffer.factoryStart(); 54 | assertEquals('2', buffer.read()); 55 | buffer.factoryStart(); 56 | assertEquals('3', buffer.read()); 57 | 58 | buffer.factoryStart(); 59 | assertEquals('4', buffer.read()); 60 | buffer.factoryStart(); 61 | assertEquals('5', buffer.read()); 62 | buffer.factoryStart(); 63 | assertEquals('6', buffer.read()); 64 | buffer.factoryStart(); 65 | assertEquals('7', buffer.read()); 66 | 67 | buffer.factoryStart(); 68 | assertEquals('8', buffer.read()); 69 | buffer.factoryStart(); 70 | assertEquals('9', buffer.read()); 71 | buffer.factoryStart(); 72 | assertEquals('A', buffer.read()); 73 | buffer.factoryStart(); 74 | assertEquals('B', buffer.read()); 75 | 76 | buffer.factoryStart(); 77 | assertEquals('C', buffer.read()); 78 | buffer.factoryStart(); 79 | assertEquals('D', buffer.read()); 80 | buffer.factoryStart(); 81 | assertEquals('E', buffer.read()); 82 | buffer.factoryStart(); 83 | assertEquals('F', buffer.read()); 84 | 85 | buffer.factoryStart(); 86 | assertEquals('G', buffer.read()); 87 | buffer.factoryStart(); 88 | assertEquals('H', buffer.read()); 89 | buffer.factoryStart(); 90 | assertEquals('I', buffer.read()); 91 | buffer.factoryStart(); 92 | assertEquals('J', buffer.read()); 93 | buffer.factoryStart(); 94 | assertEquals(-1, buffer.read()); 95 | assertTrue(buffer.endOfStreamReached); 96 | assertEquals(-1, buffer.read()); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/Container.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | import com.jenkov.container.impl.factory.*; 4 | import com.jenkov.container.itf.factory.IGlobalFactory; 5 | 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | /** 10 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 11 | */ 12 | public class Container implements IContainer { 13 | 14 | protected Map factories = null; 15 | 16 | public Container() { 17 | this.factories = new ConcurrentHashMap(); 18 | } 19 | 20 | public Container(Map factories) { 21 | this.factories = factories; 22 | } 23 | 24 | 25 | public void addFactory(String name, IGlobalFactory factory) { 26 | if(this.factories.containsKey(name)) throw 27 | new ContainerException( 28 | "Container", "FACTORY_ALREADY_EXISTS", 29 | "Container already contains a factory with this name: " + name); 30 | this.factories.put(name, new GlobalFactoryProxy(factory)); 31 | } 32 | 33 | public void addValueFactory(String id, Object value){ 34 | GlobalFactoryBase factory = new GlobalNewInstanceFactory(); 35 | factory.setLocalInstantiationFactory(new ValueFactory(value)); 36 | this.factories.put(id, new GlobalFactoryProxy(factory)); 37 | } 38 | 39 | public IGlobalFactory replaceFactory(String name, IGlobalFactory newFactory){ 40 | GlobalFactoryProxy factoryProxy = (GlobalFactoryProxy) this.factories.get(name); 41 | if(factoryProxy == null) { 42 | addFactory(name, newFactory); 43 | return null; 44 | } else { 45 | return factoryProxy.setDelegateFactory(newFactory); 46 | } 47 | } 48 | 49 | public void removeFactory(String id) { 50 | this.factories.remove(id); 51 | } 52 | 53 | public IGlobalFactory getFactory(String id) { 54 | IGlobalFactory factory = this.factories.get(id); 55 | //if(factory == null) throw new ContainerException("Unknown Factory: " + id); 56 | return factory; 57 | } 58 | 59 | public Map getFactories() { 60 | return this.factories; 61 | } 62 | 63 | public Object instance(String id, Object ... parameters){ 64 | IGlobalFactory factory = this.factories.get(id); 65 | if(factory == null) throw new ContainerException( 66 | "Container", "UNKNOWN_FACTORY", 67 | "Unknown Factory: " + id); 68 | return factory.instance(parameters); 69 | } 70 | 71 | public void init(){ 72 | for(String key : this.factories.keySet()){ 73 | Object factory = this.factories.get(key); 74 | 75 | if(factory instanceof GlobalFactoryProxy){ 76 | factory = ((GlobalFactoryProxy) factory).getDelegateFactory(); 77 | if(factory instanceof GlobalSingletonFactory){ 78 | ((GlobalSingletonFactory) factory).instance(); 79 | } 80 | } 81 | } 82 | } 83 | 84 | public void dispose(){ 85 | execPhase("dispose"); 86 | } 87 | 88 | public void execPhase(String phase) { 89 | for(String key : this.factories.keySet()){ 90 | execPhase(phase, key); 91 | } 92 | } 93 | 94 | public void execPhase(String phase, String factoryName) { 95 | Object factory = this.factories.get(factoryName); 96 | if(factory instanceof GlobalFactoryProxy){ 97 | ((GlobalFactoryProxy) factory).execPhase(phase); 98 | } 99 | } 100 | 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/ContainerException.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | import java.util.List; 4 | import java.util.ArrayList; 5 | 6 | /** 7 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 8 | */ 9 | public class ContainerException extends RuntimeException { 10 | 11 | public static final long serialVersionUID = -1; 12 | 13 | protected List infoItems = 14 | new ArrayList(); 15 | 16 | public static class InfoItem{ 17 | public String errorContext = null; 18 | public String errorCode = null; 19 | public String errorText = null; 20 | public InfoItem(String contextCode, String errorCode, 21 | String errorText){ 22 | 23 | this.errorContext = contextCode; 24 | this.errorCode = errorCode; 25 | this.errorText = errorText; 26 | } 27 | } 28 | 29 | 30 | public ContainerException(String errorContext, String errorCode, String errorMessage){ 31 | super(errorMessage); 32 | addInfo(errorContext, errorCode, errorMessage); 33 | } 34 | 35 | public ContainerException(String errorContext, String errorCode, String errorMessage, Throwable cause){ 36 | super(errorMessage, cause); 37 | addInfo(errorContext, errorCode, errorMessage); 38 | } 39 | 40 | public ContainerException addInfo(String errorContext, String errorCode, String errorText){ 41 | this.infoItems.add( 42 | new InfoItem(errorContext, errorCode, errorText)); 43 | return this; 44 | } 45 | 46 | public List getInfoItems() { 47 | return infoItems; 48 | } 49 | 50 | public String getCode(){ 51 | StringBuilder builder = new StringBuilder(); 52 | 53 | for(int i = this.infoItems.size()-1 ; i >=0; i--){ 54 | InfoItem info = 55 | this.infoItems.get(i); 56 | builder.append('['); 57 | builder.append(info.errorContext); 58 | builder.append(':'); 59 | builder.append(info.errorCode); 60 | builder.append(']'); 61 | } 62 | 63 | return builder.toString(); 64 | } 65 | 66 | public String toString(){ 67 | StringBuilder builder = new StringBuilder(); 68 | 69 | builder.append("Error Code : " + getCode()); 70 | builder.append('\n'); 71 | 72 | 73 | //append additional context information. 74 | for(int i = this.infoItems.size()-1 ; i >=0; i--){ 75 | InfoItem info = 76 | this.infoItems.get(i); 77 | builder.append("Context Info: "); 78 | builder.append('['); 79 | builder.append(info.errorContext); 80 | builder.append(':'); 81 | builder.append(info.errorCode); 82 | builder.append(']'); 83 | builder.append(" : "); 84 | builder.append(info.errorText); 85 | if(i>0) builder.append('\n'); 86 | } 87 | 88 | //append root causes and text from this exception first. 89 | if(getMessage() != null) { 90 | builder.append('\n'); 91 | if(getCause() == null){ 92 | builder.append(getMessage()); 93 | } else if(!getMessage().equals(getCause().toString())){ 94 | builder.append(getMessage()); 95 | } 96 | } 97 | appendException(builder, getCause()); 98 | 99 | return builder.toString(); 100 | } 101 | 102 | private void appendException( 103 | StringBuilder builder, Throwable throwable){ 104 | if(throwable == null) return; 105 | appendException(builder, throwable.getCause()); 106 | builder.append(throwable.toString()); 107 | builder.append('\n'); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/IContainer.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | import com.jenkov.container.itf.factory.IGlobalFactory; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * The factory manager can keep track of the factories in the application. 9 | * You can register factories, unregister factories and other stuff. 10 | * 11 | * @author Jakob Jenkov - Copyright 2005 Jenkov Development 12 | */ 13 | public interface IContainer { 14 | 15 | /** 16 | * Adds a factory to the container using the given name. 17 | * @param name A name to identify the factory by. 18 | * @param factory A factory producing some component. 19 | */ 20 | public void addFactory(String name, IGlobalFactory factory); 21 | 22 | /** 23 | * Adds a value factory to the container using the given name. 24 | * A value factory just returns the value passed in the value parameter. 25 | * Thus the value object becomes a singleton. 26 | * Value factories can be used to add constants or configuration parameters to the container, 27 | * though these can also be added in scripts. 28 | * 29 | * @param name The name to identify the factory by. 30 | * @param value The value the value factory is to return (as a singleton). 31 | */ 32 | public void addValueFactory(String name, Object value); 33 | 34 | /** 35 | * Replaces the existing factory with the given name, with the new factory passed as parameter. 36 | * All factories referencing the old factory will hereafter reference the new factory. 37 | * @param name The name of the factory to replace. 38 | * @param newFactory The new factory that is to replace the old. 39 | * @return The old factory - the one that was replaced. 40 | */ 41 | public IGlobalFactory replaceFactory(String name, IGlobalFactory newFactory); 42 | 43 | /** 44 | * Removes the factory identified by the given name from the container. 45 | * @param name The name identifying the factory to remove. 46 | */ 47 | public void removeFactory(String name); 48 | 49 | /** 50 | * Returns the factory identified by the given name. 51 | * @param name The name identifying the factory to return. 52 | * @return The factory identified by the given name. 53 | */ 54 | public IGlobalFactory getFactory(String name); 55 | 56 | /** 57 | * Returns a Map containing all the factories in this container. 58 | * @return A Map containing all the factories in this container. 59 | */ 60 | public Map getFactories(); 61 | 62 | /** 63 | * Returns instance of whatever component the factory identified by the given 64 | * name produces. 65 | * @param name The name of the factory to obtain an instance from. 66 | * @param parameters Any parameters needed by the factory to produce the component instance. 67 | * @return An instance of the component the factory identified by the given name produces. 68 | */ 69 | public Object instance(String name, Object ... parameters); 70 | 71 | /** 72 | * Initializes the container. Currently this means creating all singletons and other cached instances. 73 | */ 74 | public void init(); 75 | 76 | /** 77 | * Executes the given life cycle phase on all factories in the container. 78 | * @param phase The name of the life cycle phase to execute ("config", "dipose" etc.) 79 | */ 80 | public void execPhase(String phase); 81 | 82 | /** 83 | * Executes the given life cycle phase on the factory identified by the given name. 84 | * @param phase The name of the life cycle phase to execute ("config", "dispose" etc.) 85 | * @param name The name of the factory to execute the life cycle phase on. 86 | */ 87 | public void execPhase(String phase, String name); 88 | 89 | /** 90 | * Executes the "dispose" life cycle phase on all factories in the container. 91 | */ 92 | public void dispose(); 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/script/ScriptTokenizerInputBuffer.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import java.io.Reader; 4 | import java.io.IOException; 5 | 6 | /** 7 | 8 | */ 9 | public class ScriptTokenizerInputBuffer { 10 | 11 | protected int maxFactorySize = 128 * 128; // 128 lines with 128 characters each = 16K 12 | protected int index = 0; 13 | protected int endIndex = 0; //used if buffer is larger than input read 14 | protected Reader reader = null; 15 | public char[] buffer = null; 16 | 17 | protected int factoryStartIndex = 0; 18 | protected boolean endOfStreamReached = false; 19 | protected TokenPool tokenPool = new TokenPool(); 20 | 21 | 22 | public ScriptTokenizerInputBuffer(Reader reader) { 23 | init(reader, this.maxFactorySize); 24 | } 25 | 26 | public ScriptTokenizerInputBuffer(Reader reader, int maxFactorySize) { 27 | init(reader, maxFactorySize); 28 | } 29 | 30 | public void init(Reader reader, int maxFactorySize){ 31 | this.maxFactorySize = maxFactorySize; 32 | this.reader = reader; 33 | this.buffer = new char[maxFactorySize]; //max factory size as buffer size. 34 | try { 35 | this.endIndex = this.reader.read(this.buffer); 36 | } catch (IOException e) { 37 | throw new ParserException( 38 | "ScriptTokenizerInputBuffer", "ERROR_READING_FROM_READER", 39 | 40 | "Error reading data from Reader into ScriptTokenizerInputBuffer", e); 41 | } 42 | } 43 | 44 | public void factoryStart() { 45 | this.factoryStartIndex = this.index; 46 | this.tokenPool.freeAll(); 47 | } 48 | 49 | public int read(){ 50 | if(index < endIndex ) return buffer[index++]; 51 | if(endOfStreamReached) return -1; 52 | 53 | compressBuffer(); 54 | fillBuffer(); 55 | 56 | return read(); 57 | 58 | } 59 | 60 | /* temp method... remove later*/ 61 | public void unread(char achar){ 62 | index--; 63 | } 64 | 65 | public void unread(){ 66 | index--; 67 | } 68 | 69 | 70 | private void compressBuffer() { 71 | for(int i=this.factoryStartIndex, j=0; i< this.endIndex;) { 72 | this.buffer[j++] = this.buffer[i++]; 73 | } 74 | this.endIndex -= this.factoryStartIndex; 75 | this.index -= this.factoryStartIndex; 76 | this.tokenPool.correctIndexOfTakenTokens(this.factoryStartIndex); 77 | this.factoryStartIndex = 0; 78 | } 79 | 80 | private void fillBuffer(){ 81 | try { 82 | int charsRead = this.reader.read(this.buffer, this.endIndex, this.buffer.length - this.endIndex); 83 | if (charsRead == -1) { 84 | this.endOfStreamReached = true; 85 | } else { 86 | this.endIndex += charsRead; 87 | } 88 | } catch (IOException e) { 89 | throw new ParserException( 90 | "ScriptTokenizerInputBuffer", "ERROR_FILL_BUFFER", 91 | "Error reading data into ScriptTokenizerInputBuffer", e); 92 | } 93 | } 94 | 95 | public Token token(){ 96 | Token token = this.tokenPool.take(); 97 | token.setBuffer(this.buffer); 98 | return token; 99 | } 100 | 101 | public ParserMark mark(){ 102 | ParserMark mark = new ParserMark(); 103 | mark.markIndex = this.index - this.factoryStartIndex; 104 | return mark; 105 | } 106 | 107 | public void backtrackTo(ParserMark mark){ 108 | int absoluteMarkIndex = this.factoryStartIndex + mark.markIndex; 109 | int charsToBacktrack = this.index - absoluteMarkIndex; 110 | this.index -= charsToBacktrack; 111 | 112 | } 113 | 114 | public boolean isEndOfInputReached(){ 115 | return (this.index == this.endIndex) && this.endOfStreamReached; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/CollectionFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.ILocalFactory; 4 | 5 | import java.lang.reflect.Array; 6 | import java.lang.reflect.ParameterizedType; 7 | import java.lang.reflect.Type; 8 | import java.util.*; 9 | 10 | /** 11 | 12 | */ 13 | public class CollectionFactory extends LocalFactoryBase implements ILocalFactory { 14 | 15 | public enum CollectionKind { 16 | ARRAY, LIST, SET; 17 | } 18 | 19 | protected CollectionKind collectionKind = CollectionKind.LIST; 20 | protected Class collectionArgumentType = null; 21 | protected Type collectionGenericType = String.class; 22 | protected Type collectionRawType = null; 23 | protected Class collectionElementType = Object.class; 24 | 25 | protected List collectionContentFactories = null; 26 | 27 | public void setCollectionType(Class argumentType, Type genericType) { 28 | this.collectionArgumentType = argumentType; 29 | this.collectionGenericType = genericType; 30 | 31 | if(genericType instanceof ParameterizedType){ 32 | ParameterizedType parameterizedCollectionType = (ParameterizedType) genericType; 33 | this.collectionRawType = parameterizedCollectionType.getRawType(); 34 | this.collectionElementType = (Class) parameterizedCollectionType.getActualTypeArguments()[0]; 35 | } 36 | 37 | if(argumentType.isArray()){ 38 | this.collectionKind = CollectionKind.ARRAY; 39 | this.collectionElementType = this.collectionArgumentType.getComponentType(); 40 | } else if(FactoryUtil.isSubstitutableFor(argumentType, List.class)){ 41 | this.collectionKind = CollectionKind.LIST; 42 | } else if(FactoryUtil.isSubstitutableFor(argumentType, Set.class)){ 43 | this.collectionKind = CollectionKind.SET; 44 | } else if(FactoryUtil.isSubstitutableFor(argumentType, Collection.class)){ 45 | this.collectionKind = CollectionKind.LIST; 46 | } 47 | 48 | /* todo move this code to wrapInConversionFactoryIfNecessary, if possible. Then the factory knows as little as possible about parsing*/ 49 | FactoryBuilder builder = new FactoryBuilder(); 50 | for(int i=0; i collectionContentFactories) { 60 | this.collectionContentFactories = collectionContentFactories; 61 | } 62 | 63 | public Class getReturnType() { 64 | return this.collectionArgumentType; 65 | } 66 | 67 | public Object instance(Object[] parameters, Object[] localProducts) { 68 | if(this.collectionKind == CollectionKind.ARRAY){ 69 | Object array = Array.newInstance(this.collectionArgumentType.getComponentType(), this.collectionContentFactories.size()); 70 | for(int i=0; i test = null; 45 | public Object instance(Object... parameters) { 46 | return "test3" + test.instance(); 47 | } 48 | }); 49 | string = (String) container.instance("test3"); 50 | assertEquals("test3test", string); 51 | factory = container.getFactory("test3"); 52 | assertEquals(String.class, factory.getReturnType()); 53 | 54 | builder.addFactory("test4", null, new JavaFactory(){ 55 | public IGlobalFactory test2 = null; 56 | public String instance(Object... parameters) { 57 | return "test4" + test2.instance(); 58 | } 59 | }); 60 | string = (String) container.instance("test4"); 61 | assertEquals("test4test2test", string); 62 | factory = container.getFactory("test4"); 63 | assertEquals(String.class, factory.getReturnType()); 64 | 65 | try { 66 | builder.addFactory("test4", null, new JavaFactory(){ 67 | public IGlobalFactory test2 = null; 68 | public String instance(Object... parameters) { 69 | return "test4" + test2.instance(); 70 | } 71 | }); 72 | fail("exception should be thrown because test2 factory is parameterized to Integer"); 73 | } catch (Exception e) { 74 | //do nothing, exception expected 75 | } 76 | 77 | 78 | try { 79 | builder.addFactory("test5", null, new JavaFactory(){ 80 | public IGlobalFactory test5 = null; 81 | public String instance(Object... parameters) { 82 | return "test5" + test5.instance(); 83 | } 84 | }); 85 | fail("exception should be thrown because test5 factory does not exist"); 86 | } catch (FactoryException e) { 87 | //do nothing, exception expected 88 | } 89 | 90 | builder.addFactory("test6", new JavaFactory(){ 91 | public @Factory("test2") IGlobalFactory testXYZ = null; 92 | public String instance(Object... parameters) { 93 | return "test6" + testXYZ.instance(); 94 | } 95 | }); 96 | string = (String) container.instance("test6"); 97 | assertEquals("test6test2test", string); 98 | factory = container.getFactory("test6"); 99 | assertEquals(String.class, factory.getReturnType()); 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/FactoryFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | import com.jenkov.container.TestProduct; 7 | 8 | /** 9 | 10 | */ 11 | public class FactoryFactoryTest extends TestCase { 12 | 13 | public void testContainerInjection(){ 14 | IContainer container = new Container(); 15 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 16 | 17 | builder.addFactory("bean = \"a factory product\"; "); 18 | builder.addFactory("bean2 = com.jenkov.container.TestProduct((com.jenkov.container.IContainer) #bean1);"); 19 | TestProduct bean2 = (TestProduct) container.instance("bean2"); 20 | assertSame(container, bean2.container); 21 | 22 | builder.addFactory("bean3 = com.jenkov.container.TestProduct(); " + 23 | " config{ $bean3.container = #bean; }"); 24 | TestProduct bean3 = (TestProduct) container.instance("bean3"); 25 | assertSame(container, bean3.container); 26 | 27 | builder.addFactory("bean4 = com.jenkov.container.TestProduct().setContainer(#bean);"); 28 | TestProduct bean4 = (TestProduct) container.instance("bean4"); 29 | assertSame(container, bean4.container); 30 | 31 | builder.addFactory("bean5 = com.jenkov.container.TestProduct.staticContainer = #bean;"); 32 | IContainer containerStatic = (Container) container.instance("bean5"); 33 | assertSame(containerStatic, container); 34 | 35 | TestProduct.staticContainer = null; 36 | builder.addFactory("bean6 = com.jenkov.container.TestProduct.setStaticContainer(#bean);"); 37 | container.instance("bean6"); // returns null from void static method call. 38 | assertSame(TestProduct.staticContainer, container); 39 | 40 | } 41 | 42 | public void testFactoryInjection(){ 43 | IContainer container = new Container(); 44 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 45 | 46 | builder.addFactory("bean = \"a factory product\"; "); 47 | builder.addFactory("bean2 = com.jenkov.container.TestProduct((com.jenkov.container.ICustomFactory) #bean);"); 48 | TestProduct bean2 = (TestProduct) container.instance("bean2"); 49 | assertEquals("a factory product", bean2.factory.bean()); 50 | assertEquals("a factory product", bean2.factory.instance()); 51 | assertEquals("a factory product", bean2.factory.beanInstance()); 52 | 53 | builder.addFactory("bean3 = com.jenkov.container.TestProduct(); " + 54 | " config{ $bean3.factory = #bean; }"); 55 | TestProduct bean3 = (TestProduct) container.instance("bean3"); 56 | assertEquals("a factory product", bean3.factory.bean()); 57 | assertEquals("a factory product", bean3.factory.instance()); 58 | assertEquals("a factory product", bean3.factory.beanInstance()); 59 | 60 | builder.addFactory("bean4 = com.jenkov.container.TestProduct().setFactory(#bean);"); 61 | TestProduct bean4 = (TestProduct) container.instance("bean4"); 62 | assertEquals("a factory product", bean4.factory.bean()); 63 | assertEquals("a factory product", bean4.factory.instance()); 64 | assertEquals("a factory product", bean4.factory.beanInstance()); 65 | 66 | 67 | TestProduct.staticFactory = null; 68 | builder.addFactory("bean5 = com.jenkov.container.TestProduct.staticFactory = #bean;"); 69 | Object instance = container.instance("bean5"); //returns the factory... ?!? 70 | assertNotNull(TestProduct.staticFactory); 71 | assertEquals("a factory product", TestProduct.staticFactory.bean()); 72 | assertEquals("a factory product", TestProduct.staticFactory.instance()); 73 | assertEquals("a factory product", TestProduct.staticFactory.beanInstance()); 74 | 75 | 76 | TestProduct.staticFactory = null; 77 | builder.addFactory("bean6 = com.jenkov.container.TestProduct.setStaticFactory(#bean);"); 78 | container.instance("bean6"); // returns null from void static method call. 79 | assertNotNull(TestProduct.staticFactory); 80 | assertEquals("a factory product", TestProduct.staticFactory.bean()); 81 | assertEquals("a factory product", TestProduct.staticFactory.instance()); 82 | assertEquals("a factory product", TestProduct.staticFactory.beanInstance()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/ParserInput2Test.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | 5 | import java.io.IOException; 6 | import java.io.ByteArrayInputStream; 7 | 8 | /** 9 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 10 | */ 11 | public class ParserInput2Test extends TestCase { 12 | 13 | String inputString = "A man came through the door, and {he laughed)\n" + 14 | "Then a (woman came} too, and ; was a real annoying incident\n" + 15 | " \n" + 16 | "\n" + 17 | "\n\n" + 18 | "lalala"; 19 | 20 | public void testNextToken() throws IOException { 21 | 22 | ParserInput input = new ParserInput(new ByteArrayInputStream(inputString.getBytes())); 23 | 24 | assertParse(input, "A", 1, 2); 25 | assertParse(input, "man", 1, 6); 26 | assertParse(input, "came", 1, 11); 27 | assertParse(input, "through", 1, 19); 28 | assertParse(input, "the", 1, 23); 29 | assertParse(input, "door", 1, 28); 30 | assertParse(input, ",", 1, 29); 31 | assertParse(input, "and", 1, 33); 32 | assertParse(input, "{", 1, 35); 33 | assertParse(input, "he", 1, 37); 34 | assertParse(input, "laughed", 1, 45); 35 | assertParse(input, ")", 1, 46); 36 | 37 | assertParse(input, "Then", 2, 5); 38 | assertParse(input, "a", 2, 7); 39 | assertParse(input, "(", 2, 9); 40 | assertParse(input, "woman", 2, 14); 41 | assertParse(input, "came", 2, 19); 42 | assertParse(input, "}", 2, 20); 43 | assertParse(input, "too", 2, 24); 44 | assertParse(input, ",", 2, 25); 45 | assertParse(input, "and", 2, 29); 46 | assertParse(input, ";", 2, 31); 47 | assertParse(input, "was", 2, 35); 48 | assertParse(input, "a", 2, 37); 49 | assertParse(input, "real", 2, 42); 50 | assertParse(input, "annoying", 2, 51); 51 | assertParse(input, "incident", 2, 60); 52 | 53 | assertParse(input, "lalala", 7, 7); 54 | 55 | assertNull(input.nextToken()); 56 | assertEquals(7, input.scriptTokenizer.getLineNo()); 57 | assertEquals(7, input.scriptTokenizer.getCharNo()); 58 | 59 | } 60 | 61 | public void testPushPopMarks() throws IOException { 62 | ParserInput input = new ParserInput(new ByteArrayInputStream(inputString.getBytes())); 63 | 64 | assertParse(input, "A",1, 2); 65 | assertFalse(input.hasMark()); 66 | 67 | input.mark(); 68 | assertParse(input, "man", 1, 6); 69 | assertParse(input, "came", 1, 11); 70 | assertParse(input, "through", 1, 19); 71 | 72 | input.mark(); 73 | assertParse(input, "the", 1, 23); 74 | assertParse(input, "door", 1, 28); 75 | assertParse(input, ",", 1, 29); 76 | 77 | input.backtrack(); 78 | assertEquals(19, input.scriptTokenizer.getCharNo()); 79 | assertEquals(18, input.scriptTokenizer.inputBuffer.index); 80 | 81 | assertParse(input, "the", 1, 23); 82 | assertParse(input, "door", 1, 28); 83 | assertParse(input, ",", 1, 29); 84 | 85 | assertParse(input, "and", 1, 33); 86 | assertParse(input, "{", 1, 35); 87 | assertParse(input, "he", 1, 37); 88 | assertParse(input, "laughed", 1, 45); 89 | assertParse(input, ")", 1, 46); 90 | 91 | assertParse(input, "Then", 2, 5); 92 | assertParse(input, "a", 2, 7); 93 | assertParse(input, "(", 2, 9); 94 | assertParse(input, "woman", 2, 14); 95 | assertParse(input, "came", 2, 19); 96 | assertParse(input, "}", 2, 20); 97 | 98 | input.backtrack(); 99 | assertParse(input, "man", 1, 6); 100 | assertParse(input, "came", 1, 11); 101 | assertParse(input, "through", 1, 19); 102 | } 103 | 104 | private void assertParse(ParserInput input, String expectedValue, int lineNo, int charNo) throws IOException { 105 | Token nextToken = input.nextToken(); 106 | 107 | Token expected = new Token(); 108 | expected.setBuffer(expectedValue.toCharArray()); 109 | expected.setFrom(0); 110 | expected.setLength(expected.getBuffer().length); 111 | 112 | assertEquals(expected, nextToken); 113 | assertEquals(lineNo, input.scriptTokenizer.getLineNo()); 114 | assertEquals(charNo, input.scriptTokenizer.getCharNo()); 115 | } 116 | 117 | 118 | } -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/GlobalFlyweightTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import com.jenkov.container.Container; 4 | import com.jenkov.container.TestProduct; 5 | import com.jenkov.container.IContainer; 6 | import junit.framework.TestCase; 7 | 8 | /** 9 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 10 | */ 11 | public class GlobalFlyweightTest extends TestCase { 12 | 13 | public void testInstance_using_string(){ 14 | IContainer container = new Container(); 15 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 16 | 17 | builder.addFactory("bean = 1F java.lang.String('test'); "); 18 | 19 | String test1 = (String) container.instance("bean", "1"); 20 | String test2 = (String) container.instance("bean", "2"); 21 | assertSame(test1, container.instance("bean", "1")); 22 | assertSame(test2, container.instance("bean", "2")); 23 | 24 | assertNotSame(test1, test2); 25 | } 26 | 27 | public void testInstance(){ 28 | IContainer container = new Container(); 29 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 30 | 31 | builder.addFactory("bean = 1F com.jenkov.container.TestProduct();"); 32 | TestProduct product1 = (TestProduct) container.instance("bean", "1"); 33 | assertSame(product1, container.instance("bean", "1")); 34 | assertNotSame(container.instance("bean", "1"), container.instance("bean", "2")); 35 | assertSame(container.instance("bean", "2"), container.instance("bean", "2")); 36 | assertNull(product1.getValue1()); 37 | 38 | builder.addFactory( 39 | "bean2 = 1F com.jenkov.container.TestProduct(); " + 40 | " config{ $bean2.setValue1(\"value1\"); } "); 41 | 42 | TestProduct product2 = (TestProduct) container.instance("bean2", "1"); 43 | assertSame(product2, container.instance("bean2", "1")); 44 | assertNotSame(container.instance("bean2", "1"), container.instance("bean2", "2")); 45 | assertSame(container.instance("bean2", "2"), container.instance("bean2", "2")); 46 | assertEquals("value1", product2.getValue1()); 47 | assertEquals("value1", ((TestProduct) container.instance("bean2", "2")).getValue1()); 48 | 49 | builder.addFactory( 50 | "bean3 = 1F com.jenkov.container.TestProduct(); " + 51 | " config { $bean3.setValue1(\"value1\"); } " + 52 | " myPhase{ $bean3.setValue2(\"value2\"); }" 53 | ); 54 | 55 | TestProduct product3 = (TestProduct) container.instance("bean3", "1"); 56 | assertSame(product3, container.instance("bean3", "1")); 57 | assertNotSame(container.instance("bean3", "1"), container.instance("bean3", "2")); 58 | assertSame(container.instance("bean3", "2"), container.instance("bean3", "2")); 59 | assertEquals("value1", product3.getValue1()); 60 | assertEquals("value1", ((TestProduct) container.instance("bean3", "2")).getValue1()); 61 | assertNull(product3.getValue2()); 62 | 63 | container.execPhase("myPhase"); 64 | assertEquals("value2", product3.getValue2()); 65 | assertEquals("value2", ((TestProduct) container.instance("bean3", "2")).getValue2()); 66 | 67 | builder.addFactory( 68 | "bean4 = 1F com.jenkov.container.TestProduct(); " + 69 | " config { $bean4.setValue1(\"value1\"); } " + 70 | " myPhase{ $bean4.setValue2(\"value2\"); } " + 71 | " dispose{ $bean4.setValue2(\"disposed\");}" 72 | ); 73 | 74 | TestProduct product4 = (TestProduct) container.instance("bean4", "1"); 75 | assertSame(product4, container.instance("bean4", "1")); 76 | assertNotSame(container.instance("bean4", "1"), container.instance("bean4", "2")); 77 | assertSame(container.instance("bean4", "2"), container.instance("bean4", "2")); 78 | assertEquals("value1", product4.getValue1()); 79 | assertEquals("value1", ((TestProduct) container.instance("bean3", "2")).getValue1()); 80 | assertNull(product4.getValue2()); 81 | 82 | container.execPhase("myPhase"); 83 | assertEquals("value2", product4.getValue2()); 84 | assertEquals("value2", ((TestProduct) container.instance("bean4", "2")).getValue2()); 85 | 86 | container.dispose(); 87 | assertEquals("disposed", product4.getValue2()); 88 | assertEquals("disposed", ((TestProduct) container.instance("bean4", "2")).getValue2()); 89 | 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/MethodFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import com.jenkov.container.Container; 4 | import com.jenkov.container.TestProduct; 5 | import com.jenkov.container.impl.factory.*; 6 | import junit.framework.TestCase; 7 | 8 | /** 9 | 10 | */ 11 | public class MethodFactoryTest extends TestCase { 12 | 13 | public void testMethodModifiers(){ 14 | Container container = new Container(); 15 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 16 | 17 | try { 18 | builder.addFactory("test = * com.jenkov.container.TestProduct().createProduct();"); 19 | fail("The createProduct() method is static and trying to call it on an instance should throw exception"); 20 | } catch (ParserException e) { 21 | if(!"FactoryBuilder".equals(e.getInfoItems().get(0).errorContext)){ 22 | fail("Wrong exception caught"); 23 | } 24 | if(!"INSTANCE_METHOD_FACTORY_ERROR".equals(e.getInfoItems().get(0).errorCode)){ 25 | fail("Wrong exception caught"); 26 | } 27 | } 28 | 29 | 30 | try { 31 | builder.addFactory("test = * com.jenkov.container.TestProduct.getValue1();"); 32 | fail("The createProduct() method is static and trying to call it on an instance should throw exception"); 33 | } catch (ParserException e) { 34 | if(!"FactoryBuilder".equals(e.getInfoItems().get(0).errorContext)){ 35 | fail("Wrong exception caught"); 36 | } 37 | if(!"STATIC_METHOD_FACTORY_ERROR".equals(e.getInfoItems().get(0).errorCode)){ 38 | fail("Wrong exception caught"); 39 | } 40 | } 41 | 42 | 43 | 44 | 45 | } 46 | 47 | 48 | public void testBuildMethodFactory() { 49 | Container container = new Container(); 50 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 51 | 52 | builder.addFactory("test = * com.jenkov.container.TestProduct.createProduct();"); 53 | GlobalFactoryProxy factory = (GlobalFactoryProxy) container.getFactory("test"); 54 | assertTrue(factory.getDelegateFactory() instanceof GlobalNewInstanceFactory); 55 | GlobalNewInstanceFactory globalNewInstanceFactory = (GlobalNewInstanceFactory) factory.getDelegateFactory(); 56 | assertTrue(globalNewInstanceFactory.getLocalInstantiationFactory() instanceof LocalProductProducerFactory); 57 | assertEquals(TestProduct.class, factory.getReturnType()); 58 | assertNotNull(container.instance("test")); 59 | assertNotSame(container.instance("test"), container.instance("test")); 60 | 61 | builder.addFactory("test2 = * com.jenkov.container.TestProduct.createProduct(test);"); 62 | TestProduct product = (TestProduct) container.instance("test2"); 63 | assertNotNull(product); 64 | assertNotSame(product, product.getInternalProduct()); 65 | assertNotSame(container.instance("test2"), container.instance("test2")); 66 | 67 | builder.addFactory("test3 = * com.jenkov.container.TestProduct.createProduct(test).getInternalProduct();"); 68 | product = (TestProduct) container.instance("test3"); 69 | assertNotNull(product); 70 | assertNull(product.getInternalProduct()); 71 | assertNotSame(container.instance("test3"), container.instance("test3")); 72 | factory = (GlobalFactoryProxy) container.getFactory("test3"); 73 | assertTrue(factory.getDelegateFactory() instanceof GlobalNewInstanceFactory); 74 | globalNewInstanceFactory = (GlobalNewInstanceFactory) factory.getDelegateFactory(); 75 | assertTrue(globalNewInstanceFactory.getLocalInstantiationFactory() instanceof LocalProductProducerFactory); 76 | assertTrue(((LocalProductProducerFactory) globalNewInstanceFactory.getLocalInstantiationFactory()).getInstantiationFactory() instanceof InstanceMethodFactory); 77 | 78 | 79 | InstanceMethodFactory instanceMethodFactory = (InstanceMethodFactory) ((LocalProductProducerFactory) globalNewInstanceFactory.getLocalInstantiationFactory()).getInstantiationFactory(); 80 | assertEquals("getInternalProduct", instanceMethodFactory.getMethod().getName()); 81 | StaticMethodFactory staticMethodFactory = (StaticMethodFactory) instanceMethodFactory.getMethodInvocationTargetFactory(); 82 | assertEquals("createProduct", staticMethodFactory.getMethod().getName()); 83 | 84 | builder.addFactory("test4 = * test3.setValue1(\"lala\").setValue2(\"lala2\");"); 85 | product = (TestProduct) container.instance("test4"); 86 | assertEquals("lala", product.getValue1()); 87 | assertEquals("lala2", product.getValue2()); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/GlobalFactoryBase.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.IGlobalFactory; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | /** 11 | 12 | */ 13 | public abstract class GlobalFactoryBase implements IGlobalFactory { 14 | protected ILocalFactory localInstantiationFactory = null; 15 | // protected IGlobalFactory globalInstantiationFactory = null; 16 | protected Map> phases = new ConcurrentHashMap(); 17 | 18 | protected int localProductCount = 0; 19 | 20 | public void setLocalProductCount(int localProductCount) { 21 | this.localProductCount = localProductCount; 22 | } 23 | 24 | public int getLocalProductCount() { 25 | return localProductCount; 26 | } 27 | 28 | public ILocalFactory getLocalInstantiationFactory() { 29 | return localInstantiationFactory; 30 | } 31 | 32 | public void setLocalInstantiationFactory(ILocalFactory localInstantiationFactory) { 33 | this.localInstantiationFactory = localInstantiationFactory; 34 | } 35 | 36 | // public IGlobalFactory getGlobalInstantiationFactory() { 37 | // return globalInstantiationFactory; 38 | // } 39 | 40 | // public void setGlobalInstantiationFactory(IGlobalFactory globalInstantiationFactory) { 41 | // this.globalInstantiationFactory = globalInstantiationFactory; 42 | // } 43 | 44 | public void setPhase(String phase, List factories){ 45 | this.phases.put(phase, factories); 46 | } 47 | 48 | 49 | /** 50 | * This method is called by the container when executing a phase in a factory that supports life cycle phases. 51 | * The container knows nothing about local products, therefore this method is called. Only the concrete 52 | * factory knows about cached local products (if any). 53 | * 54 | *

55 | * This is the method a global factory will override when implementing life cycle phase behaviour, e.g. for 56 | * cached objects. 57 | * 58 | * @param phase The name of the phase to execute. For instance, "config" or "dispose". 59 | * @param parameters The parameters passed to the container when the phase begins. For instance to 60 | * an instance() method call, or an execPhase(phase, factory, parameters) call. 61 | * @return Null, or the local products the phase ends up being executed on. If executed 62 | * for several local product arrays (e.g. in pools or flyweights), null will be returned, since it does not 63 | * make sense to return anything. Returning anything would only make sense for 64 | * the "create" phase, but currently this phase does not use the execPhase() method 65 | * to carry out its work. It uses the factory.instance() methods instead. 66 | */ 67 | public Object[] execPhase(String phase, Object ... parameters){ 68 | return null; 69 | } 70 | /* 71 | { 72 | Object[] localProducts = this.localProductCount > 0? new Object[this.localProductCount] : null; 73 | return execPhase(phase, parameters, localProducts); 74 | }*/ 75 | 76 | /** 77 | * Executes a life cycle phase on the given local products, using the given input parameters. 78 | * This method is a utility method that global factories can use to implement their phase execution. 79 | * @param phase The name of the phase to execute. 80 | * @param parameters Any input parameters to pass to the phase factory chain. 81 | * @param localProducts Any local products (typically cached products) to pass to the phase factory chain. 82 | 83 | * @return Null, or the local products the phase ends up being executed on. If executed 84 | * for several local product arrays (e.g. in pools or flyweights), null will be returned, since it does not 85 | * make sense to return anything. Returning anything would only make sense for 86 | * the "create" phase, but currently this phase does not use the execPhase() method 87 | * to carry out its work. It uses the factory.instance() methods instead. 88 | */ 89 | protected Object[] execPhase(String phase, Object[] parameters, Object[] localProducts){ 90 | List phaseFactories = this.phases.get(phase); 91 | if(phaseFactories != null){ 92 | for(ILocalFactory factory : phaseFactories){ 93 | factory.instance(parameters, localProducts); 94 | } 95 | } 96 | return localProducts; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/ScriptTokenizer2Test.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | 5 | import java.io.StringReader; 6 | 7 | /** 8 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 9 | */ 10 | public class ScriptTokenizer2Test extends TestCase { 11 | 12 | public void testNextToken(){ 13 | String script = " bean = * com;\n bean2 = * blablabla();\n \n \n\r \r\n"; 14 | ScriptTokenizer tokenizer = new ScriptTokenizer(new ScriptTokenizerInputBuffer(new StringReader(script))); 15 | 16 | Token token = tokenizer.nextToken(); 17 | assertEquals(1, token.getLineNo()); 18 | assertEquals(4, token.length()); 19 | assertEquals(3, token.getFrom()); 20 | assertEquals('b', token.getBuffer()[token.getFrom()]); 21 | assertEquals('e', token.getBuffer()[token.getFrom() + 1]); 22 | assertEquals('a', token.getBuffer()[token.getFrom() + 2]); 23 | assertEquals('n', token.getBuffer()[token.getFrom() + 3]); 24 | 25 | assertEquals(4, token.getCharNoBefore()); 26 | // assertEquals(, ); 27 | 28 | token = tokenizer.nextToken(); 29 | assertEquals(1, token.getLineNo()); 30 | assertEquals(1, token.length()); 31 | assertEquals(8, token.getFrom()); 32 | assertEquals('=', token.getBuffer()[token.getFrom()]); 33 | 34 | token = tokenizer.nextToken(); 35 | assertEquals(1, token.getLineNo()); 36 | assertEquals(1, token.length()); 37 | assertEquals(10, token.getFrom()); 38 | assertEquals('*', token.getBuffer()[token.getFrom()]); 39 | 40 | token = tokenizer.nextToken(); 41 | assertEquals(1, token.getLineNo()); 42 | assertEquals(3, token.length()); 43 | assertEquals(12, token.getFrom()); 44 | assertEquals('c', token.getBuffer()[token.getFrom()]); 45 | assertEquals('o', token.getBuffer()[token.getFrom() + 1]); 46 | assertEquals('m', token.getBuffer()[token.getFrom() + 2]); 47 | 48 | token = tokenizer.nextToken(); 49 | assertEquals(1, token.getLineNo()); 50 | assertEquals(1, token.length()); 51 | assertEquals(15, token.getFrom()); 52 | assertEquals(';', token.getBuffer()[token.getFrom()]); 53 | 54 | //line 2 55 | token = tokenizer.nextToken(); 56 | assertEquals(2, token.getLineNo()); 57 | assertEquals(5, token.length()); 58 | assertEquals(21, token.getFrom()); 59 | assertEquals('b', token.getBuffer()[token.getFrom()]); 60 | assertEquals('e', token.getBuffer()[token.getFrom() + 1]); 61 | assertEquals('a', token.getBuffer()[token.getFrom() + 2]); 62 | assertEquals('n', token.getBuffer()[token.getFrom() + 3]); 63 | assertEquals('2', token.getBuffer()[token.getFrom() + 4]); 64 | 65 | token = tokenizer.nextToken(); 66 | assertEquals(2, token.getLineNo()); 67 | assertEquals(1, token.length()); 68 | assertEquals(27, token.getFrom()); 69 | assertEquals('=', token.getBuffer()[token.getFrom()]); 70 | 71 | token = tokenizer.nextToken(); 72 | assertEquals(2, token.getLineNo()); 73 | assertEquals(1, token.length()); 74 | assertEquals(29, token.getFrom()); 75 | assertEquals('*', token.getBuffer()[token.getFrom()]); 76 | 77 | token = tokenizer.nextToken(); 78 | assertEquals(2, token.getLineNo()); 79 | assertEquals(9, token.length()); 80 | assertEquals(31, token.getFrom()); 81 | assertEquals('b', token.getBuffer()[token.getFrom()]); 82 | assertEquals('l', token.getBuffer()[token.getFrom() + 1]); 83 | assertEquals('a', token.getBuffer()[token.getFrom() + 2]); 84 | assertEquals('b', token.getBuffer()[token.getFrom() + 3]); 85 | assertEquals('l', token.getBuffer()[token.getFrom() + 4]); 86 | assertEquals('a', token.getBuffer()[token.getFrom() + 5]); 87 | assertEquals('b', token.getBuffer()[token.getFrom() + 6]); 88 | assertEquals('l', token.getBuffer()[token.getFrom() + 7]); 89 | assertEquals('a', token.getBuffer()[token.getFrom() + 8]); 90 | 91 | token = tokenizer.nextToken(); 92 | assertEquals(2, token.getLineNo()); 93 | assertEquals(1, token.length()); 94 | assertEquals(40, token.getFrom()); 95 | assertEquals('(', token.getBuffer()[token.getFrom()]); 96 | 97 | token = tokenizer.nextToken(); 98 | assertEquals(2, token.getLineNo()); 99 | assertEquals(1, token.length()); 100 | assertEquals(41, token.getFrom()); 101 | assertEquals(')', token.getBuffer()[token.getFrom()]); 102 | 103 | token = tokenizer.nextToken(); 104 | assertEquals(2, token.getLineNo()); 105 | assertEquals(1, token.length()); 106 | assertEquals(42, token.getFrom()); 107 | assertEquals(';', token.getBuffer()[token.getFrom()]); 108 | 109 | token = tokenizer.nextToken(); 110 | assertNull(token); 111 | 112 | 113 | 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/ContainerTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.script.ScriptFactoryBuilder; 5 | import com.jenkov.container.java.JavaFactoryBuilder; 6 | import com.jenkov.container.java.JavaFactory; 7 | import com.jenkov.container.itf.factory.IGlobalFactory; 8 | 9 | /** 10 | 11 | */ 12 | public class ContainerTest extends TestCase { 13 | 14 | 15 | public static class TestFactory extends JavaFactory { 16 | public TestProduct instance(Object... parameters) { 17 | TestProduct product = new TestProduct(); 18 | product.setValue1("value1"); 19 | return product; 20 | } 21 | } 22 | 23 | public static class TestFactory2 extends JavaFactory { 24 | public IGlobalFactory test = null; 25 | public TestProduct instance(Object... parameters) { 26 | TestProduct product = test.instance(parameters); 27 | product.setValue2("other"); 28 | return product; 29 | } 30 | } 31 | 32 | public static class TestFactory3 extends JavaFactory { 33 | public TestProduct instance(Object... parameters) { 34 | TestProduct product = new TestProduct(); 35 | product.setValue1("value2"); 36 | return product; 37 | } 38 | } 39 | 40 | 41 | 42 | public static class StringFactory3 extends JavaFactory { 43 | public IGlobalFactory test = null; 44 | public String instance(Object ... parameters) { 45 | return "test2" + test.instance(); 46 | } 47 | } 48 | 49 | public void testReplaceScriptFactory(){ 50 | IContainer container = new Container(); 51 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 52 | 53 | builder.addFactory("test = * com.jenkov.container.TestProduct().setValue1('value1'); "); 54 | builder.addFactory("test2 = * test.setValue2('other'); "); 55 | 56 | TestProduct testProduct = (TestProduct) container.instance("test"); 57 | assertEquals("value1", testProduct.getValue1()); 58 | 59 | TestProduct testProduct2 = (TestProduct) container.instance("test2"); 60 | assertEquals("value1", testProduct2.getValue1()); 61 | assertEquals("other", testProduct2.getValue2()); 62 | 63 | builder.replaceFactory("test = * com.jenkov.container.TestProduct().setValue1('value2'); "); 64 | testProduct = (TestProduct) container.instance("test"); 65 | assertEquals("value2", testProduct.getValue1()); 66 | 67 | testProduct2 = (TestProduct) container.instance("test2"); 68 | assertEquals("value2", testProduct2.getValue1()); 69 | assertEquals("other", testProduct2.getValue2()); 70 | 71 | } 72 | 73 | public void testOther(){ 74 | IContainer container = new Container(); 75 | JavaFactoryBuilder builder = new JavaFactoryBuilder(container); 76 | 77 | builder.addFactory("test", new TestFactory()); 78 | 79 | builder.addFactory("test2", new StringFactory3()); 80 | } 81 | 82 | public void testReplaceJavaFactory() { 83 | IContainer container = new Container(); 84 | JavaFactoryBuilder builder = new JavaFactoryBuilder(container); 85 | 86 | builder.addFactory("test", new TestFactory()); 87 | 88 | TestProduct product = (TestProduct) container.instance("test"); 89 | assertEquals("value1", product.getValue1()); 90 | 91 | builder.addFactory("test2", null, new TestFactory2()); 92 | 93 | TestProduct product2 = (TestProduct) container.instance("test2"); 94 | assertEquals("value1", product2.getValue1()); 95 | assertEquals("other" , product2.getValue2()); 96 | 97 | 98 | 99 | builder.replaceFactory("test", new TestFactory3()); 100 | 101 | product = (TestProduct) container.instance("test"); 102 | assertEquals("value2", product.getValue1()); 103 | 104 | product2 = (TestProduct) container.instance("test2"); 105 | assertEquals("value2", product2.getValue1()); 106 | assertEquals("other" , product2.getValue2()); 107 | } 108 | 109 | public void testReplaceNonExistingFactory(){ 110 | IContainer container = new Container(); 111 | JavaFactoryBuilder builder = new JavaFactoryBuilder(container); 112 | 113 | builder.replaceFactory("test", new TestFactory()); 114 | TestProduct product = (TestProduct) container.instance("test"); 115 | assertEquals("value1", product.getValue1()); 116 | } 117 | 118 | public void testInit() { 119 | IContainer container = new Container(); 120 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 121 | 122 | String factoryDefinition = 123 | "singletonFactory = 1 com.jenkov.container.SingletonTestProduct(); " + 124 | " config { com.jenkov.container.SingletonTestProduct.doInit(); } "; 125 | 126 | builder.addFactory(factoryDefinition); 127 | 128 | container.init(); 129 | 130 | //TestProduct product = (TestProduct) container.instance("singletonFactory"); 131 | 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/GlobalThreadSingletonTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import junit.framework.TestCase; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.Container; 6 | import com.jenkov.container.TestProduct; 7 | 8 | /** 9 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 10 | */ 11 | public class GlobalThreadSingletonTest extends TestCase { 12 | 13 | public void testThreadSingleton_bug_by_marcus_rechtien() throws InterruptedException { 14 | Container container = new Container(); 15 | com.jenkov.container.script.ScriptFactoryBuilder builder = new com.jenkov.container.script.ScriptFactoryBuilder(container); 16 | builder.addFactory("test1 = 1T java.lang.String('test1'); "); 17 | 18 | String test1 = (String) container.instance("test1"); 19 | assertEquals("test1", test1); 20 | 21 | TestThread thread1 = new TestThread(container){ 22 | public void run(){ 23 | this.string1 = (String) container.instance("test1"); 24 | this.string2 = (String) container.instance("test1"); 25 | } 26 | }; 27 | thread1.start(); 28 | thread1.join(); 29 | assertSame(thread1.getString1(), thread1.getString2()); 30 | 31 | TestThread thread2 = new TestThread(container){ 32 | public void run(){ 33 | this.string1 = (String) container.instance("test1"); 34 | this.string2 = (String) container.instance("test1"); 35 | } 36 | }; 37 | thread2.start(); 38 | thread2.join(); 39 | assertSame(thread2.getString1(), thread2.getString2()); 40 | 41 | assertNotSame(thread1.getString1(), thread2.getString1()); 42 | } 43 | 44 | 45 | public void testInstance() throws InterruptedException { 46 | IContainer container = new Container(); 47 | ScriptFactoryBuilder builder = new ScriptFactoryBuilder(container); 48 | 49 | builder.addFactory("bean = 1T com.jenkov.container.TestProduct();"); 50 | TestProduct product1 = (TestProduct) container.instance("bean"); 51 | assertNotNull(product1); 52 | assertNull(product1.getValue1()); 53 | assertNull(product1.getValue2()); 54 | TestProduct product1_1 = (TestProduct) container.instance("bean"); 55 | assertSame(product1, product1_1); 56 | 57 | 58 | builder.addFactory( 59 | "bean2 = 1T com.jenkov.container.TestProduct();" + 60 | " config{ $bean2.setValue1(\"value1\"); }"); 61 | 62 | 63 | TestThread thread = new TestThread(container){ 64 | public void run(){ 65 | this.instance1 = container.instance("bean2"); 66 | this.instance2 = container.instance("bean2"); 67 | } 68 | }; 69 | thread.start(); 70 | thread.join(); 71 | 72 | TestProduct product2 = (TestProduct) container.instance("bean2"); 73 | assertEquals("value1", product2.getValue1()); 74 | assertNull(product2.getValue2()); 75 | 76 | assertEquals("value1", ((TestProduct)thread.getInstance1()).getValue1()); 77 | assertNull(((TestProduct)thread.getInstance1()).getValue2()); 78 | 79 | assertNotSame(product2, thread.getInstance1()); 80 | assertSame(thread.getInstance2(), thread.getInstance1()); 81 | 82 | builder.addFactory( 83 | "bean3 = 1T com.jenkov.container.TestProduct();" + 84 | " config { $bean3.setValue1(\"value1\"); } " + 85 | " myPhase{ $bean3.setValue2(\"value2\"); } " + 86 | " dispose{ $bean3.setValue2(\"disposed\"); }"); 87 | 88 | thread = new TestThread(container){ 89 | public void run(){ 90 | this.instance1 = container.instance("bean3"); 91 | this.instance2 = container.instance("bean3"); 92 | } 93 | }; 94 | thread.start(); 95 | thread.join(); 96 | 97 | TestProduct product3 = (TestProduct) container.instance("bean3"); 98 | assertEquals("value1", product2.getValue1()); 99 | assertNull(product3.getValue2()); 100 | 101 | TestProduct product3_1 = (TestProduct) container.instance("bean3"); 102 | assertSame(product3, product3_1); 103 | assertNotSame(product3, thread.getInstance1()); 104 | assertNotSame(product3, thread.getInstance2()); 105 | 106 | assertEquals("value1", ((TestProduct) thread.getInstance1()).getValue1()); 107 | assertEquals("value1", ((TestProduct) thread.getInstance2()).getValue1()); 108 | assertSame(thread.getInstance1(), thread.getInstance2()); 109 | 110 | container.execPhase("myPhase"); 111 | assertEquals("value2", product3.getValue2()); 112 | assertEquals("value2", ((TestProduct) thread.getInstance1()).getValue2()); 113 | assertEquals("value2", ((TestProduct) thread.getInstance2()).getValue2()); 114 | 115 | container.dispose(); 116 | assertEquals("disposed", product3.getValue2()); 117 | assertEquals("disposed", ((TestProduct) thread.getInstance1()).getValue2()); 118 | assertEquals("disposed", ((TestProduct) thread.getInstance2()).getValue2()); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/impl/factory/MethodFactory.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.impl.factory; 2 | 3 | import com.jenkov.container.itf.factory.FactoryException; 4 | import com.jenkov.container.itf.factory.ILocalFactory; 5 | 6 | import java.lang.reflect.Method; 7 | import java.lang.reflect.Type; 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.TypeVariable; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | 15 | */ 16 | public class MethodFactory extends LocalFactoryBase implements ILocalFactory { 17 | 18 | protected Method method = null; 19 | protected Object methodInvocationTarget = null; //todo remove this field, or change it to Class (methodOwnerClass). 20 | protected ILocalFactory methodInvocationTargetFactory = null; 21 | protected List methodArgFactories = new ArrayList(); 22 | 23 | 24 | public MethodFactory(Method method, ILocalFactory methodInvocationTargetFactory, List methodArgFactories) { 25 | if(method == null) throw new IllegalArgumentException("Method cannot be null"); 26 | this.method = method; 27 | this.methodInvocationTargetFactory = methodInvocationTargetFactory; 28 | this.methodArgFactories = methodArgFactories; 29 | } 30 | 31 | public MethodFactory(Method method, List methodArgFactories) { 32 | this.method = method; 33 | this.methodArgFactories = methodArgFactories; 34 | } 35 | 36 | 37 | public Class getReturnType() { 38 | //if a method returns void, it should return the invocation target instead, enabling method chaining on methods returning void. 39 | if(isVoidReturnType()){ 40 | if(methodInvocationTargetFactory != null) return methodInvocationTargetFactory.getReturnType(); 41 | if(methodInvocationTarget != null) return methodInvocationTarget.getClass(); 42 | } 43 | 44 | //if a method returns a parameterized product, not java.lang.Object should be returned, but the parameterized type. 45 | //Type returnType = this.method.getGenericReturnType(); 46 | //if(returnType instanceof ParameterizedType){ 47 | // return (Class) ((ParameterizedType) returnType).getActualTypeArguments()[0]; 48 | //} 49 | //if(returnType instanceof TypeVariable){ 50 | 51 | //} 52 | 53 | return this.method.getReturnType(); 54 | } 55 | 56 | public Object instance(Object[] parameters, Object[] localProducts) { 57 | Object[] arguments = FactoryUtil.toArgumentArray(this.methodArgFactories, parameters, localProducts); 58 | try { 59 | if(this.methodInvocationTargetFactory != null) { 60 | //if a method returns void, it should return the invocation target instead, enabling method chaining on methods returning void. 61 | if(isVoidReturnType()){ 62 | Object target = this.methodInvocationTargetFactory.instance(parameters, localProducts); 63 | if(target == null){ 64 | throw new NullPointerException("The object call the method " + method.toString() + " on was null"); 65 | } 66 | method.invoke(target, arguments); 67 | return target; 68 | } else { 69 | return method.invoke(this.methodInvocationTargetFactory.instance(parameters, localProducts), arguments); 70 | } 71 | } 72 | 73 | //if a method returns void, it should return the invocation target instead, enabling method chaining on methods returning void. 74 | if(isVoidReturnType()){ 75 | method.invoke(this.methodInvocationTarget, arguments); 76 | return this.methodInvocationTarget; 77 | } 78 | 79 | return method.invoke(this.methodInvocationTarget, arguments); 80 | } catch (Throwable t){ 81 | throw new FactoryException( 82 | "MethodFactory", "INSTANTIATION_ERROR", 83 | "Error instantiating object from factory method " + this.method, t); 84 | }finally{ 85 | for(int j=0; j --> "); 94 | if(this.methodInvocationTargetFactory != null){ 95 | builder.append(this.methodInvocationTargetFactory); 96 | } else { 97 | builder.append("<"); 98 | builder.append(this.methodInvocationTarget); 99 | builder.append(">"); 100 | } 101 | 102 | return builder.toString(); 103 | } 104 | 105 | //this method is added only for testability. It is not part of the IFactory interface. 106 | public ILocalFactory getMethodInvocationTargetFactory() { 107 | return methodInvocationTargetFactory; 108 | } 109 | 110 | public Method getMethod() { 111 | return method; 112 | } 113 | 114 | private boolean isVoidReturnType() { 115 | return void.class.equals(this.method.getReturnType()) || this.method.getReturnType() == null; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/TestProduct.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container; 2 | 3 | import com.jenkov.container.IContainer; 4 | 5 | import java.util.List; 6 | import java.util.Set; 7 | import java.net.URL; 8 | 9 | /** 10 | * @author Jakob Jenkov - Copyright 2004-2006 Jenkov Development 11 | */ 12 | public class TestProduct { 13 | 14 | public static final String FIELD_VALUE = "fieldValue"; 15 | 16 | protected TestProduct internalProduct = null; 17 | protected String value1 = null; 18 | protected String value2 = null; 19 | protected double decimal = 0; 20 | 21 | protected String[] stringArray = null; 22 | protected List list = null; 23 | protected Set set = null; 24 | protected URL[] urlArray = null; 25 | protected List urlList = null; 26 | protected List integerList = null; 27 | 28 | protected String[] array1 = null; 29 | protected Integer[] array2 = null; 30 | protected TestProduct[] array3 = null; 31 | 32 | protected Class classValue = null; 33 | 34 | public int instanceInt = -1; 35 | public static int staticInt = -1; 36 | 37 | public IContainer container = null; 38 | public ICustomFactory factory = null; 39 | 40 | public static IContainer staticContainer = null; 41 | public static ICustomFactory staticFactory = null; 42 | 43 | public List genericListInt = null; 44 | public List genericListUrl = null; 45 | public List normalList = null; 46 | 47 | 48 | public static TestProduct createProduct(){ 49 | return new TestProduct(); 50 | } 51 | 52 | public static TestProduct createProduct(TestProduct product){ 53 | return new TestProduct(product); 54 | } 55 | 56 | public TestProduct() { 57 | } 58 | 59 | public TestProduct(TestProduct product){ 60 | this.internalProduct = product; 61 | } 62 | 63 | public TestProduct(ICustomFactory factory) { 64 | this.factory = factory; 65 | } 66 | 67 | public TestProduct(IContainer container) { 68 | this.container = container; 69 | } 70 | 71 | public TestProduct getInternalProduct() { 72 | return internalProduct; 73 | } 74 | 75 | public String getValue1() { 76 | return value1; 77 | } 78 | 79 | public void setValue1(String value1) { 80 | this.value1 = value1; 81 | } 82 | 83 | public String getValue2() { 84 | return value2; 85 | } 86 | 87 | public void setValue2(String value2) { 88 | this.value2 = value2; 89 | } 90 | 91 | public void setValues(String value1, Object value2){ 92 | this.value1 = value1; 93 | this.value2 = value2.toString(); 94 | } 95 | 96 | public void setValues(String value1, String value2){ 97 | this.value1 = value1; 98 | this.value2 = value2; 99 | } 100 | 101 | public void setIntValue(int lengthOfString){ 102 | //System.out.println("length: " + lengthOfString); 103 | } 104 | 105 | public double getDecimal() { 106 | return decimal; 107 | } 108 | 109 | public void setDecimal(double decimal) { 110 | this.decimal = decimal; 111 | } 112 | 113 | public Class getClassValue() { 114 | return classValue; 115 | } 116 | 117 | public void setClassValue(Class classValue) { 118 | this.classValue = classValue; 119 | } 120 | 121 | public void setFactory(ICustomFactory factory) { 122 | this.factory = factory; 123 | } 124 | 125 | public void setContainer(IContainer container) { 126 | this.container = container; 127 | } 128 | 129 | public static void setStaticContainer(IContainer staticContainer) { 130 | TestProduct.staticContainer = staticContainer; 131 | } 132 | 133 | public static void setStaticFactory(ICustomFactory staticFactory) { 134 | TestProduct.staticFactory = staticFactory; 135 | } 136 | 137 | public String[] getStringArray() { 138 | return stringArray; 139 | } 140 | 141 | public void setStringArray(String[] stringArray) { 142 | this.stringArray = stringArray; 143 | } 144 | 145 | public List getList() { 146 | return list; 147 | } 148 | 149 | public void setList(List list) { 150 | this.list = list; 151 | } 152 | 153 | public Set getSet() { 154 | return set; 155 | } 156 | 157 | public void setSet(Set set) { 158 | this.set = set; 159 | } 160 | 161 | public URL[] getUrlArray() { 162 | return urlArray; 163 | } 164 | 165 | public void setUrlArray(URL[] urlArray) { 166 | this.urlArray = urlArray; 167 | } 168 | 169 | public List getUrlList() { 170 | return urlList; 171 | } 172 | 173 | public void setUrlList(List urlList) { 174 | this.urlList = urlList; 175 | } 176 | 177 | public List getIntegerList() { 178 | return integerList; 179 | } 180 | 181 | public void setIntegerList(List integerList) { 182 | this.integerList = integerList; 183 | } 184 | 185 | public String[] getArray1() { 186 | return array1; 187 | } 188 | 189 | public void setArray(String[] array1) { 190 | this.array1 = array1; 191 | } 192 | 193 | public Integer[] getArray2() { 194 | return array2; 195 | } 196 | 197 | public void setArray(Integer[] array2) { 198 | this.array2 = array2; 199 | } 200 | 201 | public TestProduct[] getArray3() { 202 | return array3; 203 | } 204 | 205 | public void setArray(TestProduct[] array3) { 206 | this.array3 = array3; 207 | } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /src/main/java/com/jenkov/container/java/JavaFactoryBuilder.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.java; 2 | 3 | import com.jenkov.container.IContainer; 4 | import com.jenkov.container.impl.factory.FactoryUtil; 5 | import com.jenkov.container.itf.factory.IGlobalFactory; 6 | import com.jenkov.container.itf.factory.FactoryException; 7 | 8 | import java.lang.reflect.Field; 9 | import java.lang.reflect.Type; 10 | import java.lang.reflect.ParameterizedType; 11 | import java.lang.reflect.Method; 12 | 13 | /** 14 | A JavaFactoryBuilder is capable of adding JavaFactory's to an IContainer instance. 15 | */ 16 | public class JavaFactoryBuilder { 17 | 18 | protected IContainer container = null; 19 | 20 | /** 21 | * Creates a new JavaFactoryBuilder which inserts its factories into the given container. 22 | * @param container The container to insert Java factories into. 23 | */ 24 | public JavaFactoryBuilder(IContainer container) { 25 | this.container = container; 26 | } 27 | 28 | /** 29 | * Adds a Java factory to the container. 30 | * The return type of the Java factory is determined by looking at the return type of 31 | * the instance() method in the Java factory added (it doesn't have to be Object). 32 | * 33 | * @param name The name to identify this factory by in the container. 34 | * @param newFactory The Java factory to add to the container. 35 | */ 36 | public void addFactory(String name, JavaFactory newFactory){ 37 | addFactory(name, null, newFactory); 38 | } 39 | 40 | /** 41 | * Adds a Java factory to the container. 42 | * @param name The name to identify this factory by in the container. 43 | * @param returnType The type of component the added factory produces. 44 | * @param newFactory The Java factory to add to the container. 45 | */ 46 | public void addFactory(String name, Class returnType, JavaFactory newFactory){ 47 | if(returnType == null) { 48 | setReturnType(newFactory); 49 | } else { 50 | newFactory.setReturnType(returnType); 51 | } 52 | injectFactories(name, newFactory); 53 | container.addFactory(name, newFactory); 54 | } 55 | 56 | /** 57 | * Adds a Java factory to the container. 58 | * The return type of the Java factory is determined by looking at the return type of 59 | * the instance() method in the Java factory added (it doesn't have to be Object). 60 | * 61 | * @param name The name to identify this factory by in the container. 62 | * @param newFactory The Java factory to add to the container. 63 | */ 64 | public void replaceFactory(String name, JavaFactory newFactory){ 65 | replaceFactory(name, null, newFactory); 66 | } 67 | 68 | /** 69 | * Adds a Java factory to the container. 70 | * @param name The name to identify this factory by in the container. 71 | * @param returnType The type of component the added factory produces. 72 | * @param newFactory The Java factory to add to the container. 73 | */ 74 | public void replaceFactory(String name, Class returnType, JavaFactory newFactory){ 75 | if(returnType == null) { 76 | setReturnType(newFactory); 77 | } else { 78 | newFactory.setReturnType(returnType); 79 | } 80 | injectFactories(name, newFactory); 81 | container.replaceFactory(name, newFactory); 82 | } 83 | 84 | private void setReturnType(JavaFactory newFactory) { 85 | try { 86 | Method method = newFactory.getClass().getMethod("instance", new Class[]{Object[].class}); 87 | newFactory.setReturnType(method.getReturnType()); 88 | } catch (NoSuchMethodException e) { 89 | throw new FactoryException( 90 | "JavaFactoryBuilder", "INSTANCE_METHOD_NOT_FOUND", 91 | "instance method not found for factory", e); 92 | } 93 | } 94 | 95 | private void injectFactories(String name, JavaFactory newFactory) { 96 | Class factoryClass = newFactory.getClass(); 97 | 98 | for(Field field : factoryClass.getFields()){ 99 | Class rawType = field.getType(); 100 | 101 | if(isFactory(rawType)){ 102 | String factoryName = field.getName(); 103 | Factory factoryAnnotation = field.getAnnotation(Factory.class); 104 | if(factoryAnnotation != null){ 105 | factoryName = factoryAnnotation.value(); 106 | } 107 | IGlobalFactory factory = container.getFactory(factoryName); 108 | if(factory == null) { 109 | throw new FactoryException( 110 | "JavaFactoryBuilder", "INJECT_FACTORIES", 111 | "Factory field/annotation name '" + factoryName + "' does not match a factory name in the container"); 112 | } 113 | Class factoryReturnType = factory.getReturnType(); 114 | 115 | Type type = field.getGenericType(); 116 | if(type instanceof ParameterizedType){ 117 | Class genericType = null; 118 | ParameterizedType pType = (ParameterizedType) type; 119 | genericType = (Class) pType.getActualTypeArguments()[0]; 120 | 121 | if(!FactoryUtil.isSubstitutableFor(factoryReturnType, genericType)){ 122 | throw new FactoryException( 123 | "JavaFactoryBuilder", "MIS_MATCHING_RETURN_TYPE", 124 | "Mismatching return type in factory named '" + name + "' for factory field '" + field.getName() + "'. " 125 | + "Factory " + field.getName() + " returns " + factory.getReturnType() + ". " 126 | + "Factory field " + field.getName() + " is parameterized to " + genericType 127 | ); 128 | } 129 | } 130 | try { 131 | field.set(newFactory, factory); 132 | } catch (IllegalAccessException e) { 133 | throw new FactoryException( 134 | "JavaFactoryBuilder", "INSTANCE_METHOD_NOT_ACCESSIBLE", 135 | "Error setting factory field " + field.getName(), e); 136 | } 137 | } 138 | } 139 | } 140 | 141 | private boolean isFactory(Class rawType) { 142 | return rawType.equals(IGlobalFactory.class); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/test/java/com/jenkov/container/script/CollectionFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.container.script; 2 | 3 | import com.jenkov.container.Container; 4 | import com.jenkov.container.IContainer; 5 | import com.jenkov.container.TestProduct; 6 | import junit.framework.TestCase; 7 | 8 | import java.util.List; 9 | import java.util.Iterator; 10 | import java.lang.reflect.Array; 11 | 12 | /** 13 | 14 | */ 15 | public class CollectionFactoryTest extends TestCase { 16 | 17 | public static int[] asIntArray(Object ... numbers){ 18 | int[] intArray = new int[numbers.length]; 19 | for(int i=0; i' ); 30 | public static final Token COMMA = new Token(',' ); 31 | public static final Token COLON = new Token(':' ); 32 | public static final Token SEMI_COLON = new Token(';' ); 33 | public static final Token DOT = new Token('.' ); 34 | public static final Token QUOTE = new Token('"' ); 35 | public static final Token QUOTE_SINGLE = new Token('\''); 36 | public static final Token EQUALS = new Token('='); 37 | public static final Token HASH = new Token('#'); 38 | public static final Token DOLLAR = new Token('$'); 39 | 40 | 41 | public static Token delimiterToken(char delimiter){ 42 | switch(delimiter){ 43 | case '{' : return Token.CURLY_LEFT; 44 | case '}' : return Token.CURLY_RIGHT; 45 | case '(' : return Token.PARENTHESIS_LEFT; 46 | case ')' : return Token.PARENTHESIS_RIGHT; 47 | case '[' : return Token.SQUARE_LEFT; 48 | case ']' : return Token.SQUARE_RIGHT; 49 | case '<' : return Token.LESS_THAN; 50 | case '>' : return Token.GREATER_THAN; 51 | case ',' : return Token.COMMA; 52 | case ';' : return Token.SEMI_COLON; 53 | case '.' : return Token.DOT; 54 | } 55 | return null; 56 | } 57 | 58 | 59 | /* location in source file */ 60 | protected int lineNo = 0; 61 | protected int charNoBefore = 0; 62 | protected int charNoAfter = 0; 63 | 64 | /* location in input buffer */ 65 | protected int from = 0; 66 | protected int length = 0; 67 | protected char[] buffer = null; 68 | 69 | 70 | protected Token() { 71 | } 72 | 73 | protected Token(String tokenValue){ 74 | this.buffer = tokenValue.toCharArray(); 75 | this.from = 0; 76 | this.length = this.buffer.length; 77 | } 78 | 79 | protected Token(char ... tokenChars){ 80 | this.buffer = tokenChars; 81 | this.from = 0; 82 | this.length = this.buffer.length; 83 | } 84 | 85 | protected Token(char[] tokenChars, int from, int length){ 86 | this.buffer = tokenChars; 87 | this.from = from; 88 | this.length = length; 89 | } 90 | 91 | public int getLineNo() { 92 | return lineNo; 93 | } 94 | 95 | public void setLineNo(int lineNo) { 96 | this.lineNo = lineNo; 97 | } 98 | 99 | public int getCharNoBefore() { 100 | return charNoBefore; 101 | } 102 | 103 | public void setCharNoBefore(int charNoBefore) { 104 | this.charNoBefore = charNoBefore; 105 | } 106 | 107 | public int getCharNoAfter() { 108 | return charNoAfter; 109 | } 110 | 111 | public void setCharNoAfter(int charNoAfter) { 112 | this.charNoAfter = charNoAfter; 113 | } 114 | 115 | public int getFrom() { 116 | return from; 117 | } 118 | 119 | public void setFrom(int from) { 120 | this.from = from; 121 | } 122 | 123 | public char[] getBuffer() { 124 | return buffer; 125 | } 126 | 127 | public void setBuffer(char[] buffer) { 128 | this.buffer = buffer; 129 | } 130 | 131 | public void append(char aChar){ 132 | //do nothing... just here to avoid compiler errors. remove later. 133 | this.length++; 134 | this.charNoAfter = this.charNoBefore + this.length; 135 | 136 | } 137 | 138 | public void setLength(int length) { 139 | this.length = length; 140 | } 141 | 142 | public int length(){ 143 | return length; 144 | } 145 | 146 | // todo check if there is any gain to be found by caching hash codes. 147 | public int hashCode() { 148 | int hashCode = 1; 149 | for(int i=0; i this.length) return false; 183 | for(int i=0; i this.length) return false; 191 | 192 | for(int i=other.length-1; i>=0; i--){ 193 | if(this.buffer[getFrom() + i] != other.buffer[other.getFrom() + i]) return false; 194 | } 195 | 196 | return true; 197 | } 198 | 199 | /* todo this method can be optimized. Calls to startsWith and endsWith can be optimized by comparing directly into the buffer instead */ 200 | public boolean isString(){ 201 | if(startsWith(Token.QUOTE) && endsWith(Token.QUOTE)) return true; 202 | if(startsWith(Token.QUOTE_SINGLE) && endsWith(Token.QUOTE_SINGLE)) return true; 203 | return false; 204 | } 205 | 206 | public boolean isInteger(){ 207 | for(int i=0; i