001/**
002 *  BioJava development code This code may be freely distributed and modified
003 *  under the terms of the GNU Lesser General Public Licence. This should be
004 *  distributed with the code. If you do not have a copy, see:
005 *  http://www.gnu.org/copyleft/lesser.html Copyright for this code is held
006 *  jointly by the individual authors. These should be listed in
007 *
008 *@author    doc comments. For more information on the BioJava project and its
009 *      aims, or to join the biojava-l mailing list, visit the home page at:
010 *      http://www.biojava.org/
011 */
012
013package org.biojava.bio.seq.io.game12;
014
015import java.util.HashSet;
016import java.util.Set;
017
018import org.biojava.bio.SimpleAnnotation;
019import org.biojava.bio.seq.StrandedFeature;
020import org.biojava.bio.seq.io.ParseException;
021import org.biojava.bio.seq.io.game.ElementRecognizer;
022import org.biojava.bio.symbol.RangeLocation;
023import org.biojava.utils.ChangeVetoException;
024import org.biojava.utils.stax.StAXContentHandler;
025import org.biojava.utils.stax.StringElementHandlerBase;
026import org.xml.sax.Attributes;
027import org.xml.sax.SAXException;
028
029/**
030 *  Handles the GAME <annotation> element
031 *
032 * @author     David Huen
033 * @since      1.2
034 */
035public class GAMEAnnotationHandler
036         extends StAXFeatureHandler {
037    // <annotation> is a container for all features of a "gene".
038    // the only important property of this container is its id
039    // which I need to capture and supply nested classes.
040
041    private Set knownTypes;
042
043    // database columns
044    String annotationName;
045    String annotationType;
046
047    // there can be multiple transcripts (aka feature_sets) in a
048    // <annotation>.  We must get the full extent of all transcripts
049    // to use as the limits.
050    int annotationLocMin = Integer.MAX_VALUE;
051    int annotationLocMax = Integer.MIN_VALUE;
052
053    StrandedFeature.Template annotationTemplate;
054
055    // subclass GAMEFeatureSetHandler to retrieve transcript info
056    private class FeatureSetHandler extends GAMEFeatureSetHandler
057    {
058        private FeatureSetHandler(StAXFeatureHandler staxenv)
059        {
060            super(staxenv);
061//            System.out.println("entering FeatureSetHandler");
062        }
063
064        public void endElementHandler(
065                String nsURI,
066                String localName,
067                String qName,
068                StAXContentHandler contentHandler)
069            throws SAXException
070        {
071            // validate
072            super.endElementHandler(nsURI, localName, qName, contentHandler);
073
074            // fill in the template with location and strand info
075            annotationTemplate.strand = transcriptStrand;
076
077            annotationLocMin = Math.min(annotationLocMin, transcript.getMin());
078            annotationLocMax = Math.max(annotationLocMax, transcript.getMax());
079
080            if (annotationTemplate.strand == null) 
081                annotationTemplate.strand = transcriptStrand;
082            else if (annotationTemplate.strand != transcriptStrand) {
083                // conflicting info
084                System.err.println("inconsistent strand info from transcripts.");
085            }
086        }
087    }
088
089    // subclass <dbxref> to write a feature property here
090    private class DbxrefHandler extends GAMEDbxrefHandler
091    {
092        private DbxrefHandler(StAXFeatureHandler staxenv)
093        {
094            super(staxenv);
095        }
096
097        public void endElementHandler(
098                String nsURI,
099                String localName,
100                String qName,
101                StAXContentHandler contentHandler)
102            throws SAXException
103        {
104            // validate before going further
105            super.endElementHandler(nsURI, localName, qName, contentHandler);
106
107            try {
108                listener.addFeatureProperty("dbxref", "dbxref:" + db_xref_db + "//" + db_xref_id);
109            }
110            catch (ParseException pe) {
111                pe.printStackTrace();
112                throw new SAXException("unexpected exception while add <dbxref> as a feature property.");
113            }
114        }
115    }
116
117    // set up factory method
118    /**
119     *  Description of the Field
120     */
121    public final static StAXHandlerFactory GAME_ANNOTATION_HANDLER_FACTORY
122             =
123        new StAXHandlerFactory() {
124            public StAXContentHandler getHandler(StAXFeatureHandler staxenv) {
125                return new GAMEAnnotationHandler(staxenv);
126            }
127        };
128
129    /**
130     *  Constructor for the GAMEAnnotationHandler object
131     *
132     *@param  staxenv   Description of the Parameter
133     *@param  parentID  Description of the Parameter
134     */
135    GAMEAnnotationHandler(StAXFeatureHandler staxenv) {
136        // setup environment
137        super(staxenv);
138
139        // initialise known types
140        knownTypesInitialiser();
141
142        // setup handlers
143        // <name>
144        super.addHandler(new ElementRecognizer.ByLocalName("name"),
145            new StAXHandlerFactory() {
146                public StAXContentHandler getHandler(StAXFeatureHandler staxenv) {
147                    return new NameHandler();
148                }
149            }
150        );
151
152        // <type>
153        super.addHandler(new ElementRecognizer.ByLocalName("type"),
154            new StAXHandlerFactory() {
155                public StAXContentHandler getHandler(StAXFeatureHandler staxenv) {
156                    return new TypeHandler();
157                }
158            }
159        );
160
161        // <seq>: never seen it used yet.
162//       super.addHandler(new ElementRecognizer.ByLocalName("seq"),
163//         GAMESeqPropHandler.GAME_SEQ_PROP_HANDLER_FACTORY);
164        // <gene>
165        super.addHandler(new ElementRecognizer.ByLocalName("gene"),
166                GAMEGeneHandler.GAME_GENE_HANDLER_FACTORY);
167        // <feature_set>
168        super.addHandler(new ElementRecognizer.ByLocalName("feature_set"),
169            new StAXHandlerFactory() {
170                public StAXContentHandler getHandler(StAXFeatureHandler staxenv) {
171                    return new FeatureSetHandler(staxenv);
172                }
173            }
174        );
175        // <dbxref>
176        super.addHandler(new ElementRecognizer.ByLocalName("dbxref"),
177            new StAXHandlerFactory() {
178                public StAXContentHandler getHandler(StAXFeatureHandler staxenv) {
179                    return new DbxrefHandler(staxenv);
180                }
181            }
182        );
183        // <Aspect>
184        super.addHandler(new ElementRecognizer.ByLocalName("aspect"),
185                GAMEAspectHandler.GAME_ASPECT_HANDLER_FACTORY);
186        // <property>
187        super.addHandler(new ElementRecognizer.ByLocalName("property"),
188                GAMEPropertyHandler.GAME_PROPERTY_HANDLER_FACTORY);
189    }
190
191
192    /**
193     *  Description of the Class
194     *
195     *@author     david
196     *@created    19 January 2002
197     */
198    private class NameHandler extends StringElementHandlerBase {
199        /**
200         *  Sets the stringValue attribute of the NameHandler object
201         *
202         *@param  s  The new stringValue value
203         */
204        protected void setStringValue(String s) {
205            annotationName = s.trim();
206        }
207    }
208
209    /**
210     *  Description of the Class
211     *
212     *@author     david
213     *@created    19 January 2002
214     */
215    private class TypeHandler extends StringElementHandlerBase {
216        /**
217         *  Sets the stringValue attribute of the TypeHandler object
218         *
219         *@param  s  The new stringValue value
220         */
221        protected void setStringValue(String s) {
222            annotationType = s.trim();
223        }
224    }
225
226    private void knownTypesInitialiser()
227    {
228        // initialise a String array
229        String [] types = {"gene", "tRNA", "snRNA", "pseudogene", "transposon", "snoRNA", "misc. non-coding RNA", 
230            "transposable_element", "miscellaneous curator's observation"};
231
232        // now initialise the knownTypes Set
233        knownTypes = new HashSet();
234
235        for (int i=0; i < types.length; i++) {
236            knownTypes.add(types[i]);
237        }
238    }
239
240    public void startElementHandler(
241            String nsURI,
242            String localName,
243            String qName,
244            Attributes attrs) 
245        throws SAXException 
246    {
247        // indicate start of sequence
248        try {
249//            System.out.println("local name is " + localName);
250            annotationTemplate = new StrandedFeature.Template();
251            annotationTemplate.annotation = new SimpleAnnotation();
252
253            // there should be an id in the attributes, get it
254            String id = attrs.getValue("id");
255
256            try {
257                if (id != null) annotationTemplate.annotation.setProperty("id", id);
258            }
259            catch (ChangeVetoException cve) {
260                cve.printStackTrace();
261                throw new SAXException("unexpected ChangeVetoException when setting id!");
262            }
263
264            listener.startFeature(annotationTemplate);
265        }
266        catch (ParseException pe) {
267            pe.printStackTrace();
268            throw new SAXException("error in GAMEAnnotationHandler.");
269        }
270    }
271
272
273    public void endElementHandler(
274            String nsURI,
275            String localName,
276            String qName,
277            StAXContentHandler contentHandler) 
278        throws SAXException
279    {
280        // fill in the template as best can
281        // confirm that it is something I expect
282        if (!knownTypes.contains(annotationType)) {
283             System.err.println("<annotation> of type " + annotationType + " encountered when gene expected");
284        }
285
286        // ganbatte!
287        annotationTemplate.type = annotationType;
288        annotationTemplate.source = "";
289        annotationTemplate.location = new RangeLocation(annotationLocMin, annotationLocMax);
290
291        // bear in mind we are completely dependent on the SeqIOListener
292        // to set the location and strand!!!!
293
294        // indicate end of sequence
295        try {
296            listener.endFeature();
297        }
298        catch (ParseException pe) {
299            pe.printStackTrace();
300            throw new SAXException("error in GAMEAnnotationHandler.");
301        }
302    }
303}
304