com.excelsiorjet.api.tasks.JetProject Maven / Gradle / Ivy
/*
* Copyright (c) 2016-2017, Excelsior LLC.
*
* This file is part of Excelsior JET API.
*
* Excelsior JET API is free software:
* you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Excelsior JET API is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Excelsior JET API.
* If not, see .
*
*/
package com.excelsiorjet.api.tasks;
import com.excelsiorjet.api.ExcelsiorJet;
import com.excelsiorjet.api.JetHomeException;
import com.excelsiorjet.api.log.Log;
import com.excelsiorjet.api.platform.Host;
import com.excelsiorjet.api.tasks.config.*;
import com.excelsiorjet.api.tasks.config.compiler.*;
import com.excelsiorjet.api.tasks.config.dependencies.DependencySettings;
import com.excelsiorjet.api.tasks.config.dependencies.OptimizationPreset;
import com.excelsiorjet.api.tasks.config.dependencies.ProjectDependency;
import com.excelsiorjet.api.tasks.config.excelsiorinstaller.ExcelsiorInstallerConfig;
import com.excelsiorjet.api.tasks.config.packagefile.PackageFile;
import com.excelsiorjet.api.tasks.config.runtime.RuntimeConfig;
import com.excelsiorjet.api.tasks.config.windowsservice.WindowsServiceConfig;
import com.excelsiorjet.api.util.Txt;
import com.excelsiorjet.api.util.Utils;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.Attributes.Name;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import static com.excelsiorjet.api.log.Log.logger;
import static com.excelsiorjet.api.tasks.config.PackagingType.*;
import static com.excelsiorjet.api.util.Txt.s;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
/**
* Collection of Excelsior JET compiler and packager parameters that can be configured by an external build tool,
* such as Maven or Gradle. More precisely, it is assumed that a plugin into that build tool configures these parameters,
* so there is a section specific to that plugin in a bigger project, such as {@code pom.xml} or {@code build.gradle},
* mentioned below as the enclosing project.
*
* An instance of this class can be constructed with the build pattern methods and used by Excelsior JET tasks
* such as {@link JetBuildTask}, {@link TestRunTask}.
*
* The class performs validation of the parameters via the {@link #validate(ExcelsiorJet, boolean)} method.
* During validation, it sets default parameter values derived from other parameters,
* so it is not necessary to set all the parameters.
* That said, some parameters are required. For instance, {@link #mainClass} is required for plain Java SE applications.
*
* @see JetBuildTask
* @see TestRunTask
*/
public class JetProject {
private static final String JET_OUTPUT_DIR = "jet";
private static final String BUILD_DIR = "build";
private static final String PACKAGE_FILES_DIR = "packagefiles";
private static final String APP_DIR = "app";
private static final String SPRING_BOOT_JAR_MAIN_CLASS = "org.springframework.boot.loader.JarLauncher";
private static final String SPRING_BOOT_WAR_MAIN_CLASS = "org.springframework.boot.loader.WarLauncher";
private static final String SPRING_BOOT_VERSION_ATTR = "Spring-Boot-Version";
private static final String SPRING_BOOT_START_CLASS_ATTR = "Start-Class";
/**
* Name and version of the plugin that created this project.
*/
private String creatorPlugin;
/**
* Name of the project. For Maven, project artifactId is used as project name by default.
*/
private String projectName;
/**
* Project group id. Unique identifier that can be shared by multiple projects.
* Usually reverse domain name is used for group id such as "com.example".
*/
private String groupId;
/**
* Project version. Required for Excelsior Installer.
* Note: To specify a different (more precise) version number for the Windows executable version-information resource,
* use the {@link WindowsVersionInfoConfig#version} parameter.
*/
private String version;
/**
* Application type. Currently, Plain Java SE Applications, Invocation Dynamic Libraries, Windows Services,
* Tomcat and Spring Boot Applications are supported.
*
* @see ApplicationType#PLAIN
* @see ApplicationType#DYNAMIC_LIBRARY
* @see ApplicationType#WINDOWS_SERVICE
* @see ApplicationType#TOMCAT
* @see ApplicationType#SPRING_BOOT
*/
private ApplicationType appType;
/**
* Build (target) directory of the enclosing project where Java sources are built into class files
* and a project artifact. It is assumed that main artifact (jar or war) is placed
* to this directory before Excelsior JET build.
*/
private File targetDir;
/**
* Directory that contains Excelsior JET specific resource files such as application icons, installer splash, etc.
* It is recommended to place the directory in the source root directory,
* and plugins by default sets the directory to "jetresources" subfolder of the source root directory.
*/
private File jetResourcesDir;
/**
* Directory for temporary files generated during the build process
* and the target directory for the resulting package.
* The default is the "jet" subdirectory of {@link #targetDir}.
*/
private File jetOutputDir;
/**
* Excelsior JET project build directory.
*
* The value is set to "build" subdirectory of {@link #jetOutputDir}.
*/
private File jetBuildDir;
/**
* Target directory where the plugin places the executable, the required Excelsior JET Runtime files and
* package files you configured with {@link #packageFiles} and {@link #packageFilesDir}.
*
* The value is set to "app" subdirectory of {@link #jetOutputDir}.
*/
private File jetAppDir;
/**
* Directory containing additional package files - README, license, media, help files, native libraries, and the like.
* The contents of the directory will be recursively copied to the final application package.
*
* By default, the value is set to "packageFiles" subfolder of {@link #jetResourcesDir}
*
* @see #packageFiles
*/
private File packageFilesDir;
/**
* If you only need to add a few additional package files,
* it may be more convenient to specify them separately rather than prepare a {@link #packageFilesDir} directory.
*/
private List packageFiles;
/**
* Name of the final artifact of the enclosing project. Used as the default value for {@link #mainJar} and {@link #mainWar},
* and to derive the default names of final artifacts created by {@link JetBuildTask} such as zip file, installer, and so on.
*/
private String artifactName;
/**
* The main application jar for plain Java SE and Spring Boot applications.
* By default, {@link #artifactName}.jar is used.
*
* @see ApplicationType#PLAIN
*/
private File mainJar;
/**
* The main application class for plain Java SE applications.
*
* @see ApplicationType#PLAIN
*/
private String mainClass;
/**
* The main web application archive for Tomcat and Spring Boot applications.
* By default, {@link #artifactName}.war is used.
*
* @see ApplicationType#TOMCAT
*/
private File mainWar;
/**
* Tomcat web applications specific parameters.
*
* @see ApplicationType#TOMCAT
* @see TomcatConfig#tomcatHome
* @see TomcatConfig#warDeployName
* @see TomcatConfig#hideConfig
* @see TomcatConfig#genScripts
*/
private TomcatConfig tomcatConfiguration;
/**
* Execution profiles configuration parameters.
* You can configure the filesystem location and base name of all application execution profiles,
* whether they can be collected locally, i.e. on the machine where the build takes place,
* and the maximum profile age when they are considered outdated.
*
* @see ExecProfilesConfig#outputDir
* @see ExecProfilesConfig#outputName
* @see ExecProfilesConfig#profileLocally
* @see ExecProfilesConfig#daysToWarnAboutOutdatedProfiles
* @see ExecProfilesConfig#checkExistence
* @see ExecProfilesConfig#testRunTimeout
* @see ExecProfilesConfig#profileRunTimeout
*/
private ExecProfilesConfig execProfilesConfiguration;
/**
* Defines system properties and JVM arguments to be passed to the Excelsior JET JVM at runtime, e.g.:
* {@code -Dmy.prop1 -Dmy.prop2=value -ea -Xmx1G -Xss128M -Djet.gc.ratio=11}.
*
* Please note that only some of the non-standard Oracle HotSpot JVM arguments
* (those prefixed with {@code -X}) are recognized.
* For instance, the {@code -Xms} argument setting the initial Java heap size on HotSpot
* has no meaning for the Excelsior JET JVM, which has a completely different
* memory management policy. At the same time, Excelsior JET provides its own system properties
* for GC tuning, such as {@code -Djet.gc.ratio}.
*
*/
private String[] jvmArgs;
/**
* Application packaging mode. Permitted values are:
*
* - zip
* - zip archive with a self-contained application package (default)
* - tar-gz
* - tar.gz archive with a self-contained application package
* - excelsior-installer
* - self-extracting installer with standard GUI for Windows
* and command-line interface for Linux
* - osx-app-bundle
* - OS X application bundle
* - native-bundle
* - Excelsior Installer setups for Windows and Linux, application bundle for OS X
* - none
* - skip packaging altogether
*
*/
private String excelsiorJetPackaging;
/**
* Application vendor name. Required for Windows version-information resource and Excelsior Installer.
*/
private String vendor;
/**
* Product name. Required for Windows version-information resource and Excelsior Installer.
*/
private String product;
/**
* The inception year of this project.
*
* Used to construct the default value of {@link WindowsVersionInfoConfig#copyright}.
*/
private String inceptionYear;
/**
* (Windows) If set to {@code true}, a version-information resource will be added to the final executable.
*
* @see WindowsVersionInfoConfig#company
* @see WindowsVersionInfoConfig#product
* @see WindowsVersionInfoConfig#version
* @see WindowsVersionInfoConfig#copyright
* @see WindowsVersionInfoConfig#description
*/
private Boolean addWindowsVersionInfo;
/**
* Windows version-information resource description.
*/
private WindowsVersionInfoConfig windowsVersionInfoConfiguration;
/**
* Optimization presets define the default optimization mode for application dependencies.
* There are two optimization presets available: {@code typical} and {@code smart}.
*
*
* - {@code typical} (default)
* -
* Compile all classes from all dependencies to optimized native code.
*
* - {@code smart}
* -
* Use heuristics to determine which of the project dependencies are libraries and
* compile them selectively, leaving the supposedly unused classes in bytecode form.
*
*
*
* For details, refer to the Excelsior JET User's Guide, Chapter "JET Control Panel",
* section "Step 3: Selecing a compilation mode / Classpath Grid / Selective Optimization".
*
*
* Note: Unlike the identically named preset of the JET Control Panal,
* selecting the {@code smart} preset does NOT automatically enable the Global Optimizer.
*
*
* @see #dependencies
* @see DependencySettings
* @see #globalOptimizer
*/
private String optimizationPreset;
/**
* If set to {@code true}, the Global Optimizer is enabled,
* providing higher performance and lower memory usage for the compiled application.
*
*
* The Global Optimizer detects the Java Platform API classes that your application actually uses,
* and compiles them together with your application classes into a single executable.
* The remaining classes are kept in the bytecode form. For details, refer to the Chapter
* "Global Optimizer" in the Excelsior JET User's Guide.
*
*
* Note: Performing a Test Run is mandatory when the Global Optimizer is enabled.
* The Global Optimizer is enabled automatically when you enable Java Runtime Slim-Down.
*
* @see TestRunTask
* @see RuntimeConfig#slimDown
*/
private boolean globalOptimizer;
/**
* List of managed (i.e. Maven or Gradle) dependencies specified by the user of an API client.
*/
private List projectDependencies;
/**
* List of {@code projectDependencies} settings and not managed dependencies specified by the user of an API client.
*/
private List dependencies;
/**
* Internal representation of project dependencies calculated from {@code projectDependencies} and {@code dependencies}
*/
private List classpathEntries;
/**
* Runtime configuration parameters.
*
* @see RuntimeConfig#flavor
* @see RuntimeConfig#profile
* @see RuntimeConfig#components
* @see RuntimeConfig#locales
* @see RuntimeConfig#diskFootprintReduction
* @see RuntimeConfig#location
*/
private RuntimeConfig runtimeConfiguration;
/**
* Trial version configuration parameters.
*
* @see TrialVersionConfig#expireInDays
* @see TrialVersionConfig#expireDate
* @see TrialVersionConfig#expireMessage
*/
private TrialVersionConfig trialVersion;
/**
* Excelsior Installer configuration parameters.
*
* @see ExcelsiorInstallerConfig#eula
* @see ExcelsiorInstallerConfig#eulaEncoding
* @see ExcelsiorInstallerConfig#installerSplash
*/
private ExcelsiorInstallerConfig excelsiorInstallerConfiguration;
/**
* Windows Service configuration parameters.
*
* @see WindowsServiceConfig#name
* @see WindowsServiceConfig#displayName
* @see WindowsServiceConfig#description
* @see WindowsServiceConfig#arguments
* @see WindowsServiceConfig#logOnType
* @see WindowsServiceConfig#allowDesktopInteraction
* @see WindowsServiceConfig#startupType
* @see WindowsServiceConfig#startServiceAfterInstall
* @see WindowsServiceConfig#dependencies
*/
private WindowsServiceConfig windowsServiceConfiguration;
/**
* OS X Application Bundle configuration parameters.
*
* @see OSXAppBundleConfig#fileName
* @see OSXAppBundleConfig#bundleName
* @see OSXAppBundleConfig#identifier
* @see OSXAppBundleConfig#shortVersion
* @see OSXAppBundleConfig#icon
* @see OSXAppBundleConfig#developerId
* @see OSXAppBundleConfig#publisherId
*/
private OSXAppBundleConfig osxBundleConfiguration;
/**
* Target executable name. If not set, the main class name is used.
*/
private String outputName;
/**
* If set to {@code true}, the multi-app mode is enabled for the resulting executable
* (it mimicks the command line syntax of the conventional {@code java} launcher).
*/
private boolean multiApp;
/**
* Enable/disable startup accelerator.
* If enabled, the compiled application will run after build
* for {@link #profileStartupTimeout} seconds for collecting a startup profile.
*/
private boolean profileStartup;
/**
* The duration of the after-build profiling session in seconds. Upon exhaustion,
* the application will be automatically terminated.
*/
private int profileStartupTimeout;
/**
* If set to {@code true}, enables protection of application data - reflection information,
* string literals, and resource files packed into the executable, if any.
*
* @see #cryptSeed
*/
private boolean protectData;
/**
* Sets a seed string that will be used by the Excelsior JET compiler to generate a key for
* scrambling the data that the executable contains.
* If data protection is enabled, but {@code cryptSeed} is not set explicitly, a random value is used.
*
* You may want to set a {@code cryptSeed} value if you need the data to be protected in a stable way.
*
*
* @see #protectData
*/
private String cryptSeed;
/**
* (Windows) .ico file to associate with the resulting executable file.
*
* By default "icon.ico" of {@link #jetResourcesDir} folder is used.
*/
private File icon;
/**
* Splash image to display upon application start up.
*
* By default, the file "splash.png" from the {@link #jetResourcesDir} folder is used.
* If it does not exist, but a splash image is specified in the manifest
* of the application JAR file, that image will be used automatically.
*/
private File splash;
/**
* The JET Runtime supports three modes of stack trace printing: {@code minimal}, {@code full}, and {@code none}.
*
* In the {@code minimal} mode (default), line numbers and names of some methods are omitted in call stack entries,
* but the class names are exact.
*
*
* In the {@code full} mode, the stack trace info includes all line numbers and method names.
* However, enabling the full stack trace has a side effect - substantial growth of the resulting
* executable size, approximately by 30%.
*
*
* In the {@code none} mode, Throwable.printStackTrace() methods print a few fake elements.
* It may result in performance improvement if the application throws and catches exceptions repeatedly.
* Note, however, that some third-party APIs may rely on stack trace printing. One example
* is the Log4J API that provides logging services.
*
*/
private String stackTraceSupport;
/**
* Controls the aggressiveness of method inlining.
* Available values are:
* {@code aggressive} (default), {@code very-aggressive}, {@code medium}, {@code low}, {@code tiny-methods-only}.
*
* If you need to reduce the size of the executable,
* set the {@code low} or {@code tiny-methods-only} option. Note that it does not necessarily worsen application performance.
*
*/
private String inlineExpansion;
/**
* Allocate on the stack the Java objects that do not escape the scope
* of the allocating method. By default, the parameter is set to {@code true}.
*
* This optimization may increase the consumption of stack memory
* by application threads, so you may wish to disable it if your application runs
* thousands of threads simultaneously.
*/
private boolean stackAllocation;
/**
* (Windows) If set to {@code true}, the resulting executable file will not have a console upon startup.
*/
private boolean hideConsole;
/**
* Additional compiler options and equations.
* The commonly used compiler options and equations are mapped to the respective project parameters,
* so usually there is no need to specify them with this parameter.
* However, the compiler also has some advanced options and equations
* that you may find in the Excelsior JET User's Guide, plus some troubleshooting settings
* that the Excelsior JET Support team may suggest to you.
* You may enumerate such options and equations with this parameter and they will be appended to the
* Excelsior JET project generated by {@link JetBuildTask}.
*
* Care must be taken when using this parameter to avoid conflicts with other project parameters.
*
*/
private String[] compilerOptions;
/**
* Command line arguments passed to the application during a Test Run, startup profiling,
* execution profiling and normal run.
* You may also set the parameter via the {@code jet.runArgs} system property, where arguments
* are comma separated (use "\" to escape commas inside arguments,
* i.e. {@code -Djet.runArgs="arg1,Hello\, World"} will be passed to your application as
* {@code arg1 "Hello, World"}).
*/
private String[] runArgs;
/**
* Command-line parameters for multi-app executables. If set, overrides the {@link #runArgs} parameter.
* ]
* If you set {@link #multiApp} to {@code true}, the resulting executable expects its command line
* arguments to be in the respective format:
*
* {@code [VM-options] main-class [arguments]} or
* {@code [VM-options] -args [arguments]} (use default main class)
*
*
* So if you need to alter the main class and/or VM properties during startup profiling,
* execution profiling, or normal run, set this parameter.
*
*
* You may also set the parameter via the {@code jet.multiAppRunArgs} system property, where arguments
* are comma separated (use "\" to escape commas inside arguments,
* i.e. {@code -Djet.multiAppRunArgs="-args,arg1,Hello\, World"} will be passed to your application
* as {@code -args arg1 "Hello, World"})
*
*/
private String[] multiAppRunArgs;
/**
* Project Database placement configuration.
*
* @see PDBConfig
*/
private PDBConfig pdbConfiguration;
/**
* Termination policy for {@link StopTask}. Permitted values are:
*
* - ctrl-c
* - Send Ctrl-C event to a running application
* - halt
* - call java.lang.Shutdown.halt() (System.exit()) within a running application
*
*
* Applications may perform some shutdown actions upon termination (e.g. close a database).
* Some applications do not terminate well on System.exit() call such as Tomcat and Spring Boot applications.
* So by default, we use Ctrl-C termination policy for such applications to terminate properly.
*/
private String terminationPolicy;
/**
* Sets a build tool specific logger and build tool specific messages overriding common ones
* that should be shown to a user.
*/
public static void configureEnvironment(Log log, ResourceBundle messages) {
Log.logger = log;
Txt.log = log;
Txt.setAdditionalMessages(messages);
}
/**
* Constructor with required parameters of the project.
* Usually they can be derived from the enclosing project(pom.xml, build.gradle).
*
* @param creatorPlugin name and version of the plugin that creates this project.
* @param projectName project name
* @param groupId project groupId
* @param version project version
* @param appType application type
* @param targetDir target directory of the enclosing project
* @param jetResourcesDir directory with jet specific resources
*/
public JetProject(String creatorPlugin, String projectName, String groupId, String version, ApplicationType appType, File targetDir, File jetResourcesDir) {
this.creatorPlugin = requireNonNull(creatorPlugin, "plugin cannot be null");
this.projectName = requireNonNull(projectName, "projectName cannot be null");
this.groupId = requireNonNull(groupId, "groupId cannot be null");
this.version = requireNonNull(version, "version cannot be null");
this.appType = requireNonNull(appType, "appType cannot be null");
this.targetDir = requireNonNull(targetDir, "targetDir cannot be null");
this.jetResourcesDir = requireNonNull(jetResourcesDir, "jetResourcesDir cannot be null");
}
///////////////// Validation ////////////////
/**
* Validates project parameters and sets the default values derived from other parameters.
* @param validateForBuild if set to {@code false} the method does not validate parameters that are used only for project build
*/
public void validate(ExcelsiorJet excelsiorJet, boolean validateForBuild) throws JetTaskFailureException {
if ((Log.logger == null) || (Txt.log == null)) {
throw new IllegalStateException("Please call JetProject.configureEnvironment() before using JetProject");
}
if (artifactName == null) {
artifactName = projectName;
}
if ((mainWar != null) && (mainJar != null)) {
throw new JetTaskFailureException(s("JetApi.BothMainJarAndWarSet.Failure"));
}
switch (appType) {
case WINDOWS_SERVICE:
if (!excelsiorJet.isWindowsServicesSupported()) {
throw new JetTaskFailureException(s("JetApi.WinServiceNotSupported.Failure"));
}
checkMainJar();
break;
case SPRING_BOOT:
if (!excelsiorJet.isSpringBootSupported()) {
throw new JetTaskFailureException(s("JetApi.SpringBootNotSupported.Failure"));
}
if (!checkSpringBootArtifact()) {
throw new JetTaskFailureException(s("JetApi.SpringBoot.ArchiveIsNotSpringBootArchive.Failure", mainJar.getAbsolutePath()));
}
break;
case PLAIN:
case DYNAMIC_LIBRARY:
checkMainJar();
break;
case TOMCAT:
if (!excelsiorJet.isTomcatSupported()) {
throw new JetTaskFailureException(s("JetApi.TomcatNotSupported.Failure"));
}
checkMainWar();
tomcatConfiguration.fillDefaults(mainWar.getName());
break;
default:
throw new AssertionError("Unknown application type");
}
// check main class
switch (appType) {
case PLAIN:
case WINDOWS_SERVICE:
if (Utils.isEmpty(mainClass)) {
throw new JetTaskFailureException(s("JetApi.MainNotSpecified.Failure"));
} else {
//normalize main
mainClass = mainClass.replace('.', '/');
}
if ((appType == ApplicationType.PLAIN) &&
mainClass.equals(SPRING_BOOT_JAR_MAIN_CLASS.replace('.', '/')) &&
checkSpringBootArtifact(mainJar, true, false)) {
if (!excelsiorJet.isSpringBootSupported()) {
throw new JetTaskFailureException(s("JetApi.SpringBootNotSupported.Failure"));
}
appType = ApplicationType.SPRING_BOOT;
}
break;
case DYNAMIC_LIBRARY:
//no need to check main here
break;
case TOMCAT:
mainClass = "org/apache/catalina/startup/Bootstrap";
break;
case SPRING_BOOT:
String springBootMainClass = isMainArtifactJar() ? SPRING_BOOT_JAR_MAIN_CLASS : SPRING_BOOT_WAR_MAIN_CLASS;
mainClass = springBootMainClass.replace('.', '/');
break;
default:
throw new AssertionError("Unknown application type");
}
if (jetOutputDir == null) {
jetOutputDir = new File(targetDir, JET_OUTPUT_DIR);
}
if (jetBuildDir == null) {
jetBuildDir = new File(jetOutputDir, BUILD_DIR);
}
if (jetAppDir == null) {
jetAppDir = new File(jetOutputDir, APP_DIR);
}
packageFilesDir = checkFileWithDefault(packageFilesDir, PACKAGE_FILES_DIR, "packageFilesDir");
if (excelsiorJetPackaging == null) {
excelsiorJetPackaging = ZIP.toString();
}
//check packaging type
switch (PackagingType.validate(excelsiorJetPackaging)) {
case ZIP:
case NONE:
break;
case TAR_GZ:
if (excelsiorJet.isCrossCompilation() && Host.isWindows()) {
// Cannot pack to tar.gz on Windows for Linux target
// because we do not know what files should have executable Unix mode
// in the resulting tar.gz archive.
// Should be supported in xpack.
throw new JetTaskFailureException(s("JetApi.TarGZOnWindowsHostLinuxTarget.NotSupported"));
}
break;
case EXCELSIOR_INSTALLER:
if (!excelsiorJet.isExcelsiorInstallerSupported()) {
logger.warn(s("JetApi.NoExcelsiorInstaller.Warning"));
excelsiorJetPackaging = ZIP.toString();
}
break;
case OSX_APP_BUNDLE:
if (!excelsiorJet.getTargetOS().isOSX()) {
logger.warn(s("JetApi.OSXBundleOnNotOSX.Warning"));
excelsiorJetPackaging = ZIP.toString();
}
break;
case NATIVE_BUNDLE:
if (excelsiorJet.getTargetOS().isOSX()) {
excelsiorJetPackaging = OSX_APP_BUNDLE.toString();
} else if (excelsiorJet.isExcelsiorInstallerSupported()){
excelsiorJetPackaging = EXCELSIOR_INSTALLER.toString();
} else {
excelsiorJetPackaging = ZIP.toString();
}
break;
default:
throw new AssertionError("Unknown packaging type: " + excelsiorJetPackaging);
}
if ((appType == ApplicationType.WINDOWS_SERVICE) && (excelsiorJetPackaging() == EXCELSIOR_INSTALLER) &&
!excelsiorJet.isWindowsServicesInExcelsiorInstallerSupported()) {
throw new JetTaskFailureException(s("JetApi.WinServiceInEINotSupported.Failure"));
}
execProfilesConfiguration.fillDefaults(this, excelsiorJet);
// Override run args from system property
String runArgs = System.getProperty("jet.runArgs");
if (runArgs != null) {
this.runArgs = Utils.parseRunArgs(runArgs);
}
if ((packageFilesDir() != null) && appType == ApplicationType.TOMCAT) {
throw new JetTaskFailureException(s("JetApi.PackageFilesForTomcat.Error", "packageFilesDir"));
}
if (packageFiles.size() > 0) {
if (appType == ApplicationType.TOMCAT) {
throw new JetTaskFailureException(s("JetApi.PackageFilesForTomcat.Error", "packageFiles"));
}
for (PackageFile pFile: packageFiles) {
if (pFile.path == null) {
throw new JetTaskFailureException(s("JetApi.PathNotSetForPackageFile.Error"));
}
pFile.validate("JetApi.PackageFileDoesNotExist.Error");
}
}
if (terminationPolicy == null) {
terminationPolicy = TerminationPolicy.CTRL_C.toString();
} else {
TerminationPolicy.validate(terminationPolicy);
}
if (validateForBuild) {
validateForBuild(excelsiorJet);
}
processDependencies();
}
private void checkMainJar() throws JetTaskFailureException {
if (mainJar == null) {
mainJar = new File(targetDir, artifactName + ".jar");
}
if (!mainJar.exists()) {
throw new JetTaskFailureException(s("JetApi.MainJarNotFound.Failure", mainJar.getAbsolutePath()));
}
}
private void checkMainWar() throws JetTaskFailureException {
if (mainWar == null) {
mainWar = new File(targetDir, artifactName + ".war");
}
if (!mainWar.exists()) {
throw new JetTaskFailureException(s("JetApi.MainWarNotFound.Failure", mainWar.getAbsolutePath()));
}
if (!mainWar.getName().endsWith(TomcatConfig.WAR_EXT)) {
throw new JetTaskFailureException(s("JetApi.MainWarShouldEndWithWar.Failure", mainWar.getAbsolutePath()));
}
}
void processDependencies() throws JetTaskFailureException {
if (optimizationPreset == null) {
optimizationPreset = OptimizationPreset.TYPICAL.toString();
} else {
OptimizationPreset.validate(optimizationPreset);
}
for (DependencySettings dependency : dependencies) {
if (dependency.path == null && dependency.groupId == null && dependency.artifactId == null) {
throw new JetTaskFailureException(s("JetApi.DependencyIdRequired"));
} else if (dependency.path != null && (dependency.groupId != null || dependency.artifactId != null || dependency.version != null)) {
throw new JetTaskFailureException(s("JetApi.InvalidDependencySetting", dependency.idStr()));
} else if (dependency.path != null && dependency.path.isDirectory()) {
if (dependency.pack != null && !ClasspathEntry.PackType.NONE.userValue.equals(dependency.pack)) {
throw new JetTaskFailureException(s("JetApi.NotPackedDirectory", dependency.path));
}
}
if (dependency.packagePath != null && dependency.disableCopyToPackage != null && dependency.disableCopyToPackage) {
throw new JetTaskFailureException(s("JetApi.DependencySettingsCannotHavePackagePathAndDisabledCopyToPackage", dependency.idStr()));
}
}
// allProjectDependencies = project dependencies + main artifact
List allProjectDependencies = new ArrayList<>(projectDependencies);
ProjectDependency mainArtifactDep = new ProjectDependency(groupId, projectName, version, mainArtifact(), true);
// in original implementation main artifact is preceded other dependencies
allProjectDependencies.add(0, mainArtifactDep);
List dependenciesSettings = new ArrayList<>();
List externalDependencies = new ArrayList<>();
Set ids = new HashSet<>();
for (DependencySettings dependencySettings : dependencies) {
List matchedDependencies = dependenciesMatchedBy(allProjectDependencies, dependencySettings);
if (matchedDependencies.size() == 0){
if (dependencySettings.hasPathOnly()) {
externalDependencies.add(dependencySettings);
} else {
throw new JetTaskFailureException(s("JetApi.NoDependenciesForDependencySettings", dependencySettings.idStr()));
}
} else {
dependenciesSettings.add(dependencySettings);
}
if (dependencySettings.isArtifactOnly() && matchedDependencies.size() > 1) {
List dependencyIds = matchedDependencies.stream().
map(d -> d.idStr(false)).
collect(toList());
throw new JetTaskFailureException(s("JetApi.AmbiguousArtifactIdOnlyDependencySettings", dependencySettings.idStr(), String.join(", ", dependencyIds)));
}
if (ids.contains(dependencySettings.idStr())) {
throw new JetTaskFailureException(s("JetApi.DuplicateDependencySettingsId", dependencySettings.idStr()));
}
ids.add(dependencySettings.idStr());
}
for (DependencySettings externalDependency : externalDependencies) {
if (appType == ApplicationType.TOMCAT) {
throw new JetTaskFailureException(s("JetApi.ApplicationCannotHaveExternalDependencies", externalDependency.path, "Tomcat web"));
} else if (appType == ApplicationType.SPRING_BOOT) {
throw new JetTaskFailureException(s("JetApi.ApplicationCannotHaveExternalDependencies", externalDependency.path, "Spring Boot"));
}
if (!externalDependency.path.exists()) {
throw new JetTaskFailureException(s("JetApi.ExternalDependencyDoesNotExist", externalDependency.path));
}
}
DependencySettingsResolver dependencySettingsResolver = new DependencySettingsResolver(optimizationPreset(), groupId, dependenciesSettings);
classpathEntries = new ArrayList<>();
switch (appType()) {
case PLAIN:
case DYNAMIC_LIBRARY:
case WINDOWS_SERVICE:
{
// Values of the seenDeps HashMap can either be of type ProjectDependevcy or DependencySettings.
// DependencySettings are put there while processing external dependencies.
HashMap seenDeps = new HashMap<>();
for (ProjectDependency prjDep : allProjectDependencies) {
ClasspathEntry cpEntry = dependencySettingsResolver.resolve(prjDep);
String packagePath = toPathRelativeToJetBuildDir(cpEntry).toString();
ProjectDependency oldDep = (ProjectDependency) seenDeps.put(packagePath, prjDep);
if (oldDep != null) {
throw new JetTaskFailureException(s("JetApi.OverlappedDependency", prjDep, oldDep));
} else {
classpathEntries.add(cpEntry);
}
}
for (DependencySettings extDep : externalDependencies) {
ClasspathEntry cpEntry = new ClasspathEntry(extDep, false);
Object oldDep = seenDeps.put(toPathRelativeToJetBuildDir(cpEntry).toString(), extDep);
if (oldDep != null) {
throw new JetTaskFailureException(s("JetApi.OverlappedExternalDependency", extDep.path, oldDep));
}
classpathEntries.add(cpEntry);
}
}
break;
case TOMCAT:
case SPRING_BOOT:
HashMap seenDeps = new HashMap<>();
for (ProjectDependency prjDep : allProjectDependencies) {
if (!prjDep.isMainArtifact || dependencySettingsResolver.hasSettingsFor(prjDep)) {
ClasspathEntry cpEntry = dependencySettingsResolver.resolve(prjDep);
ProjectDependency oldDep = null;
if (!prjDep.isMainArtifact) {
String depName = cpEntry.path.getName();
oldDep = seenDeps.put(depName, prjDep);
}
if (oldDep != null) {
throw new JetTaskFailureException(s("JetApi.OverlappedTomcatOrSpringBootDependency",
prjDep, oldDep, isMainArtifactJar() ? "jar": "war"));
} else {
classpathEntries.add(cpEntry);
}
}
}
break;
default:
throw new AssertionError("Unknown application type: " + appType());
}
}
private List dependenciesMatchedBy(List projectDependencies, DependencySettings dependencySetting) {
return projectDependencies.stream().
filter(dependencySetting::matches).
collect(toList());
}
private void validateForBuild(ExcelsiorJet excelsiorJet) throws JetTaskFailureException {
icon = checkFileWithDefault(icon, "icon.ico", "icon");
splash = checkFileWithDefault(splash, "splash.png", "splash");
if (outputName == null) {
if ((appType() == ApplicationType.DYNAMIC_LIBRARY) && excelsiorJet.getTargetOS().isUnix()) {
//add lib prefix to output name
outputName = "lib" + projectName;
} else {
outputName = projectName;
}
}
if (stackTraceSupport == null) {
stackTraceSupport = StackTraceSupportType.MINIMAL.toString();
} else {
StackTraceSupportType.validate(stackTraceSupport);
}
if (inlineExpansion == null) {
inlineExpansion = InlineExpansionType.AGGRESSIVE.toString();
} else {
InlineExpansionType.validate(inlineExpansion);
}
// check version info
try {
checkVersionInfo(excelsiorJet);
if (multiApp && !excelsiorJet.isMultiAppSupported()) {
throw new JetTaskFailureException(s("JetApi.NoMultiappInStandard.Failure"));
}
// Override multiApp run args from system property
String multiAppRunArgs = System.getProperty("jet.multiAppRunArgs");
if (multiAppRunArgs != null) {
this.multiAppRunArgs = Utils.parseRunArgs(multiAppRunArgs);
}
if (multiApp || appType() == ApplicationType.TOMCAT) { //tomcat is always multiApp
if (Utils.isEmpty(this.multiAppRunArgs) && !Utils.isEmpty(this.runArgs)) {
this.multiAppRunArgs = Utils.prepend("-args", this.runArgs);
}
} else if (!Utils.isEmpty(this.multiAppRunArgs)) {
throw new JetTaskFailureException(s("JetApi.MultiAppRunArgsNotForMultiApp.Failure"));
}
if (profileStartup) {
if (!excelsiorJet.isStartupAcceleratorSupported()) {
// startup accelerator is enabled by default,
// so if it is not supported, no warn about it.
profileStartup = false;
}
}
runtimeConfiguration.fillDefaults(this, excelsiorJet);
checkTrialVersionConfig(excelsiorJet);
checkGlobal(excelsiorJet);
checkExcelsiorInstallerConfig(excelsiorJet);
checkWindowsServiceConfig();
checkOSXBundleConfig();
pdbConfiguration.fillDefaults(this, excelsiorJet);
checkProtectData(excelsiorJet);
} catch (JetHomeException e) {
throw new JetTaskFailureException(e.getMessage());
}
}
public File checkFileWithDefault(File file, String defaultFileName, String notExistParam) throws JetTaskFailureException {
return Utils.checkFileWithDefault(file, new File(jetResourcesDir, defaultFileName),
"JetApi.FileDoesNotExist.Error", notExistParam);
}
private void checkVersionInfo(ExcelsiorJet excelsiorJet) throws JetHomeException, JetTaskFailureException {
if (addWindowsVersionInfo == null) {
addWindowsVersionInfo = !windowsVersionInfoConfiguration.isEmpty();
}
if (!addWindowsVersionInfo && !windowsVersionInfoConfiguration.isEmpty()) {
throw new JetTaskFailureException(s("JetApi.AddWindowsVersionInfo.Failure"));
}
if (!excelsiorJet.getTargetOS().isWindows()) {
addWindowsVersionInfo = false;
}
if (addWindowsVersionInfo && !excelsiorJet.isWindowsVersionInfoSupported()) {
logger.warn(s("JetApi.NoVersionInfoInStandard.Warning"));
addWindowsVersionInfo = false;
}
if (addWindowsVersionInfo || excelsiorJetPackaging().isNativeBundle()) {
if (Utils.isEmpty(vendor)) {
//No organization name. Get it from groupId.
if (Utils.isEmpty(groupId)) {
if (addWindowsVersionInfo) {
throw new JetTaskFailureException(s("JetApi.VendorIsNotSetForVersionInfo"));
} else {
throw new JetTaskFailureException(s("JetApi.VendorIsNotSetForPackaging", excelsiorJetPackaging().toString()));
}
}
String[] groupId = groupId().split("\\.");
if (groupId.length >= 2) {
vendor = groupId[1];
} else {
vendor = groupId[0];
}
vendor = Character.toUpperCase(vendor.charAt(0)) + vendor.substring(1);
}
if (Utils.isEmpty(product)) {
// no project name, get it from artifactId.
product = projectName;
}
}
if (addWindowsVersionInfo) {
windowsVersionInfoConfiguration.fillDefaults(this);
}
}
ExecProfilesConfig execProfiles() {
return execProfilesConfiguration;
}
private void checkGlobal(ExcelsiorJet excelsiorJet) throws JetHomeException, JetTaskFailureException {
if (globalOptimizer) {
if (!excelsiorJet.isGlobalOptimizerSupported()) {
logger.warn(s("JetApi.NoGlobal.Warning"));
globalOptimizer = false;
}
}
if (globalOptimizer) {
ExecProfilesConfig execProfiles = execProfiles();
if (!execProfiles.getUsg().exists()) {
throw new JetTaskFailureException(s("JetApi.NoTestRun.Failure"));
}
}
}
private void checkTrialVersionConfig(ExcelsiorJet excelsiorJet) throws JetTaskFailureException, JetHomeException {
if ((trialVersion != null) && trialVersion.isDefined()) {
if ((trialVersion.expireInDays >= 0) && (trialVersion.expireDate != null)) {
throw new JetTaskFailureException(s("JetApi.AmbiguousExpireSetting.Failure"));
}
if (trialVersion.expireMessage == null || trialVersion.expireMessage.isEmpty()) {
throw new JetTaskFailureException(s("JetApi.NoExpireMessage.Failure"));
}
if (!excelsiorJet.isTrialSupported()) {
logger.warn(s("JetApi.NoTrialsInStandard.Warning"));
trialVersion = null;
}
} else {
trialVersion = null;
}
}
private void checkExcelsiorInstallerConfig(ExcelsiorJet excelsiorJet) throws JetTaskFailureException {
if (excelsiorJetPackaging() == EXCELSIOR_INSTALLER) {
excelsiorInstallerConfiguration.fillDefaults(this, excelsiorJet);
}
}
private void checkWindowsServiceConfig() throws JetTaskFailureException {
if ((appType() == ApplicationType.WINDOWS_SERVICE) ||
(appType == ApplicationType.TOMCAT) &&
(excelsiorJetPackaging() == EXCELSIOR_INSTALLER) &&
tomcatConfiguration.installWindowsService
)
{
windowsServiceConfiguration.fillDefaults(this);
}
}
private void checkOSXBundleConfig() throws JetTaskFailureException {
if (excelsiorJetPackaging() == OSX_APP_BUNDLE) {
String fourDigitVersion = Utils.deriveFourDigitVersion(version);
osxBundleConfiguration.fillDefaults(this, outputName, product,
Utils.deriveFourDigitVersion(version),
Utils.deriveFourDigitVersion(fourDigitVersion.substring(0, fourDigitVersion.lastIndexOf('.'))));
if (osxBundleConfiguration.icon == null) {
logger.warn(s("JetApi.NoIconForOSXAppBundle.Warning"));
}
}
}
private void checkProtectData(ExcelsiorJet excelsiorJet) throws JetTaskFailureException {
if (protectData) {
if (!excelsiorJet.isDataProtectionSupported()) {
throw new JetTaskFailureException(s("JetApi.NoDataProtectionInStandard.Failure"));
} else {
if (cryptSeed == null) {
File cryptSeedFile = new File(pdbConfiguration.pdbLocation(), "cryptseed");
if (cryptSeedFile.exists()) {
//read cryptseed from PDB if exists.
try {
cryptSeed = Files.readAllLines(cryptSeedFile.toPath()).get(0);
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
}
if (cryptSeed == null) {
cryptSeed = Utils.randomAlphanumeric(64);
//store cryptseed to pdb to stabalize it.
pdbConfiguration().pdbLocation().mkdirs();
try (Writer writer = new BufferedWriter(new FileWriter(cryptSeedFile))) {
writer.write(cryptSeed);
} catch (IOException e) {
logger.warn(e.getMessage(), e);
}
}
}
}
}
}
/**
* Checks that either the mainWar or the mainJar parameter is specified, and that
* the respective file exists and conforms to the Spring Boot jar or war structure.
*/
private boolean checkSpringBootArtifact() throws JetTaskFailureException {
boolean isSpringBootArchive = false;
if ((mainJar == null) && (mainWar == null)) {
//both parameters are null, try to autodetect
mainJar = new File(targetDir, artifactName + ".jar");
mainWar = new File(targetDir, artifactName + ".war");
if (mainJar.exists() && mainWar.exists()) {
throw new JetTaskFailureException(s("JetApi.BothMainJarAndWarFound.Failure", mainJar.getAbsolutePath(), mainWar.getAbsolutePath()));
} else if (mainJar.exists()) {
isSpringBootArchive = true;
mainWar = null;
} else if (mainWar.exists()) {
mainJar = null;
} else {
throw new JetTaskFailureException(s("JetApi.MainJarOrWarNotFound.Failure", mainJar.getAbsolutePath(), mainWar.getAbsolutePath()));
}
} else if (mainJar != null) {
if (!mainJar.exists()) {
throw new JetTaskFailureException(s("JetApi.MainJarNotFound.Failure", mainJar.getAbsolutePath()));
}
isSpringBootArchive = true;
} else {
assert mainWar !=null;
if (!mainWar.exists()) {
throw new JetTaskFailureException(s("JetApi.MainWarNotFound.Failure", mainWar.getAbsolutePath()));
}
}
return checkSpringBootArtifact(mainArtifact(), isSpringBootArchive, true);
}
/**
* Returns {@code true} for supported versions.
*/
private boolean checkSpringBootVersion(String version) {
String[] versionParts = version.split("\\.");
if (versionParts.length < 2) {
return false;
}
try {
int major = Integer.valueOf(versionParts[0]);
int minor = Integer.valueOf(versionParts[1]);
return (major > 1) || (major == 1) && (minor >= 4);
} catch (NumberFormatException e) {
return false;
}
}
/**
* Checks that {@code mainArtifact} conforms to the Spring Boot jar or war structure according
* {@code checkJar} parameter.
*
* @param mainArtifact artifact to check
* @param checkJar if the artifact is jar
* @param failOnVersionCheck if we should throw an exception on unsupported Spring Boot version
* @return {@code true} if the artifact conforms to the respecitve Spring Boot archive structure.
*
* @throws JetTaskFailureException if {@code failOnVersionCheck} and Spring Boot version is not supported
*/
private boolean checkSpringBootArtifact(File mainArtifact, boolean checkJar, boolean failOnVersionCheck) throws JetTaskFailureException {
Manifest manifest;
try {
manifest = new JarFile(mainArtifact).getManifest();
} catch (IOException e) {
return false;
}
if (manifest == null) {
return false;
}
Attributes mainAttributes = manifest.getMainAttributes();
String main = mainAttributes.getValue(Name.MAIN_CLASS);
if (checkJar) {
if (!SPRING_BOOT_JAR_MAIN_CLASS.equals(main)) {
return false;
}
} else {
if (!SPRING_BOOT_WAR_MAIN_CLASS.equals(main)) {
return false;
}
}
String startClass = mainAttributes.getValue(SPRING_BOOT_START_CLASS_ATTR);
if (startClass == null) {
return false;
}
String springBootVersion = mainAttributes.getValue(SPRING_BOOT_VERSION_ATTR);
if ((springBootVersion != null) && !checkSpringBootVersion(springBootVersion)) {
if (failOnVersionCheck) {
throw new JetTaskFailureException(Txt.s("JetApi.SpringBoot.NotSupportedVersion.Failure", mainJar.getAbsolutePath(), springBootVersion));
} else {
return false;
}
}
return true;
}
private void copyClasspathEntry(ClasspathEntry classpathEntry, File to) throws JetTaskWrappedException {
try {
Utils.mkdir(to.getParentFile());
if (classpathEntry.path.isFile()) {
Utils.copyFile(classpathEntry.path.toPath(), to.toPath());
} else {
Utils.copyDirectory(classpathEntry.path.toPath(), to.toPath());
}
} catch (IOException | JetTaskFailureException e) {
// this method is called from lambda so wrap IOException into RuntimeException for conveniences
throw new JetTaskWrappedException(e);
}
}
/**
* Copies project dependencies.
*
* @return list of dependencies relative to buildDir
*/
List copyClasspathEntries() throws JetTaskFailureException, IOException {
try {
classpathEntries.forEach(a -> {
Path pathInJetBuildDir = toPathRelativeToJetBuildDir(a);
File dst = jetBuildDir.toPath().resolve(pathInJetBuildDir).toFile();
copyClasspathEntry(a, dst);
});
return classpathEntries;
} catch (JetTaskWrappedException e) {
// catch and unwrap io exception thrown by copyClasspathEntry in forEach lambda
throw new IOException(s("JetApi.ErrorCopyingDependency.Exception"), e.getCause());
}
}
/**
* Copies the master Tomcat server to the build directory and main project artifact (.war)
* to the "webapps" folder of copied Tomcat.
*/
void copyTomcatAndWar() throws IOException {
try {
Utils.copyDirectory(Paths.get(tomcatConfiguration.tomcatHome), tomcatInBuildDir().toPath());
String warName = tomcatConfiguration.warDeployName;
Utils.copyFile(mainWar.toPath(), new File(tomcatInBuildDir(), TomcatConfig.WEBAPPS_DIR + File.separator + warName).toPath());
} catch (IOException e) {
throw new IOException(s("JetApi.ErrorCopyingTomcat.Exception", tomcatConfiguration.tomcatHome), e);
}
}
/**
* Copies Spring Boot jar/war to the build directory.
*/
void copySpringBootArtifact() throws IOException {
try {
Utils.copyFile(mainArtifact().toPath(), new File(jetBuildDir, mainArtifact().getName()).toPath());
} catch (IOException e) {
throw new IOException(s("JetApi.ErrorCopyingSpringBootArchive.Exception", mainArtifact().getAbsolutePath()), e.getCause());
}
}
File createBuildDir() throws JetTaskFailureException {
File buildDir = this.jetBuildDir;
Utils.mkdir(buildDir);
return buildDir;
}
File tomcatInBuildDir() {
return new File(jetBuildDir, new File(tomcatConfiguration.tomcatHome).getName());
}
////////// Getters //////////////
public String creatorPlugin() {
return creatorPlugin;
}
public String projectName() {
return projectName;
}
public String groupId() {
return groupId;
}
public String artifactName() {
return artifactName;
}
public File jetResourcesDir() {
return jetResourcesDir;
}
public String vendor() {
return vendor;
}
public String product() {
return product;
}
String mainClass() {
return mainClass;
}
TomcatConfig tomcatConfiguration() {
return tomcatConfiguration;
}
public List classpathEntries() {
return classpathEntries;
}
File packageFilesDir() {
return packageFilesDir;
}
List packageFiles() {
return packageFiles;
}
String[] jvmArgs() {
return jvmArgs;
}
boolean isAddWindowsVersionInfo() {
return addWindowsVersionInfo;
}
public String inceptionYear() {
return inceptionYear;
}
PackagingType excelsiorJetPackaging() {
return PackagingType.fromString(excelsiorJetPackaging);
}
WindowsVersionInfoConfig windowsVersionInfoConfiguration() {
return windowsVersionInfoConfiguration;
}
OptimizationPreset optimizationPreset() {
return OptimizationPreset.fromString(optimizationPreset);
}
public boolean globalOptimizer() {
return globalOptimizer;
}
public RuntimeConfig runtimeConfiguration() {
return runtimeConfiguration;
}
TrialVersionConfig trialVersion() {
return trialVersion;
}
ExcelsiorInstallerConfig excelsiorInstallerConfiguration() {
return excelsiorInstallerConfiguration;
}
WindowsServiceConfig windowsServiceConfiguration() {
return windowsServiceConfiguration;
}
public String version() {
return version;
}
OSXAppBundleConfig osxBundleConfiguration() {
return osxBundleConfiguration;
}
public String outputName() {
return outputName;
}
boolean multiApp() {
return multiApp;
}
boolean profileStartup() {
return profileStartup;
}
boolean protectData() {
return protectData;
}
String cryptSeed() {
return cryptSeed;
}
File icon() {
return icon;
}
File splash() {
return splash;
}
StackTraceSupportType stackTraceSupport() {
return StackTraceSupportType.fromString(stackTraceSupport);
}
InlineExpansionType inlineExpansion() {
return InlineExpansionType.fromString(inlineExpansion);
}
boolean stackAllocation() {
return stackAllocation;
}
boolean hideConsole() {
return hideConsole;
}
int profileStartupTimeout() {
return profileStartupTimeout;
}
public File jetOutputDir() {
return jetOutputDir;
}
public ApplicationType appType() {
return appType;
}
String[] compilerOptions() {
return compilerOptions;
}
public String[] runArgs() {
return runArgs;
}
public String[] multiAppRunArgs() {
return multiAppRunArgs;
}
public String[] exeRunArgs() {
return (multiApp || appType == ApplicationType.TOMCAT) ? multiAppRunArgs : runArgs;
}
PDBConfig pdbConfiguration() {
return pdbConfiguration;
}
public String getTerminationVMProp(File termFile) {
switch (TerminationPolicy.fromString(terminationPolicy)) {
case CTRL_C:
return "-Djet.ctrlc.signal.file=" + termFile.getAbsolutePath();
case HALT:
return "-Djet.terminator=" + termFile.getAbsolutePath();
default:
throw new AssertionError("Unknown termination policy:" + terminationPolicy);
}
}
////////// Builder methods ////////////////////
public JetProject mainWar(File mainWar) {
this.mainWar = mainWar;
return this;
}
public JetProject mainJar(File mainJar) {
this.mainJar = mainJar;
return this;
}
public JetProject mainClass(String mainClass) {
this.mainClass = mainClass;
return this;
}
public JetProject tomcatConfiguration(TomcatConfig tomcatConfiguration) {
this.tomcatConfiguration = tomcatConfiguration;
return this;
}
public JetProject projectDependencies(List projectDependencies) {
this.projectDependencies = projectDependencies;
return this;
}
public JetProject dependencies(List dependencies) {
this.dependencies = dependencies;
return this;
}
public JetProject artifactName(String artifactName) {
this.artifactName = artifactName;
return this;
}
public JetProject packageFilesDir(File packageFilesDir) {
this.packageFilesDir = packageFilesDir;
return this;
}
public JetProject packageFiles(List packageFiles) {
this.packageFiles = packageFiles;
return this;
}
public JetProject execProfiles(ExecProfilesConfig execProfilesConfig) {
this.execProfilesConfiguration = execProfilesConfig;
return this;
}
public JetProject jvmArgs(String[] jvmArgs) {
this.jvmArgs = jvmArgs;
return this;
}
public JetProject addWindowsVersionInfo(Boolean addWindowsVersionInfo) {
this.addWindowsVersionInfo = addWindowsVersionInfo;
return this;
}
public JetProject excelsiorJetPackaging(String excelsiorJetPackaging) {
this.excelsiorJetPackaging = excelsiorJetPackaging;
return this;
}
public JetProject vendor(String vendor) {
this.vendor = vendor;
return this;
}
public JetProject product(String product) {
this.product = product;
return this;
}
public JetProject windowsVersionInfoConfiguration(WindowsVersionInfoConfig windowsVersionInfoConfiguration) {
this.windowsVersionInfoConfiguration = windowsVersionInfoConfiguration;
return this;
}
public JetProject inceptionYear(String inceptionYear) {
this.inceptionYear = inceptionYear;
return this;
}
public JetProject optimizationPreset(String optimizationPreset) {
this.optimizationPreset = optimizationPreset;
return this;
}
public JetProject globalOptimizer(boolean globalOptimizer) {
this.globalOptimizer = globalOptimizer;
return this;
}
public JetProject runtimeConfiguration(RuntimeConfig runtimeConfiguration) {
this.runtimeConfiguration = runtimeConfiguration;
return this;
}
public JetProject trialVersion(TrialVersionConfig trialVersion) {
this.trialVersion = trialVersion;
return this;
}
public JetProject excelsiorInstallerConfiguration(ExcelsiorInstallerConfig excelsiorInstallerConfiguration) {
this.excelsiorInstallerConfiguration = excelsiorInstallerConfiguration;
return this;
}
public JetProject windowsServiceConfiguration(WindowsServiceConfig windowsServiceConfiguration) {
this.windowsServiceConfiguration = windowsServiceConfiguration;
return this;
}
public JetProject version(String version) {
this.version = version;
return this;
}
public JetProject osxBundleConfiguration(OSXAppBundleConfig osxBundleConfiguration) {
this.osxBundleConfiguration = osxBundleConfiguration;
return this;
}
public JetProject outputName(String outputName) {
this.outputName = outputName;
return this;
}
public JetProject multiApp(boolean multiApp) {
this.multiApp = multiApp;
return this;
}
public JetProject profileStartup(boolean profileStartup) {
this.profileStartup = profileStartup;
return this;
}
public JetProject protectData(boolean protectData) {
this.protectData = protectData;
return this;
}
public JetProject cryptSeed(String cryptSeed) {
this.cryptSeed = cryptSeed;
return this;
}
public JetProject icon(File icon) {
this.icon = icon;
return this;
}
public JetProject splash(File splash) {
this.splash = splash;
return this;
}
public JetProject stackTraceSupport(String stackTraceSupport) {
this.stackTraceSupport = stackTraceSupport;
return this;
}
public JetProject inlineExpansion(String inlineExpansion) {
this.inlineExpansion = inlineExpansion;
return this;
}
public JetProject stackAllocation(boolean stackAllocation) {
this.stackAllocation = stackAllocation;
return this;
}
public JetProject hideConsole(boolean hideConsole) {
this.hideConsole = hideConsole;
return this;
}
public JetProject profileStartupTimeout(int profileStartupTimeout) {
this.profileStartupTimeout = profileStartupTimeout;
return this;
}
public JetProject jetOutputDir(File jetOutputDir) {
this.jetOutputDir = jetOutputDir;
return this;
}
public JetProject jetBuildDir(File jetBuildDir) {
this.jetBuildDir = jetBuildDir;
return this;
}
public JetProject jetAppDir(File jetAppDir) {
this.jetAppDir = jetAppDir;
return this;
}
public JetProject compilerOptions(String[] compilerOptions) {
this.compilerOptions = compilerOptions;
return this;
}
public JetProject runArgs(String[] runArgs) {
this.runArgs = runArgs;
return this;
}
public JetProject multiAppRunArgs(String[] runArgs) {
this.multiAppRunArgs = runArgs;
return this;
}
public JetProject pdbConfiguration(PDBConfig pdbConfig) {
pdbConfiguration = pdbConfig;
return this;
}
public JetProject terminationPolicy(String terminationPolicy) {
this.terminationPolicy = terminationPolicy;
return this;
}
public File jetBuildDir() {
return jetBuildDir;
}
public File jetAppDir() {
return jetAppDir;
}
public File jetAppToProfileDir() {
return execProfilesConfiguration.profilingImageDir;
}
public boolean isProfileLocally() {
return execProfilesConfiguration.profileLocally;
}
public boolean isMainArtifactJar() {
return mainJar != null;
}
public File mainArtifact() {
switch (appType) {
case TOMCAT:
return mainWar;
case SPRING_BOOT:
return isMainArtifactJar() ? mainJar : mainWar;
default:
return mainJar;
}
}
public static ApplicationType checkAndGetAppType(String appType) throws JetTaskFailureException {
return ApplicationType.validate(appType);
}
Path toPathRelativeToJetBuildDir(ClasspathEntry classpathEntry) {
Path libPath;
Path jetBuildDir = jetBuildDir().toPath();
Path jetLibDir = jetBuildDir.resolve("lib");
if (classpathEntry.packagePath == null) {
if (classpathEntry.path.isFile()) {
libPath = jetLibDir.resolve(classpathEntry.path.getName());
} else {
libPath = jetBuildDir.resolve(classpathEntry.path.getName());
}
} else {
libPath = jetBuildDir.resolve(classpathEntry.packagePath).resolve(classpathEntry.path.getName());
}
return jetBuildDir.relativize(libPath);
}
String exeRelativePath(ExcelsiorJet excelsiorJet) {
//TODO: add configuration to customize exe location.
switch (appType) {
case PLAIN:
case WINDOWS_SERVICE:
case SPRING_BOOT:
return excelsiorJet.getTargetOS().mangleExeName(outputName());
case DYNAMIC_LIBRARY:
return excelsiorJet.getTargetOS().mangleDllName(outputName(), false);
case TOMCAT:
return "bin" + File.separatorChar + excelsiorJet.getTargetOS().mangleExeName(outputName());
default:
throw new AssertionError("Unknown apptype: " + appType);
}
}
}