Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
AbstractJavaGeneratorMojo |
|
| 7.0;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ö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 | * <configuration> | |
200 | * ... | |
201 | * <arguments> | |
202 | * <argument>-Xfluent-api</argument> | |
203 | * <argument>somefile</argument> | |
204 | * </arguments> | |
205 | * </configuration> | |
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 | * <configuration> | |
259 | * ... | |
260 | * <xsdPathWithinArtifact>META-INF/jaxb/xsd</xsdPathWithinArtifact> | |
261 | * </configuration> | |
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 | } |