1 /* 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.internal.ws.wscompile; 27 28 import com.sun.codemodel.internal.JCodeModel; 29 import com.sun.tools.internal.ws.processor.generator.GeneratorExtension; 30 import com.sun.tools.internal.ws.resources.ConfigurationMessages; 31 import com.sun.tools.internal.ws.resources.WscompileMessages; 32 import com.sun.tools.internal.ws.util.ForkEntityResolver; 33 import com.sun.tools.internal.ws.wsdl.document.jaxws.JAXWSBindingsConstants; 34 import com.sun.tools.internal.ws.wsdl.document.schema.SchemaConstants; 35 import com.sun.tools.internal.xjc.api.SchemaCompiler; 36 import com.sun.tools.internal.xjc.api.SpecVersion; 37 import com.sun.tools.internal.xjc.api.XJC; 38 import com.sun.tools.internal.xjc.reader.Util; 39 import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory; 40 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; 41 import com.sun.xml.internal.ws.util.ServiceFinder; 42 import com.sun.xml.internal.ws.util.JAXWSUtils; 43 import com.sun.xml.internal.ws.util.xml.XmlUtil; 44 import org.w3c.dom.Element; 45 import org.xml.sax.EntityResolver; 46 import org.xml.sax.InputSource; 47 import org.xml.sax.helpers.LocatorImpl; 48 49 import javax.xml.namespace.QName; 50 import javax.xml.stream.XMLStreamReader; 51 52 import java.io.ByteArrayInputStream; 53 import java.io.ByteArrayOutputStream; 54 import java.io.File; 55 import java.io.IOException; 56 import java.io.InputStream; 57 import java.io.Reader; 58 import java.lang.reflect.Array; 59 import java.net.MalformedURLException; 60 import java.net.URL; 61 import java.util.ArrayList; 62 import java.util.Arrays; 63 import java.util.List; 64 import java.util.HashMap; 65 import java.util.logging.Level; 66 import java.util.logging.Logger; 67 68 /** 69 * @author Vivek Pandey 70 */ 71 public class WsimportOptions extends Options { 72 /** 73 * -wsdlLocation 74 */ 75 public String wsdlLocation; 76 77 /** 78 * Actually stores {@link com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver}, but the field 79 * type is made to {@link org.xml.sax.EntityResolver} so that XJC can be 80 * used even if resolver.jar is not available in the classpath. 81 */ 82 public EntityResolver entityResolver = null; 83 84 /** 85 * The -p option that should control the default Java package that 86 * will contain the generated code. Null if unspecified. 87 */ 88 public String defaultPackage = null; 89 90 /** 91 * The -clientjar option to package client artifacts as jar 92 */ 93 public String clientjar = null; 94 95 /** 96 * -XadditionalHeaders 97 */ 98 public boolean additionalHeaders; 99 100 /** 101 * The option indicates the dir where the jwsImpl will be generated. 102 */ 103 public File implDestDir = null; 104 105 /** 106 * optional, generated impl file only for the ordered serviceName 107 * Note: It is a QName string, formatted as: "{" + Namespace URI + "}" + local part 108 */ 109 public String implServiceName = null; 110 111 /** 112 * optional, generated impl file only for the ordered portName 113 * Note: It is a QName string, formatted as: "{" + Namespace URI + "}" + local part 114 */ 115 public String implPortName = null; 116 117 /** 118 * optional, if true JWS file is generated 119 */ 120 public boolean isGenerateJWS = false; 121 122 /** 123 * Setting disableSSLHostVerification to true disables the SSL Hostname verification while fetching the wsdls. 124 * -XdisableSSLHostVerification 125 */ 126 public boolean disableSSLHostnameVerification; 127 128 /** 129 * Setting useBaseResourceAndURLToLoadWSDL to true causes generated Service classes to load the WSDL file from 130 * a URL generated from the base resource. 131 * -XuseBaseResourceAndURLToLoadWSDL 132 */ 133 public boolean useBaseResourceAndURLToLoadWSDL = false; 134 135 /** 136 * Java module name in {@code module-info.java}. 137 */ 138 private String javaModule = null; 139 140 /** 141 * JAXB's {@link SchemaCompiler} to be used for handling the schema portion. 142 * This object is also configured through options. 143 */ 144 private SchemaCompiler schemaCompiler = XJC.createSchemaCompiler(); 145 146 /** 147 * Authentication file 148 */ 149 public File authFile = null; 150 151 //can user.home value be null? 152 public static final String defaultAuthfile 153 = System.getProperty("user.home") + System.getProperty("file.separator") 154 + ".metro" + System.getProperty("file.separator") + "auth"; 155 156 /** 157 * Setting disableAuthenticator to true disables the DefaultAuthenticator. 158 * -XdisableAuthenticator 159 */ 160 public boolean disableAuthenticator; 161 162 public String proxyAuth = null; 163 private String proxyHost = null; 164 private String proxyPort = null; 165 166 /** 167 * Additional arguments 168 */ 169 public HashMap<String, String> extensionOptions = new HashMap<String, String>(); 170 171 /** 172 * All discovered {@link Plugin}s. 173 * This is lazily parsed, so that we can take '-cp' option into account. 174 * 175 * @see #getAllPlugins() 176 */ 177 private List<Plugin> allPlugins; 178 179 /** 180 * {@link Plugin}s that are enabled in this compilation. 181 */ 182 public final List<Plugin> activePlugins = new ArrayList<Plugin>(); 183 184 public JCodeModel getCodeModel() { 185 if(codeModel == null) 186 codeModel = new JCodeModel(); 187 return codeModel; 188 } 189 190 public SchemaCompiler getSchemaCompiler() { 191 schemaCompiler.setTargetVersion(SpecVersion.parse(target.getVersion())); 192 if(entityResolver != null) { 193 //set if its not null so as not to override catalog option specified via xjc args 194 schemaCompiler.setEntityResolver(entityResolver); 195 } 196 return schemaCompiler; 197 } 198 199 public void setCodeModel(JCodeModel codeModel) { 200 this.codeModel = codeModel; 201 } 202 203 private JCodeModel codeModel; 204 205 /** 206 * This captures jars passed on the commandline and passes them to XJC and puts them in the classpath for compilation 207 */ 208 public List<String> cmdlineJars = new ArrayList<String>(); 209 210 /** 211 * Gets all the {@link Plugin}s discovered so far. 212 * 213 * <p> 214 * A plugins are enumerated when this method is called for the first time, 215 * by taking {@link #classpath} into account. That means 216 * "-cp plugin.jar" has to come before you specify options to enable it. 217 */ 218 public List<Plugin> getAllPlugins() { 219 if(allPlugins==null) { 220 allPlugins = new ArrayList<Plugin>(); 221 allPlugins.addAll(Arrays.asList(findServices(Plugin.class, getClassLoader()))); 222 } 223 return allPlugins; 224 } 225 226 /** 227 * Gets Java module name option. 228 * @return Java module name option or {@code null} if this option was not set. 229 */ 230 public String getModuleName() { 231 return javaModule; 232 } 233 234 /** 235 * Parses arguments and fill fields of this object. 236 * 237 * @exception BadCommandLineException 238 * thrown when there's a problem in the command-line arguments 239 */ 240 @Override 241 public final void parseArguments( String[] args ) throws BadCommandLineException { 242 243 for (int i = 0; i < args.length; i++) { 244 if(args[i].length()==0) 245 throw new BadCommandLineException(); 246 if (args[i].charAt(0) == '-') { 247 int j = parseArguments(args,i); 248 if(j==0) 249 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_INVALID_OPTION(args[i])); 250 i += (j-1); 251 } else { 252 if(args[i].endsWith(".jar")) { 253 254 try { 255 cmdlineJars.add(args[i]); 256 schemaCompiler.getOptions().scanEpisodeFile(new File(args[i])); 257 258 } catch (com.sun.tools.internal.xjc.BadCommandLineException e) { 259 //Driver.usage(jaxbOptions,false); 260 throw new BadCommandLineException(e.getMessage(), e); 261 } 262 } else{ 263 addFile(args[i]); 264 } 265 } 266 } 267 268 if (encoding != null && schemaCompiler.getOptions().encoding == null) { 269 try { 270 schemaCompiler.getOptions().parseArgument( 271 new String[] {"-encoding", encoding}, 0); 272 } catch (com.sun.tools.internal.xjc.BadCommandLineException ex) { 273 Logger.getLogger(WsimportOptions.class.getName()).log(Level.SEVERE, null, ex); 274 } 275 } 276 277 if(destDir == null) 278 destDir = new File("."); 279 if(sourceDir == null) 280 sourceDir = destDir; 281 } 282 283 /** -Xno-addressing-databinding option to disable addressing namespace data binding. This is 284 * experimental switch and will be working as a temporary workaround till 285 * jaxb can provide a better way to selelctively disable compiling of an 286 * schema component. 287 * **/ 288 public boolean noAddressingBbinding; 289 290 @Override 291 public int parseArguments(String[] args, int i) throws BadCommandLineException { 292 int j = super.parseArguments(args ,i); 293 if(j>0) return j; // understood by the super class 294 295 if (args[i].equals("-b")) { 296 addBindings(requireArgument("-b", args, ++i)); 297 return 2; 298 } else if (args[i].equals("-wsdllocation")) { 299 wsdlLocation = requireArgument("-wsdllocation", args, ++i); 300 return 2; 301 } else if (args[i].equals("-XadditionalHeaders")) { 302 additionalHeaders = true; 303 return 1; 304 } else if (args[i].equals("-XdisableSSLHostnameVerification")) { 305 disableSSLHostnameVerification = true; 306 return 1; 307 } else if (args[i].equals("-p")) { 308 defaultPackage = requireArgument("-p", args, ++i); 309 return 2; 310 } else if (args[i].equals("-m")) { 311 javaModule = requireArgument("-m", args, ++i); 312 return 2; 313 } else if (args[i].equals("-catalog")) { 314 String catalog = requireArgument("-catalog", args, ++i); 315 try { 316 if (entityResolver == null) { 317 if (catalog != null && catalog.length() > 0) 318 entityResolver = XmlUtil.createEntityResolver(JAXWSUtils.getFileOrURL(JAXWSUtils.absolutize(Util.escapeSpace(catalog)))); 319 } else if (catalog != null && catalog.length() > 0) { 320 EntityResolver er = XmlUtil.createEntityResolver(JAXWSUtils.getFileOrURL(JAXWSUtils.absolutize(Util.escapeSpace(catalog)))); 321 entityResolver = new ForkEntityResolver(er, entityResolver); 322 } 323 } catch (IOException e) { 324 throw new BadCommandLineException(WscompileMessages.WSIMPORT_FAILED_TO_PARSE(catalog, e.getMessage())); 325 } 326 return 2; 327 } else if (args[i].startsWith("-httpproxy:")) { 328 String value = args[i].substring(11); 329 if (value.length() == 0) { 330 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_INVALID_OPTION(args[i])); 331 } 332 parseProxy(value); 333 if (proxyHost != null || proxyPort != null) { 334 System.setProperty("proxySet", "true"); 335 } 336 if (proxyHost != null) { 337 System.setProperty("proxyHost", proxyHost); 338 } 339 if (proxyPort != null) { 340 System.setProperty("proxyPort", proxyPort); 341 } 342 return 1; 343 } else if (args[i].equals("-Xno-addressing-databinding")) { 344 noAddressingBbinding = true; 345 return 1; 346 } else if (args[i].startsWith("-B")) { 347 // JAXB option pass through. 348 String[] subCmd = new String[args.length-i]; 349 System.arraycopy(args,i,subCmd,0,subCmd.length); 350 subCmd[0] = subCmd[0].substring(2); // trim off the first "-B" 351 352 com.sun.tools.internal.xjc.Options jaxbOptions = schemaCompiler.getOptions(); 353 try { 354 int r = jaxbOptions.parseArgument(subCmd, 0); 355 if(r==0) { 356 //Driver.usage(jaxbOptions,false); 357 throw new BadCommandLineException(WscompileMessages.WSIMPORT_NO_SUCH_JAXB_OPTION(subCmd[0])); 358 } 359 return r; 360 } catch (com.sun.tools.internal.xjc.BadCommandLineException e) { 361 //Driver.usage(jaxbOptions,false); 362 throw new BadCommandLineException(e.getMessage(),e); 363 } 364 } else if (args[i].equals("-Xauthfile")) { 365 String authfile = requireArgument("-Xauthfile", args, ++i); 366 authFile = new File(authfile); 367 return 2; 368 } else if (args[i].equals("-clientjar")) { 369 clientjar = requireArgument("-clientjar", args, ++i); 370 return 2; 371 } else if (args[i].equals("-implDestDir")) { 372 implDestDir = new File(requireArgument("-implDestDir", args, ++i)); 373 if (!implDestDir.exists()) 374 throw new BadCommandLineException(WscompileMessages.WSCOMPILE_NO_SUCH_DIRECTORY(implDestDir.getPath())); 375 return 2; 376 } else if (args[i].equals("-implServiceName")) { 377 implServiceName = requireArgument("-implServiceName", args, ++i); 378 return 2; 379 } else if (args[i].equals("-implPortName")) { 380 implPortName = requireArgument("-implPortName", args, ++i); 381 return 2; 382 } else if (args[i].equals("-generateJWS")) { 383 isGenerateJWS = true; 384 return 1; 385 } else if (args[i].equals("-XuseBaseResourceAndURLToLoadWSDL")) { 386 useBaseResourceAndURLToLoadWSDL = true; 387 return 1; 388 } else if (args[i].equals("-XdisableAuthenticator")) { 389 disableAuthenticator = true; 390 return 1; 391 } 392 393 // handle additional options 394 for (GeneratorExtension f:ServiceFinder.find(GeneratorExtension.class)) { 395 if (f.validateOption(args[i])) { 396 extensionOptions.put(args[i], requireArgument(args[i], args, ++i)); 397 return 2; 398 } 399 } 400 401 // see if this is one of the extensions 402 for( Plugin plugin : getAllPlugins() ) { 403 try { 404 if(('-' + plugin.getOptionName()).equals(args[i])) { 405 activePlugins.add(plugin); 406 plugin.onActivated(this); 407 return 1; 408 } 409 int r = plugin.parseArgument(this, args, i); 410 if (r != 0) { 411 return r; 412 } 413 } catch (IOException e) { 414 throw new BadCommandLineException(e.getMessage(),e); 415 } 416 } 417 418 return 0; // what's this option? 419 } 420 421 public void validate() throws BadCommandLineException { 422 if (wsdls.isEmpty()) { 423 throw new BadCommandLineException(WscompileMessages.WSIMPORT_MISSING_FILE()); 424 } 425 426 if(wsdlLocation !=null && clientjar != null) { 427 throw new BadCommandLineException(WscompileMessages.WSIMPORT_WSDLLOCATION_CLIENTJAR()); 428 } 429 if(wsdlLocation == null){ 430 wsdlLocation = wsdls.get(0).getSystemId(); 431 } 432 433 434 } 435 436 @Override 437 protected void addFile(String arg) throws BadCommandLineException { 438 addFile(arg, wsdls, ".wsdl"); 439 } 440 441 private final List<InputSource> wsdls = new ArrayList<InputSource>(); 442 private final List<InputSource> schemas = new ArrayList<InputSource>(); 443 private final List<InputSource> bindingFiles = new ArrayList<InputSource>(); 444 private final List<InputSource> jaxwsCustomBindings = new ArrayList<InputSource>(); 445 private final List<InputSource> jaxbCustomBindings = new ArrayList<InputSource>(); 446 private final List<Element> handlerConfigs = new ArrayList<Element>(); 447 448 /** 449 * There is supposed to be one handler chain per generated SEI. 450 * TODO: There is possible bug, how to associate a @HandlerChain 451 * with each port on the generated SEI. For now lets preserve the JAXWS 2.0 FCS 452 * behaviour and generate only one @HandlerChain on the SEI 453 */ 454 public Element getHandlerChainConfiguration(){ 455 if(handlerConfigs.size() > 0) 456 return handlerConfigs.get(0); 457 return null; 458 } 459 460 public void addHandlerChainConfiguration(Element config){ 461 handlerConfigs.add(config); 462 } 463 464 public InputSource[] getWSDLs() { 465 return wsdls.toArray(new InputSource[wsdls.size()]); 466 } 467 468 public InputSource[] getSchemas() { 469 return schemas.toArray(new InputSource[schemas.size()]); 470 } 471 472 public InputSource[] getWSDLBindings() { 473 return jaxwsCustomBindings.toArray(new InputSource[jaxwsCustomBindings.size()]); 474 } 475 476 public InputSource[] getSchemaBindings() { 477 return jaxbCustomBindings.toArray(new InputSource[jaxbCustomBindings.size()]); 478 } 479 480 public void addWSDL(File source) { 481 addWSDL(fileToInputSource(source)); 482 } 483 484 public void addWSDL(InputSource is) { 485 wsdls.add(absolutize(is)); 486 } 487 488 public void addSchema(File source) { 489 addSchema(fileToInputSource(source)); 490 } 491 492 public void addSchema(InputSource is) { 493 schemas.add(is); 494 } 495 496 private InputSource fileToInputSource(File source) { 497 try { 498 String url = source.toURL().toExternalForm(); 499 return new InputSource(Util.escapeSpace(url)); 500 } catch (MalformedURLException e) { 501 return new InputSource(source.getPath()); 502 } 503 } 504 505 /** 506 * Recursively scan directories and add all XSD files in it. 507 */ 508 public void addGrammarRecursive(File dir) { 509 addRecursive(dir, ".wsdl", wsdls); 510 addRecursive(dir, ".xsd", schemas); 511 } 512 513 /** 514 * Adds a new input schema. 515 */ 516 public void addWSDLBindFile(InputSource is) { 517 jaxwsCustomBindings.add(new RereadInputSource(absolutize(is))); 518 } 519 520 public void addSchemmaBindFile(InputSource is) { 521 jaxbCustomBindings.add(new RereadInputSource(absolutize(is))); 522 } 523 524 private void addRecursive(File dir, String suffix, List<InputSource> result) { 525 File[] files = dir.listFiles(); 526 if (files == null) return; // work defensively 527 528 for (File f : files) { 529 if (f.isDirectory()) 530 addRecursive(f, suffix, result); 531 else if (f.getPath().endsWith(suffix)) 532 result.add(absolutize(fileToInputSource(f))); 533 } 534 } 535 536 private InputSource absolutize(InputSource is) { 537 // absolutize all the system IDs in the input, 538 // so that we can map system IDs to DOM trees. 539 try { 540 URL baseURL = new File(".").getCanonicalFile().toURL(); 541 is.setSystemId(new URL(baseURL, is.getSystemId()).toExternalForm()); 542 } catch (IOException e) { 543 // ignore 544 } 545 return is; 546 } 547 548 public void addBindings(String name) throws BadCommandLineException { 549 addFile(name, bindingFiles, null); 550 } 551 552 /** 553 * Parses a token to a file (or a set of files) 554 * and add them as {@link InputSource} to the specified list. 555 * 556 * @param suffix If the given token is a directory name, we do a recusive search 557 * and find all files that have the given suffix. 558 */ 559 private void addFile(String name, List<InputSource> target, String suffix) throws BadCommandLineException { 560 Object src; 561 try { 562 src = Util.getFileOrURL(name); 563 } catch (IOException e) { 564 throw new BadCommandLineException(WscompileMessages.WSIMPORT_NOT_A_FILE_NOR_URL(name)); 565 } 566 if (src instanceof URL) { 567 target.add(absolutize(new InputSource(Util.escapeSpace(((URL) src).toExternalForm())))); 568 } else { 569 File fsrc = (File) src; 570 if (fsrc.isDirectory()) { 571 addRecursive(fsrc, suffix, target); 572 } else { 573 target.add(absolutize(fileToInputSource(fsrc))); 574 } 575 } 576 } 577 578 579 /** 580 * Exposing it as a public method to allow external tools such as NB to read from wsdl model and work on it. 581 * TODO: WSDL model needs to be exposed - basically at tool time we need to use the runtimw wsdl model 582 * 583 * Binding files could be jaxws or jaxb. This method identifies jaxws and jaxb binding files and keeps them separately. jaxb binding files are given separately 584 * to JAXB in {@link com.sun.tools.internal.ws.processor.modeler.wsdl.JAXBModelBuilder} 585 * 586 * @param receiver {@link ErrorReceiver} 587 */ 588 public final void parseBindings(ErrorReceiver receiver){ 589 for (InputSource is : bindingFiles) { 590 XMLStreamReader reader = 591 XMLStreamReaderFactory.create(is,true); 592 XMLStreamReaderUtil.nextElementContent(reader); 593 if (reader.getName().equals(JAXWSBindingsConstants.JAXWS_BINDINGS)) { 594 jaxwsCustomBindings.add(new RereadInputSource(is)); 595 } else if (reader.getName().equals(JAXWSBindingsConstants.JAXB_BINDINGS) || 596 reader.getName().equals(new QName(SchemaConstants.NS_XSD, "schema"))) { 597 jaxbCustomBindings.add(new RereadInputSource(is)); 598 } else { 599 LocatorImpl locator = new LocatorImpl(); 600 locator.setSystemId(reader.getLocation().getSystemId()); 601 locator.setPublicId(reader.getLocation().getPublicId()); 602 locator.setLineNumber(reader.getLocation().getLineNumber()); 603 locator.setColumnNumber(reader.getLocation().getColumnNumber()); 604 receiver.warning(locator, ConfigurationMessages.CONFIGURATION_NOT_BINDING_FILE(is.getSystemId())); 605 } 606 } 607 } 608 609 /** 610 * Get extension argument 611 */ 612 public String getExtensionOption(String argument) { 613 return extensionOptions.get(argument); 614 } 615 616 private void parseProxy(String text) throws BadCommandLineException { 617 int i = text.lastIndexOf('@'); 618 int j = text.lastIndexOf(':'); 619 620 if (i > 0) { 621 proxyAuth = text.substring(0, i); 622 if (j > i) { 623 proxyHost = text.substring(i + 1, j); 624 proxyPort = text.substring(j + 1); 625 } else { 626 proxyHost = text.substring(i + 1); 627 proxyPort = "8080"; 628 } 629 } else { 630 //no auth info 631 if (j < 0) { 632 //no port 633 proxyHost = text; 634 proxyPort = "8080"; 635 } else { 636 proxyHost = text.substring(0, j); 637 proxyPort = text.substring(j + 1); 638 } 639 } 640 try { 641 Integer.valueOf(proxyPort); 642 } catch (NumberFormatException e) { 643 throw new BadCommandLineException(WscompileMessages.WSIMPORT_ILLEGAL_PROXY(text)); 644 } 645 } 646 647 /** 648 * Looks for all "META-INF/services/[className]" files and 649 * create one instance for each class name found inside this file. 650 */ 651 private static <T> T[] findServices(Class<T> clazz, ClassLoader classLoader) { 652 ServiceFinder<T> serviceFinder = ServiceFinder.find(clazz, classLoader); 653 List<T> r = new ArrayList<T>(); 654 for (T t : serviceFinder) { 655 r.add(t); 656 } 657 return r.toArray((T[]) Array.newInstance(clazz, r.size())); 658 } 659 660 private static final class ByteStream extends ByteArrayOutputStream { 661 byte[] getBuffer() { 662 return buf; 663 } 664 } 665 666 private static final class RereadInputStream extends InputStream { 667 private InputStream is; 668 private ByteStream bs; 669 670 RereadInputStream(InputStream is) { 671 this.is = is; 672 this.bs = new ByteStream(); 673 } 674 675 @Override 676 public int available() throws IOException { 677 return is.available(); 678 } 679 680 @Override 681 public void close() throws IOException { 682 if (bs != null) { 683 InputStream i = new ByteArrayInputStream(bs.getBuffer()); 684 bs = null; 685 is.close(); 686 is = i; 687 } 688 } 689 690 @Override 691 public synchronized void mark(int readlimit) { 692 is.mark(readlimit); 693 } 694 695 @Override 696 public boolean markSupported() { 697 return is.markSupported(); 698 } 699 700 @Override 701 public int read() throws IOException { 702 int r = is.read(); 703 if (bs != null) 704 bs.write(r); 705 return r; 706 } 707 708 @Override 709 public int read(byte[] b, int off, int len) throws IOException { 710 int r = is.read(b, off, len); 711 if (r > 0 && bs != null) 712 bs.write(b, off, r); 713 return r; 714 } 715 716 @Override 717 public int read(byte[] b) throws IOException { 718 int r = is.read(b); 719 if (r > 0 && bs != null) 720 bs.write(b, 0, r); 721 return r; 722 } 723 724 @Override 725 public synchronized void reset() throws IOException { 726 is.reset(); 727 } 728 } 729 730 private static final class RereadInputSource extends InputSource { 731 private InputSource is; 732 733 RereadInputSource(InputSource is) { 734 this.is = is; 735 } 736 737 @Override 738 public InputStream getByteStream() { 739 InputStream i = is.getByteStream(); 740 if (i != null && !(i instanceof RereadInputStream)) { 741 i = new RereadInputStream(i); 742 is.setByteStream(i); 743 } 744 return i; 745 } 746 747 @Override 748 public Reader getCharacterStream() { 749 // TODO Auto-generated method stub 750 return is.getCharacterStream(); 751 } 752 753 @Override 754 public String getEncoding() { 755 return is.getEncoding(); 756 } 757 758 @Override 759 public String getPublicId() { 760 return is.getPublicId(); 761 } 762 763 @Override 764 public String getSystemId() { 765 return is.getSystemId(); 766 } 767 768 @Override 769 public void setByteStream(InputStream byteStream) { 770 is.setByteStream(byteStream); 771 } 772 773 @Override 774 public void setCharacterStream(Reader characterStream) { 775 is.setCharacterStream(characterStream); 776 } 777 778 @Override 779 public void setEncoding(String encoding) { 780 is.setEncoding(encoding); 781 } 782 783 @Override 784 public void setPublicId(String publicId) { 785 is.setPublicId(publicId); 786 } 787 788 @Override 789 public void setSystemId(String systemId) { 790 is.setSystemId(systemId); 791 } 792 } 793 794 @Override 795 protected void disableXmlSecurity() { 796 super.disableXmlSecurity(); 797 schemaCompiler.getOptions().disableXmlSecurity = true; 798 } 799 }