org.apache.cxf.maven_plugin.Java2WSMojo Maven / Gradle / Ivy
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.maven_plugin;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.commons.lang3.SystemUtils;
import org.apache.cxf.helpers.FileUtils;
import org.apache.cxf.helpers.JavaUtils;
import org.apache.cxf.tools.common.CommandInterfaceUtils;
import org.apache.cxf.tools.java2ws.JavaToWS;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
/**
* @goal java2ws
* @description CXF Java To Webservice Tool
* @requiresDependencyResolution test
* @threadSafe
*/
public class Java2WSMojo extends AbstractMojo {
/**
* @parameter
* @required
*/
private String className;
/**
* @parameter expression="${project.build.outputDirectory}"
* @required
*/
private String classpath;
/**
* @parameter
*/
private String outputFile;
/**
* @parameter
*/
private Boolean soap12;
/**
* @parameter
*/
private String targetNamespace;
/**
* @parameter
*/
private String serviceName;
/**
* @parameter
*/
private Boolean verbose;
/**
* @parameter
*/
private Boolean quiet;
/**
* @parameter
*/
private String address;
/**
* @parameter
*/
private String classifier;
/**
* @parameter expression="${project.compileClasspathElements}"
* @required
*/
private List> classpathElements;
/**
* @parameter expression="${project}"
* @required
*/
private MavenProject project;
/**
* Maven ProjectHelper.
*
* @component
* @readonly
*/
private MavenProjectHelper projectHelper;
/**
* @parameter
*/
private String argline;
/**
* @parameter
*/
private String frontend;
/**
* @parameter
*/
private String databinding;
/**
* @parameter default-value="false"
*/
private Boolean genWsdl;
/**
* @parameter default-value="false"
*/
private Boolean genServer;
/**
* @parameter default-value="false"
*/
private Boolean genClient;
/**
* @parameter default-value="false"
*/
private Boolean genWrapperbean;
/**
* @parameter
*/
private String portName;
/**
* Attach the generated wsdl file to the list of files to be deployed
* on install. This means the wsdl file will be copied to the repository
* with groupId, artifactId and version of the project and type "wsdl".
*
* With this option you can use the maven repository as a Service Repository.
*
* @parameter default-value="true"
*/
private Boolean attachWsdl;
/**
* The plugin dependencies, needed for the fork mode.
*
* @parameter expression="${plugin.artifacts}"
* @required
* @readonly
*/
private List pluginArtifacts;
/**
* Specifies whether the JavaToWs execution should be skipped.
*
* @parameter default-value="false"
* @since 2.4
*/
private Boolean skip;
/**
* Allows running the JavaToWs in a separate process.
*
* @parameter default-value="false"
* @since 2.4
*/
private Boolean fork;
/**
* Sets the Java executable to use when fork parameter is true
.
*
* @parameter default-value="${java.home}/bin/java"
* @since 2.4
*/
private String javaExecutable;
/**
* Sets the JVM arguments (i.e. -Xms128m -Xmx128m
) if fork is set to true
.
*
* @parameter
* @since 2.4
*/
private String additionalJvmArgs;
/**
* Determines how the classpath is applied to the executed command,
* either as a command line argument, or as an environment variable
* for the executing process. Only applicable when fork is set to true
* (which is always the case for JDK 9+).
*
* Primarily useful on Windows because of length limitations for command arguments,
* which is why the default is true
in that case.
*
* @parameter default-value="false"
* @since 3.3
*/
private Boolean classpathAsEnvVar;
/**
* Disable garbage collection at the end of the execution.
*
* @parameter expression="${cxf.skipGarbageCollection}" default-value="false"
* @since 3.3.1
*/
private boolean skipGarbageCollection;
public void execute() throws MojoExecutionException {
boolean requiresModules = JavaUtils.isJava9Compatible();
if (requiresModules) {
// Since JEP 261 ("Jigsaw"), access to some packages must be granted
fork = true;
boolean skipXmlWsModule = JavaUtils.isJava11Compatible(); //
additionalJvmArgs = "--add-exports=jdk.xml.dom/org.w3c.dom.html=ALL-UNNAMED "
+ "--add-exports=java.xml/com.sun.org.apache.xerces.internal.impl.xs=ALL-UNNAMED "
+ (skipXmlWsModule ? "" : "--add-opens java.xml.ws/javax.xml.ws.wsaddressing=ALL-UNNAMED ")
+ "--add-opens java.base/java.security=ALL-UNNAMED "
+ "--add-opens java.base/java.net=ALL-UNNAMED "
+ "--add-opens java.base/java.lang=ALL-UNNAMED "
+ "--add-opens java.base/java.util=ALL-UNNAMED "
+ "--add-opens java.base/java.util.concurrent=ALL-UNNAMED "
+ (additionalJvmArgs == null ? "" : additionalJvmArgs);
}
if (fork && SystemUtils.IS_OS_WINDOWS) {
// Windows does not allow for very long command lines,
// so by default CLASSPATH environment variable is used.
classpathAsEnvVar = true;
}
System.setProperty("org.apache.cxf.JDKBugHacks.defaultUsesCaches", "true");
if (skip) {
getLog().info("Skipping Java2WS execution");
return;
}
ClassLoaderSwitcher classLoaderSwitcher = new ClassLoaderSwitcher(getLog());
try {
String cp = classLoaderSwitcher.switchClassLoader(project, false,
classpath, classpathElements);
if (fork) {
List artifactsPath = new ArrayList<>(pluginArtifacts.size());
for (Artifact a : pluginArtifacts) {
File file = a.getFile();
if (file == null) {
throw new MojoExecutionException("Unable to find file for artifact "
+ a.getGroupId() + ":" + a.getArtifactId()
+ ":" + a.getVersion());
}
artifactsPath.add(file.getPath());
}
cp = StringUtils.join(artifactsPath.iterator(), File.pathSeparator) + File.pathSeparator + cp;
}
List args = initArgs(classpathAsEnvVar ? null : cp);
processJavaClass(args, classpathAsEnvVar ? cp : null);
} finally {
classLoaderSwitcher.restoreClassLoader();
}
if (!skipGarbageCollection) {
System.gc();
}
}
private List initArgs(String cp) {
List args = new ArrayList<>();
if (fork) {
if (!StringUtils.isEmpty(additionalJvmArgs)) {
String[] split = additionalJvmArgs.split("\\s+");
args.addAll(Arrays.asList(split));
}
// @see JavaToWS#isExitOnFinish()
args.add("-DexitOnFinish=true");
}
if (!StringUtils.isEmpty(cp)) {
// classpath arg
args.add("-cp");
args.add(cp);
}
if (fork) {
args.add(JavaToWS.class.getCanonicalName());
}
// outputfile arg
if (outputFile == null && project != null) {
// Put the wsdl in target/generated/wsdl
int i = className.lastIndexOf('.');
// Prone to OoBE, but then it's wrong anyway
String name = className.substring(i + 1);
outputFile = (project.getBuild().getDirectory() + "/generated/wsdl/" + name + ".wsdl")
.replace("/", File.separator);
}
if (outputFile != null) {
// JavaToWSDL freaks out if the directory of the outputfile doesn't exist, so lets
// create it since there's no easy way for the user to create it beforehand in maven
FileUtils.mkDir(new File(outputFile).getParentFile());
args.add("-o");
args.add(outputFile);
/*
Contributor's comment:
Sometimes JavaToWSDL creates Java code for the wrappers. I don't *think* this is
needed by the end user.
*/
// Commiter's comment:
// Yes, it's required, it's defined in the JAXWS spec.
if (project != null) {
project.addCompileSourceRoot(new File(outputFile).getParentFile().getAbsolutePath());
}
}
if (!StringUtils.isEmpty(frontend)) {
args.add("-frontend");
args.add(frontend);
}
if (!StringUtils.isEmpty(databinding)) {
args.add("-databinding");
args.add(databinding);
}
if (genWrapperbean) {
args.add("-wrapperbean");
}
if (genWsdl) {
args.add("-wsdl");
}
if (genServer) {
args.add("-server");
}
if (genClient) {
args.add("-client");
}
// soap12 arg
if (soap12 != null && soap12.booleanValue()) {
args.add("-soap12");
}
// target namespace arg
if (!StringUtils.isEmpty(targetNamespace)) {
args.add("-t");
args.add(targetNamespace);
}
// servicename arg
if (!StringUtils.isEmpty(serviceName)) {
args.add("-servicename");
args.add(serviceName);
}
// verbose arg
if (verbose != null && verbose.booleanValue()) {
args.add("-verbose");
}
// quiet arg
if (quiet != null && quiet.booleanValue()) {
args.add("-quiet");
}
// address arg
if (!StringUtils.isEmpty(address)) {
args.add("-address");
args.add(address);
}
// portname arg
if (!StringUtils.isEmpty(portName)) {
args.add("-portname");
args.add(portName);
}
if (argline != null) {
StringTokenizer stoken = new StringTokenizer(argline, " ");
while (stoken.hasMoreTokens()) {
args.add(stoken.nextToken());
}
}
// classname arg
args.add(className);
return args;
}
private void processJavaClass(List args, String cp) throws MojoExecutionException {
if (!fork) {
try {
CommandInterfaceUtils.commandCommonMain();
JavaToWS j2w = new JavaToWS(args.toArray(new String[0]));
j2w.run();
} catch (OutOfMemoryError e) {
getLog().debug(e);
StringBuilder msg = new StringBuilder(128);
msg.append(e.getMessage()).append('\n');
msg.append("Try to run this goal using the true and "
+ "-Xms128m -Xmx128m parameters.");
throw new MojoExecutionException(msg.toString(), e);
} catch (Throwable e) {
getLog().debug(e);
throw new MojoExecutionException(e.getMessage(), e);
}
} else {
getLog().info("Running java2ws in fork mode...");
Commandline cmd = new Commandline();
cmd.getShell().setQuotedArgumentsEnabled(true); // for JVM args
cmd.setWorkingDirectory(project.getBuild().getDirectory());
try {
cmd.setExecutable(getJavaExecutable().getAbsolutePath());
} catch (IOException e) {
getLog().debug(e);
throw new MojoExecutionException(e.getMessage(), e);
}
cmd.addArguments(args.toArray(new String[0]));
if (classpathAsEnvVar && !StringUtils.isEmpty(cp)) {
cmd.addEnvironment("CLASSPATH", cp);
}
CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
String cmdLine = CommandLineUtils.toString(cmd.getCommandline());
int exitCode;
try {
exitCode = CommandLineUtils.executeCommandLine(cmd, out, err);
} catch (CommandLineException e) {
getLog().debug(e);
StringBuilder msg = new StringBuilder(e.getMessage());
if (!(fork && classpathAsEnvVar)) {
msg.append('\n');
msg.append("Try to run this goal using true and "
+ "true .");
}
msg.append('\n');
msg.append("Command line was: ").append(cmdLine).append('\n');
if (classpathAsEnvVar && !StringUtils.isEmpty(cp)) {
msg.append(" CLASSPATH env: ").append(cp).append('\n');
}
msg.append('\n');
throw new MojoExecutionException(msg.toString(), e);
}
String output = StringUtils.isEmpty(out.getOutput()) ? null : '\n' + out.getOutput().trim();
if (exitCode != 0) {
if (StringUtils.isNotEmpty(output)) {
getLog().info(output);
}
StringBuilder msg = new StringBuilder("\nExit code: ");
msg.append(exitCode);
if (StringUtils.isNotEmpty(err.getOutput())) {
msg.append(" - ").append(err.getOutput());
}
msg.append('\n');
msg.append("Command line was: ").append(cmdLine).append('\n');
if (classpathAsEnvVar && !StringUtils.isEmpty(cp)) {
msg.append(" CLASSPATH env: ").append(cp).append('\n');
}
msg.append('\n');
throw new MojoExecutionException(msg.toString());
}
if (StringUtils.isNotEmpty(err.getOutput()) && err.getOutput().contains("JavaToWS Error")) {
StringBuilder msg = new StringBuilder();
msg.append(err.getOutput());
msg.append('\n');
msg.append("Command line was: ").append(cmdLine).append('\n');
if (classpathAsEnvVar && !StringUtils.isEmpty(cp)) {
msg.append(" CLASSPATH env: ").append(cp).append('\n');
}
msg.append('\n');
throw new MojoExecutionException(msg.toString());
}
}
// Attach the generated wsdl file to the artifacts that get deployed
// with the enclosing project
if (attachWsdl && outputFile != null) {
File wsdlFile = new File(outputFile);
if (wsdlFile.exists()) {
boolean hasWsdlAttached = false;
for (Artifact a : project.getAttachedArtifacts()) {
if ("wsdl".equals(a.getType()) && classifier != null && classifier.equals(a.getClassifier())) {
hasWsdlAttached = true;
}
}
if (!hasWsdlAttached) {
if (classifier != null) {
projectHelper.attachArtifact(project, wsdlFile.getName(), classifier, wsdlFile);
} else {
projectHelper.attachArtifact(project, wsdlFile.getName(), wsdlFile);
}
}
}
}
}
private File getJavaExecutable() throws IOException {
String exe = (SystemUtils.IS_OS_WINDOWS && !javaExecutable.endsWith(".exe")) ? ".exe" : "";
File javaExe = new File(javaExecutable + exe);
if (!javaExe.isFile()) {
throw new IOException("The java executable '" + javaExe
+ "' doesn't exist or is not a file. Verify the parameter.");
}
return javaExe;
}
}