001    /**
002     * Copyright (C) 2010 The Roslin Institute <contact andy.law@roslin.ed.ac.uk>
003     *
004     * This file is part of the Ensembl Java API demonstration project developed by the
005     * Bioinformatics Group at The Roslin Institute, The Royal (Dick) School of
006     * Veterinary Studies, University of Edinburgh.
007     *
008     * This is free software: you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (version 3) as published by
010     * the Free Software Foundation.
011     *
012     * This software is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015     * GNU General Public License for more details.
016     *
017     * You should have received a copy of the GNU General Public License
018     * in this software distribution. If not, see <http://www.gnu.org/licenses/gpl-3.0.html/>.
019     */
020    
021    package uk.ac.roslin.ensembl.dao.database;
022    
023    import java.util.ArrayList;
024    import java.util.HashMap;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Set;
028    import java.util.TreeMap;
029    import java.util.logging.Level;
030    import java.util.logging.Logger;
031    import uk.ac.roslin.ensembl.datasourceaware.core.DAChromosome;
032    import uk.ac.roslin.ensembl.dao.database.factory.DBDAOSingleSpeciesCoreFactory;
033    import uk.ac.roslin.ensembl.dao.database.factory.DBDAOSingleSpeciesFactory;
034    import uk.ac.roslin.ensembl.exception.ConfigurationException;
035    import uk.ac.roslin.ensembl.exception.DAOException;
036    import uk.ac.roslin.ensembl.config.EnsemblDBType;
037    import uk.ac.roslin.ensembl.datasourceaware.core.DACoordinateSystem;
038    import uk.ac.roslin.ensembl.model.ObjectType;
039    import uk.ac.roslin.ensembl.model.core.CoordinateSystem;
040    import uk.ac.roslin.ensembl.model.database.SingleSpeciesCoreDatabase;
041    import uk.ac.roslin.ensembl.config.EnsemblCoordSystemType;
042    import uk.ac.roslin.ensembl.config.FeatureType;
043    import uk.ac.roslin.ensembl.model.database.Registry;
044    
045    /**
046     *
047     * @author paterson
048     */
049    public class DBSingleSpeciesCoreDatabase extends DBSingleSpeciesDatabase implements SingleSpeciesCoreDatabase {
050    
051        private List<DACoordinateSystem> coordSystems = new ArrayList<DACoordinateSystem>();
052        private TreeMap<Integer, DACoordinateSystem> rankedCoordSystemsHash = new TreeMap<Integer, DACoordinateSystem>();
053        private TreeMap<Integer, DACoordinateSystem> idCoordSystemsHash = new TreeMap<Integer, DACoordinateSystem>();
054        private Integer chromosomeLevelID = null;
055        private Integer sequenceLevelID = null;
056        private Integer topLevelID = null;
057        private DACoordinateSystem chromosomeLevelCS = null;
058        private DACoordinateSystem sequenceLevelCS = null;
059        private DACoordinateSystem topLevelCS = null;
060        private HashMap<FeatureType, String> defaultBuildLevels = new HashMap<FeatureType, String>();
061        private HashMap<FeatureType, HashMap<DACoordinateSystem, Integer>> featureCSHash = null;
062        private HashMap<DACoordinateSystem, List<FeatureType>> CSFeatureHash = null;
063    
064        public DBSingleSpeciesCoreDatabase(String db_name, EnsemblDBType type, Registry registry) throws ConfigurationException {
065            super(db_name, type, registry);
066        }
067    
068        @Override
069        public DBDAOSingleSpeciesCoreFactory getCoreFactory() {
070            if (this.factory == null) {
071                try {
072                    this.factory = DBDAOSingleSpeciesFactory.makeFactory(this);
073                } catch (Exception ex) {
074                }
075            }
076    
077            if (this.factory != null) {
078                return (DBDAOSingleSpeciesCoreFactory) this.factory;
079            } else {
080                return null;
081            }
082        }
083    
084        
085        private List<DACoordinateSystem> fetchCS() throws DAOException {
086            List<DACoordinateSystem> coords = new ArrayList<DACoordinateSystem>();
087            //can throw DAOException
088            if ( this.getCoreFactory()!=null) {
089                coords = this.getCoreFactory().getCoordinateSystemDAO().
090                    getCoordinateSystems();
091            } else {
092               return coords;
093            }        
094            return coords;
095        }
096        
097        private void setCoordinateSytems(List<DACoordinateSystem> coords) throws DAOException {
098    
099            this.coordSystems.clear();
100            this.coordSystems.addAll(coords);
101    
102            //set  the ids for the top, chromosome and sequence levels
103    
104            for (DACoordinateSystem cs : coordSystems) {
105    
106                this.rankedCoordSystemsHash.put(cs.getRank(), cs);
107                this.idCoordSystemsHash.put(cs.getId(), cs);
108    
109                if (cs.getRank().equals(1)) {
110                    this.topLevelCS = cs;
111                    this.topLevelID = cs.getId();
112                    if (cs.getType() == EnsemblCoordSystemType.chromosome) {
113                        this.chromosomeLevelCS = cs;
114                        this.chromosomeLevelID = cs.getId();
115                    }
116                }
117    
118                if (cs.isSequenceLevel()) {
119                    this.sequenceLevelCS = cs;
120                    this.sequenceLevelID = cs.getId();
121                }
122            }
123    
124            //if the top rank wasnt chromosome level, find the highest ranked chromosome level
125    
126            if (this.chromosomeLevelID == null) {
127    
128    
129                Iterator<Integer> it = this.rankedCoordSystemsHash.keySet().iterator();
130                while (it.hasNext()) {
131                    DACoordinateSystem cs = this.rankedCoordSystemsHash.get(it.next());
132                    if (cs.getType() == EnsemblCoordSystemType.chromosome) {
133                        this.chromosomeLevelID = cs.getId();
134                        break;
135                    }
136                }
137            }
138    
139    
140        }
141    
142        private void lazyLoadCoordinateSytems() throws DAOException {
143    
144            this.coordSystems.clear();
145    
146            List<DACoordinateSystem> coords = this.fetchCS();
147    
148            if (!coords.isEmpty()) {
149                   this.setCoordinateSytems(coords);
150            }
151    
152            //set nil values to prevent repeating lazy load
153    
154            if (this.chromosomeLevelID == null) {
155                this.chromosomeLevelID = 0;
156            }
157            if (this.topLevelID == null) {
158                this.topLevelID = 0;
159            }
160            if (this.sequenceLevelID == null) {
161                this.sequenceLevelID = 0;
162            }
163           
164        }
165    
166        @Override
167        public DACoordinateSystem getCSByID(Integer id) throws DAOException {
168            DACoordinateSystem out = null;
169            if (topLevelID == null && this.coordSystems.isEmpty()) {
170    
171                    //lazyload can throw DAOException
172                    lazyLoadCoordinateSytems();
173    
174            }
175    
176            out = this.idCoordSystemsHash.get(id);
177    
178            return out;
179        }
180    
181        @Override
182        public DACoordinateSystem getTopLevelCoordSystem() throws DAOException {
183            if (topLevelID == null && this.coordSystems.isEmpty()) {
184                //lazyload can throw DAOException
185                lazyLoadCoordinateSytems();
186            }
187            return topLevelCS;
188        }
189    
190        @Override
191        public DACoordinateSystem getChromosomeLevelCoordSystem() throws DAOException {
192            if (chromosomeLevelID == null && this.coordSystems.isEmpty()) {
193                //lazyload can throw DAOException
194                lazyLoadCoordinateSytems();
195            }
196            return chromosomeLevelCS;
197        }
198    
199        @Override
200        public DACoordinateSystem getSequenceLevelCoordSystem() throws DAOException {
201            if (sequenceLevelID == null && this.coordSystems.isEmpty()) {
202                //lazyload can throw DAOException
203                lazyLoadCoordinateSytems();
204            }
205            return sequenceLevelCS;
206        }
207    
208        @Override
209        public DAChromosome getChromosomeByName(String name) throws DAOException {
210            if (this.getCoreFactory()!=null){
211                return this.getCoreFactory().getChromosomeDAO().getChromosomeByName(name);
212            } else {
213                return null;
214            }
215    
216        }
217    
218        @Override
219        public List<DAChromosome> getChromosomes() throws DAOException {
220            if (this.getCoreFactory()!=null){
221                return this.getCoreFactory().getChromosomeDAO().getChromosomes();
222             } else {
223                return new ArrayList<DAChromosome>();
224            }
225        }
226    
227        private void setFeatureCSHash() throws DAOException {
228    
229            if (sequenceLevelID == null && this.coordSystems.isEmpty()) {
230                //lazyload can throw DAOException
231                lazyLoadCoordinateSytems();
232            }
233    
234            featureCSHash = new HashMap<FeatureType, HashMap<DACoordinateSystem, Integer>>();
235            CSFeatureHash = new HashMap<DACoordinateSystem, List<FeatureType>>();
236    
237            for (DACoordinateSystem c : this.coordSystems) {
238                CSFeatureHash.put(c, new ArrayList<FeatureType>());
239    
240            }
241    
242    
243            if (this.getCoreFactory() != null) {
244    
245                try {
246    
247                    this.getCoreFactory().getCoordinateSystemDAO().setFeatureCS();
248    
249                } catch (DAOException e) {
250                    featureCSHash = null;
251                    CSFeatureHash = null;
252                    throw e;
253                }
254            }
255    
256        }
257    
258        @Override
259        public Set<DACoordinateSystem> getCSForFeature(ObjectType featureType) throws DAOException {
260    
261                if (this.featureCSHash == null) {
262                    this.setFeatureCSHash();
263                }
264    
265    
266            if (this.featureCSHash != null
267                    && this.featureCSHash.containsKey(featureType)) {
268                return this.featureCSHash.get(featureType).keySet();
269            } else {
270    
271                return null;
272            }
273        }
274    
275        @Override
276        public List<FeatureType> getFeaturesForCS(CoordinateSystem coordSys) throws DAOException{
277    
278    
279                if (this.featureCSHash == null) {
280                    this.setFeatureCSHash();
281                }
282    
283    
284            if (this.CSFeatureHash != null
285                    && this.CSFeatureHash.containsKey(coordSys)) {
286                return this.CSFeatureHash.get(coordSys);
287            } else {
288                return null;
289            }
290        }
291    
292        @Override
293        public Integer getMaxLengthForFeature(ObjectType featureType, CoordinateSystem cs) throws DAOException {
294    
295            if ( featureType == null || cs == null ) {
296                return null;
297            }
298    
299                if (this.featureCSHash == null) {
300                    this.setFeatureCSHash();
301                }
302    
303    
304    
305            if (this.featureCSHash != null
306                    && this.featureCSHash.containsKey(featureType)
307                    && this.featureCSHash.get(featureType).containsKey(cs)) {
308                return this.featureCSHash.get(featureType).get(cs);
309            } else {
310                return null;
311            }
312    
313        }
314    
315        @Override
316        public void addFeatureCS(String featureType, Integer csID, Integer maxLength) {
317    
318            FeatureType type = null;
319            DACoordinateSystem cs = null;
320    
321            type = FeatureType.getFeatureType(featureType);
322            cs = this.idCoordSystemsHash.get(csID);
323    
324            if (type == null || cs == null) {
325                return;
326            } else {
327                if (!this.featureCSHash.containsKey(type)) {
328                    this.featureCSHash.put(type, new HashMap<DACoordinateSystem, Integer>());
329                }
330                this.featureCSHash.get(type).put(cs, maxLength);
331    
332                this.CSFeatureHash.get(cs).add(type);
333    
334            }
335    
336    
337        }
338    
339        @Override
340        public void setBuildLevel(String featureKey, String level) {
341            String temp = featureKey.replace("build.level", "");
342    
343            if (FeatureType.getFeatureType(temp) != null) {
344                this.defaultBuildLevels.put(FeatureType.getFeatureType(temp), level);
345            }
346        }
347    
348        @Override
349        public String getBuildLevel(String featureType) throws DAOException{
350            if (FeatureType.getFeatureType(featureType) != null) {
351                if (defaultBuildLevels.isEmpty()) {
352                    this.getRegistry().setCoreDBBuildLevels(this);
353                }
354                return this.defaultBuildLevels.get(FeatureType.getFeatureType(featureType));
355            } else {
356                return null;
357            }
358        }
359    
360        @Override
361        public DACoordinateSystem getBuildCoordSystem(String featureType) throws DAOException {
362    
363                if (FeatureType.getFeatureType(featureType) != null) {
364                    if (defaultBuildLevels.isEmpty()) {
365                        this.getRegistry().setCoreDBBuildLevels(this);
366                    }
367                    String level = this.defaultBuildLevels.get(FeatureType.getFeatureType(featureType));
368                    if (level != null && level.equalsIgnoreCase("toplevel")) {
369                        return this.getTopLevelCoordSystem();
370                    } else {
371                        return null;
372                    }
373    
374    //                //are there other values possible?
375    //                else if (level.equalsIgnoreCase("chromosomelevel")) {
376    //                    return this.getChromosomeLevelCoordSystem();
377    //                } else if (level.equalsIgnoreCase("sequencelevel")) {
378    //                    return this.getSequenceLevelCoordSystem();
379    //                }
380                }
381    
382            return null;
383    
384        }
385    
386        //dont really want this public - just for testing
387        public HashMap<FeatureType, String> getBuildLevels() {
388            if (defaultBuildLevels.isEmpty()) {
389                try {
390                    lazyLoadCoordinateSytems();
391                } catch (DAOException ex) {
392                    
393                }
394            }
395            return defaultBuildLevels;
396        }
397    }