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.orm.hibernate;
020
021import java.io.IOException;
022import java.sql.SQLException;
023import java.util.ArrayList;
024import java.util.HashMap;
025import java.util.Iterator;
026import java.util.List;
027import java.util.Map;
028
029import lucee.commons.io.log.Log;
030import lucee.loader.util.Util;
031import lucee.runtime.Component;
032import lucee.runtime.PageContext;
033import lucee.runtime.db.DataSource;
034import lucee.runtime.db.DatasourceConnection;
035import lucee.runtime.exp.PageException;
036import lucee.runtime.orm.ORMConfiguration;
037import lucee.runtime.orm.ORMSession;
038import lucee.runtime.orm.hibernate.naming.CFCNamingStrategy;
039import lucee.runtime.orm.hibernate.naming.DefaultNamingStrategy;
040import lucee.runtime.orm.hibernate.naming.SmartNamingStrategy;
041import lucee.runtime.orm.naming.NamingStrategy;
042import lucee.runtime.type.Collection;
043import lucee.runtime.type.Collection.Key;
044import lucee.runtime.type.KeyImpl;
045import lucee.runtime.type.Struct;
046import lucee.runtime.type.util.ListUtil;
047
048import org.hibernate.SessionFactory;
049import org.hibernate.cfg.Configuration;
050import org.hibernate.engine.SessionFactoryImplementor;
051import org.hibernate.engine.query.QueryPlanCache;
052
053public class SessionFactoryData {
054
055        public List<Component> tmpList;
056        
057        private final Map<Key,DataSource> sources=new HashMap<Key, DataSource>();
058        private final Map<Key,Map<String, CFCInfo>> cfcs=new HashMap<Key, Map<String,CFCInfo>>();
059        private final Map<Key,Configuration> configurations=new HashMap<Key,Configuration>();
060        private final Map<Key,SessionFactory> factories=new HashMap<Key,SessionFactory>();
061        private final Map<Key,QueryPlanCache> queryPlanCaches=new HashMap<Key,QueryPlanCache>();
062        
063        private final ORMConfiguration ormConf;
064        private NamingStrategy namingStrategy;
065        private final HibernateORMEngine engine;
066        private Struct tableInfo=CommonUtil.createStruct();
067        private String cfcNamingStrategy;
068
069        
070        
071        public SessionFactoryData(HibernateORMEngine engine,ORMConfiguration ormConf) {
072                this.engine=engine;
073                this.ormConf=ormConf;
074        }
075        
076        public ORMConfiguration getORMConfiguration(){
077                return ormConf;
078        }
079        public HibernateORMEngine getEngine(){
080                return engine;
081        }
082        
083        public QueryPlanCache getQueryPlanCache(Key datasSourceName) {
084                QueryPlanCache qpc = queryPlanCaches.get(datasSourceName);
085                if(qpc==null){
086                        queryPlanCaches.put(datasSourceName, qpc=new QueryPlanCache((SessionFactoryImplementor) getFactory(datasSourceName)));
087                }
088                return qpc;
089        }
090
091        
092        public NamingStrategy getNamingStrategy() throws PageException {
093                if(namingStrategy==null) {
094                        String strNamingStrategy=ormConf.namingStrategy();
095                        if(Util.isEmpty(strNamingStrategy,true)) {
096                                namingStrategy=DefaultNamingStrategy.INSTANCE;
097                        }
098                        else {
099                                strNamingStrategy=strNamingStrategy.trim();
100                                if("default".equalsIgnoreCase(strNamingStrategy)) 
101                                        namingStrategy=DefaultNamingStrategy.INSTANCE;
102                                else if("smart".equalsIgnoreCase(strNamingStrategy)) 
103                                        namingStrategy=SmartNamingStrategy.INSTANCE;
104                                else {
105                                        CFCNamingStrategy cfcNS = new CFCNamingStrategy(cfcNamingStrategy==null?strNamingStrategy:cfcNamingStrategy);
106                                        cfcNamingStrategy=cfcNS.getComponent().getPageSource().getComponentName();
107                                        namingStrategy=cfcNS;
108                                        
109                                }
110                        }
111                }
112                if(namingStrategy==null) return DefaultNamingStrategy.INSTANCE;
113                return namingStrategy;
114        }
115        
116        
117        public CFCInfo checkExistent(PageContext pc,Component cfc) throws PageException {
118                CFCInfo info = getCFC(HibernateCaster.getEntityName(cfc), null);
119                if(info!=null) return info;
120                
121                throw ExceptionUtil.createException(this,null,"there is no mapping definition for component ["+cfc.getAbsName()+"]","");
122        }
123        
124        public List<String> getEntityNames() {
125                Iterator<Map<String, CFCInfo>> it = cfcs.values().iterator();
126                List<String> names=new ArrayList<String>();
127                Iterator<CFCInfo> _it;
128                while(it.hasNext()){
129                        _it = it.next().values().iterator();
130                        while(_it.hasNext()){
131                                names.add(HibernateCaster.getEntityName(_it.next().getCFC()));
132                        }
133                }
134                return names;
135        }
136
137        public Component getEntityByEntityName(String entityName,boolean unique) throws PageException {
138                Component cfc;
139                
140                // first check cfcs for this entity
141                CFCInfo info = getCFC(entityName,null);
142                if(info!=null) {
143                        cfc=info.getCFC();
144                        return unique?(Component)cfc.duplicate(false):cfc;
145                }
146                
147                // if parsing is in progress, the cfc can be found here
148                if(tmpList!=null){
149                        Iterator<Component> it = tmpList.iterator();
150                        while(it.hasNext()){
151                                cfc=it.next();
152                                if(HibernateCaster.getEntityName(cfc).equalsIgnoreCase(entityName))
153                                        return unique?(Component)cfc.duplicate(false):cfc;
154                        }
155                }
156                throw ExceptionUtil.createException((ORMSession)null,null,"entity ["+entityName+"] does not exist","");
157        }
158        
159
160
161        public Component getEntityByCFCName(String cfcName,boolean unique) throws PageException {
162                String name=cfcName;
163                int pointIndex=cfcName.lastIndexOf('.');
164                if(pointIndex!=-1) {
165                        name=cfcName.substring(pointIndex+1);
166                }
167                else 
168                        cfcName=null;
169                
170                
171                
172                Component cfc;
173                List<String> names=new ArrayList<String>();
174                
175                List<Component> list = tmpList;
176                if(list!=null){
177                        int index=0;
178                        Iterator<Component> it2 = list.iterator();
179                        while(it2.hasNext()){
180                                cfc=it2.next();
181                                names.add(cfc.getName());
182                                if(HibernateUtil.isEntity(ormConf,cfc,cfcName,name)) //if(cfc.equalTo(name))
183                                        return unique?(Component)cfc.duplicate(false):cfc;
184                        }
185                }
186                else {
187                        // search cfcs
188                        Iterator<Map<String, CFCInfo>> it = cfcs.values().iterator();
189                        Map<String, CFCInfo> _cfcs;
190                        while(it.hasNext()){
191                                _cfcs = it.next();
192                                Iterator<CFCInfo> _it = _cfcs.values().iterator();
193                                while(_it.hasNext()){
194                                        cfc=_it.next().getCFC();
195                                        names.add(cfc.getName());
196                                        if(HibernateUtil.isEntity(ormConf,cfc,cfcName,name)) //if(cfc.instanceOf(name))
197                                                return unique?(Component)cfc.duplicate(false):cfc;
198                                }
199                        }
200                }
201                
202                CFCInfo info = getCFC(name,null);
203                if(info!=null) {
204                        cfc=info.getCFC();
205                        return unique?(Component)cfc.duplicate(false):cfc;
206                }
207                
208                throw ExceptionUtil.createException((ORMSession)null,null,"entity ["+name+"] "+(Util.isEmpty(cfcName)?"":"with cfc name ["+cfcName+"] ")+"does not exist, existing  entities are ["+ListUtil.listToList(names, ", ")+"]","");
209                
210        }
211
212        // Datasource specific
213        public Configuration getConfiguration(DataSource ds){
214                return configurations.get(KeyImpl.init(ds.getName()));
215        }
216        public Configuration getConfiguration(Key key){
217                return configurations.get(key);
218        }
219
220        public void setConfiguration(Log log,String mappings, DatasourceConnection dc) throws PageException, SQLException, IOException {
221                configurations.put(KeyImpl.init(dc.getDatasource().getName()),HibernateSessionFactory.createConfiguration(log,mappings,dc,this));
222        }
223
224
225        public void buildSessionFactory(Key datasSourceName) {
226                //Key key=KeyImpl.init(ds.getName());
227                Configuration conf = getConfiguration(datasSourceName);
228                if(conf==null) throw new RuntimeException("cannot build factory because there is no configuration"); // this should never happen
229                factories.put(datasSourceName, conf.buildSessionFactory());
230        }
231
232        public SessionFactory getFactory(Key datasSourceName){
233                SessionFactory factory = factories.get(datasSourceName);
234                if(factory==null && getConfiguration(datasSourceName)!=null) buildSessionFactory(datasSourceName);// this should never be happen
235                return factory;
236        }
237        
238
239        public void reset() {
240                configurations.clear();
241                Iterator<SessionFactory> it = factories.values().iterator();
242                while(it.hasNext()){
243                        it.next().close();
244                }
245                factories.clear();
246                //namingStrategy=null; because the ormconf not change, this has not to change as well
247                tableInfo=CommonUtil.createStruct();
248        }
249        
250
251        public Struct getTableInfo(DatasourceConnection dc, String tableName) throws PageException {
252                Collection.Key keyTableName=CommonUtil.createKey(tableName);
253                Struct columnsInfo = (Struct) tableInfo.get(keyTableName,null);
254                if(columnsInfo!=null) return columnsInfo;
255                
256                columnsInfo = HibernateUtil.checkTable(dc,tableName,this);
257        tableInfo.setEL(keyTableName,columnsInfo);
258        return columnsInfo;
259        }
260
261        
262        // CFC methods
263        public void addCFC(String entityName, CFCInfo info) {
264                DataSource ds = info.getDataSource();
265                Key dsn=KeyImpl.init(ds.getName());
266                                
267                Map<String, CFCInfo> map = cfcs.get(dsn);
268                if(map==null) cfcs.put(dsn, map=new HashMap<String, CFCInfo>());
269                map.put(HibernateUtil.id(entityName), info);
270                sources.put(dsn, ds);
271        }
272        
273
274        CFCInfo getCFC(String entityName, CFCInfo defaultValue) {
275                Iterator<Map<String, CFCInfo>> it = cfcs.values().iterator();
276                while(it.hasNext()){
277                        CFCInfo info = it.next().get(HibernateUtil.id(entityName));
278                        if(info!=null) return info;
279                }
280                return defaultValue;
281        }
282
283        public Map<Key, Map<String, CFCInfo>> getCFCs() {
284                return cfcs;
285        }
286
287        /*public Map<String, CFCInfo> getCFCs(DataSource ds) {
288                Key key=KeyImpl.init(ds.getName());
289                Map<String, CFCInfo> rtn = cfcs.get(key);
290                if(rtn==null) return new HashMap<String, CFCInfo>();
291                return rtn;
292        }*/
293        
294        public Map<String, CFCInfo> getCFCs(Key datasSourceName) {
295                Map<String, CFCInfo> rtn = cfcs.get(datasSourceName);
296                if(rtn==null) return new HashMap<String, CFCInfo>();
297                return rtn;
298        }
299        
300        public void clearCFCs() {
301                cfcs.clear();
302        }
303
304        public int sizeCFCs() {
305                Iterator<Map<String, CFCInfo>> it = cfcs.values().iterator();
306                int size=0;
307                while(it.hasNext()){
308                        size+=it.next().size();
309                }
310                return size;
311        }
312
313        public DataSource[] getDataSources() {
314                return sources.values().toArray(new DataSource[sources.size()]);
315        }
316
317        public void init() {
318                Iterator<Key> it = cfcs.keySet().iterator();
319                while(it.hasNext()){
320                        getFactory(it.next());
321                }
322        }
323        
324        public Map<Key, SessionFactory> getFactories() {
325                Iterator<Key> it = cfcs.keySet().iterator();
326                Map<Key,SessionFactory> map=new HashMap<Key, SessionFactory>();
327                Key key;
328                while(it.hasNext()){
329                        key = it.next();
330                        map.put(key, getFactory(key));
331                }
332                return map;
333        }
334
335        public DataSource getDataSource(Key datasSourceName) {
336                return sources.get(datasSourceName);
337        }
338}