001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.hivemind.parse;
016    
017    import java.io.IOException;
018    import java.net.URL;
019    
020    import javax.xml.parsers.FactoryConfigurationError;
021    import javax.xml.parsers.ParserConfigurationException;
022    import javax.xml.parsers.SAXParser;
023    import javax.xml.parsers.SAXParserFactory;
024    
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.apache.hivemind.ApplicationRuntimeException;
028    import org.apache.hivemind.ClassResolver;
029    import org.apache.hivemind.ErrorHandler;
030    import org.apache.hivemind.Resource;
031    import org.xml.sax.InputSource;
032    import org.xml.sax.SAXException;
033    
034    /**
035     * The XmlResourceProcessor processes XML {@link Resource resources} using the
036     * {@link DescriptorParser} which is used as a SAX ContentHandler. The result of
037     * {@link #processResource(Resource) processing a resource} is a {@link ModuleDescriptor}.
038     * 
039     * @see org.apache.hivemind.parse.DescriptorParser
040     * @see org.apache.hivemind.ModuleDescriptorProvider
041     * @since 1.1
042     * @author Knut Wannheden
043     */
044    public class XmlResourceProcessor
045    {
046        private static final Log LOG = LogFactory.getLog(XmlResourceProcessor.class);
047    
048        protected ClassResolver _resolver;
049    
050        protected ErrorHandler _errorHandler;
051    
052        private DescriptorParser _contentHandler;
053    
054        private SAXParser _saxParser;
055    
056        public XmlResourceProcessor(ClassResolver resolver, ErrorHandler errorHandler)
057        {
058            _resolver = resolver;
059            _errorHandler = errorHandler;
060        }
061    
062        /**
063         * Initializes the {@link DescriptorParser parser},
064         * {@link #processResource(Resource) processes} the Resource, resets the parser, and finally
065         * returns the parsed {@link ModuleDescriptor}.
066         * 
067         * @throws ApplicationRuntimeException
068         *             Thrown if errors are encountered while parsing the resource.
069         */
070        public ModuleDescriptor processResource(Resource resource)
071        {
072            if (_contentHandler == null)
073                _contentHandler = new DescriptorParser(_errorHandler);
074    
075            _contentHandler.initialize(resource, _resolver);
076    
077            try
078            {
079                if (LOG.isDebugEnabled())
080                    LOG.debug("Parsing " + resource);
081    
082                ModuleDescriptor descriptor = parseResource(resource, getSAXParser(), _contentHandler);
083    
084                if (LOG.isDebugEnabled())
085                    LOG.debug("Result: " + descriptor);
086    
087                return descriptor;
088            }
089            catch (ApplicationRuntimeException e)
090            {
091                throw e;
092            }
093            catch (Exception e)
094            {
095                _saxParser = null;
096    
097                throw new ApplicationRuntimeException(
098                        ParseMessages.errorReadingDescriptor(resource, e), resource, _contentHandler
099                                .getLocation(), e);
100            }
101            finally
102            {
103                _contentHandler.resetParser();
104            }
105        }
106    
107        /**
108         * Returns the ModuleDescriptor obtained by parsing the specified Resource using the given
109         * {@link SAXParser} and {@link DescriptorParser}. Called by {@link #processResource(Resource)}
110         * after the DescriptorParser has been
111         * {@link DescriptorParser#initialize(Resource, ClassResolver) initialized}. Suitable for
112         * overriding by subclasses.
113         */
114        protected ModuleDescriptor parseResource(Resource resource, SAXParser parser,
115                DescriptorParser contentHandler) throws SAXException, IOException
116        {
117            InputSource source = getInputSource(resource);
118    
119            parser.parse(source, contentHandler);
120    
121            return contentHandler.getModuleDescriptor();
122        }
123    
124        private InputSource getInputSource(Resource resource)
125        {
126            try
127            {
128                URL url = resource.getResourceURL();
129    
130                return new InputSource(url.openStream());
131            }
132            catch (Exception e)
133            {
134                throw new ApplicationRuntimeException(ParseMessages.missingResource(resource),
135                        resource, null, e);
136            }
137        }
138    
139        private SAXParser getSAXParser() throws ParserConfigurationException, SAXException,
140                FactoryConfigurationError
141        {
142            if (_saxParser == null)
143                _saxParser = SAXParserFactory.newInstance().newSAXParser();
144    
145            return _saxParser;
146        }
147    
148    }