001package org.biopax.paxtools.impl.level3;
002
003
004import org.biopax.paxtools.model.BioPAXElement;
005import org.biopax.paxtools.model.level3.*;
006import org.biopax.paxtools.util.BPCollections;
007import org.biopax.paxtools.util.ClassFilterSet;
008import org.hibernate.annotations.Cache;
009import org.hibernate.annotations.*;
010import org.hibernate.search.annotations.Indexed;
011
012import javax.persistence.Entity;
013import javax.persistence.*;
014import java.util.Set;
015
016import static org.biopax.paxtools.util.SetEquivalenceChecker.hasEquivalentIntersection;
017
018@Entity
019@Proxy(proxyClass=Evidence.class)
020@Indexed
021@DynamicUpdate @DynamicInsert
022@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
023public class EvidenceImpl extends XReferrableImpl implements Evidence
024{
025
026        private Set<ExperimentalForm> experimentalForm;
027        private Set<Score> confidence;
028        private Set<EvidenceCodeVocabulary> evidenceCode;
029
030        /**
031         * Constructor.
032         */
033        public EvidenceImpl()
034        {
035                this.confidence = BPCollections.I.createSafeSet();
036                this.evidenceCode = BPCollections.I.createSafeSet();
037                this.experimentalForm = BPCollections.I.createSafeSet();
038        }
039
040        //
041        // BioPAXElement interface implementation
042        //
043        ////////////////////////////////////////////////////////////////////////////
044
045        @Transient
046        public Class<? extends Evidence> getModelInterface()
047        {
048                return Evidence.class;
049        }
050
051
052        //
053        // Evidence interface implementation
054        //
055        ////////////////////////////////////////////////////////////////////////////
056
057
058        /**
059         * Confidence in the containing instance.  Usually a statistical measure.
060         *
061         * @return a set of scores representing confidence
062         */
063    @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
064        @OneToMany(targetEntity = ScoreImpl.class)//, cascade={CascadeType.ALL})
065        @JoinTable(name="confidence")           
066        public Set<Score> getConfidence()
067        {
068                return confidence;
069        }
070
071        /**
072         * Confidence in the containing instance.  Usually a statistical measure.
073         *
074         * WARNING: This method should only be used for batch operations and with care. For regular
075         * manipulation use add/remove instead.
076         *
077         * @param confidence a set of scores representing confidence
078         */
079
080        public void setConfidence(Set<Score> confidence)
081        {
082                this.confidence = confidence;
083        }
084
085        /**
086         * Confidence in the containing instance.  Usually a statistical measure.
087         *
088         * @param confidence a new confidence measure to add
089         */
090        public void addConfidence(Score confidence)
091        {
092                if(confidence != null)
093                        this.confidence.add(confidence);
094        }
095
096        /**
097         * Confidence in the containing instance.  Usually a statistical measure.
098         *
099         * @param confidence a confidence measure to be removed.
100         */
101        public void removeConfidence(Score confidence)
102        {
103                if(confidence != null)
104                        this.confidence.remove(confidence);
105        }
106
107
108        /**
109         * A pointer to a term in an external controlled vocabulary, such as the GO, PSI-MI or BioCyc
110         * evidence codes, that describes the nature of the support, such as 'traceable author statement'
111         * or 'yeast two-hybrid'.
112         *
113         * @return a set of evidence codes  for this evidence type.
114         */
115    @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
116        @ManyToMany(targetEntity = EvidenceCodeVocabularyImpl.class)
117        @JoinTable(name="evidencecode")
118        public Set<EvidenceCodeVocabulary> getEvidenceCode()
119        {
120                return evidenceCode;
121        }
122
123        /**
124         * A pointer to a term in an external controlled vocabulary, such as the GO, PSI-MI or BioCyc
125         * evidence codes, that describes the nature of the support, such as 'traceable author statement'
126         * or 'yeast two-hybrid'.
127         *
128         * WARNING: This method should only be used for batch operations and with care. For regular
129         * manipulation use add/remove instead.
130         *
131         * @param evidenceCode a new set of evidence codes  for this evidence type.
132         */
133        public void setEvidenceCode(Set<EvidenceCodeVocabulary> evidenceCode)
134        {
135                this.evidenceCode = evidenceCode;
136        }
137
138        /**
139         * A pointer to a term in an external controlled vocabulary, such as the GO, PSI-MI or BioCyc
140         * evidence codes, that describes the nature of the support, such as 'traceable author statement'
141         * or 'yeast two-hybrid'.
142         *
143         * @param evidenceCode a new evidence code  for this evidence.
144         */
145        public void addEvidenceCode(EvidenceCodeVocabulary evidenceCode)
146        {
147                if(evidenceCode != null)
148                        this.evidenceCode.add(evidenceCode);
149        }
150
151        /**
152         * A pointer to a term in an external controlled vocabulary, such as the GO, PSI-MI or BioCyc
153         * evidence codes, that describes the nature of the support, such as 'traceable author statement'
154         * or 'yeast two-hybrid'.
155         *
156         * @param evidenceCode to be removed
157         */
158        public void removeEvidenceCode(EvidenceCodeVocabulary evidenceCode)
159        {
160                if(evidenceCode != null)
161                        this.evidenceCode.remove(evidenceCode);
162        }
163
164    @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
165        @ManyToMany(targetEntity = ExperimentalFormImpl.class)//, cascade={CascadeType.ALL})
166        @JoinTable(name="experimentalForm")     
167        public Set<ExperimentalForm> getExperimentalForm()
168        {
169                return experimentalForm;
170        }
171
172        public void setExperimentalForm(Set<ExperimentalForm> experimentalForm)
173        {
174                this.experimentalForm = experimentalForm;
175        }
176
177        public void addExperimentalForm(ExperimentalForm experimentalForm)
178        {
179                if(experimentalForm != null)
180                        this.experimentalForm.add(experimentalForm);
181        }
182
183        public void removeExperimentalForm(ExperimentalForm experimentalForm)
184        {
185                if(experimentalForm != null)
186                        this.experimentalForm.remove(experimentalForm);
187        }
188
189// ------------------------ INTERFACE METHODS ------------------------
190
191        /**
192         * Answers whether two Evidence objects are semantically equivalent.
193         * (Currently, it considers only member UnificationXrefs and EvidenceCodeVocabularies
194         * for comparison...)
195         * 
196         * TODO: review; add comparing ExperimentalForm and Confidence values...
197         * 
198         */
199        @Override
200        protected boolean semanticallyEquivalent(BioPAXElement element) {
201                if(! (element instanceof Evidence) ) return false;
202                Evidence that = (Evidence) element; // not null (guaranteed by here)
203                boolean hasAllEquivEvidenceCodes = false;
204                
205                if(this.getEvidenceCode().isEmpty()) {
206                        if(that.getEvidenceCode().isEmpty()) {
207                                hasAllEquivEvidenceCodes = true;
208                        }
209                } else {
210                        if(!that.getEvidenceCode().isEmpty()) {
211                                Set<EvidenceCodeVocabulary> shorter;
212                                Set<EvidenceCodeVocabulary> longer;
213                                if (this.getEvidenceCode().size() < that.getEvidenceCode().size())
214                                {
215                                        shorter = this.getEvidenceCode();
216                                        longer  = that.getEvidenceCode();
217                                } else {
218                                        longer = this.getEvidenceCode();
219                                        shorter  = that.getEvidenceCode();
220                                }
221                                
222                                /* each ECV in the 'shorter' set must find its equivalent
223                                 * in the 'longer' set; 
224                                 * otherwise two Evidence objects (this and that) are not equiv.
225                                 */
226                                hasAllEquivEvidenceCodes = true; // initial guess
227                                for(EvidenceCodeVocabulary secv : shorter) {
228                                        boolean foundEquiv = false;
229                                        for(EvidenceCodeVocabulary lecv : longer) {
230                                                if(secv.isEquivalent(lecv)) {
231                                                        foundEquiv = true;
232                                                }
233                                        }
234                                        if(!foundEquiv) {
235                                                hasAllEquivEvidenceCodes = false;
236                                                break;
237                                        }
238                                }
239                        }
240                }
241                
242                //consider publication xrefs!
243                boolean hasCommonPublicationXref = hasEquivalentIntersection(
244                                new ClassFilterSet<Xref, PublicationXref>(getXref(), PublicationXref.class),
245                                new ClassFilterSet<Xref, PublicationXref>(that.getXref(), PublicationXref.class));
246                
247                return super.semanticallyEquivalent(element) && hasAllEquivEvidenceCodes && hasAllEquivEvidenceCodes;
248        }
249
250}