001    /*
002     @license.text@
003      */
004    package biz.hammurapi.sql;
005    
006    import java.lang.reflect.Constructor;
007    import java.lang.reflect.InvocationTargetException;
008    import java.sql.ResultSet;
009    import java.sql.SQLException;
010    
011    import biz.hammurapi.config.RuntimeConfigurationException;
012    import biz.hammurapi.convert.ConverterClosure;
013    import biz.hammurapi.convert.ConvertingService;
014    
015    
016    /**
017     * Base class for SQLC generated projectors.
018     * @author Pavel Vlasov
019     *
020     * @version $Revision: 1.3 $
021     */
022    public class SmartProjector implements Projector {
023        private ConverterClosure converter;
024            private Class targetClass;
025            private Class sourceClass;
026            private Constructor sourceClassConstructor;
027    
028            public Object project(ResultSet rs) throws SQLException {
029                    Object ret;
030                    if (targetClass==null) {
031                            ret = defaultProject(rs);
032                    } else {
033                            if (sourceClass.isAssignableFrom(targetClass)) {
034                                    ret=project(rs, targetClass);
035                            } else {
036                                    ret=ConvertingService.convert(defaultProject(rs), targetClass);
037                            }
038                    }
039                    
040                    if (converter==null) {
041                            return ret;
042                    }
043                    
044                    return converter.convert(ret);
045        }
046    
047        /**
048             * @param rs
049             * @param ret
050             * @return
051             * @throws SQLException
052             */
053            private Object defaultProject(ResultSet rs) throws SQLException {
054                    try {
055                            if (!sourceClassConstructor.isAccessible()) {
056                                    sourceClassConstructor.setAccessible(true); // To use private nested classes.
057                            }
058                            return sourceClassConstructor.newInstance(new Object[] {rs});
059                    } catch (Exception e) {
060                            throw new SQLExceptionEx(e);
061                    }
062            }
063    
064            /**
065             * @param rs
066             * @return
067         * @throws SQLException
068             * @throws InstantiationException
069             * @throws IllegalAccessException
070             * @throws InvocationTargetException
071             * @throws NoSuchMethodException
072             */
073            private Object project(ResultSet rs, Class clazz) throws SQLException {                 
074                    try {
075                            Constructor constructor = clazz.getConstructor(new Class[] {ResultSet.class});
076                            if (!constructor.isAccessible()) {
077                                    constructor.setAccessible(true); // To use private nested classes.
078                            }
079                            return constructor.newInstance(new Object[] {rs});
080                    } catch (Exception e) {
081                            throw new SQLExceptionEx(e);
082                    }
083            }
084    
085            public SmartProjector(Class sourceClass) {
086            this.sourceClass=sourceClass;
087            try {
088                            this.sourceClassConstructor=sourceClass.getConstructor(new Class[] {ResultSet.class});
089                    } catch (SecurityException e) {
090                            throw new RuntimeConfigurationException("Caused by: "+e, e);
091                    } catch (NoSuchMethodException e) {
092                            throw new RuntimeConfigurationException("Constructor from ResultSet not found in "+sourceClass+": "+e, e);
093                    }
094        }
095        
096        public SmartProjector(Class sourceClass, Class targetClass, ConverterClosure converter) {
097            this.converter=converter;
098            this.targetClass=targetClass;
099            this.sourceClass=sourceClass;
100            try {
101                            this.sourceClassConstructor=sourceClass.getConstructor(new Class[] {ResultSet.class});
102                    } catch (SecurityException e) {
103                            throw new RuntimeConfigurationException("Caused by: "+e, e);
104                    } catch (NoSuchMethodException e) {
105                            throw new RuntimeConfigurationException("Constructor from ResultSet not found in "+sourceClass+": "+e, e);
106                    }
107        }       
108    }