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    package uk.ac.roslin.ensembl.datasourceaware.core;
021    
022    import java.util.ArrayList;
023    import java.util.Date;
024    import java.util.HashMap;
025    import java.util.HashSet;
026    import java.util.List;
027    import java.util.Set;
028    import org.apache.log4j.Logger;
029    import uk.ac.roslin.ensembl.config.EnsemblCoordSystemType;
030    import uk.ac.roslin.ensembl.config.EnsemblDBType;
031    import uk.ac.roslin.ensembl.config.FeatureType;
032    import uk.ac.roslin.ensembl.model.MappingSet;
033    import uk.ac.roslin.ensembl.dao.factory.DAOCoreFactory;
034    import uk.ac.roslin.ensembl.datasourceaware.DAXRef;
035    import uk.ac.roslin.ensembl.exception.DAOException;
036    import uk.ac.roslin.ensembl.model.Mapping;
037    import uk.ac.roslin.ensembl.model.ObjectType;
038    import uk.ac.roslin.ensembl.model.core.Chromosome;
039    import uk.ac.roslin.ensembl.model.core.CoordinateSystem;
040    import uk.ac.roslin.ensembl.model.core.Feature;
041    import uk.ac.roslin.ensembl.model.database.CollectionCoreDatabase;
042    import uk.ac.roslin.ensembl.model.database.SingleSpeciesCoreDatabase;
043    
044    /**
045     *
046     * @author tpaterso
047     */
048    public abstract class DAFeature extends DACoreObject implements Feature {
049    
050        protected MappingSet mappings = new MappingSet();
051        protected HashMap<ObjectType, MappingSet> objectTypeMappings = new HashMap<ObjectType, MappingSet>();
052        protected Set<ObjectType> mappedObjectTypes = new HashSet<ObjectType>();
053        protected Date creationDate = null;
054        protected Date modificationDate = null;
055        protected String description = null;
056        protected DAXRef displayXRef = null;
057        protected List<DAXRef> xrefs = new ArrayList<DAXRef>();
058        protected String displayName = null;
059        private Status status = Status.UNKNOWN;
060        protected Boolean current = null;
061    
062        final static Logger LOGGER = Logger.getLogger(DAFeature.class);
063    
064        public DAFeature() {
065            super();
066        }
067    
068        public DAFeature(DAOCoreFactory factory) {
069            super(factory);
070        }
071    
072        public MappingSet getMappings() {
073            //we haven't got the lazy load working here yet
074            return this.mappings;
075        }
076    
077        //Should Be Private?? and call by named object type methods ??
078        public MappingSet getMappings(ObjectType targetType) {
079    
080            if (this.objectTypeMappings.containsKey(targetType)) {
081                return this.objectTypeMappings.get(targetType);
082            } else if (this.isObjectTypeMapped(targetType)) {
083                this.objectTypeMappings.put(targetType, new MappingSet());
084                return this.objectTypeMappings.get(targetType);
085            } else {
086                try {
087                    //we haven't got the lazy load working here yet
088                    this.reinitialize();
089                } catch (DAOException ex) {
090                    LOGGER.warn("failed to reinitialize a feature by accessing database", ex);
091                }
092                return this.objectTypeMappings.get(targetType);
093            }
094        }
095    
096        public Boolean addMapping(Mapping mapping) {
097    
098    //        //check we haven't already added a mapping for an object with this id!
099    //        if (mapping.getTarget() != null) {
100    //
101    //            for (Mapping m : this.mappings) {
102    //                if (m.getTarget() != null && m.getTarget().getId().equals(mapping.getTarget().getId())) {
103    //                    return;
104    //                }
105    //            }
106    //        }
107    
108            //if we fail to add the mapping this will be false
109            if (this.mappings.add((Mapping) mapping)) {
110    
111                ObjectType t = mapping.getTargetType();
112    
113                if (t != null) {
114                    if (!this.objectTypeMappings.containsKey(t)) {
115                        this.objectTypeMappings.put(t, new MappingSet());
116                    }
117    
118                    this.objectTypeMappings.get(t).add((Mapping) mapping);
119                }
120                return true;
121            }
122    
123            return false;
124    
125        }
126    
127        public void addMappedObjectType(ObjectType mappedType) {
128            mappedObjectTypes.add(mappedType);
129        }
130    
131        public Boolean isObjectTypeMapped(ObjectType mappedType) {
132            return mappedObjectTypes.contains(mappedType);
133        }
134    
135        // can there be more than one of these?
136        public MappingSet getTopLevelMappings() throws DAOException {
137    
138            CoordinateSystem topCS = null;
139            MappingSet out = new MappingSet();
140    
141            if (this.getDaoFactory()==null) {
142                throw new DAOException("No DAOFactory Set on this DAFeature");
143            }
144    
145            try {
146                    if (this.getDaoFactory().getDBType().equals(EnsemblDBType.core)) {
147    
148                        topCS = ((SingleSpeciesCoreDatabase) this.getDaoFactory().getDatabase()).getTopLevelCoordSystem();
149    
150                    } else if (this.getDaoFactory().getDBType().equals(EnsemblDBType.collection_core)) {
151                        topCS = ((CollectionCoreDatabase) this.getDaoFactory().getDatabase()).getTopLevelCS(this.getSpecies());
152    
153                    }
154                } catch (DAOException dex) {
155                    LOGGER.warn("Failed to get the top level coordinate System for a Feature "
156                            +this.getClass().getSimpleName()+ " "+this.getId(), dex);
157                    throw dex;
158                } catch (Exception ex) {
159                    LOGGER.warn("Failed to get the top level coordinate System for a Feature "
160                            +this.getClass().getSimpleName()+ " "+this.getId(), ex);
161                    throw new DAOException("Failed to retrieve top level CoordinateSystem for this CoreDatabase", ex);
162                }
163    
164            if (topCS != null) {
165    
166                out = this.getMappings(topCS.getType());
167                this.addMappedObjectType(topCS.getType());
168            } else {
169                return null;
170            }
171    
172    
173            return out;
174        }
175    
176        /**
177         * Utility method to pull back a single mapping of this Feature on a Given chromosome.
178         * This should be the mapping stored at initialisation.
179         * If the Feature has implemented a resinitialize method this may be called.
180         * @param chr
181         * @return a single Mapping
182         */
183        public Mapping getChromosomeMapping(Chromosome chr) {
184            
185            if (chr==null) {
186                return null;
187            }
188            MappingSet s = this.getMappings(EnsemblCoordSystemType.chromosome);
189            for (Mapping m : s) {
190                if (m.getTarget()==chr) {
191                    return m;
192                }
193            }
194            return null;
195        }
196        
197        public MappingSet getAnnotationLevelMappings() throws DAOException  {
198    
199            if (this.getDaoFactory()==null) {
200                throw new DAOException("No DAOFactory Set on this DAFeature");
201            }
202    
203            Set<? extends CoordinateSystem> annotCS = null;
204    
205            try {
206                if (this.getDaoFactory().getDBType().equals(EnsemblDBType.core)) {
207    
208                    annotCS = ((SingleSpeciesCoreDatabase) this.getDaoFactory().getDatabase()).getCSForFeature(this.getType());
209    
210                } else if (this.getDaoFactory().getDBType().equals(EnsemblDBType.collection_core)) {
211                    annotCS = ((CollectionCoreDatabase) this.getDaoFactory().getDatabase())
212                            .getCSForFeature(this.getSpecies(),this.getType());
213                }
214            } catch (DAOException dex) {
215                    LOGGER.warn("Failed to get the annotation level coordinate System for a Feature "
216                            +this.getClass().getSimpleName()+ " "+this.getId(), dex);
217                    throw dex;
218                } catch (Exception ex) {
219                    LOGGER.warn("Failed to get the annotation level coordinate System for a Feature "
220                            +this.getClass().getSimpleName()+ " "+this.getId(), ex);
221                    throw new DAOException("Failed to retrieve annotation level CoordinateSystem for this CoreDatabase", ex);
222                }
223    
224            if (annotCS==null || annotCS.isEmpty()) {
225                LOGGER.warn("Failed to get the annotation level coordinate System for a Feature "
226                        +this.getClass().getSimpleName()+ " "+this.getId());
227                return null;
228            }
229    
230            MappingSet out = new MappingSet();
231    
232            for (CoordinateSystem cs : annotCS ) {
233    
234                MappingSet t = this.getMappings(cs.getType());
235                this.addMappedObjectType(cs.getType());
236                if (t != null) {
237                   out.addAll(t);
238                }
239    
240            }
241    
242            return out;
243        }
244    
245        public MappingSet getBuildLevelMappings() throws DAOException{
246    
247            if (this.getDaoFactory()==null) {
248                throw new DAOException("No DAOFactory Set on this DAFeature");
249            }
250    
251            MappingSet out = new MappingSet();
252            CoordinateSystem buildCS = null;
253            
254            try {
255                if (this.getDaoFactory().getDBType().equals(EnsemblDBType.core)) {
256    
257                    buildCS = ((SingleSpeciesCoreDatabase) this.getDaoFactory().getDatabase()).getBuildCoordSystem(this.getType().toString());
258    
259                } else if (this.getDaoFactory().getDBType().equals(EnsemblDBType.collection_core)) {
260                    buildCS = ((CollectionCoreDatabase) this.getDaoFactory().getDatabase()).getBuildCoordSystem(this.getSpecies(),this.getType().toString() );
261    
262                }
263            } catch (DAOException dex) {
264                    LOGGER.warn("Failed to get the build level coordinate system for this database "
265                            +this.getClass().getSimpleName()+ " "+this.getId(), dex);
266                    throw dex;
267                } catch (Exception ex) {
268                    LOGGER.warn("Failed to get the build level coordinate system for this database "
269                            +this.getClass().getSimpleName()+ " "+this.getId(), ex);
270                    throw new DAOException("Failed to retrieve build level CoordinateSystem for this CoreDatabase", ex);
271                }
272    
273            if (buildCS != null) {
274    
275                out = this.getMappings(buildCS.getType());
276                this.addMappedObjectType(buildCS.getType());
277            } else {
278                return null;
279            }
280    
281            return out;
282        }
283    
284        public void clearAllMappings() {
285                mappings.clear();
286                mappedObjectTypes.clear();
287                objectTypeMappings.clear();
288        }
289    
290        public String getDescription()  {
291            return description;
292        }
293    
294        public void setDescription(String description) {
295            this.description = description;
296        }
297    
298        public Date getCreationDate() {
299            return creationDate;
300        }
301    
302        public void setCreationDate(Date creationDate) {
303            this.creationDate = creationDate;
304        }
305    
306        public Date getModificationDate() {
307            return modificationDate;
308        }
309    
310        public void setModificationDate(Date modificationDate) {
311            this.modificationDate = modificationDate;
312        }
313    
314        public DAXRef getDisplayXRef() {
315            return displayXRef;
316        }
317    
318        public void setDisplayXRef(DAXRef xref) {
319            this.displayXRef = xref;
320            if (xref!=null) {
321                this.xrefs.add(xref);
322            }
323        }
324    
325        public List<DAXRef> getXRefs() {
326            return xrefs;
327        }
328    
329        public void addXRefs(List<DAXRef> xrefs) {
330            this.xrefs.addAll(xrefs);
331        }
332    
333        abstract void reinitialize() throws DAOException ;
334    
335        public static enum Status {
336            KNOWN,
337            NOVEL,
338            PUTATIVE,
339            PREDICTED,
340            KNOWN_BY_PROJECTION,
341            UNKNOWN;
342        }
343    
344        public String getStatus() {
345            return this.status.toString();
346        }
347    
348        public void setStatus(String status) {
349            try {
350                this.status = Status.valueOf(status);
351            } catch (IllegalArgumentException e) {
352                this.status = Status.UNKNOWN;
353            }
354        }
355    
356        public String getDisplayName() {
357            return displayName ;
358        }
359    
360        public void setDisplayName(String displayName) {
361            this.displayName = displayName;
362        }
363    
364        public Boolean isCurrent() {
365            return current;
366        }
367    
368        public void setCurrent(Boolean current) {
369            this.current = current;
370        }
371     
372    }