001    package railo.runtime.db;
002    
003    import java.util.Map;
004    import java.util.TimeZone;
005    
006    import org.apache.commons.collections.map.ReferenceMap;
007    
008    import railo.commons.lang.ClassException;
009    import railo.commons.lang.ClassUtil;
010    import railo.commons.lang.StringUtil;
011    import railo.runtime.config.Config;
012    import railo.runtime.engine.ThreadLocalPageContext;
013    import railo.runtime.op.Caster;
014    import railo.runtime.type.Collection;
015    import railo.runtime.type.Struct;
016    
017    
018    /**
019     * 
020     */
021    public final class DataSourceImpl implements Cloneable, DataSource {
022    
023        private String dsn;
024            private String username;
025            private String password;
026        private boolean readOnly;
027        private Class clazz;
028        private String host;
029        private String database;
030        private int port;
031        private String dsnTranslated;
032        private int connectionLimit;
033        private int connectionTimeout;
034        private boolean blob;
035        private boolean clob;
036        private int allow;
037        private Struct custom;
038        private String name;
039            private long metaCacheTimeout;
040            private Map<String,ProcMetaCollection> procedureColumnCache;
041            private boolean validate;
042            private boolean storage;
043            private TimeZone timezone;
044        
045            /**
046             * constructor of the class
047             * @param name 
048             * @param clazz 
049             * @param host 
050             * @param dsn
051             * @param database 
052             * @param port 
053             * @param username
054             * @param password
055             * @param connectionLimit 
056             * @param connectionTimeout 
057             * @param blob 
058             * @param clob 
059             * @param allow 
060             * @param custom 
061             * @param readOnly 
062             * @throws ClassException 
063             */
064        public DataSourceImpl(String name,String className, String host, String dsn, String database, int port, String username, String password, 
065                int connectionLimit, int connectionTimeout,long metaCacheTimeout, boolean blob, boolean clob, int allow, Struct custom, boolean readOnly, 
066                boolean validate,boolean storage, TimeZone timezone) throws ClassException {
067            this(name, toClass(className), host, dsn, database, port, username, password, connectionLimit, connectionTimeout,metaCacheTimeout, blob, clob, allow, custom, readOnly,validate,storage,timezone);
068            
069            }
070        
071        private static Class toClass(String className) throws ClassException {
072            try {
073                            return Class.forName(className);
074                    } 
075                    catch (ClassNotFoundException e) {
076                            Config config = ThreadLocalPageContext.getConfig();
077                            if(config!=null) return ClassUtil.loadClass(config.getClassLoader(),className);
078                            return ClassUtil.loadClass(className);
079                    }
080            }
081    
082            private DataSourceImpl(String name,Class clazz, String host, String dsn, String database, int port, String username, String password, 
083                int connectionLimit, int connectionTimeout,long metaCacheTimeout, boolean blob, boolean clob, int allow, Struct custom, boolean readOnly, 
084                boolean validate,boolean storage,TimeZone timezone) {
085            if(allow<0) allow=ALLOW_ALL;
086            this.name=name;
087            this.clazz=clazz;
088            this.host=host;
089            this.database=database;
090            this.dsn=dsn; 
091            this.port=port;
092            this.username=username;
093                this.password=password;
094    
095            this.connectionLimit=connectionLimit;
096            this.connectionTimeout=connectionTimeout;
097            this.blob=blob;
098            this.clob=clob;
099            this.allow=allow;
100            this.readOnly=readOnly;
101            this.custom=custom;
102            this.validate=validate;
103            this.storage=storage;
104            
105            this.dsnTranslated=dsn; 
106            this.metaCacheTimeout= metaCacheTimeout;
107            this.timezone=timezone;
108            translateDsn();
109            
110            //      throw new DatabaseException("can't find class ["+classname+"] for jdbc driver, check if driver (jar file) is inside lib folder",e.getMessage(),null,null,null);
111            
112            }
113        private void translateDsn() {
114            dsnTranslated=replace(dsnTranslated,"host",host,false);
115            dsnTranslated=replace(dsnTranslated,"database",database,false);
116            dsnTranslated=replace(dsnTranslated,"port",Caster.toString(port),false);
117            dsnTranslated=replace(dsnTranslated,"username",username,false);
118            dsnTranslated=replace(dsnTranslated,"password",password,false);
119            
120            Collection.Key[] keys = custom==null?new Collection.Key[0]:custom.keys();
121            for(int i=0;i<keys.length;i++) {
122                dsnTranslated=replace(dsnTranslated,keys[i].getString(),Caster.toString(custom.get(keys[i],null),""),true);
123            }
124        }
125    
126        private String replace(String src, String name, String value,boolean doQueryString) {
127            if(StringUtil.indexOfIgnoreCase(src,"{"+name+"}")!=-1) {
128                return StringUtil.replace(dsnTranslated,"{"+name+"}",value,false);
129            }
130            if(!doQueryString) return src;
131            if(clazz.getName().indexOf("microsoft")!=-1 || clazz.getName().indexOf("jtds")!=-1)
132                    return src+=';'+name+'='+value;
133            return src+=((src.indexOf('?')!=-1)?'&':'?')+name+'='+value;
134        }
135    
136        /**
137         * @see railo.runtime.db.DataSource#getDsnOriginal()
138         */
139        public String getDsnOriginal() {
140            return dsn;
141        }
142        
143        /**
144         * @see railo.runtime.db.DataSource#getDsnTranslated()
145         */
146        public String getDsnTranslated() {
147            return dsnTranslated;
148        }
149        
150        /**
151         * @see railo.runtime.db.DataSource#getPassword()
152         */
153        public String getPassword() {
154            return password;
155        }
156        /**
157         * @see railo.runtime.db.DataSource#getUsername()
158         */
159        public String getUsername() {
160            return username;
161        }
162        
163        /**
164         * @see railo.runtime.db.DataSource#isReadOnly()
165         */
166        public boolean isReadOnly() {
167            return readOnly;
168        }
169        
170        /**
171         * @see railo.runtime.db.DataSource#hasAllow(int)
172         */
173        public boolean hasAllow(int allow) {
174            return (this.allow&allow)>0;
175        }
176        
177        /**
178         * @see railo.runtime.db.DataSource#getClazz()
179         */
180        public Class getClazz() {
181            return clazz;
182        }
183    
184        /**
185         * @see railo.runtime.db.DataSource#getDatabase()
186         */
187        public String getDatabase() {
188            return database;
189        }
190    
191        /**
192         * @see railo.runtime.db.DataSource#getPort()
193         */
194        public int getPort() {
195            return port;
196        }
197    
198        /**
199         * @see railo.runtime.db.DataSource#getHost()
200         */
201        public String getHost() {
202            return host;
203        }
204        
205        /**
206         * @see railo.runtime.db.DataSource#clone()
207         */
208        public Object clone() {
209            return new DataSourceImpl(name,clazz, host, dsn, database, port, username, password, connectionLimit, connectionTimeout,metaCacheTimeout, blob, clob, allow, custom, readOnly,validate,storage,timezone);
210        }
211    
212        /**
213         * @see railo.runtime.db.DataSource#cloneReadOnly()
214         */
215        public DataSource cloneReadOnly() {
216            return new DataSourceImpl(name,clazz, host, dsn, database, port, username, password, connectionLimit, connectionTimeout,metaCacheTimeout, blob, clob, allow,custom, true,validate,storage,timezone);
217        }
218    
219        /**
220         * @see railo.runtime.db.DataSource#isBlob()
221         */
222        public boolean isBlob() {
223            return blob;
224        }
225    
226        /**
227         * @see railo.runtime.db.DataSource#isClob()
228         */
229        public boolean isClob() {
230            return clob;
231        }
232    
233        /**
234         * @see railo.runtime.db.DataSource#getConnectionLimit()
235         */
236        public int getConnectionLimit() {
237            return connectionLimit;
238        }
239    
240        /**
241         * @see railo.runtime.db.DataSource#getConnectionTimeout()
242         */
243        public int getConnectionTimeout() {
244            return connectionTimeout;
245        }
246    
247    
248            //FUTURE add to interface
249            public long getMetaCacheTimeout() {
250                    return metaCacheTimeout;
251            } 
252            
253            // FUTURE add to interface
254            public TimeZone getTimeZone() {
255                    return timezone;
256            } 
257    
258        /**
259         * @see railo.runtime.db.DataSource#getCustomValue(java.lang.String)
260         */
261        public String getCustomValue(String key) {
262            return Caster.toString(custom.get(key,null),"");
263        }
264        
265        /**
266         * @see railo.runtime.db.DataSource#getCustomNames()
267         */
268        public String[] getCustomNames() {
269            return custom.keysAsString();
270        }
271        
272        /**
273         * @see railo.runtime.db.DataSource#getCustoms()
274         */
275        public Struct getCustoms() {
276            return (Struct)custom.clone();
277        }
278    
279        /**
280         * @see railo.runtime.db.DataSource#hasSQLRestriction()
281         */
282        public boolean hasSQLRestriction() {
283            return this.allow!=DataSource.ALLOW_ALL;
284        }
285    
286        /**
287         * @see railo.runtime.db.DataSource#getName()
288         */
289        public String getName() {
290            return name;
291        }
292    
293        /**
294         * @see railo.runtime.db.DataSource#setClazz(java.lang.Class)
295         */
296        public void setClazz(Class clazz) {
297            this.clazz = clazz;
298        }
299    
300            /**
301             *
302             * @see java.lang.Object#toString()
303             */
304            public String toString() {
305                    return this.dsnTranslated;
306            }
307    
308            /**
309             *
310             * @see java.lang.Object#equals(java.lang.Object)
311             */
312            public boolean equals(Object obj) {
313                    if(this==obj)return true;
314                    if(!(obj instanceof DataSourceImpl)) return false;
315                    DataSourceImpl ds = (DataSourceImpl)obj;
316                    return this.getDsnTranslated().equals(ds.getDsnTranslated());
317            } 
318    
319            public Map<String,ProcMetaCollection> getProcedureColumnCache() {
320                    if(procedureColumnCache==null)
321                            procedureColumnCache=new ReferenceMap();
322                    return procedureColumnCache;
323            }
324            /* *
325             *
326             * @see railo.runtime.db.DataSource#getMaxConnection()
327             * /
328            public int getMaxConnection() {
329                    return maxConnection;
330            }*/
331    
332            public boolean validate() {
333                    return validate;
334            }
335    
336            public boolean isStorage() {
337                    return storage;
338            }
339    
340            /* *
341             * @param maxConnection the maxConnection to set
342             * /
343            protected void setMaxConnection(int maxConnection) {
344                    this.maxConnection = maxConnection;
345            }*/
346    
347    }