001    package org.tynamo.builder;
002    
003    import org.slf4j.Logger;
004    import org.tynamo.exception.TynamoRuntimeException;
005    
006    import java.lang.reflect.Constructor;
007    import java.util.HashMap;
008    import java.util.Map;
009    
010    /**
011     * Fulfils the "Director" role in the Tynamo implementation of
012     * GOF's <a href="http://en.wikipedia.org/wiki/Builder_pattern">Builder pattern</a>
013     *
014     * Constructs an object using the Builder interface
015     */
016    public class BuilderDirector
017    {
018    
019            private final Logger logger;
020    
021            Map<Class, Builder> builders;
022    
023            public BuilderDirector(Logger logger)
024            {
025                    this.logger = logger;
026                    builders = new HashMap<Class, Builder>();
027            }
028    
029            public BuilderDirector(Logger logger, Map<Class, Builder> builders)
030            {
031                    this.logger = logger;
032                    this.builders = builders;
033            }
034    
035            /**
036             * Create a new instance of an object of class 'type' using a Builder.
037             *
038             * @param type is a class whose instance should be created, it shouldn't be NULL
039             * @return a newly created object
040             */
041            public <T> T createNewInstance(final Class<T> type)
042            {
043                    Builder<T> builder = (Builder<T>) builders.get(type);
044                    if (builder != null)
045                    {
046                            return builder.build();
047                    } else
048                    {
049                            return createNewInstanceFromEmptyConstructor(type);
050                    }
051            }
052    
053            /**
054             * Create a new instance of an object of class 'type' using an empty constructor.
055             *
056             * @param type is a class whose instance should be created
057             * @return a newly created object
058             */
059            private <T> T createNewInstanceFromEmptyConstructor(final Class<T> type)
060            {
061                    try
062                    {
063                            Constructor constructor = type.getDeclaredConstructor();
064                            constructor.setAccessible(true);
065                            return (T) constructor.newInstance();
066    
067                    } catch (Exception ex)
068                    {
069                            logger.error(String.format("Can't create an instance of %s using an empty constructor.", type));
070                            throw new TynamoRuntimeException(ex, type);
071                    }
072            }
073    }