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