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