001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.utils.stax;
022
023import java.util.ArrayList;
024import java.util.List;
025
026import org.xml.sax.Attributes;
027import org.xml.sax.Locator;
028import org.xml.sax.SAXException;
029import org.xml.sax.helpers.DefaultHandler;
030
031/**
032 * Lightweight adaptor which translates SAX content events into
033 * StAX form, and provides delegation services.
034 *
035 * @author Thomas Down
036 */
037
038public class SAX2StAXAdaptor extends DefaultHandler {
039    private List stack;
040    private HandlerBinding current;
041        
042    {
043        stack = new ArrayList();
044    }
045
046    /**
047     * Construct a new SAX Content handler which wraps a StAX
048     * handler.
049     */
050
051    public SAX2StAXAdaptor(StAXContentHandler rootHandler) {
052        current = new HandlerBinding(rootHandler);
053        stack.add(current);
054    }
055
056    public void startDocument() throws SAXException {
057        current.handler.startTree();
058    }
059
060    public void endDocument() throws SAXException {
061        current.handler.endTree();
062    }
063
064    public void characters(char[] ch,
065                           int start,
066                           int end)
067        throws SAXException
068    {
069        current.handler.characters(ch, start, end);
070    }
071
072    public void ignorableWhitespace(char[] ch,
073                                    int start,
074                                    int end)
075        throws SAXException
076    {
077        current.handler.ignorableWhitespace(ch, start, end);
078    }
079
080    public void startPrefixMapping(String prefix, String uri)
081        throws SAXException
082    {
083        current.handler.startPrefixMapping(prefix, uri);
084    }
085
086    public void endPrefixMapping(String prefix)
087        throws SAXException
088    {
089        current.handler.endPrefixMapping(prefix);
090    }
091
092    public void processingInstruction(String target, String data)
093        throws SAXException
094    {
095        current.handler.processingInstruction(target, data);
096    }
097
098    public void setDocumentLocator(Locator locator) {
099        current.handler.setDocumentLocator(locator);
100    }
101
102    public void skippedEntity(String name)
103        throws SAXException
104    {
105        current.handler.skippedEntity(name);
106    }
107
108    public void startElement(final String nsURI,
109                             final String localName,
110                             final String qName,
111                             final Attributes attrs)
112        throws SAXException
113    {
114        S2SDelegationManager dm = new S2SDelegationManager();
115        current.handler.startElement(nsURI,
116                                     localName,
117                                     qName,
118                                     attrs,
119                                     dm);
120
121        if (dm.getDelegate() != null) {
122            current = new HandlerBinding(dm.getDelegate());
123            stack.add(current);
124            current.handler.startTree();
125            startElement(nsURI, localName, qName, attrs); // Recurse until someone
126                                                          // takes responsibility. 
127        } else {
128            current.count++;
129        }
130    }
131
132    private static class S2SDelegationManager implements DelegationManager {
133        private StAXContentHandler delegate;
134
135        public void delegate(StAXContentHandler handler) 
136            throws SAXException
137        {
138            if (this.delegate != null) {
139                throw new SAXException("Tried to multiply delegate a single StAX element");
140            }
141
142            this.delegate = handler;
143        }
144
145        private StAXContentHandler getDelegate() {
146            return delegate;
147        }
148    }
149
150    public void endElement(String nsURI, String localName, String qName)
151        throws SAXException
152    {
153        current.handler.endElement(nsURI, localName, qName, null);
154        current.count--;
155        while (current.count == 0 && stack.size() > 1) {
156            StAXContentHandler oldHandler = current.handler;
157            current.handler.endTree();
158            stack.remove(stack.size() - 1);
159            current = (HandlerBinding) stack.get(stack.size() - 1);
160            current.handler.endElement(nsURI, localName, qName, oldHandler);
161        }
162    }
163
164    private class HandlerBinding {
165        public StAXContentHandler handler;
166        public int count;
167
168        private HandlerBinding(StAXContentHandler handler) {
169            this.handler = handler;
170            this.count = 0;
171        }
172    }
173}