1 package org.codehaus.mojo.jaxb2.javageneration;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import com.sun.tools.xjc.Driver;
23 import org.apache.maven.plugin.MojoExecutionException;
24 import org.apache.maven.plugin.MojoFailureException;
25 import org.apache.maven.plugins.annotations.Parameter;
26 import org.apache.maven.settings.Proxy;
27 import org.apache.maven.settings.Settings;
28 import org.codehaus.mojo.jaxb2.AbstractJaxbMojo;
29 import org.codehaus.mojo.jaxb2.NoSchemasException;
30 import org.codehaus.mojo.jaxb2.shared.FileSystemUtilities;
31 import org.codehaus.mojo.jaxb2.shared.arguments.ArgumentBuilder;
32 import org.codehaus.mojo.jaxb2.shared.environment.EnvironmentFacet;
33 import org.codehaus.mojo.jaxb2.shared.environment.ToolExecutionEnvironment;
34 import org.codehaus.mojo.jaxb2.shared.environment.classloading.ThreadContextClassLoaderBuilder;
35 import org.codehaus.mojo.jaxb2.shared.environment.locale.LocaleFacet;
36 import org.codehaus.mojo.jaxb2.shared.environment.logging.LoggingHandlerEnvironmentFacet;
37 import org.codehaus.mojo.jaxb2.shared.environment.sysprops.SystemPropertyChangeEnvironmentFacet;
38 import org.codehaus.mojo.jaxb2.shared.environment.sysprops.SystemPropertySaveEnvironmentFacet;
39 import org.codehaus.plexus.util.FileUtils;
40 import org.codehaus.plexus.util.IOUtil;
41
42 import java.io.File;
43 import java.io.FileWriter;
44 import java.net.HttpURLConnection;
45 import java.net.URISyntaxException;
46 import java.net.URL;
47 import java.net.URLConnection;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.List;
51
52 /**
53 * <p>Abstract superclass for Mojos generating Java source or binaries from XML schema(s) by invoking the JAXB XJC
54 * binding compiler. Most of the Configuration options for the AbstractJavaGeneratorMojo are set or copied to the
55 * XJC directly; refer to their documentation in the <a href="https://jaxb.java.net/">JAXB Reference Implementation</a>
56 * site.</p>
57 *
58 * @author <a href="mailto:lj@jguru.se">Lennart Jörelid</a>
59 * @see <a href="https://jaxb.java.net/">The JAXB Reference Implementation</a>
60 */
61 public abstract class AbstractJavaGeneratorMojo extends AbstractJaxbMojo {
62
63 private static final List<String> PROXY_PROPERTY_KEYS = Arrays.asList("http.proxyHost", "http.proxyPort", "https.proxyHost", "https.proxyPort");
64
65 private static final int XJC_COMPLETED_OK = 0;
66
67 /**
68 * <p>Corresponding XJC parameter: {@code catalog}.</p>
69 * <p>Specify catalog files to resolve external entity references.
70 * Supports TR9401, XCatalog, and OASIS XML Catalog format.</p>
71 */
72 @Parameter
73 protected File catalog;
74
75 /**
76 * <strong>Deprecated - will be removed in a future release</strong>
77 * <p>From plugin version 2.4, this parameter will not be used.
78 * Instead, episode files are generated by default with all JAXB operations.</p>
79 * <p>Starting with plugin version 2.4, use the parameter {@link #episodeFileName} to provide a custom
80 * name of the generated episode File (or rely on the standard file name {@link #STANDARD_EPISODE_FILENAME}).</p>
81 *
82 * @since 2.0
83 * @deprecated
84 */
85 @Deprecated
86 @Parameter(defaultValue = "true")
87 protected boolean generateEpisode;
88
89 /**
90 * <p>Corresponding XJC parameter: {@code episode}.</p>
91 * <p>Generate an episode file with the supplied name from this XJC compilation, so that other schemas that rely
92 * on this schema can be compiled later and rely on classes that are generated from this compilation.
93 * The generated episode file is simply a JAXB customization file (but with vendor extensions), normally known
94 * as a <em>binding file</em> with the suffix <code>.xjb</code>.</p>
95 * <p>If the <code>episodeFileName</code> parameter is not given, the episode file name is synthesized on the form
96 * <code>"episode_" + executionID + ".xjb"</code> - typically something like <em>episode_my_xjc.xjb</em>, but
97 * it depends on the actual ID given in the execution element:</p>
98 * <pre>
99 * <code>
100 * <executions>
101 * <execution>
102 * <id>my_xjc</id>
103 * <goals>
104 * <goal>xjc</goal>
105 * </goals>
106 * </execution>
107 * </executions>
108 * </code>
109 * </pre>
110 *
111 * @see #STANDARD_EPISODE_FILENAME
112 * @since 2.4
113 */
114 @Parameter
115 protected String episodeFileName;
116
117 /**
118 * <p>Sets the HTTP/HTTPS proxy to be used by the XJC, on the format
119 * {@code [user[:password]@]proxyHost[:proxyPort]}.
120 * All information is retrieved from the active proxy within the standard maven settings file.</p>
121 */
122 @Parameter(defaultValue = "${settings}", readonly = true)
123 protected Settings settings;
124
125 /**
126 * <p>Defines the content type of sources for the XJC. To simplify usage of the JAXB2 maven plugin,
127 * all source files are assumed to have the same type of content.</p>
128 * <p>This parameter replaces the previous multiple-choice boolean configuration options for the
129 * jaxb2-maven-plugin (i.e. dtd, xmlschema, relaxng, relaxng-compact, wsdl), and
130 * corresponds to setting one of those flags as an XJC argument.</p>
131 *
132 * @since 2.0
133 */
134 @Parameter(defaultValue = "XmlSchema")
135 protected SourceContentType sourceType;
136
137 /**
138 * <p>Corresponding XJC parameter: {@code npa}.</p>
139 * <p>Suppress the generation of package level annotations into {@code package-info.java}.
140 * Using this switch causes the generated code to internalize those annotations into the other
141 * generated classes.</p>
142 *
143 * @since 2.0
144 */
145 @Parameter(defaultValue = "false")
146 protected boolean noPackageLevelAnnotations;
147
148 /**
149 * <p>Corresponding XJC parameter: {@code no-header}.</p>
150 * <p>Suppress the generation of a file header comment that includes some note and timestamp.
151 * Using this makes the generated code more diff-friendly.</p>
152 *
153 * @since 2.0
154 */
155 @Parameter(defaultValue = "false")
156 protected boolean noGeneratedHeaderComments;
157
158 /**
159 * <p>Corresponding XJC parameter: {@code mark-generated}.</p>
160 * <p>This feature causes all of the generated code to have {@code @Generated} annotation.</p>
161 *
162 * @since 2.0
163 */
164 @Parameter(defaultValue = "false")
165 protected boolean addGeneratedAnnotation;
166
167 /**
168 * <p>Corresponding XJC parameter: {@code nv}.</p>
169 * <p>By default, the XJC binding compiler performs strict validation of the source schema before processing it.
170 * Use this option to disable strict schema validation. This does not mean that the binding compiler will not
171 * perform any validation, it simply means that it will perform less-strict validation.</p>
172 *
173 * @since 2.0
174 */
175 @Parameter(defaultValue = "false")
176 protected boolean laxSchemaValidation;
177
178 /**
179 * <p>Corresponding XJC parameter: {@code quiet}.</p>
180 * <p>Suppress compiler output, such as progress information and warnings.</p>
181 */
182 @Parameter(defaultValue = "false")
183 protected boolean quiet;
184
185 /**
186 * <p>Corresponding XJC parameter: {@code verbose}.</p>
187 * <p>Tells XJC to be extra verbose, such as printing informational messages or displaying stack traces.</p>
188 */
189 @Parameter(property = "xjc.verbose", defaultValue = "false")
190 protected boolean verbose;
191
192 /**
193 * <p>Corresponding XJC parameter: {@code extension}.</p>
194 * <p>By default, the XJC binding compiler strictly enforces the rules outlined in the Compatibility chapter of
195 * the JAXB Specification. Appendix E.2 defines a set of W3C XML Schema features that are not completely
196 * supported by JAXB v1.0. In some cases, you may be allowed to use them in the "-extension" mode enabled by
197 * this switch. In the default (strict) mode, you are also limited to using only the binding customizations
198 * defined in the specification.</p>
199 */
200 @Parameter(defaultValue = "true")
201 protected boolean extension;
202
203 /**
204 * Fails the Mojo execution if no XSDs/schemas are found.
205 *
206 * @since 1.3
207 */
208 @Parameter(defaultValue = "true")
209 protected boolean failOnNoSchemas;
210
211 /**
212 * <p>Removes all files from the output directory before running XJC.</p>
213 */
214 @Parameter(defaultValue = "true")
215 protected boolean clearOutputDir;
216
217 /**
218 * <p>Corresponding XJC parameter: {@code readOnly}.</p>
219 * <p>By default, the XJC binding compiler does not write-protect the Java source files it generates.
220 * Use this option to force the XJC binding compiler to mark the generated Java sources read-only.</p>
221 *
222 * @since 2.0
223 */
224 @Parameter(defaultValue = "false")
225 protected boolean readOnly;
226
227 /**
228 * <p>List of ordered extra arguments to the XJC command. Each extra argument is interpreted as a word, intended
229 * to be copied verbatim to the XJC argument list with spaces in between:</p>
230 * <pre>
231 * <code>
232 * <configuration>
233 * ...
234 * <arguments>
235 * <argument>-Xfluent-api</argument>
236 * <argument>somefile</argument>
237 * </arguments>
238 * </configuration>
239 * </code>
240 * </pre>
241 * <p>The arguments configured above yields the following extra arguments to the XJC command:
242 * <code>-Xfluent-api -episode somefile</code></p>
243 *
244 * @since 2.0
245 * @deprecated This should be removed in the 2.0+ release, as all arguments should be handled by other parameters.
246 */
247 @Parameter(property = "xjc.arguments")
248 protected List<String> arguments;
249
250 /**
251 * <p>Corresponding XJC parameter: {@code enableIntrospection}.</p>
252 * <p>Enable correct generation of Boolean getters/setters to enable Bean Introspection APIs.</p>
253 *
254 * @since 1.4
255 */
256 @Parameter(defaultValue = "false")
257 private boolean enableIntrospection;
258
259 /**
260 * <p>Corresponding XJC parameter: {@code p}.</p>
261 * <p>The package under which the source files will be generated. Quoting the XJC documentation:
262 * "Specifying a target package via this command-line option overrides any binding customization for package
263 * name and the default package name algorithm defined in the specification".</p>
264 */
265 @Parameter
266 protected String packageName;
267
268 /**
269 * <p>Corresponding XJC parameter: {@code target}.</p>
270 * <p>Permitted values: {@code "2.0"} and {@code "2.1"}. Avoid generating code that relies on JAXB newer than the
271 * version given. This will allow the generated code to run with JAXB 2.0 runtime (such as JavaSE 6.)</p>
272 *
273 * @since 1.3
274 */
275 @Parameter
276 protected String target;
277
278 /**
279 * <p>If provided, this parameter indicates that the XSDs used by XJC to generate Java code should be
280 * copied into the resulting artifact of this project (the JAR, WAR or whichever artifact type is generated).
281 * The value of the {@code xsdPathWithinArtifact} parameter is the relative path within the artifact where
282 * all source XSDs are copied to (hence the name "XSD Path Within Artifact").</p>
283 * <p>The target directory is created within the artifact if it does not already exist.
284 * If the {@code xsdPathWithinArtifact} parameter is not given, the XSDs used to generate Java code are
285 * <em>not</em> included within the project's artifact.</p>
286 * <p><em>Example:</em>Adding the sample configuration below would copy all source XSDs to the given directory
287 * within the resulting JAR (and/or test-JAR). If the directory {@code META-INF/jaxb/xsd} does not exist, it
288 * will be created.</p>
289 * <pre>
290 * <code>
291 * <configuration>
292 * ...
293 * <xsdPathWithinArtifact>META-INF/jaxb/xsd</xsdPathWithinArtifact>
294 * </configuration>
295 * </code>
296 * </pre>
297 * <p><strong>Note</strong>: This parameter was previously called {@code includeSchemasOutputPath}
298 * in the 1.x versions of this plugin, but was renamed and re-documented for improved usability and clarity.</p>
299 *
300 * @since 2.0
301 */
302 @Parameter
303 protected String xsdPathWithinArtifact;
304
305 /**
306 * <p>If set to <code>true</code>, the system property <code>enableExternalEntityProcessing</code> is set for the
307 * duration of the Java generation by this plugin, permitting DTD sources to use external entity URIs such as
308 * <code>file://</code>. Typically, this is used in conjunction with the <code>sourceType</code> similar to the
309 * configuration snippet below where DTDs are used as sourceType and read from the <code>src/main/dtd</code>
310 * directory. This implies a <code>file://</code> URI.</p>
311 * <pre>
312 * <code>
313 * <configuration>
314 * ...
315 * <sourceType>dtd</sourceType>
316 * <sources>
317 * <source>src/main/dtd</source>
318 * </sources>
319 * <externalEntityProcessing>true</externalEntityProcessing>
320 * </configuration>
321 * </code>
322 * </pre>
323 *
324 * @since 2.4
325 */
326 @Parameter(defaultValue = "false")
327 protected boolean externalEntityProcessing;
328
329 /**
330 * <p>Java generation is required if any of the file products is outdated/stale.</p>
331 * {@inheritDoc}
332 */
333 @Override
334 protected boolean isReGenerationRequired() {
335
336 //
337 // Use the stale flag method to identify if we should re-generate the java source code from the supplied
338 // Xml Schema. Basically, we should regenerate the JAXB code if:
339 //
340 // a) The staleFile does not exist
341 // b) The staleFile exists and is older than one of the sources (XSD or XJB files).
342 // "Older" is determined by comparing the modification timestamp of the staleFile and the source files.
343 //
344 final File staleFile = getStaleFile();
345 final String debugPrefix = "StaleFile [" + FileSystemUtilities.getCanonicalPath(staleFile) + "]";
346
347 boolean stale = !staleFile.exists();
348 if (stale) {
349 getLog().debug(debugPrefix + " not found. JAXB (re-)generation required.");
350 } else {
351
352 final List<URL> sourceXSDs = getSources();
353 final List<File> sourceXJBs = getSourceXJBs();
354
355 if (getLog().isDebugEnabled()) {
356 getLog().debug(debugPrefix + " found. Checking timestamps on source XSD and XJB "
357 + "files to determine if JAXB (re-)generation is required.");
358 }
359
360 final long staleFileLastModified = staleFile.lastModified();
361 for (URL current : sourceXSDs) {
362
363 final URLConnection sourceXsdConnection;
364 try {
365 sourceXsdConnection = current.openConnection();
366 sourceXsdConnection.connect();
367 } catch (Exception e) {
368
369 // Can't determine if the staleFile is younger than this sourceXSD.
370 // Re-generate to be on the safe side.
371 stale = true;
372 break;
373 }
374
375 try {
376 if (sourceXsdConnection.getLastModified() > staleFileLastModified) {
377
378 if (getLog().isDebugEnabled()) {
379 getLog().debug(current.toString() + " is newer than the stale flag file.");
380 }
381 stale = true;
382 }
383 } finally {
384 if (sourceXsdConnection instanceof HttpURLConnection) {
385 ((HttpURLConnection) sourceXsdConnection).disconnect();
386 }
387 }
388 }
389
390 for (File current : sourceXJBs) {
391 if (current.lastModified() > staleFileLastModified) {
392
393 if (getLog().isDebugEnabled()) {
394 getLog().debug(FileSystemUtilities.getCanonicalPath(current)
395 + " is newer than the stale flag file.");
396 }
397
398 stale = true;
399 break;
400 }
401 }
402 }
403
404 // All done.
405 return stale;
406 }
407
408 /**
409 * {@inheritDoc}
410 */
411 @Override
412 protected boolean performExecution() throws MojoExecutionException, MojoFailureException {
413
414 boolean updateStaleFileTimestamp = false;
415
416 try {
417
418 // Setup the Tool's execution environment
419 ToolExecutionEnvironment environment = null;
420 try {
421
422 // Create a LocaleFacet if the user has configured an explicit Locale for the tool.
423 final LocaleFacet localeFacet = locale == null ? null : LocaleFacet.createFor(locale, getLog());
424
425 // Create the ToolExecutionEnvironment
426 environment = new ToolExecutionEnvironment(getLog(),
427 ThreadContextClassLoaderBuilder.createFor(this.getClass(), getLog(), getEncoding(false))
428 .addPaths(getClasspath()),
429 LoggingHandlerEnvironmentFacet.create(getLog(), getClass(), getEncoding(false)),
430 localeFacet);
431
432 // Add any extra configured EnvironmentFacets, as configured in the POM.
433 if (extraFacets != null) {
434 for (EnvironmentFacet current : extraFacets) {
435 environment.add(current);
436 }
437 }
438
439 // Handle extended properties?
440 if (externalEntityProcessing) {
441
442 final List<SystemPropertyChangeEnvironmentFacet> sysPropChanges =
443 SystemPropertyChangeEnvironmentFacet.getBuilder(getLog())
444 .addOrChange("enableExternalEntityProcessing", "" + externalEntityProcessing)
445 .build();
446
447 for (SystemPropertyChangeEnvironmentFacet current : sysPropChanges) {
448 environment.add(current);
449 }
450 }
451
452 // XJC overwrites proxy properties if so inclined, so we use this facet to save them
453 for (String key : PROXY_PROPERTY_KEYS) {
454 environment.add(new SystemPropertySaveEnvironmentFacet(key, getLog()));
455 }
456
457 // Setup the environment.
458 environment.setup();
459
460 // Compile the XJC arguments
461 final String[] xjcArguments = getXjcArguments(environment.getClassPathAsArgument(), episodeFileName);
462
463 // Ensure that the outputDirectory exists, but only clear it if does not already
464 FileSystemUtilities.createDirectory(getOutputDirectory(), clearOutputDir);
465
466 // Do we need to re-create the episode file's parent directory.
467 final boolean reCreateEpisodeFileParentDirectory = generateEpisode && clearOutputDir;
468 if (reCreateEpisodeFileParentDirectory) {
469 getEpisodeFile(episodeFileName);
470 }
471
472 // Check the system properties.
473 logSystemPropertiesAndBasedir();
474
475 // Fire XJC
476 if (XJC_COMPLETED_OK != Driver.run(xjcArguments, new XjcLogAdapter(getLog()))) {
477
478 final StringBuilder errorMsgBuilder = new StringBuilder();
479 errorMsgBuilder.append("\n+=================== [XJC Error]\n");
480 errorMsgBuilder.append("|\n");
481
482 final List<URL> sourceXSDs = getSources();
483 for (int i = 0; i < sourceXSDs.size(); i++) {
484 errorMsgBuilder.append("| " + i + ": ").append(sourceXSDs.get(i).toString()).append("\n");
485 }
486
487 errorMsgBuilder.append("|\n");
488 errorMsgBuilder.append("+=================== [End XJC Error]\n");
489 throw new MojoExecutionException(errorMsgBuilder.toString());
490 }
491
492 // Indicate that the output directory was updated.
493 getBuildContext().refresh(getOutputDirectory());
494
495 // Update the modification timestamp of the staleFile.
496 updateStaleFileTimestamp = true;
497
498 } finally {
499
500 if (environment != null) {
501 environment.restore();
502 }
503 }
504
505 // Add the generated source root to the project, enabling tooling and other plugins to see them.
506 addGeneratedSourcesToProjectSourceRoot();
507
508 // Copy all source XSDs to the resulting artifact?
509 if (xsdPathWithinArtifact != null) {
510
511 final String buildOutputDirectory = getProject().getBuild().getOutputDirectory();
512 final File targetXsdDirectory = new File(buildOutputDirectory, xsdPathWithinArtifact);
513 FileUtils.forceMkdir(targetXsdDirectory);
514
515 for (URL current : getSources()) {
516
517 String fileName = null;
518 if ("file".equalsIgnoreCase(current.getProtocol())) {
519 fileName = new File(current.getPath()).getName();
520 } else if ("jar".equalsIgnoreCase(current.getProtocol())) {
521
522 // Typical JAR path
523 // jar:file:/path/to/aJar.jar!/some/path/xsd/aResource.xsd
524 final int bangIndex = current.toString().indexOf("!");
525 if (bangIndex == -1) {
526 throw new MojoExecutionException("Illegal JAR URL [" + current.toString()
527 + "]: lacks a '!'");
528 }
529
530 final String internalPath = current.toString().substring(bangIndex + 1);
531 fileName = new File(internalPath).getName();
532 } else {
533 throw new MojoExecutionException("Could not extract FileName from URL [" + current + "]");
534 }
535
536 final File targetFile = new File(targetXsdDirectory, fileName);
537 if (targetFile.exists()) {
538
539 // TODO: Should we throw an exception here instead?
540 getLog().warn("File [" + FileSystemUtilities.getCanonicalPath(targetFile)
541 + "] already exists. Not copying XSD file [" + current.getPath() + "] to it.");
542 }
543 IOUtil.copy(current.openStream(), new FileWriter(targetFile));
544 }
545
546 // Refresh the BuildContext
547 getBuildContext().refresh(targetXsdDirectory);
548 }
549 } catch (MojoExecutionException e) {
550 throw e;
551 } catch (NoSchemasException e) {
552 if (failOnNoSchemas) {
553 throw new MojoExecutionException("", e);
554 }
555 } catch (Exception e) {
556 throw new MojoExecutionException(e.getMessage(), e);
557 }
558
559 // All done.
560 return updateStaleFileTimestamp;
561 }
562
563 /**
564 * Override this method to acquire a List holding all URLs to the JAXB sources for which this
565 * AbstractJavaGeneratorMojo should generate Java files. Sources are assumed to be in the form given by
566 * the {@code sourceType} value.
567 *
568 * @return A non-null List holding URLs to sources for the XJC generation.
569 * @see #sourceType
570 */
571 @Override
572 protected abstract List<URL> getSources();
573
574 /**
575 * Override this method to retrieve a list of Files to all XJB files for which this
576 * AbstractJavaGeneratorMojo should generate Java files.
577 *
578 * @return A non-null List holding binding files.
579 */
580 protected abstract List<File> getSourceXJBs();
581
582 /**
583 * Adds any directories containing the generated XJC classes to the appropriate Project compilation sources;
584 * either {@code TestCompileSourceRoot} or {@code CompileSourceRoot} depending on the exact Mojo implementation
585 * of this AbstractJavaGeneratorMojo.
586 */
587 protected abstract void addGeneratedSourcesToProjectSourceRoot();
588
589 //
590 // Private helpers
591 //
592
593 private String[] getXjcArguments(final String classPath, final String episodeFileNameOrNull)
594 throws MojoExecutionException, NoSchemasException {
595
596 final ArgumentBuilder builder = new ArgumentBuilder();
597
598 // Add all flags on the form '-flagName'
599 builder.withFlag(true, sourceType.getXjcArgument());
600 builder.withFlag(noPackageLevelAnnotations, "npa");
601 builder.withFlag(laxSchemaValidation, "nv");
602 builder.withFlag(verbose, "verbose");
603 builder.withFlag(quiet, "quiet");
604 builder.withFlag(enableIntrospection, "enableIntrospection");
605 builder.withFlag(extension, "extension");
606 builder.withFlag(readOnly, "readOnly");
607 builder.withFlag(noGeneratedHeaderComments, "no-header");
608 builder.withFlag(addGeneratedAnnotation, "mark-generated");
609
610 // Add all arguments on the form '-argumentName argumentValue'
611 // (i.e. in 2 separate elements of the returned String[])
612 builder.withNamedArgument("httpproxy", getProxyString(settings.getActiveProxy()));
613 builder.withNamedArgument("encoding", getEncoding(true));
614 builder.withNamedArgument("p", packageName);
615 builder.withNamedArgument("target", target);
616 builder.withNamedArgument("d", getOutputDirectory().getAbsolutePath());
617 builder.withNamedArgument("classpath", classPath);
618
619 // We must add the -extension flag in order to generate the episode file.
620 if (!extension) {
621
622 if (getLog().isInfoEnabled()) {
623 getLog().info("Adding 'extension' flag to XJC arguments, to generate an episode "
624 + "file named '" + (episodeFileName == null ? STANDARD_EPISODE_FILENAME : episodeFileName)
625 + "'. (XJCs 'episode' argument requires that the 'extension' argument is provided).");
626 }
627 }
628 builder.withFlag(true, "extension");
629
630 final File episodeFile = getEpisodeFile(episodeFileNameOrNull);
631 builder.withNamedArgument("episode", FileSystemUtilities.getCanonicalPath(episodeFile));
632
633 if (catalog != null) {
634 builder.withNamedArgument("catalog", FileSystemUtilities.getCanonicalPath(catalog));
635 }
636
637 if (arguments != null) {
638 builder.withPreCompiledArguments(arguments);
639 }
640
641 for (File current : getSourceXJBs()) {
642
643 // Shorten the argument?
644 // final String strippedXjbPath = FileSystemUtilities.relativize(
645 // current.getAbsolutePath(), getProject().getBasedir());
646
647 // Each XJB must be given as a separate argument.
648 builder.withPreCompiledArguments(Arrays.asList("-b", current.getAbsolutePath()));
649 }
650
651 final List<URL> sourceXSDs = getSources();
652 if (sourceXSDs.isEmpty()) {
653
654 // If we have no XSDs, we are not going to be able to run XJC.
655 getLog().warn("No XSD files found. Please check your plugin configuration.");
656 throw new NoSchemasException();
657
658 } else {
659
660 final List<String> unwrappedSourceXSDs = new ArrayList<String>();
661 for (URL current : sourceXSDs) {
662
663 // Shorten the argument if possible.
664 if ("file".equalsIgnoreCase(current.getProtocol())) {
665 try {
666 unwrappedSourceXSDs.add(new File(current.toURI()).getPath());
667 } catch (final URISyntaxException e) {
668 throw new MojoExecutionException(e.getMessage(), e);
669 }
670 } else {
671 unwrappedSourceXSDs.add(current.toString());
672 }
673 }
674
675 builder.withPreCompiledArguments(unwrappedSourceXSDs);
676 }
677
678 // All done.
679 return logAndReturnToolArguments(builder.build(), "XJC");
680 }
681
682 private String getProxyString(final Proxy activeProxy) {
683
684 // Check sanity
685 if (activeProxy == null) {
686 return null;
687 }
688
689 // The XJC proxy argument should be on the form
690 // [user[:password]@]proxyHost[:proxyPort]
691 //
692 // builder.withNamedArgument("httpproxy", httpproxy);
693 //
694 final StringBuilder proxyBuilder = new StringBuilder();
695 if (activeProxy.getUsername() != null) {
696
697 // Start with the username.
698 proxyBuilder.append(activeProxy.getUsername());
699
700 // Append the password if provided.
701 if (activeProxy.getPassword() != null) {
702 proxyBuilder.append(":").append(activeProxy.getPassword());
703 }
704
705 proxyBuilder.append("@");
706 }
707
708 // Append hostname and port.
709 proxyBuilder.append(activeProxy.getHost()).append(":").append(activeProxy.getPort());
710
711 // All done.
712 return proxyBuilder.toString();
713 }
714 }