23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package com.sun.tools.internal.xjc; |
26 package com.sun.tools.internal.xjc; |
27 |
27 |
|
28 import java.io.BufferedReader; |
|
29 import java.io.File; |
|
30 import java.io.FileInputStream; |
|
31 import java.io.IOException; |
|
32 import java.io.InputStreamReader; |
|
33 import java.io.PrintWriter; |
|
34 import java.io.StringWriter; |
|
35 import java.net.MalformedURLException; |
|
36 import java.net.URL; |
|
37 import java.net.URLClassLoader; |
|
38 import java.security.AccessController; |
|
39 import java.security.PrivilegedAction; |
|
40 import java.text.SimpleDateFormat; |
|
41 import java.util.ArrayList; |
|
42 import java.util.Date; |
|
43 import java.util.Enumeration; |
|
44 import java.util.HashSet; |
|
45 import java.util.List; |
|
46 import java.util.ServiceLoader; |
|
47 import java.util.Set; |
|
48 |
28 import com.sun.codemodel.internal.CodeWriter; |
49 import com.sun.codemodel.internal.CodeWriter; |
29 import com.sun.codemodel.internal.JPackage; |
50 import com.sun.codemodel.internal.JPackage; |
30 import com.sun.codemodel.internal.JResourceFile; |
51 import com.sun.codemodel.internal.JResourceFile; |
31 import com.sun.codemodel.internal.writer.FileCodeWriter; |
52 import com.sun.codemodel.internal.writer.FileCodeWriter; |
32 import com.sun.codemodel.internal.writer.PrologCodeWriter; |
53 import com.sun.codemodel.internal.writer.PrologCodeWriter; |
35 import com.sun.tools.internal.xjc.api.SpecVersion; |
56 import com.sun.tools.internal.xjc.api.SpecVersion; |
36 import com.sun.tools.internal.xjc.generator.bean.field.FieldRendererFactory; |
57 import com.sun.tools.internal.xjc.generator.bean.field.FieldRendererFactory; |
37 import com.sun.tools.internal.xjc.model.Model; |
58 import com.sun.tools.internal.xjc.model.Model; |
38 import com.sun.tools.internal.xjc.reader.Util; |
59 import com.sun.tools.internal.xjc.reader.Util; |
39 import com.sun.xml.internal.bind.api.impl.NameConverter; |
60 import com.sun.xml.internal.bind.api.impl.NameConverter; |
|
61 import java.net.URI; |
|
62 import java.net.URISyntaxException; |
|
63 import java.nio.charset.Charset; |
|
64 import java.nio.charset.IllegalCharsetNameException; |
|
65 import java.util.Locale; |
|
66 import java.util.logging.Level; |
|
67 import java.util.logging.Logger; |
|
68 |
40 import org.xml.sax.EntityResolver; |
69 import org.xml.sax.EntityResolver; |
41 import org.xml.sax.InputSource; |
70 import org.xml.sax.InputSource; |
42 |
|
43 import java.io.BufferedReader; |
|
44 import java.io.File; |
|
45 import java.io.FileInputStream; |
|
46 import java.io.IOException; |
|
47 import java.io.InputStreamReader; |
|
48 import java.io.PrintWriter; |
|
49 import java.io.StringWriter; |
|
50 import java.net.MalformedURLException; |
|
51 import java.net.URI; |
|
52 import java.net.URISyntaxException; |
|
53 import java.net.URL; |
|
54 import java.net.URLClassLoader; |
|
55 import java.nio.charset.Charset; |
|
56 import java.nio.charset.IllegalCharsetNameException; |
|
57 import java.security.AccessController; |
|
58 import java.security.PrivilegedAction; |
|
59 import java.text.SimpleDateFormat; |
|
60 import java.util.ArrayList; |
|
61 import java.util.Date; |
|
62 import java.util.Enumeration; |
|
63 import java.util.HashSet; |
|
64 import java.util.List; |
|
65 import java.util.Locale; |
|
66 import java.util.ServiceLoader; |
|
67 import java.util.Set; |
|
68 import java.util.logging.Level; |
|
69 import java.util.logging.Logger; |
|
70 |
|
71 import javax.xml.catalog.CatalogFeatures; |
|
72 import javax.xml.catalog.CatalogFeatures.Feature; |
|
73 import javax.xml.catalog.CatalogManager; |
|
74 |
71 |
75 /** |
72 /** |
76 * Global options. |
73 * Global options. |
77 * |
74 * |
78 * <p> |
75 * <p> |
179 * {@link JPackage#addResourceFile(JResourceFile)}. |
176 * {@link JPackage#addResourceFile(JResourceFile)}. |
180 */ |
177 */ |
181 public File targetDir = new File("."); |
178 public File targetDir = new File("."); |
182 |
179 |
183 /** |
180 /** |
184 * Actually stores {@link CatalogResolver}, but the field |
181 * On JDK 8 an odler stores {@code CatalogResolver}, but the field |
185 * type is made to {@link EntityResolver} so that XJC can be |
182 * type is made to {@link EntityResolver} so that XJC can be |
186 * used even if resolver.jar is not available in the classpath. |
183 * used even if resolver.jar is not available in the classpath. |
187 */ |
184 */ |
188 public EntityResolver entityResolver = null; |
185 public EntityResolver entityResolver = null; |
189 |
186 |
206 public String defaultPackage2 = null; |
203 public String defaultPackage2 = null; |
207 |
204 |
208 /** |
205 /** |
209 * Input schema files as a list of {@link InputSource}s. |
206 * Input schema files as a list of {@link InputSource}s. |
210 */ |
207 */ |
211 private final List<InputSource> grammars = new ArrayList<InputSource>(); |
208 private final List<InputSource> grammars = new ArrayList<>(); |
212 |
209 |
213 private final List<InputSource> bindFiles = new ArrayList<InputSource>(); |
210 private final List<InputSource> bindFiles = new ArrayList<>(); |
214 |
211 |
215 // Proxy setting. |
212 // Proxy setting. |
216 private String proxyHost = null; |
213 private String proxyHost = null; |
217 private String proxyPort = null; |
214 private String proxyPort = null; |
218 public String proxyAuth = null; |
215 public String proxyAuth = null; |
219 |
216 |
220 /** |
217 /** |
221 * {@link Plugin}s that are enabled in this compilation. |
218 * {@link Plugin}s that are enabled in this compilation. |
222 */ |
219 */ |
223 public final List<Plugin> activePlugins = new ArrayList<Plugin>(); |
220 public final List<Plugin> activePlugins = new ArrayList<>(); |
224 |
221 |
225 /** |
222 /** |
226 * All discovered {@link Plugin}s. |
223 * All discovered {@link Plugin}s. |
227 * This is lazily parsed, so that we can take '-cp' option into account. |
224 * This is lazily parsed, so that we can take '-cp' option into account. |
228 * |
225 * |
231 private List<Plugin> allPlugins; |
228 private List<Plugin> allPlugins; |
232 |
229 |
233 /** |
230 /** |
234 * Set of URIs that plug-ins recognize as extension bindings. |
231 * Set of URIs that plug-ins recognize as extension bindings. |
235 */ |
232 */ |
236 public final Set<String> pluginURIs = new HashSet<String>(); |
233 public final Set<String> pluginURIs = new HashSet<>(); |
237 |
234 |
238 /** |
235 /** |
239 * This allocator has the final say on deciding the class name. |
236 * This allocator has the final say on deciding the class name. |
240 */ |
237 */ |
241 public ClassNameAllocator classNameAllocator; |
238 public ClassNameAllocator classNameAllocator; |
355 * |
352 * |
356 * <p> |
353 * <p> |
357 * A plugins are enumerated when this method is called for the first time, |
354 * A plugins are enumerated when this method is called for the first time, |
358 * by taking {@link #classpaths} into account. That means |
355 * by taking {@link #classpaths} into account. That means |
359 * "-cp plugin.jar" has to come before you specify options to enable it. |
356 * "-cp plugin.jar" has to come before you specify options to enable it. |
|
357 * @return |
360 */ |
358 */ |
361 public List<Plugin> getAllPlugins() { |
359 public List<Plugin> getAllPlugins() { |
362 if(allPlugins==null) { |
360 if(allPlugins==null) { |
363 allPlugins = findServices(Plugin.class); |
361 allPlugins = findServices(Plugin.class); |
364 } |
362 } |
373 } |
371 } |
374 public void setSchemaLanguage(Language _schemaLanguage) { |
372 public void setSchemaLanguage(Language _schemaLanguage) { |
375 this.schemaLanguage = _schemaLanguage; |
373 this.schemaLanguage = _schemaLanguage; |
376 } |
374 } |
377 |
375 |
378 /** Input schema files. */ |
376 /** Input schema files. |
|
377 * @return */ |
379 public InputSource[] getGrammars() { |
378 public InputSource[] getGrammars() { |
380 return grammars.toArray(new InputSource[grammars.size()]); |
379 return grammars.toArray(new InputSource[grammars.size()]); |
381 } |
380 } |
382 |
381 |
383 /** |
382 /** |
384 * Adds a new input schema. |
383 * Adds a new input schema. |
|
384 * @param is |
385 */ |
385 */ |
386 public void addGrammar( InputSource is ) { |
386 public void addGrammar( InputSource is ) { |
387 grammars.add(absolutize(is)); |
387 grammars.add(absolutize(is)); |
388 } |
388 } |
389 |
389 |
430 logger.log(Level.FINE, "{0}, {1}", new Object[]{is.getSystemId(), e.getLocalizedMessage()}); |
431 logger.log(Level.FINE, "{0}, {1}", new Object[]{is.getSystemId(), e.getLocalizedMessage()}); |
431 } |
432 } |
432 return is; |
433 return is; |
433 } |
434 } |
434 |
435 |
435 /** Input external binding files. */ |
436 /** Input external binding files. |
|
437 * @return */ |
436 public InputSource[] getBindFiles() { |
438 public InputSource[] getBindFiles() { |
437 return bindFiles.toArray(new InputSource[bindFiles.size()]); |
439 return bindFiles.toArray(new InputSource[bindFiles.size()]); |
438 } |
440 } |
439 |
441 |
440 /** |
442 /** |
441 * Adds a new binding file. |
443 * Adds a new binding file. |
|
444 * @param is |
442 */ |
445 */ |
443 public void addBindFile( InputSource is ) { |
446 public void addBindFile( InputSource is ) { |
444 bindFiles.add(absolutize(is)); |
447 bindFiles.add(absolutize(is)); |
445 } |
448 } |
446 |
449 |
447 /** |
450 /** |
448 * Adds a new binding file. |
451 * Adds a new binding file. |
|
452 * @param bindFile |
449 */ |
453 */ |
450 public void addBindFile( File bindFile ) { |
454 public void addBindFile( File bindFile ) { |
451 bindFiles.add(fileToInputSource(bindFile)); |
455 bindFiles.add(fileToInputSource(bindFile)); |
452 } |
456 } |
453 |
457 |
454 /** |
458 /** |
455 * Recursively scan directories and add all ".xjb" files in it. |
459 * Recursively scan directories and add all ".xjb" files in it. |
|
460 * @param dir |
456 */ |
461 */ |
457 public void addBindFileRecursive( File dir ) { |
462 public void addBindFileRecursive( File dir ) { |
458 addRecursive(dir,".xjb",bindFiles); |
463 addRecursive(dir,".xjb",bindFiles); |
459 } |
464 } |
460 |
465 |
461 public final List<URL> classpaths = new ArrayList<URL>(); |
466 public final List<URL> classpaths = new ArrayList<>(); |
462 /** |
467 /** |
463 * Gets a classLoader that can load classes specified via the |
468 * Gets a classLoader that can load classes specified via the |
464 * -classpath option. |
469 * -classpath option. |
|
470 * @param parent |
|
471 * @return |
465 */ |
472 */ |
466 public ClassLoader getUserClassLoader( ClassLoader parent ) { |
473 public ClassLoader getUserClassLoader( ClassLoader parent ) { |
467 if (classpaths.isEmpty()) |
474 if (classpaths.isEmpty()) |
468 return parent; |
475 return parent; |
469 return new URLClassLoader( |
476 return new URLClassLoader( |
480 |
487 |
481 /** |
488 /** |
482 * Parses an option {@code args[i]} and return |
489 * Parses an option {@code args[i]} and return |
483 * the number of tokens consumed. |
490 * the number of tokens consumed. |
484 * |
491 * |
|
492 * @param args |
|
493 * @param i |
485 * @return |
494 * @return |
486 * 0 if the argument is not understood. Returning 0 |
495 * 0 if the argument is not understood. Returning 0 |
487 * will let the caller report an error. |
496 * will let the caller report an error. |
488 * @exception BadCommandLineException |
497 * @exception BadCommandLineException |
489 * If the callee wants to provide a custom message for an error. |
498 * If the callee wants to provide a custom message for an error. |
608 if(!file.exists()) { |
617 if(!file.exists()) { |
609 throw new BadCommandLineException( |
618 throw new BadCommandLineException( |
610 Messages.format(Messages.NO_SUCH_FILE,file)); |
619 Messages.format(Messages.NO_SUCH_FILE,file)); |
611 } |
620 } |
612 |
621 |
613 try { |
622 try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"))) { |
614 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8")); |
|
615 parseProxy(in.readLine()); |
623 parseProxy(in.readLine()); |
616 in.close(); |
|
617 } catch (IOException e) { |
624 } catch (IOException e) { |
618 throw new BadCommandLineException( |
625 throw new BadCommandLineException( |
619 Messages.format(Messages.FAILED_TO_PARSE,file,e.getMessage()),e); |
626 Messages.format(Messages.FAILED_TO_PARSE,file,e.getMessage()),e); |
620 } |
627 } |
621 |
628 |
637 if (args[i].equals("-port")) { |
644 if (args[i].equals("-port")) { |
638 proxyPort = requireArgument("-port",args,++i); |
645 proxyPort = requireArgument("-port",args,++i); |
639 return 2; |
646 return 2; |
640 } |
647 } |
641 if( args[i].equals("-catalog") ) { |
648 if( args[i].equals("-catalog") ) { |
642 // use javax.xml.catalog to resolve external entities. |
649 // use Sun's "XML Entity and URI Resolvers" by Norman Walsh |
|
650 // to resolve external entities. |
|
651 // https://xerces.apache.org/xml-commons/components/resolver/resolver-article.html |
643 |
652 |
644 File catalogFile = new File(requireArgument("-catalog",args,++i)); |
653 File catalogFile = new File(requireArgument("-catalog",args,++i)); |
645 try { |
654 try { |
646 addCatalog(catalogFile); |
655 addCatalog(catalogFile); |
647 } catch (IOException e) { |
656 } catch (IOException e) { |
650 } |
659 } |
651 return 2; |
660 return 2; |
652 } |
661 } |
653 if( args[i].equals("-Xtest-class-name-allocator") ) { |
662 if( args[i].equals("-Xtest-class-name-allocator") ) { |
654 classNameAllocator = new ClassNameAllocator() { |
663 classNameAllocator = new ClassNameAllocator() { |
|
664 @Override |
655 public String assignClassName(String packageName, String className) { |
665 public String assignClassName(String packageName, String className) { |
656 System.out.printf("assignClassName(%s,%s)\n",packageName,className); |
666 System.out.printf("assignClassName(%s,%s)\n",packageName,className); |
657 return className+"_Type"; |
667 return className+"_Type"; |
658 } |
668 } |
659 }; |
669 }; |
734 } |
744 } |
735 } |
745 } |
736 |
746 |
737 /** |
747 /** |
738 * Obtains an operand and reports an error if it's not there. |
748 * Obtains an operand and reports an error if it's not there. |
|
749 * @param optionName |
|
750 * @param args |
|
751 * @param i |
|
752 * @return |
|
753 * @throws com.sun.tools.internal.xjc.BadCommandLineException |
739 */ |
754 */ |
740 public String requireArgument(String optionName, String[] args, int i) throws BadCommandLineException { |
755 public String requireArgument(String optionName, String[] args, int i) throws BadCommandLineException { |
741 if (i == args.length || args[i].startsWith("-")) { |
756 if (i == args.length || args[i].startsWith("-")) { |
742 throw new BadCommandLineException( |
757 throw new BadCommandLineException( |
743 Messages.format(Messages.MISSING_OPERAND,optionName)); |
758 Messages.format(Messages.MISSING_OPERAND,optionName)); |
771 target.add(absolutize(fileToInputSource(fsrc))); |
786 target.add(absolutize(fileToInputSource(fsrc))); |
772 } |
787 } |
773 } |
788 } |
774 } |
789 } |
775 |
790 |
776 /** |
|
777 * Adds a new catalog file. |
|
778 */ |
|
779 public void addCatalog(File catalogFile) throws IOException { |
|
780 URI newUrl = catalogFile.toURI(); |
|
781 if (!catalogUrls.contains(newUrl)) { |
|
782 catalogUrls.add(newUrl); |
|
783 } |
|
784 try { |
|
785 entityResolver = CatalogManager.catalogResolver(catalogFeatures, |
|
786 catalogUrls.stream().toArray(URI[]::new)); |
|
787 } catch (Exception ex) { |
|
788 entityResolver = null; |
|
789 } |
|
790 } |
|
791 |
|
792 // Since javax.xml.catalog is unmodifiable we need to track catalog |
791 // Since javax.xml.catalog is unmodifiable we need to track catalog |
793 // URLs added and create new catalog each time addCatalog is called |
792 // URLs added and create new catalog each time addCatalog is called |
794 private final ArrayList<URI> catalogUrls = new ArrayList<>(); |
793 private final ArrayList<URI> catalogUrls = new ArrayList<>(); |
795 |
794 |
796 // Cache CatalogFeatures instance for future usages. |
795 /** |
797 // Resolve feature is set to "continue" value for backward compatibility. |
796 * Adds a new catalog file.Use created or existed resolver to parse new catalog file. |
798 private static CatalogFeatures catalogFeatures = CatalogFeatures.builder() |
797 * @param catalogFile |
799 .with(Feature.RESOLVE, "continue") |
798 * @throws java.io.IOException |
800 .build(); |
799 */ |
|
800 public void addCatalog(File catalogFile) throws IOException { |
|
801 URI newUri = catalogFile.toURI(); |
|
802 if (!catalogUrls.contains(newUri)) { |
|
803 catalogUrls.add(newUri); |
|
804 } |
|
805 entityResolver = CatalogUtil.getCatalog(entityResolver, catalogFile, catalogUrls); |
|
806 } |
|
807 |
801 /** |
808 /** |
802 * Parses arguments and fill fields of this object. |
809 * Parses arguments and fill fields of this object. |
803 * |
810 * |
|
811 * @param args |
804 * @exception BadCommandLineException |
812 * @exception BadCommandLineException |
805 * thrown when there's a problem in the command-line arguments |
813 * thrown when there's a problem in the command-line arguments |
806 */ |
814 */ |
807 public void parseArguments( String[] args ) throws BadCommandLineException { |
815 public void parseArguments( String[] args ) throws BadCommandLineException { |
808 |
816 |
859 Messages.format(Messages.PLUGIN_LOAD_FAILURE,pluginLoadFailure)); |
867 Messages.format(Messages.PLUGIN_LOAD_FAILURE,pluginLoadFailure)); |
860 } |
868 } |
861 |
869 |
862 /** |
870 /** |
863 * Finds the {@code META-INF/sun-jaxb.episode} file to add as a binding customization. |
871 * Finds the {@code META-INF/sun-jaxb.episode} file to add as a binding customization. |
|
872 * @param jar |
|
873 * @throws com.sun.tools.internal.xjc.BadCommandLineException |
864 */ |
874 */ |
865 public void scanEpisodeFile(File jar) throws BadCommandLineException { |
875 public void scanEpisodeFile(File jar) throws BadCommandLineException { |
866 try { |
876 try { |
867 URLClassLoader ucl = new URLClassLoader(new URL[]{jar.toURL()}); |
877 URLClassLoader ucl = new URLClassLoader(new URL[]{jar.toURL()}); |
868 Enumeration<URL> resources = ucl.findResources("META-INF/sun-jaxb.episode"); |
878 Enumeration<URL> resources = ucl.findResources("META-INF/sun-jaxb.episode"); |
897 return Language.XMLSCHEMA; |
908 return Language.XMLSCHEMA; |
898 } |
909 } |
899 |
910 |
900 /** |
911 /** |
901 * Creates a configured CodeWriter that produces files into the specified directory. |
912 * Creates a configured CodeWriter that produces files into the specified directory. |
|
913 * @return |
|
914 * @throws java.io.IOException |
902 */ |
915 */ |
903 public CodeWriter createCodeWriter() throws IOException { |
916 public CodeWriter createCodeWriter() throws IOException { |
904 return createCodeWriter(new FileCodeWriter( targetDir, readOnly, encoding )); |
917 return createCodeWriter(new FileCodeWriter( targetDir, readOnly, encoding )); |
905 } |
918 } |
906 |
919 |
907 /** |
920 /** |
908 * Creates a configured CodeWriter that produces files into the specified directory. |
921 * Creates a configured CodeWriter that produces files into the specified directory. |
|
922 * @param core |
|
923 * @return |
909 */ |
924 */ |
910 public CodeWriter createCodeWriter( CodeWriter core ) { |
925 public CodeWriter createCodeWriter( CodeWriter core ) { |
911 if(noFileHeader) |
926 if(noFileHeader) |
912 return core; |
927 return core; |
913 |
928 |
914 return new PrologCodeWriter( core,getPrologComment() ); |
929 return new PrologCodeWriter( core,getPrologComment() ); |
915 } |
930 } |
916 |
931 |
917 /** |
932 /** |
918 * Gets the string suitable to be used as the prolog comment baked into artifacts. |
933 * Gets the string suitable to be used as the prolog comment baked into artifacts.This is the string like "This file was generated by the JAXB RI on YYYY/mm/dd..." |
919 * This is the string like "This file was generated by the JAXB RI on YYYY/mm/dd..." |
934 * @return |
920 */ |
935 */ |
921 public String getPrologComment() { |
936 public String getPrologComment() { |
922 // generate format syntax: <date> 'at' <time> |
937 // generate format syntax: <date> 'at' <time> |
923 String format = |
938 String format = |
924 Messages.format(Messages.DATE_FORMAT) |
939 Messages.format(Messages.DATE_FORMAT) |
941 /** |
956 /** |
942 * Looks for all "META-INF/services/[className]" files and |
957 * Looks for all "META-INF/services/[className]" files and |
943 * create one instance for each class name found inside this file. |
958 * create one instance for each class name found inside this file. |
944 */ |
959 */ |
945 private <T> List<T> findServices( Class<T> clazz) { |
960 private <T> List<T> findServices( Class<T> clazz) { |
946 final List<T> result = new ArrayList<T>(); |
961 final List<T> result = new ArrayList<>(); |
947 final boolean debug = getDebugPropertyValue(); |
962 final boolean debug = getDebugPropertyValue(); |
948 try { |
963 try { |
949 // TCCL allows user plugins to be loaded even if xjc is in jdk |
964 // TCCL allows user plugins to be loaded even if xjc is in jdk |
950 // We have to use our SecureLoader to obtain it because we are trying to avoid SecurityException |
965 // We have to use our SecureLoader to obtain it because we are trying to avoid SecurityException |
951 final ClassLoader tccl = SecureLoader.getContextClassLoader(); |
966 final ClassLoader tccl = SecureLoader.getContextClassLoader(); |