public class Capsule extends Object implements Runnable
This API is to be used by caplets (custom capsules) to programmatically (rather than declaratively) configure the capsule and possibly provide custom behavior.
All non-final protected methods may be overridden by caplets. These methods will usually be called once, but they must be idempotent,
i.e. if called numerous times they must always return the same value, and produce the same effect as if called once.
Overridden methods need not be thread-safe, and are guaranteed to be called by a single thread at a time.
Overridable (non-final) methods must never be called directly by caplet code, except by their overrides.
Final methods implement various utility or accessors, which may be freely used by caplets.
Caplets might consider overriding one of the following powerful methods:
attribute
, getVarValue
,
processOutgoingPath
, prelaunch
.
For command line option handling, see OPTION
.
Attributes should be registered with ATTRIBUTE
.
Modifier | Constructor and Description |
---|---|
protected |
Capsule(Capsule pred)
Caplets that will be listed on the manifest's
Caplets attribute must use this constructor. |
protected |
Capsule(Path jarFile)
Constructs a capsule.
|
Modifier and Type | Method and Description |
---|---|
protected Path |
addTempFile(Path p) |
protected <T> T |
attribute(Map.Entry<String,T> attr)
CAPLET OVERRIDE ONLY: Returns the value of the given capsule attribute with consideration to the capsule's mode.
|
protected static <T> Map.Entry<String,T> |
ATTRIBUTE(String attrName,
T type,
T defaultValue,
boolean allowModal,
String description)
Registers a manifest attribute.
|
protected Path |
buildAppCacheDir()
Returns the path of the application cache (this is the directory where the capsule is extracted if necessary).
|
protected List<String> |
buildArgs(List<String> args)
Returns a list of command line arguments to pass to the application.
|
protected Map<String,String> |
buildEnvironmentVariables(Map<String,String> env)
Returns a map of environment variables (property-value pairs).
|
protected ProcessBuilder |
buildProcess()
Constructs a
ProcessBuilder that is later used to launch the capsule. |
protected Path |
chooseJavaHome()
Chooses which Java installation to use for running the app.
|
protected int |
chooseLogLevel()
Chooses and returns the capsules log level.
|
protected String |
chooseMode()
Chooses this capsule's mode.
|
protected void |
cleanup()
Called when the capsule exits after a successful or failed attempt to launch the application.
|
protected static int |
compareVersions(String a,
String b)
Compares two dotted software versions.
|
protected static int |
compareVersions(String a,
String b,
int n)
Compares two dotted software versions, regarding only the first several version components.
|
protected static List<String> |
exec(int numLines,
ProcessBuilder pb)
Executes a command and returns its output as a list of lines.
|
protected static List<String> |
exec(int numLines,
String... cmd)
Executes a command and returns its output as a list of lines.
|
protected static List<String> |
exec(ProcessBuilder pb)
Executes a command and returns its output as a list of lines.
|
protected static List<String> |
exec(String... cmd)
Executes a command and returns its output as a list of lines.
|
protected void |
extractCapsule(Path dir)
Extracts the capsule's contents into the app cache directory.
|
protected void |
finalizeCapsule()
Called once the capsule construction has been completed (after loading of wrapped capsule, if applicable).
|
protected Path |
getAppCache()
This capsule's cache directory, or
null if capsule has been configured not to extract, or the app cache dir hasn't been set up yet. |
protected String |
getAppId()
Returns the app's ID.
|
protected <T> T |
getAttribute(Map.Entry<String,T> attr)
Returns the value of the given manifest attribute with consideration to the capsule's mode.
|
protected <T extends Capsule> |
getCallTarget(Class<T> clazz) |
protected static InputStream |
getEntryInputStream(Path jar,
String name) |
protected static String |
getenv(String envName)
Returns the value of an environment variable - should be used instead of
System.getenv(envName) . |
protected Path |
getJarFile()
This capsule's JAR file.
|
protected Path |
getJavaExecutable()
Returns the path to the executable that will be used to launch Java.
|
protected static Path |
getJavaExecutable(Path javaHome)
Finds the path to the executable that will be used to launch Java within the given
javaHome . |
protected Path |
getJavaHome()
The path to the Java installation this capsule's app will use.
|
protected static Map<String,List<Path>> |
getJavaHomes()
Returns all found Java installations.
|
protected static int |
getLogLevel()
Capsule's log level
|
protected String |
getMode()
This capsule's current mode.
|
protected String |
getModeDescription(String mode)
Returns the description of the given mode.
|
protected Set<String> |
getModes()
Returns the names of all modes defined in this capsule's manifest.
|
protected static String |
getNativeLibExtension()
The suffix of a native library on this OS.
|
protected static FileAttribute<?>[] |
getPermissions(Path p)
Returns the permissions of the given file or directory.
|
protected List<Path> |
getPlatformNativeLibraryPath()
Returns the default native library path for the Java platform the application uses.
|
protected static String |
getProperty(String propName)
Returns a system property - should be used instead of
System.getProperty(propName) . |
protected String |
getVarValue(String var)
Resolves
$VARNAME or ${VARNAME} in attribute values. |
protected Path |
getWritableAppCache()
Returns a writable directory that can be used to store files related to launching the capsule.
|
protected boolean |
hasAttribute(Map.Entry<String,?> attr)
Tests whether the given attribute is found in the manifest.
|
protected boolean |
hasCaplet(String name)
Checks whether a caplet with the given class name is installed.
|
protected boolean |
isEmptyCapsule() |
protected static boolean |
isLogging(int level)
Tests if the given log level is currently being logged.
|
protected static boolean |
isMac()
Tests whether the current OS is MacOS.
|
protected static boolean |
isUnix()
Tests whether the current OS is UNIX/Linux.
|
protected static boolean |
isWindows()
Tests whether the current OS is Windows.
|
protected boolean |
isWrapperCapsule()
Whether or not this is an empty capsule
|
protected static List<Path> |
listDir(Path dir,
String glob,
boolean regular)
Returns the contents of a directory.
|
protected Capsule |
loadTargetCapsule(ClassLoader parent,
Path jarFile)
Loads the wrapped capsule when this capsule is the wrapper.
|
protected static void |
log(int level,
String str)
Prints a message to stderr if the given log-level is being logged.
|
static void |
main(String[] args) |
protected static Path |
move(Path what,
Path fromDir,
Path toDir)
Returns a path to a file or directory moved from
fromDir to toDir . |
protected String |
name(Map.Entry<String,?> attribute)
Returns an attribute's name.
|
protected void |
onError(Throwable t)
Called when an unhandled exception is thrown, to display error information to the user before shutting down.
|
protected static String |
OPTION(String optionName,
String defaultValue,
String methodName,
boolean wrapperOnly,
String description)
Registers a capsule command-line option.
|
protected static String |
OPTION(String optionName,
String defaultValue,
String methodName,
String description)
|
protected Process |
postlaunch(Process child)
Called after the application is launched by the capsule.
|
protected ProcessBuilder |
prelaunch(List<String> jvmArgs,
List<String> args)
Returns a configured
ProcessBuilder that is later used to launch the capsule. |
protected String |
processOutgoingPath(Path p)
Every path emitted by the capsule to the app's command line, system properties or environment variables is
first passed through this method.
|
protected static void |
setProperty(String propName,
String value)
Sets a system property.
|
protected <T extends Capsule> |
sup(Class<T> caplet)
The first caplet in the caplet chain starting with the current one and going up (back) that is of the requested type.
|
protected static Boolean |
T_BOOL()
Represents the attribute type
Boolean |
protected static Double |
T_DOUBLE()
Represents the attribute type
Double |
protected static <E> List<E> |
T_LIST(E type)
A
List of type type |
protected static Long |
T_LONG()
Represents the attribute type
Long |
protected static <E> Map<String,E> |
T_MAP(E type,
E defaultValue)
A
Map from String to type type |
protected static <E> Set<E> |
T_SET(E type)
A
Set of type type |
protected static String |
T_STRING()
Represents the attribute type
String |
String |
toString() |
protected Path |
verifyAppCache()
Returns this capsule's cache directory.
|
protected static final Map.Entry<String,String> ATTR_APP_ID
"com.acme.bestwordprocessor"
protected static final Map.Entry<String,String> ATTR_APP_NAME
"The Best Word Processor"
protected static final Map.Entry<String,String> ATTR_CAPSULE_IN_CLASS_PATH
protected static final Map.Entry<String,Map<String,String>> ATTR_MIN_UPDATE_VERSION
protected static final Map.Entry<String,Map<String,String>> ATTR_NATIVE_DEPENDENCIES
protected static final Map.Entry<String,Map<String,String>> ATTR_SYSTEM_PROPERTIES
protected static final int LOG_DEBUG
protected static final int LOG_NONE
protected static final int LOG_QUIET
protected static final int LOG_VERBOSE
protected static final PrintStream STDERR
protected static final PrintStream STDOUT
public static final String VERSION
protected Capsule(Capsule pred)
Caplets
attribute must use this constructor.
Caplets are required to have a constructor with the same signature as this constructor, and pass their arguments to up to this constructor.pred
- The capsule preceding this one in the chain (caplets must not access the passed capsule in their constructor).protected Capsule(Path jarFile)
This constructor is used by a caplet that will be listed in the manifest's Main-Class
attribute.
Caplets are encouraged to "override" the other constructor
so that they may be listed
in the Caplets
attribute.
This constructor or that of a subclass must not make use of any registered capsule options, as they may not have been properly pre-processed yet.
jarFile
- the path to the JAR fileprotected <T> T attribute(Map.Entry<String,T> attr)
super.attribute(attr)
calls in the caplet's implementation of this method.
The default implementation parses and returns the relevant manifest attribute or its default value if undefined.
attr
- the attributegetAttribute(Map.Entry)
protected static final <T> Map.Entry<String,T> ATTRIBUTE(String attrName, T type, T defaultValue, boolean allowModal, String description)
attrName
- the attribute's nametype
- the attribute's type, obtained by calling one (or a combination) of the "type" methods:
T_STRING
, T_BOOL
, T_LONG
, T_DOUBLE
,
T_LIST
, T_MAP
, T_SET
defaultValue
- the attribute's default value, or null
for none; a null
value for collection or map types will be transformed into the type's empty value (i.e. empty list, empty map, etc.)allowModal
- whether the attribute is modal (i.e. can be specified per mode); if false
, then the attribute is only allowed in the manifest's main section.description
- a description of the attributeprotected Path buildAppCacheDir()
protected List<String> buildArgs(List<String> args)
args
- The command line arguments passed to the capsule at launchprotected Map<String,String> buildEnvironmentVariables(Map<String,String> env)
env
- the current environmentprotected ProcessBuilder buildProcess()
ProcessBuilder
that is later used to launch the capsule.
The returned process builder should contain the command minus the application arguments (which are later constructed by
buildArgs
and appended to the command).buildEnvironmentVariables
.
This implementation tries to create a process running a startup script, and, if one has not been set, constructs a Java process.
This method should be overridden to add new types of processes the capsule can launch (like, say, Python scripts).
If all you want is to configure the returned ProcessBuilder
, for example to set IO stream redirection,
you should override prelaunch
.
ProcessBuilder
(must never be null
).protected Path chooseJavaHome()
null
if the current JVM is to be used.protected int chooseLogLevel()
protected String chooseMode()
protected void cleanup()
super.cleanup()
even in the event of an abnormal termination
(i.e. when an exception is thrown). This method must not throw any exceptions. All exceptions origination by cleanup
must be wither ignored completely or printed to STDERR.protected static final int compareVersions(String a, String b)
a
- first versionb
- second version0
if a == b
; > 0
if a > b
; < 0
if a < b
;protected static final int compareVersions(String a, String b, int n)
a
- first versionb
- second versionn
- the number of (most significant) components to consider0
if a == b
; > 0
if a > b
; < 0
if a < b
;protected static List<String> exec(int numLines, ProcessBuilder pb) throws IOException
numLines
, or if numLines < 0
, then the method will wait for the child process
to terminate, and throw an exception if the command returns an exit value != 0
.numLines
- the maximum number of lines to read, or -1
for an unbounded numberpb
- the ProcessBuilder
that will be used to launch the commandIOException
protected static List<String> exec(int numLines, String... cmd) throws IOException
numLines
, or if numLines < 0
, then the method will wait for the child process
to terminate, and throw an exception if the command returns an exit value != 0
.numLines
- the maximum number of lines to read, or -1
for an unbounded numbercmd
- the commandIOException
protected static List<String> exec(ProcessBuilder pb) throws IOException
!= 0
.
exec(-1, pb
}.pb
- the ProcessBuilder
that will be used to launch the commandIOException
protected static List<String> exec(String... cmd) throws IOException
!= 0
.
exec(-1, cmd
}.cmd
- the commandIOException
protected void extractCapsule(Path dir) throws IOException
IOException
protected void finalizeCapsule()
protected final Path getAppCache()
null
if capsule has been configured not to extract, or the app cache dir hasn't been set up yet.protected final String getAppId()
protected final <T> T getAttribute(Map.Entry<String,T> attr)
ATTRIBUTE()
).
Note that caplets may manipulate the value this method returns by overriding attribute(Map.Entry)
.
attr
- the attributeprotected static InputStream getEntryInputStream(Path jar, String name) throws IOException
IOException
protected static String getenv(String envName)
System.getenv(envName)
.protected final Path getJarFile()
protected Path getJavaExecutable()
capsule.java.cmd
property or the JAVACMD
environment variable,
and if not set, returns the value of getJavaExecutable(getJavaHome())
.protected static final Path getJavaExecutable(Path javaHome)
javaHome
.protected final Path getJavaHome()
protected static Map<String,List<Path>> getJavaHomes()
protected static final int getLogLevel()
protected final String getMode()
protected final String getModeDescription(String mode)
protected final Set<String> getModes()
protected static final String getNativeLibExtension()
protected static FileAttribute<?>[] getPermissions(Path p) throws IOException
IOException
protected List<Path> getPlatformNativeLibraryPath()
protected static final String getProperty(String propName)
System.getProperty(propName)
.protected String getVarValue(String var)
$VARNAME
or ${VARNAME}
in attribute values.var
- the variable nameprotected final Path getWritableAppCache()
protected final boolean hasAttribute(Map.Entry<String,?> attr)
attr
- the attributeprotected final boolean hasCaplet(String name)
protected final boolean isEmptyCapsule()
protected static final boolean isLogging(int level)
protected static final boolean isMac()
protected static final boolean isUnix()
protected static final boolean isWindows()
protected final boolean isWrapperCapsule()
protected static final List<Path> listDir(Path dir, String glob, boolean regular)
null
as the glob pattern is the same as passing "*"
dir
- the directoryglob
- the glob pattern to use to filter the entries, or null
if all entries are to be returnedregular
- whether only regular files should be returnedprotected Capsule loadTargetCapsule(ClassLoader parent, Path jarFile)
parent
- theprotected static final void log(int level, String str)
public static final void main(String[] args)
protected static Path move(Path what, Path fromDir, Path toDir)
fromDir
to toDir
.
This method does not actually moves any files in the filesystem.what
- the path to move; must start with fromDir
fromDir
- the directory containing what
toDir
- the directory what
is moved totoDir
.protected void onError(Throwable t)
protected static final String OPTION(String optionName, String defaultValue, String methodName, boolean wrapperOnly, String description)
Capsule options are system properties beginning with the prefix ".capsule", normally passed to the capsule as -D flags on the command line.
Options can be top-level *actions* (like print dependency tree or list JVMs), in which case the methodName
argument must
be the name of a method used to launch the action instead of launching the capsule.
Options can have a default value, which will be automatically assigned to the system property if undefined. The default values
"true"
and "false"
are treated specially. If one of them is the assigned default value, and the system property
is defined with with a value of the empty string, then it will be re-assigned the value "true"
.
Simple Command Line Options for Wrapper Capsules
When the capsule serves as a wrapper (i.e. it's an empty capsule used to launch an executable artifact or another capsule)
then the options can also be passed to the capsule as simple command line options (arguments starting with a hyphen),
with the "capsule." prefix removed, and every '.' character replaced with a '-'.
These command line arguments will automatically be converted to system properties, which will take their value from the argument
following the option (i.e. -option value
), unless the option is given one of the special default values
"true"
or "false"
, in which case it is treated as a flag with no arguments (note that an option with the default
value "true"
will therefore not be able to be turned off if simple options are used).
defaultValue
- the option's default value ("true"
and "false"
are specially treated; see above).optionName
- the name of the system property for the option; must begin with "capsule."
.methodName
- if non-null, then the option is a top-level action (like print dependency tree or list JVMs),
and this is the method which will run the action.
The method must accept a single args
parameter of type List<String>
.wrapperOnly
- whether or not the option is available in wrapper capsules onlydescription
- a description of the option.protected static final String OPTION(String optionName, String defaultValue, String methodName, String description)
protected Process postlaunch(Process child)
null
, the capsule will exit immediately,
without waiting for the child process to terminate. This method is also allowed to never return.child
- the child process running the applicationprotected ProcessBuilder prelaunch(List<String> jvmArgs, List<String> args)
ProcessBuilder
that is later used to launch the capsule.
The ProcessBuilder's IO redirection is left in its default settings.
Caplets may override this method to display a message prior to launch, or to configure the process's IO streams.
For more elaborate manipulation of the Capsule's launched process, consider overriding buildProcess
.jvmArgs
- the JVM arguments listed on the command lineargs
- the application command-line argumentsProcessBuilder
(if null
, the launch will be aborted).protected String processOutgoingPath(Path p)
p
- the pathprotected static final void setProperty(String propName, String value)
protected final <T extends Capsule> T sup(Class<T> caplet)
protected static final Boolean T_BOOL()
Boolean
protected static final Double T_DOUBLE()
Double
protected static final <E> List<E> T_LIST(E type)
List
of type type
protected static final Long T_LONG()
Long
protected static final <E> Map<String,E> T_MAP(E type, E defaultValue)
Map
from String
to type type
protected static final <E> Set<E> T_SET(E type)
Set
of type type
protected static final String T_STRING()
String
protected final Path verifyAppCache()
getAppCache()
is that this method throws an exception if the app cache
cannot be retrieved, while getAppCache()
returns null
.IllegalStateException
- if the app cache hasn't been set up (yet).