/**
* Licensed to the Austrian Association for Software Tool Integration (AASTI)
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. The AASTI 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.openengsb.loom.csharp.comon.wsdltodll;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.openengsb.loom.csharp.comon.wsdltodll.csfilehandling.FileComparer;
/**
* Goal which creates a DLL from a WSDL file.
*
* @goal run
* @phase process-sources
*/
public class WsdlToDll extends AbstractMojo {
private static final String LINUX_WSDL_SERVER_PARAMETER = "-server";
private static final String LINUX_WSDL_COMMAND = "wsdl2";
private static final String LINUX_CSC_COMMAND = "mcs";
private static final String WINDWOS_WSDL_SERVER_PARAMETER = "/serverInterface";
private static final String WINDOWS_WSDL_COMMAND = "wsdl.exe";
private static final String WINDOWS_CSC_COMMAND = "csc.exe";
private static final String NUGET_COMMAND = "nuget";
private String cscCommand;
private String wsdlCommand;
private String serverParameter;
private Boolean windowsModus;
/**
* Owner of the Nuget package
*
* @parameter
* @required default-Value="OpenEngSB"
*/
private String owner;
/**
* Author of the nuget package.
*
* @parameter
* @required default-Value="OpenEngSB
*/
private String author = "OpenEngSB";
/**
* The Url of the project
*
* @parameter
* @optional default-Value=null
*/
private String projectUrl;
/**
* Url to the license
*
* @parameter
* @optional Default-Value=null
*/
private String licenseUrl;
/**
* Url to the icon
*
* @parameter
* @optional Default-Value=null
*/
private String iconUrl;
/**
* Location of the file.
*
* @parameter
* @required Default-Value=false
*/
private boolean requireLicenseAcceptance;
/**
* Location of the file.
*
* @parameter
* @required Default-Value=""
*/
private String releaseNotes;
/**
* Location of the file.
*
* @parameter
* @required Default-Value=OpenEngSB 2012
*/
private String copyright;
/**
* List of default pathes where to search for the installation of the .net framework.
*/
private static final String[] DEFAULT_WSDL_PATHS = new String[]{
System.getenv("ProgramFiles(x86)") + "\\Microsoft SDKs\\Windows\\",
System.getenv("ProgramFiles") + "\\Microsoft SDKs\\Windows\\" };
private static final String[] DEFAULT_CSC_PATHS = new String[]{
System.getenv("windir") + "\\Microsoft.NET\\Framework64\\",
System.getenv("windir") + "\\Microsoft.NET\\Framework\\" };
/**
* Location of the file.
*
* @parameter default-Value=null
* @required
*/
private File outputDirectory;
/**
* Location of the wsdl.exe command
*
* @parameter default-Value=null
*/
private File wsdlExeFolderLocation;
/**
* Location of the csc command.
*
* @parameter default-Value=null
*/
private File cscFolderLocation;
/**
* Nuget folder
*
* @parameter default-Value=null
*/
private String nugetFolder;
/**
* Create the Nuget Packages
*
* @parameter default-Value=false
*/
private boolean generateNugetPackage;
/**
* Location of the wsdl file
*
* @parameter
* @required
*/
private List<String> wsdlLocations;
/**
* Namespace of the WSDL file. This should be the namespace in which a domain should be located.
*
* @parameter
* @required
*/
private String namespace;
/**
* Version that should be written to the resulting DLL
*
* @parameter
* @required
*/
private String targetVersion;
private String nugetLib;
private List<String> cspath = new ArrayList<String>();
/**
* Find and executes the commands wsdl.exe and csc.exe
*/
@Override
public void execute() throws MojoExecutionException {
checkParameters();
windowsModus = isWindows();
if (windowsModus) {
setWindowsVariables();
} else {
setLinuxVariables();
}
createDllFromWsdl();
}
private void checkParameters() throws MojoExecutionException {
if (generateNugetPackage && nugetFolder == null) {
throw new MojoExecutionException(
"The nugetFolder has to be defined when nuget packaging is enabled");
}
}
private void setWindowsVariables() {
cscCommand = WINDOWS_CSC_COMMAND;
wsdlCommand = WINDOWS_WSDL_COMMAND;
serverParameter = WINDWOS_WSDL_SERVER_PARAMETER;
}
private void setLinuxVariables() {
cscCommand = LINUX_CSC_COMMAND;
wsdlCommand = LINUX_WSDL_COMMAND;
serverParameter = LINUX_WSDL_SERVER_PARAMETER;
}
private boolean isWindows() {
String os = System.getProperty("os.name");
if (!outputDirectory.exists()) {
outputDirectory.mkdirs();
}
getLog().info("Operation system:" + os);
return os.toUpperCase().contains("WINDOWS");
}
/**
* Windows mode for maven execution
*
* @throws MojoExecutionException
*/
private void createDllFromWsdl() throws MojoExecutionException {
getLog().info("Execute WSDl to cs command");
wsdlCommand();
getLog().info("Execute cs to dll command");
cscCommand();
if (generateNugetPackage) {
if (isLinux()) {
throw new MojoExecutionException(
"At this point, mono and nuget does not work so well together."
+ "Please execute the plugin with nuget under Windows");
}
nugetLib = nugetFolder + "lib";
getLog().info("Create Nuget folder structure");
createNugetStructure();
getLog().info("Copy the dlls to the nuget structure");
copyFilesToNuget();
getLog().info("Generate " + namespace + " .nuspec");
generateNugetPackedFile();
getLog().info("Pack .nuspec to a nuget package");
nugetPackCommand();
}
}
private String findWsdlCommand() throws MojoExecutionException {
if (isLinux()) {
if (isMonoCommandInstalled(wsdlCommand)) {
return wsdlCommand;
}
throw new MojoExecutionException("The program '" + wsdlCommand
+ "' is currently not installed. You can install it by typing: "
+ "sudo apt-get install mono-devel");
}
if (wsdlExeFolderLocation != null) {
return wsdlExeFolderLocation.getAbsolutePath();
}
for (File sdk : findAllInstalledSDKs(DEFAULT_WSDL_PATHS)) {
File bindir = new File(sdk, "bin");
File wsdlFile = new File(bindir, wsdlCommand);
if (wsdlFile.exists()) {
wsdlExeFolderLocation = wsdlFile;
return wsdlFile.getAbsolutePath();
}
}
throw new MojoExecutionException("unable to find " + wsdlCommand
+ " in paths " + Arrays.toString(DEFAULT_WSDL_PATHS) + "\n "
+ "You can specify the path manually by adding the argument \n"
+ " -DwsdlExeFolderLocation=\"C:\\path\\to\\wsdl.exe\"");
}
private boolean isMonoCommandInstalled(String command) {
List<String> commandList = new LinkedList<String>();
commandList.add(command);
return isMonoCommandInstalled(commandList);
}
private boolean isMonoCommandInstalled(List<String> command) {
ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true);
builder.command(command);
try {
executeACommand(builder.start());
} catch (MojoExecutionException | IOException | InterruptedException e) {
return false;
}
return true;
}
private String findCscCommand() throws MojoExecutionException {
if (isLinux()) {
List<String> commands = new LinkedList<String>();
commands.add(cscCommand);
commands.add("/help");
if (isMonoCommandInstalled(commands)) {
return cscCommand;
}
throw new MojoExecutionException("The program '" + cscCommand
+ "' is currently not installed. You can install it by typing: "
+ "sudo apt-get install mono-" + cscCommand);
}
if (cscFolderLocation != null) {
return cscFolderLocation.getAbsolutePath();
}
for (File sdk : findAllInstalledSDKs(DEFAULT_CSC_PATHS)) {
File file = new File(sdk, cscCommand);
getLog().info(
"Trying to find " + cscCommand + " in "
+ sdk.getAbsolutePath());
if (file.exists()) {
cscFolderLocation = file.getAbsoluteFile();
return file.getAbsolutePath();
}
}
throw new MojoExecutionException("unable to find " + cscCommand
+ " in paths " + Arrays.toString(DEFAULT_CSC_PATHS) + "\n "
+ "You can specify the path manually by adding the argument \n"
+ " -DcscFolderLocation=\"C:\\path\\to\\csc.exe\"");
}
private boolean isLinux() {
return !windowsModus;
}
private Collection<File> findAllInstalledSDKs(String[] paths) {
Collection<File> result = new LinkedList<File>();
for (String s : paths) {
File[] findAllInstalledSDKs = findInstalledSDKs(s);
result.addAll(Arrays.asList(findAllInstalledSDKs));
}
return result;
}
private File[] findInstalledSDKs(String path) {
File file = new File(path);
if (!file.exists()) {
return new File[0];
}
File[] installedSDKs = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
Arrays.sort(installedSDKs, new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
return o2.getName().compareTo(o1.getName());
}
});
return installedSDKs;
}
/**
* Search for the wsdl command and execute it when it is found
*/
private void wsdlCommand() throws MojoExecutionException {
String cmd = findWsdlCommand();
int i = 0;
for (String location : wsdlLocations) {
String outputFilename = new File(outputDirectory, namespace + (i++)
+ ".cs").getAbsolutePath();
String[] command = new String[]{ cmd, serverParameter,
"/n:" + namespace, location, "/out:" + outputFilename };
ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true);
builder.command(command);
try {
executeACommand(builder.start());
} catch (IOException | InterruptedException e) {
throw new MojoExecutionException(
"Error, while executing command: "
+ Arrays.toString(command) + "\n", e);
}
cspath.add(outputFilename);
}
try {
FileComparer.removeSimilaritiesAndSaveFiles(cspath, getLog(),
windowsModus);
} catch (IOException e) {
throw new MojoExecutionException(
"It was not possible, to remove similarities form the files",
e);
}
}
/**
* Search for the csc command and execute it when it is found
*/
private void cscCommand() throws MojoExecutionException {
generateAssemblyInfo();
String cscPath = findCscCommand();
List<String> commandList = new LinkedList<String>(cspath);
commandList.add(0, cscPath);
commandList.add(1, "/target:library");
commandList.add(2, "/out:" + namespace + ".dll");
if (isLinux()) {
commandList.add(3, "/reference:System.Web.Services");
}
String[] command = commandList.toArray(new String[commandList.size()]);
ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true);
builder.directory(outputDirectory);
builder.command(command);
try {
executeACommand(builder.start());
} catch (InterruptedException | IOException e) {
throw new MojoExecutionException("Error, while executing command: "
+ Arrays.toString(command) + "\n", e);
}
}
/**
* Generate the nuget structe (for example a lib folder)
*/
private void createNugetStructure() {
(new File(nugetLib)).mkdirs();
}
private void copyFilesToNuget() throws MojoExecutionException {
File folder = outputDirectory;
for (File file : folder.listFiles()) {
if (file.getAbsoluteFile().toPath().toString().endsWith(".dll")) {
try {
getLog().info(
"COPY FILE"
+ (new File(nugetLib)).getAbsoluteFile()
.toPath());
Files.copy(file.getAbsoluteFile().toPath(), (new File(
nugetLib + "/" + file.getName()))
.getAbsoluteFile().toPath(), REPLACE_EXISTING);
} catch (IOException ex) {
throw new MojoExecutionException(ex.getMessage());
}
}
}
}
/**
* Execute nuget command to pack the .nuspec
*/
private void nugetPackCommand() throws MojoExecutionException {
List<String> commandList = new LinkedList<String>();
commandList.add(0, NUGET_COMMAND);
commandList.add(1, "pack");
String[] command = commandList.toArray(new String[commandList.size()]);
ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true);
builder.directory(new File(nugetFolder));
builder.command(command);
try {
executeACommand(builder.start());
} catch (InterruptedException | IOException e) {
throw new MojoExecutionException("Error, while executing command: "
+ Arrays.toString(command) + "\n", e);
}
}
private void generateAssemblyInfo() throws MojoExecutionException {
StringBuilder assemblyInfoBuilder = new StringBuilder();
assemblyInfoBuilder.append("using System.Reflection;\n");
assemblyInfoBuilder.append("[assembly: AssemblyTitle(\"")
.append(namespace).append("\")]\n");
assemblyInfoBuilder.append("[assembly: AssemblyProduct(\"")
.append(namespace).append("\")]\n");
assemblyInfoBuilder.append("[assembly: AssemblyCompany(\"")
.append(owner).append("\")]\n");
assemblyInfoBuilder.append("[assembly: AssemblyDescription(\"")
.append(namespace + "_domain_dll").append("\")]\n");
assemblyInfoBuilder.append("[assembly: AssemblyCopyright(\"")
.append("Copyright @ " + owner).append("\")]\n");
String truncatedVersion = targetVersion.replaceAll("-.*", "");
assemblyInfoBuilder.append("[assembly: AssemblyVersion(\"")
.append(truncatedVersion).append("\")]\n");
assemblyInfoBuilder.append("[assembly: AssemblyFileVersion(\"")
.append(truncatedVersion).append("\")]\n");
assemblyInfoBuilder
.append("[assembly: AssemblyInformationalVersion(\"")
.append(targetVersion).append("\")]\n");
File assemblyInfo = new File(outputDirectory, "AssemblyInfo.cs");
FileWriter writer = null;
try {
writer = new FileWriter(assemblyInfo);
writer.write(assemblyInfoBuilder.toString());
} catch (IOException e) {
throw new MojoExecutionException(
"unable to write generated AssemblyInfo.cs", e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
// ignore that
}
}
}
cspath.add(assemblyInfo.getAbsolutePath());
}
private void generateNugetPackedFile() throws MojoExecutionException {
StringBuilder assemblyInfoBuilder = new StringBuilder();
assemblyInfoBuilder.append("<?xml version=\"1.0\"?>\n");
assemblyInfoBuilder.append("<package >\n");
assemblyInfoBuilder.append(" <metadata>\n");
assemblyInfoBuilder.append(" <id>" + namespace + "</id>\n");
assemblyInfoBuilder.append(" <version>" + targetVersion
+ "</version>\n");
assemblyInfoBuilder.append(" <authors>" + author + "</authors>\n");
assemblyInfoBuilder.append(" <owners>" + owner + "</owners>\n");
if (licenseUrl != null) {
assemblyInfoBuilder.append(" <licenseUrl>" + licenseUrl
+ "</licenseUrl>\n");
}
if (projectUrl != null) {
assemblyInfoBuilder.append(" <projectUrl>" + projectUrl
+ "</projectUrl>\n");
}
if (iconUrl != null) {
assemblyInfoBuilder.append(" <iconUrl>" + iconUrl
+ "</iconUrl>\n");
}
assemblyInfoBuilder.append(" <requireLicenseAcceptance>"
+ requireLicenseAcceptance + "</requireLicenseAcceptance>\n");
assemblyInfoBuilder.append(" <description>" + namespace + " dll"
+ "</description>\n");
assemblyInfoBuilder.append(" <releaseNotes>" + releaseNotes
+ "</releaseNotes>\n");
assemblyInfoBuilder.append(" <copyright>" + copyright
+ "</copyright>\n");
assemblyInfoBuilder.append(" </metadata>\n");
assemblyInfoBuilder.append("</package >\n");
File assemblyInfo = new File(nugetFolder, namespace + ".nuspec");
FileWriter writer = null;
try {
writer = new FileWriter(assemblyInfo);
writer.write(assemblyInfoBuilder.toString());
} catch (IOException e) {
throw new MojoExecutionException(
"unable to write generated Nugetpacketfile.cs", e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
// ignore that
}
}
}
cspath.add(assemblyInfo.getAbsolutePath());
}
private void executeACommand(Process child) throws IOException,
MojoExecutionException, InterruptedException {
BufferedReader brout = new BufferedReader(new InputStreamReader(
child.getInputStream()));
String error = "";
String tmpLine;
String input = "";
String last = "";
boolean isAWarningLines = false;
while ((tmpLine = brout.readLine()) != null) {
if (isNotALineToFilter(tmpLine)) {
if (isAWarningLines) {
if (isNotAMonoWsdlWarningLine(tmpLine)) {
isAWarningLines = false;
} else {
continue;
}
}
input += tmpLine + "\n";
} else {
isAWarningLines = isLinux();
}
last = tmpLine;
}
getLog().info("Waiting until process is finished");
child.waitFor();
if (child.exitValue() > 0) {
throw new MojoExecutionException(input);
}
// Because the wsdl.exe can not be executed in a outputDirectory, the
// file has to be moved to the corresponding
// folder
if (last.contains("'") && last.contains(".cs")) {
String filepath = last.split("'")[1];
File file = new File(filepath);
boolean moved = file.renameTo(new File(outputDirectory, file
.getName()));
if (!moved) {
throw new MojoExecutionException("Unable to move file: "
+ file.getAbsolutePath());
}
input += "Moving file " + file.getName() + " to " + cspath + "\n";
getLog().info(input);
}
if (child.waitFor() != 0) {
throw new MojoExecutionException(error);
}
}
/**
* Checks if the output string from the command prompt is a line that can be ignored or not
*
* @param line
* @return
*/
private boolean isNotAMonoWsdlWarningLine(String line) {
return !line.startsWith(" ") && !line.equals("");
}
/**
* Checks if the line is not a line to filter
*
* @param line
* @return
*/
private boolean isNotALineToFilter(String line) {
return !(line.startsWith("Schema validation error:")
|| line.startsWith("Warning:") || line.contains("warnings"));
}
}