1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/* 2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2009 Mike Cumings 3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Licensed under the Apache License, Version 2.0 (the "License"); 5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License. 6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at 7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * http://www.apache.org/licenses/LICENSE-2.0 9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software 11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS, 12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and 14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License. 15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage com.kenai.jbosh; 18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.ByteArrayInputStream; 20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.IOException; 21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.InputStream; 22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.lang.ref.SoftReference; 23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.logging.Level; 24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.logging.Logger; 25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport javax.xml.parsers.ParserConfigurationException; 26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport javax.xml.parsers.SAXParser; 27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport javax.xml.parsers.SAXParserFactory; 28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xml.sax.Attributes; 29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xml.sax.SAXException; 30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xml.sax.helpers.DefaultHandler; 31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Implementation of the BodyParser interface which uses the SAX API 34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * that is part of the JDK. Due to the fact that we can cache and reuse 35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * SAXPArser instances, this has proven to be significantly faster than the 36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * use of the javax.xml.stream API introduced in Java 6 while simultaneously 37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * providing an implementation accessible to Java 5 users. 38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenfinal class BodyParserSAX implements BodyParser { 40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Logger. 43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static final Logger LOG = 45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Logger.getLogger(BodyParserSAX.class.getName()); 46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * SAX parser factory. 49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static final SAXParserFactory SAX_FACTORY; 51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen static { 52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen SAX_FACTORY = SAXParserFactory.newInstance(); 53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen SAX_FACTORY.setNamespaceAware(true); 54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen SAX_FACTORY.setValidating(false); 55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Thread local to contain a SAX parser instance for each thread that 59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * attempts to use one. This allows us to gain an order of magnitude of 60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * performance as a result of not constructing parsers for each 61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * invocation while retaining thread safety. 62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static final ThreadLocal<SoftReference<SAXParser>> PARSER = 64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen new ThreadLocal<SoftReference<SAXParser>>() { 65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen @Override protected SoftReference<SAXParser> initialValue() { 66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return new SoftReference<SAXParser>(null); 67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen }; 69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * SAX event handler class. 72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static final class Handler extends DefaultHandler { 74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final BodyParserResults result; 75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final SAXParser parser; 76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private String defaultNS = null; 77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private Handler(SAXParser theParser, BodyParserResults results) { 79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen parser = theParser; 80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen result = results; 81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@inheritDoc} 85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen @Override 87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void startElement( 88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final String uri, 89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final String localName, 90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final String qName, 91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final Attributes attributes) { 92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (LOG.isLoggable(Level.FINEST)) { 93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.finest("Start element: " + qName); 94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.finest(" URI: " + uri); 95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.finest(" local: " + localName); 96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen BodyQName bodyName = AbstractBody.getBodyQName(); 99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Make sure the first element is correct 100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (!(bodyName.getNamespaceURI().equals(uri) 101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen && bodyName.getLocalPart().equals(localName))) { 102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw(new IllegalStateException( 103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen "Root element was not '" + bodyName.getLocalPart() 104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen + "' in the '" + bodyName.getNamespaceURI() 105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen + "' namespace. (Was '" + localName + "' in '" + uri 106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen + "')")); 107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Read in the attributes, making sure to expand the namespaces 110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // as needed. 111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (int idx=0; idx < attributes.getLength(); idx++) { 112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String attrURI = attributes.getURI(idx); 113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (attrURI.length() == 0) { 114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen attrURI = defaultNS; 115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String attrLN = attributes.getLocalName(idx); 117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String attrVal = attributes.getValue(idx); 118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (LOG.isLoggable(Level.FINEST)) { 119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.finest(" Attribute: {" + attrURI + "}" 120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen + attrLN + " = '" + attrVal + "'"); 121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen BodyQName aqn = BodyQName.create(attrURI, attrLN); 124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen result.addBodyAttributeValue(aqn, attrVal); 125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen parser.reset(); 128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@inheritDoc} 132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * This implementation uses this event hook to keep track of the 134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * default namespace on the body element. 135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen @Override 137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void startPrefixMapping( 138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final String prefix, 139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final String uri) { 140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (prefix.length() == 0) { 141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (LOG.isLoggable(Level.FINEST)) { 142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.finest("Prefix mapping: <DEFAULT> => " + uri); 143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen defaultNS = uri; 145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } else { 146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (LOG.isLoggable(Level.FINEST)) { 147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.info("Prefix mapping: " + prefix + " => " + uri); 148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /////////////////////////////////////////////////////////////////////////// 154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // BodyParser interface methods: 155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@inheritDoc} 158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public BodyParserResults parse(String xml) throws BOSHException { 160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen BodyParserResults result = new BodyParserResults(); 161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Exception thrown; 162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen InputStream inStream = new ByteArrayInputStream(xml.getBytes()); 164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen SAXParser parser = getSAXParser(); 165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen parser.parse(inStream, new Handler(parser, result)); 166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return result; 167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (SAXException saxx) { 168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen thrown = saxx; 169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (IOException iox) { 170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen thrown = iox; 171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw(new BOSHException("Could not parse body:\n" + xml, thrown)); 173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /////////////////////////////////////////////////////////////////////////// 176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Private methods: 177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets a SAXParser for use in parsing incoming messages. 180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return parser instance 182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static SAXParser getSAXParser() { 184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen SoftReference<SAXParser> ref = PARSER.get(); 185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen SAXParser result = ref.get(); 186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (result == null) { 187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Exception thrown; 188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen result = SAX_FACTORY.newSAXParser(); 190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ref = new SoftReference<SAXParser>(result); 191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen PARSER.set(ref); 192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return result; 193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (ParserConfigurationException ex) { 194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen thrown = ex; 195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (SAXException ex) { 196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen thrown = ex; 197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw(new IllegalStateException( 199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen "Could not create SAX parser", thrown)); 200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } else { 201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen result.reset(); 202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return result; 203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen} 207