001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.db;
020
021import java.util.Iterator;
022import java.util.Map.Entry;
023import java.util.TimeZone;
024
025import lucee.commons.lang.ClassException;
026import lucee.commons.lang.StringUtil;
027import lucee.runtime.config.ConfigWebFactory;
028import lucee.runtime.op.Caster;
029import lucee.runtime.type.Collection.Key;
030import lucee.runtime.type.KeyImpl;
031import lucee.runtime.type.Struct;
032import lucee.runtime.type.util.CollectionUtil;
033
034
035/**
036 * 
037 */
038public final class DataSourceImpl  extends DataSourceSupport {
039
040    private String connStr;
041    private String host;
042    private String database;
043    private int port;
044    private String connStrTranslated;
045    private Struct custom;
046        private boolean validate;
047        private String dbdriver;
048        private final boolean literalTimestampWithTSOffset;
049    
050        /**
051         * constructor of the class
052         * @param name 
053         * @param className
054         * @param host 
055         * @param dsn
056         * @param database 
057         * @param port 
058         * @param username
059         * @param password
060         * @param connectionLimit 
061         * @param connectionTimeout 
062         * @param blob 
063         * @param clob 
064         * @param allow 
065         * @param custom 
066         * @param readOnly 
067         * @throws ClassException 
068         */
069    public DataSourceImpl(String name,String className, String host, String dsn, String database, int port, String username, String password, 
070            int connectionLimit, int connectionTimeout,long metaCacheTimeout, boolean blob, boolean clob, int allow, Struct custom, boolean readOnly, 
071            boolean validate, boolean storage, TimeZone timezone, String dbdriver, boolean literalTimestampWithTSOffset) throws ClassException {
072
073        this(name, toClass(className), host, dsn, database, port, username, password, connectionLimit, connectionTimeout,metaCacheTimeout, blob, clob, allow, custom, readOnly, validate, storage, timezone, dbdriver,literalTimestampWithTSOffset);
074        }
075
076        private DataSourceImpl(String name, Class<?> clazz, String host, String dsn, String database, int port, String username, String password,
077            int connectionLimit, int connectionTimeout, long metaCacheTimeout, boolean blob, boolean clob, int allow, Struct custom, boolean readOnly,
078            boolean validate, boolean storage, TimeZone timezone, String dbdriver, boolean literalTimestampWithTSOffset) {
079
080                super(name, clazz,username,ConfigWebFactory.decrypt(password),blob,clob,connectionLimit, connectionTimeout, metaCacheTimeout, timezone, allow<0?ALLOW_ALL:allow, storage, readOnly);
081                        
082        this.host=host;
083        this.database=database;
084        this.connStr=dsn; 
085        this.port=port;
086
087        this.custom=custom;
088        this.validate=validate;
089        
090        this.connStrTranslated=dsn; 
091        translateDsn();
092
093                this.dbdriver = dbdriver;
094                this.literalTimestampWithTSOffset=literalTimestampWithTSOffset;
095        
096        //      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);
097        
098        }
099    private void translateDsn() {
100        connStrTranslated=replace(connStrTranslated,"host",host,false);
101        connStrTranslated=replace(connStrTranslated,"database",database,false);
102        connStrTranslated=replace(connStrTranslated,"port",Caster.toString(port),false);
103        connStrTranslated=replace(connStrTranslated,"username",getUsername(),false);
104        connStrTranslated=replace(connStrTranslated,"password",getPassword(),false);
105        
106        //Collection.Key[] keys = custom==null?new Collection.Key[0]:custom.keys();
107        if(custom!=null) {
108                Iterator<Entry<Key, Object>> it = custom.entryIterator();
109                Entry<Key, Object> e;
110            while(it.hasNext()) {
111                        e = it.next();
112                    connStrTranslated=replace(connStrTranslated,e.getKey().getString(),Caster.toString(e.getValue(),""),true);
113                }
114        }
115    }
116
117    private String replace(String src, String name, String value,boolean doQueryString) {
118        if(StringUtil.indexOfIgnoreCase(src,"{"+name+"}")!=-1) {
119            return StringUtil.replace(connStrTranslated,"{"+name+"}",value,false);
120        }
121        if(!doQueryString) return src;
122        if(getClazz().getName().indexOf("microsoft")!=-1 || getClazz().getName().indexOf("jtds")!=-1)
123                return src+=';'+name+'='+value;
124        else if(getClazz().getName().indexOf("teradata")!=-1)
125                return src+='/'+name+'='+value;
126        return src+=((src.indexOf('?')!=-1)?'&':'?')+name+'='+value;
127    }
128
129    @Override
130    public String getDsnOriginal() {
131        return getConnectionString();
132    }
133
134    @Override
135    public String getConnectionString() {
136        return connStr;
137    }
138    
139    @Override
140    public String getDsnTranslated() {
141        return getConnectionStringTranslated();
142    }
143    
144    @Override
145    public String getConnectionStringTranslated() {
146        return connStrTranslated;
147    }
148
149    @Override
150    public String getDatabase() {
151        return database;
152    }
153
154    @Override
155    public int getPort() {
156        return port;
157    }
158
159    @Override
160    public String getHost() {
161        return host;
162    }
163    
164    @Override
165    public Object clone() {
166        return new DataSourceImpl(getName(),getClazz(), host, connStr, database, port, getUsername(), getPassword(), getConnectionLimit(), getConnectionTimeout(),getMetaCacheTimeout(), isBlob(), isClob(), allow, custom, isReadOnly(),validate,isStorage(),getTimeZone(), dbdriver,literalTimestampWithTSOffset);
167    }
168
169    @Override
170    public DataSource cloneReadOnly() {
171        return new DataSourceImpl(getName(),getClazz(), host, connStr, database, port, getUsername(), getPassword(), getConnectionLimit(), getConnectionTimeout(),getMetaCacheTimeout(), isBlob(), isClob(), allow,custom, true,validate,isStorage(),getTimeZone(), dbdriver,literalTimestampWithTSOffset);
172    }
173
174    @Override
175    public String getCustomValue(String key) {
176        return Caster.toString(custom.get(KeyImpl.init(key),null),"");
177    }
178    
179    @Override
180    public String[] getCustomNames() {
181        return CollectionUtil.keysAsString(custom);
182    }
183    
184    @Override
185    public Struct getCustoms() {
186        return (Struct)custom.clone();
187    }
188    
189    public boolean getLiteralTimestampWithTSOffset() {
190        return literalTimestampWithTSOffset;
191    }
192
193    @Override
194    public boolean validate() {
195                return validate;
196        }
197
198        public String getDbDriver() {
199                return dbdriver;
200        }
201}