001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.converter.jaxp; 018 019import java.io.*; 020import java.security.AccessController; 021import java.security.PrivilegedAction; 022import java.util.concurrent.BlockingQueue; 023import java.util.concurrent.LinkedBlockingQueue; 024 025import javax.xml.stream.XMLEventReader; 026import javax.xml.stream.XMLEventWriter; 027import javax.xml.stream.XMLInputFactory; 028import javax.xml.stream.XMLOutputFactory; 029import javax.xml.stream.XMLResolver; 030import javax.xml.stream.XMLStreamException; 031import javax.xml.stream.XMLStreamReader; 032import javax.xml.stream.XMLStreamWriter; 033import javax.xml.transform.Result; 034import javax.xml.transform.Source; 035 036import org.apache.camel.Converter; 037import org.apache.camel.Exchange; 038import org.apache.camel.util.IOHelper; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042/** 043 * A converter of StAX objects 044 * 045 * @version 046 */ 047@Converter 048public class StaxConverter { 049 private static final Logger LOG = LoggerFactory.getLogger(StaxConverter.class); 050 051 private static final BlockingQueue<XMLInputFactory> INPUT_FACTORY_POOL; 052 private static final BlockingQueue<XMLOutputFactory> OUTPUT_FACTORY_POOL; 053 static { 054 int i = 20; 055 try { 056 String s = AccessController.doPrivileged(new PrivilegedAction<String>() { 057 @Override 058 public String run() { 059 return System.getProperty("org.apache.cxf.staxutils.pool-size", "-1"); 060 } 061 }); 062 i = Integer.parseInt(s); 063 } catch (Throwable t) { 064 //ignore 065 i = 20; 066 } 067 try { 068 // if we have more cores than 20, then use that 069 int cores = Runtime.getRuntime().availableProcessors(); 070 if (cores > i) { 071 i = cores; 072 } 073 } catch (Throwable t) { 074 // ignore 075 i = 20; 076 } 077 078 if (i <= 0) { 079 i = 20; 080 } 081 082 LOG.debug("StaxConverter pool size: {}", i); 083 084 INPUT_FACTORY_POOL = new LinkedBlockingQueue<XMLInputFactory>(i); 085 OUTPUT_FACTORY_POOL = new LinkedBlockingQueue<XMLOutputFactory>(i); 086 } 087 088 private XMLInputFactory inputFactory; 089 private XMLOutputFactory outputFactory; 090 091 @Converter 092 public XMLEventWriter createXMLEventWriter(OutputStream out, Exchange exchange) throws XMLStreamException { 093 XMLOutputFactory factory = getOutputFactory(); 094 try { 095 return factory.createXMLEventWriter(IOHelper.buffered(out), IOHelper.getCharsetName(exchange)); 096 } finally { 097 returnXMLOutputFactory(factory); 098 } 099 } 100 101 @Converter 102 public XMLEventWriter createXMLEventWriter(Writer writer) throws XMLStreamException { 103 XMLOutputFactory factory = getOutputFactory(); 104 try { 105 return factory.createXMLEventWriter(IOHelper.buffered(writer)); 106 } finally { 107 returnXMLOutputFactory(factory); 108 } 109 } 110 111 @Converter 112 public XMLEventWriter createXMLEventWriter(Result result) throws XMLStreamException { 113 XMLOutputFactory factory = getOutputFactory(); 114 try { 115 return factory.createXMLEventWriter(result); 116 } finally { 117 returnXMLOutputFactory(factory); 118 } 119 } 120 121 @Converter 122 public XMLStreamWriter createXMLStreamWriter(OutputStream outputStream, Exchange exchange) throws XMLStreamException { 123 XMLOutputFactory factory = getOutputFactory(); 124 try { 125 return factory.createXMLStreamWriter(IOHelper.buffered(outputStream), IOHelper.getCharsetName(exchange)); 126 } finally { 127 returnXMLOutputFactory(factory); 128 } 129 } 130 131 @Converter 132 public XMLStreamWriter createXMLStreamWriter(Writer writer) throws XMLStreamException { 133 XMLOutputFactory factory = getOutputFactory(); 134 try { 135 return factory.createXMLStreamWriter(IOHelper.buffered(writer)); 136 } finally { 137 returnXMLOutputFactory(factory); 138 } 139 } 140 141 @Converter 142 public XMLStreamWriter createXMLStreamWriter(Result result) throws XMLStreamException { 143 XMLOutputFactory factory = getOutputFactory(); 144 try { 145 return factory.createXMLStreamWriter(result); 146 } finally { 147 returnXMLOutputFactory(factory); 148 } 149 } 150 151 /** 152 * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters. 153 */ 154 @Deprecated 155 public XMLStreamReader createXMLStreamReader(InputStream in) throws XMLStreamException { 156 XMLInputFactory factory = getInputFactory(); 157 try { 158 return factory.createXMLStreamReader(IOHelper.buffered(in)); 159 } finally { 160 returnXMLInputFactory(factory); 161 } 162 } 163 164 @Converter 165 public XMLStreamReader createXMLStreamReader(InputStream in, Exchange exchange) throws XMLStreamException { 166 XMLInputFactory factory = getInputFactory(); 167 try { 168 String charsetName = IOHelper.getCharsetName(exchange, false); 169 if (charsetName == null) { 170 return factory.createXMLStreamReader(IOHelper.buffered(in)); 171 } else { 172 return factory.createXMLStreamReader(IOHelper.buffered(in), charsetName); 173 } 174 } finally { 175 returnXMLInputFactory(factory); 176 } 177 } 178 179 @Converter 180 public XMLStreamReader createXMLStreamReader(File file, Exchange exchange) throws XMLStreamException, FileNotFoundException { 181 XMLInputFactory factory = getInputFactory(); 182 try { 183 return factory.createXMLStreamReader(IOHelper.buffered(new FileInputStream(file)), IOHelper.getCharsetName(exchange)); 184 } finally { 185 returnXMLInputFactory(factory); 186 } 187 } 188 189 @Converter 190 public XMLStreamReader createXMLStreamReader(Reader reader) throws XMLStreamException { 191 XMLInputFactory factory = getInputFactory(); 192 try { 193 return factory.createXMLStreamReader(IOHelper.buffered(reader)); 194 } finally { 195 returnXMLInputFactory(factory); 196 } 197 } 198 199 @Converter 200 public XMLStreamReader createXMLStreamReader(Source in) throws XMLStreamException { 201 XMLInputFactory factory = getInputFactory(); 202 try { 203 return factory.createXMLStreamReader(in); 204 } finally { 205 returnXMLInputFactory(factory); 206 } 207 } 208 209 @Converter 210 public XMLStreamReader createXMLStreamReader(String string) throws XMLStreamException { 211 XMLInputFactory factory = getInputFactory(); 212 try { 213 return factory.createXMLStreamReader(new StringReader(string)); 214 } finally { 215 returnXMLInputFactory(factory); 216 } 217 } 218 219 /** 220 * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters. 221 */ 222 @Deprecated 223 public XMLEventReader createXMLEventReader(InputStream in) throws XMLStreamException { 224 XMLInputFactory factory = getInputFactory(); 225 try { 226 return factory.createXMLEventReader(IOHelper.buffered(in)); 227 } finally { 228 returnXMLInputFactory(factory); 229 } 230 } 231 232 @Converter 233 public XMLEventReader createXMLEventReader(InputStream in, Exchange exchange) throws XMLStreamException { 234 XMLInputFactory factory = getInputFactory(); 235 try { 236 String charsetName = IOHelper.getCharsetName(exchange, false); 237 if (charsetName == null) { 238 return factory.createXMLEventReader(IOHelper.buffered(in)); 239 } else { 240 return factory.createXMLEventReader(IOHelper.buffered(in), charsetName); 241 } 242 } finally { 243 returnXMLInputFactory(factory); 244 } 245 } 246 247 @Converter 248 public XMLEventReader createXMLEventReader(File file, Exchange exchange) throws XMLStreamException, FileNotFoundException { 249 XMLInputFactory factory = getInputFactory(); 250 try { 251 return factory.createXMLEventReader(IOHelper.buffered(new FileInputStream(file)), IOHelper.getCharsetName(exchange)); 252 } finally { 253 returnXMLInputFactory(factory); 254 } 255 } 256 257 @Converter 258 public XMLEventReader createXMLEventReader(Reader reader) throws XMLStreamException { 259 XMLInputFactory factory = getInputFactory(); 260 try { 261 return factory.createXMLEventReader(IOHelper.buffered(reader)); 262 } finally { 263 returnXMLInputFactory(factory); 264 } 265 } 266 267 @Converter 268 public XMLEventReader createXMLEventReader(XMLStreamReader reader) throws XMLStreamException { 269 XMLInputFactory factory = getInputFactory(); 270 try { 271 return factory.createXMLEventReader(reader); 272 } finally { 273 returnXMLInputFactory(factory); 274 } 275 } 276 277 @Converter 278 public XMLEventReader createXMLEventReader(Source in) throws XMLStreamException { 279 XMLInputFactory factory = getInputFactory(); 280 try { 281 return factory.createXMLEventReader(in); 282 } finally { 283 returnXMLInputFactory(factory); 284 } 285 } 286 287 @Converter 288 public InputStream createInputStream(XMLStreamReader reader, Exchange exchange) { 289 XMLOutputFactory factory = getOutputFactory(); 290 try { 291 String charsetName = IOHelper.getCharsetName(exchange, false); 292 return new XMLStreamReaderInputStream(reader, charsetName, factory); 293 } finally { 294 returnXMLOutputFactory(factory); 295 } 296 } 297 298 @Converter 299 public Reader createReader(XMLStreamReader reader, Exchange exchange) { 300 XMLOutputFactory factory = getOutputFactory(); 301 try { 302 return new XMLStreamReaderReader(reader, factory); 303 } finally { 304 returnXMLOutputFactory(factory); 305 } 306 } 307 308 private static boolean isWoodstox(Object factory) { 309 return factory.getClass().getPackage().getName().startsWith("com.ctc.wstx"); 310 } 311 312 private XMLInputFactory getXMLInputFactory() { 313 XMLInputFactory f = INPUT_FACTORY_POOL.poll(); 314 if (f == null) { 315 f = createXMLInputFactory(true); 316 } 317 return f; 318 } 319 320 private void returnXMLInputFactory(XMLInputFactory factory) { 321 if (factory != inputFactory) { 322 INPUT_FACTORY_POOL.offer(factory); 323 } 324 } 325 326 private XMLOutputFactory getXMLOutputFactory() { 327 XMLOutputFactory f = OUTPUT_FACTORY_POOL.poll(); 328 if (f == null) { 329 f = XMLOutputFactory.newInstance(); 330 } 331 return f; 332 } 333 334 private void returnXMLOutputFactory(XMLOutputFactory factory) { 335 if (factory != outputFactory) { 336 OUTPUT_FACTORY_POOL.offer(factory); 337 } 338 } 339 340 public static XMLInputFactory createXMLInputFactory(boolean nsAware) { 341 XMLInputFactory factory = XMLInputFactory.newInstance(); 342 setProperty(factory, XMLInputFactory.IS_NAMESPACE_AWARE, nsAware); 343 setProperty(factory, XMLInputFactory.SUPPORT_DTD, Boolean.FALSE); 344 setProperty(factory, XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.FALSE); 345 setProperty(factory, XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE); 346 factory.setXMLResolver(new XMLResolver() { 347 public Object resolveEntity(String publicID, String systemID, 348 String baseURI, String namespace) 349 throws XMLStreamException { 350 throw new XMLStreamException("Reading external entities is disabled"); 351 } 352 }); 353 354 if (isWoodstox(factory)) { 355 // just log a debug as we are good then 356 LOG.debug("Created Woodstox XMLInputFactory: {}", factory); 357 } else { 358 // log a hint that woodstock may be a better factory to use 359 LOG.info("Created XMLInputFactory: {}. DOMSource/DOMResult may have issues with {}. We suggest using Woodstox.", factory, factory); 360 } 361 return factory; 362 } 363 364 private static void setProperty(XMLInputFactory f, String p, Object o) { 365 try { 366 f.setProperty(p, o); 367 } catch (Throwable t) { 368 //ignore 369 } 370 } 371 372 // Properties 373 //------------------------------------------------------------------------- 374 375 public XMLInputFactory getInputFactory() { 376 if (inputFactory == null) { 377 return getXMLInputFactory(); 378 } 379 return inputFactory; 380 } 381 382 public XMLOutputFactory getOutputFactory() { 383 if (outputFactory == null) { 384 return getXMLOutputFactory(); 385 } 386 return outputFactory; 387 } 388 389 public void setInputFactory(XMLInputFactory inputFactory) { 390 this.inputFactory = inputFactory; 391 } 392 393 public void setOutputFactory(XMLOutputFactory outputFactory) { 394 this.outputFactory = outputFactory; 395 } 396 397}