use of com.oracle.bedrock.runtime.options.DisplayName in project oracle-bedrock by coherence-community.
the class AbstractRemoteApplicationLauncher method launch.
@Override
public A launch(Platform platform, MetaClass<A> metaClass, OptionsByType optionsByType) {
// establish the diagnostics output table
Table diagnosticsTable = new Table();
diagnosticsTable.getOptions().add(Table.orderByColumn(0));
if (platform != null) {
diagnosticsTable.addRow("Target Platform", platform.getName());
}
// ----- establish the launch Options for the Application -----
// add the platform options
OptionsByType launchOptions = OptionsByType.of(platform.getOptions()).addAll(optionsByType);
// add the meta-class options
metaClass.onLaunching(platform, launchOptions);
// ---- establish the default Options ----
// define the PlatformSeparators as Unix if they are not already defined
launchOptions.addIfAbsent(PlatformSeparators.forUnix());
// define the default Platform Shell (assume BASH)
launchOptions.addIfAbsent(Shell.is(Shell.Type.BASH));
// define the "local.address" variable so that is can be used for resolving this platform address
launchOptions.add(Variable.with("local.address", LocalPlatform.get().getAddress().getHostAddress()));
// ----- establish an identity for the application -----
// add a unique runtime id for expression support
launchOptions.add(Variable.with("bedrock.runtime.id", UUID.randomUUID()));
// ----- establish default Profiles for this Platform (and Builder) -----
// auto-detect and add externally defined profiles
launchOptions.addAll(Profiles.getProfiles());
for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
profile.onLaunching(platform, metaClass, launchOptions);
}
// ----- add the diagnostic table to the options so it can be used by the terminal -----
launchOptions.add(diagnosticsTable);
// ----- prior to launching the application, let the implementation enhance the launch options -----
onLaunching(launchOptions);
// ----- give the MetaClass a last chance to manipulate any options -----
metaClass.onLaunch(platform, launchOptions);
// ----- determine the display name for the application -----
DisplayName displayName = getDisplayName(launchOptions);
// determine the Executable
Executable executable = launchOptions.get(Executable.class);
// ----- deploy remote application artifacts -----
// determine the DeploymentArtifacts based on those specified by the Deployment option
ArrayList<DeploymentArtifact> artifactsToDeploy = new ArrayList<>();
Deployment deployment = launchOptions.get(Deployment.class);
if (deployment != null) {
try {
artifactsToDeploy.addAll(deployment.getDeploymentArtifacts(platform, launchOptions));
} catch (Exception e) {
throw new RuntimeException("Failed to determine artifacts to deploy", e);
}
}
// determine the separators for the platform
PlatformSeparators separators = launchOptions.get(PlatformSeparators.class);
// assume the remote directory is the working directory
WorkingDirectory workingDirectory = launchOptions.getOrSetDefault(WorkingDirectory.class, WorkingDirectory.temporaryDirectory());
File remoteDirectoryFile = workingDirectory.resolve(platform, launchOptions);
if (remoteDirectoryFile == null) {
remoteDirectoryFile = WorkingDirectory.temporaryDirectory().resolve(platform, launchOptions);
}
String remoteDirectory = separators.asPlatformFileName(remoteDirectoryFile.toString());
// Set the resolved working directory back into the options
launchOptions.add(WorkingDirectory.at(remoteDirectoryFile));
if (remoteDirectoryFile != null) {
diagnosticsTable.addRow("Working Directory", remoteDirectoryFile.toString());
}
// Obtain the RemoteShell that will be used to launch the process
RemoteTerminalBuilder terminalBuilder = launchOptions.getOrSetDefault(RemoteTerminalBuilder.class, RemoteTerminals.ssh());
RemoteTerminal terminal = terminalBuilder.build(platform);
// create the working directory
terminal.makeDirectories(remoteDirectory, launchOptions);
// deploy any artifacts required
Deployer deployer = launchOptions.getOrSetDefault(Deployer.class, new SftpDeployer());
DeployedArtifacts deployedArtifacts = deployer.deploy(artifactsToDeploy, remoteDirectory, platform, launchOptions.asArray());
// add the remote directory as something to clean up
deployedArtifacts.add(remoteDirectoryFile);
if (!deployedArtifacts.isEmpty()) {
// when we've deployed artifacts we need to add a listener to clean them up
launchOptions.add(Decoration.of(new ApplicationListener<A>() {
@Override
public void onClosing(A application, OptionsByType optionsByType) {
// nothing to do on closing
}
@Override
public void onClosed(A application, OptionsByType optionsByType) {
Level logLevel = optionsByType.get(LaunchLogging.class).isEnabled() ? Level.INFO : Level.OFF;
try (DiagnosticsRecording diagnostics = DiagnosticsRecording.create("Undeploy Diagnostics for " + application.getName() + " on platform " + platform.getName()).using(LOGGER, logLevel)) {
diagnostics.add("Platform", "Resource");
try (DiagnosticsRecording local = DiagnosticsRecording.section("Local Platform")) {
// clean up the locally created temporary artifacts
artifactsToDeploy.stream().filter(DeploymentArtifact::isTemporary).forEach(artifact -> {
try {
// attempt to remove the local file
artifact.getSourceFile().delete();
// include diagnostics
local.add(artifact.getSourceFile().toString());
} catch (Exception e) {
// log exceptions when attempting to remove local sources
LOGGER.log(Level.WARNING, "Failed to remove temporary " + artifact.toString() + " for application " + application.getName(), e);
// include diagnostics
local.add(artifact.getSourceFile() + " (failed to undeploy)");
}
});
}
// undeploy the deployed artifacts
deployer.undeploy(deployedArtifacts, platform, launchOptions.asArray());
}
}
@Override
public void onLaunched(A application) {
// nothing to do after launching
}
}));
}
// Realize the application arguments
Arguments arguments = launchOptions.get(Arguments.class);
List<String> argList = arguments.resolve(platform, launchOptions);
// Set the actual arguments used back into the options
launchOptions.add(Arguments.of(argList));
// TODO: put a try/catch around the terminal.launch here so we can clean up the RemoteExecutor if
// the application failed to launch
// determine the application class that will represent the running application
Class<? extends A> applicationClass = metaClass.getImplementationClass(platform, launchOptions);
diagnosticsTable.addRow("Application", displayName.resolve(launchOptions));
if (argList.size() > 0) {
diagnosticsTable.addRow("Application Arguments ", argList.stream().collect(Collectors.joining(" ")));
}
diagnosticsTable.addRow("Application Launch Time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
// ----- start the process and establish the application -----
// launch the remote process
RemoteApplicationProcess remoteProcess = terminal.launch(this, applicationClass, launchOptions);
// adapt the remote process into something that the application can use
ApplicationProcess process = adapt(remoteProcess);
// create the Application based on the RemoteApplicationProcess
A application;
try {
// attempt to find a constructor(Platform, JavaApplicationProcess, Options)
Constructor<? extends A> constructor = ReflectionHelper.getCompatibleConstructor(applicationClass, platform.getClass(), process.getClass(), OptionsByType.class);
// create the application
application = constructor.newInstance(platform, process, launchOptions);
} catch (Exception e) {
throw new RuntimeException("Failed to instantiate the Application class specified by the MetaClass:" + metaClass, e);
}
// ----- after launching the application, let the implementation interact with the application -----
onLaunched(application, launchOptions);
// ----- notify the MetaClass that the application has been launched -----
metaClass.onLaunched(platform, application, launchOptions);
for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
profile.onLaunched(platform, application, launchOptions);
}
// notify the ApplicationListener-based Options that the application has been launched
for (ApplicationListener listener : launchOptions.getInstancesOf(ApplicationListener.class)) {
listener.onLaunched(application);
}
return application;
}
use of com.oracle.bedrock.runtime.options.DisplayName in project oracle-bedrock by coherence-community.
the class AbstractAssembly method expand.
/**
* Expands the number of {@link Application}s in the {@link Assembly} by launching and adding the specified number
* of {@link Application}s on the provided {@link Infrastructure} using the zero or more provided {@link Option}s.
*
* @param count the number of instances of the {@link Application} that should be launched and added
* to the {@link Assembly}
* @param infrastructure the {@link Infrastructure} on which to launch the {@link Application}s
* @param applicationClass the class of {@link Application}
* @param options the {@link Option}s to use for launching the {@link Application}s
*
* @see Platform#launch(String, Option...)
* @see AssemblyBuilder#include(int, Class, Option...)
*/
public void expand(int count, Infrastructure infrastructure, Class<? extends A> applicationClass, Option... options) {
// we keep track of the new applications that are launched
ArrayList<A> launchedApplications = new ArrayList<>();
// determine the common expandingOptions
OptionsByType expandingOptions = OptionsByType.of(optionsByType).addAll(options);
for (int i = 0; i < count; i++) {
// establish the launch options for the next application
OptionsByType launchOptions = OptionsByType.of(expandingOptions);
// include a discriminator for the application about to be launched
// (if it has a DisplayName, doesn't have a Discriminator and there are more than one to launch)
DisplayName displayName = launchOptions.getOrDefault(DisplayName.class, null);
if (displayName != null && !launchOptions.contains(Discriminator.class)) {
// acquire the discriminator counter for the application DisplayName
AtomicInteger counter = discriminators.computeIfAbsent(displayName, name -> new AtomicInteger(0));
// create a discriminator for the application
launchOptions.addIfAbsent(Discriminator.of(counter.incrementAndGet()));
}
// attempt to launch the application
try {
// acquire the platform from the infrastructure based on the launch options
Platform platform = infrastructure.getPlatform(launchOptions.asArray());
// launch the application
A application = platform.launch(applicationClass, launchOptions.asArray());
// remember the application
// (so we can add it to the assembly once they are all launched)
launchedApplications.add(application);
} catch (Throwable throwable) {
// ensure all recently launched applications are shutdown to prevent applications staying around
for (A application : launchedApplications) {
try {
application.close();
} catch (Throwable t) {
// we ignore any issues when the application fails to close
}
}
throw new RuntimeException("Failed to launch one of the desired " + applicationClass.getSimpleName() + "(s) out of " + count + " requested. " + "Automatically closed " + launchedApplications.size() + " that were successfully created. The options provided where " + launchOptions, throwable);
}
}
// include the launched applications in the assembly
for (A application : launchedApplications) {
// ensure the assembly is a feature of the application so that it can be called back for lifecycle events
application.add(Assembly.class, this);
// add the application to the assembly
applications.add(application);
}
// notify the assembly that it has expanded with the launched applications
onExpanded(launchedApplications, expandingOptions);
}
use of com.oracle.bedrock.runtime.options.DisplayName in project oracle-bedrock by coherence-community.
the class SimpleApplicationLauncher method launch.
@Override
public Application launch(Platform platform, MetaClass<Application> metaClass, OptionsByType optionsByType) {
// establish the diagnostics output table
Table diagnosticsTable = new Table();
diagnosticsTable.getOptions().add(Table.orderByColumn(0));
if (platform != null) {
diagnosticsTable.addRow("Target Platform", platform.getName());
}
// ----- establish the launch Options for the Application -----
// add the platform options
OptionsByType launchOptions = OptionsByType.of(platform.getOptions()).addAll(optionsByType);
// add the meta-class options
metaClass.onLaunching(platform, launchOptions);
// ----- establish default Profiles for this Platform (and Builder) -----
// auto-detect and add externally defined profiles
launchOptions.addAll(Profiles.getProfiles());
for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
profile.onLaunching(platform, metaClass, launchOptions);
}
// ----- give the MetaClass a last chance to manipulate any options -----
metaClass.onLaunch(platform, launchOptions);
// ----- determine the display name for the application -----
// ensure there's a display name
DisplayName displayName = launchOptions.getOrSetDefault(DisplayName.class, DisplayName.of(launchOptions.get(Executable.class).getName()));
// ---- establish the underlying ProcessBuilder -----
// determine the Executable
Executable executable = launchOptions.get(Executable.class);
if (executable == null) {
throw new IllegalArgumentException("Failed to define an Executable option");
}
// we'll use the native operating system process builder to create
// and manage the local application process
LocalProcessBuilder processBuilder = createProcessBuilder(StringHelper.doubleQuoteIfNecessary(executable.getName()));
// ----- establish the working directory -----
// set the working directory for the Process
WorkingDirectory workingDirectory = launchOptions.getOrSetDefault(WorkingDirectory.class, WorkingDirectory.currentDirectory());
File directory = workingDirectory.resolve(platform, launchOptions);
// Set the resolved working directory back into the options
launchOptions.add(WorkingDirectory.at(directory));
if (directory != null) {
processBuilder.directory(directory);
diagnosticsTable.addRow("Working Directory", directory.toString());
}
// ----- establish environment variables -----
EnvironmentVariables environmentVariables = launchOptions.get(EnvironmentVariables.class);
switch(environmentVariables.getSource()) {
case Custom:
processBuilder.environment().clear();
diagnosticsTable.addRow("Environment Variables", "(cleared)");
break;
case ThisApplication:
processBuilder.environment().clear();
processBuilder.environment().putAll(System.getenv());
diagnosticsTable.addRow("Environment Variables", "(based on parent process)");
break;
case TargetPlatform:
diagnosticsTable.addRow("Environment Variables", "(based on platform defaults)");
break;
}
// add the optionally defined environment variables
Properties variables = environmentVariables.realize(platform, launchOptions.asArray());
for (String variableName : variables.stringPropertyNames()) {
processBuilder.environment().put(variableName, variables.getProperty(variableName));
}
if (variables.size() > 0) {
Table table = Tabularize.tabularize(variables);
diagnosticsTable.addRow("", table.toString());
}
// ----- establish the application command line to execute -----
List<String> command = processBuilder.command();
// add the arguments to the command for the process
List<String> arguments = launchOptions.get(Arguments.class).resolve(platform, launchOptions);
command.addAll(arguments);
diagnosticsTable.addRow("Application", displayName.resolve(launchOptions));
diagnosticsTable.addRow("Application Executable ", executable.getName());
if (arguments.size() > 0) {
diagnosticsTable.addRow("Application Arguments ", arguments.stream().collect(Collectors.joining(" ")));
}
diagnosticsTable.addRow("Application Launch Time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
// set the actual arguments used back into the options
launchOptions.add(Arguments.of(arguments));
// should the standard error be redirected to the standard out?
ErrorStreamRedirection redirection = launchOptions.get(ErrorStreamRedirection.class);
processBuilder.redirectErrorStream(redirection.isEnabled());
boolean launchLogging = optionsByType.get(LaunchLogging.class).isEnabled();
if (launchLogging && LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Oracle Bedrock " + Bedrock.getVersion() + ": Starting Application...\n" + "------------------------------------------------------------------------\n" + diagnosticsTable.toString() + "\n" + "------------------------------------------------------------------------\n");
}
// ----- start the process and establish the application -----
// create and start the native process
Process process;
try {
process = processBuilder.start(launchOptions);
} catch (IOException e) {
throw new RuntimeException("Failed to build the underlying native process for the application", e);
}
// determine the application class that will represent the running application
Class<? extends Application> applicationClass = metaClass.getImplementationClass(platform, launchOptions);
Application application;
try {
// attempt to find a constructor(Platform, LocalApplicationProcess, Options)
Constructor<? extends Application> constructor = ReflectionHelper.getCompatibleConstructor(applicationClass, platform.getClass(), LocalApplicationProcess.class, OptionsByType.class);
// create the application
application = constructor.newInstance(platform, new LocalApplicationProcess(process), launchOptions);
} catch (Exception e) {
throw new RuntimeException("Failed to instantiate the Application class specified by the MetaClass:" + metaClass, e);
}
// ----- notify the MetaClass that the application has been launched -----
metaClass.onLaunched(platform, application, launchOptions);
for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
profile.onLaunched(platform, application, launchOptions);
}
// notify the ApplicationListener-based Options that the application has been realized
for (ApplicationListener listener : launchOptions.getInstancesOf(ApplicationListener.class)) {
listener.onLaunched(application);
}
return application;
}
use of com.oracle.bedrock.runtime.options.DisplayName in project oracle-bedrock by coherence-community.
the class LocalJavaApplicationLauncher method launch.
@Override
public A launch(Platform platform, MetaClass<A> metaClass, OptionsByType optionsByType) {
// establish the diagnostics output table
Table diagnosticsTable = new Table();
diagnosticsTable.getOptions().add(Table.orderByColumn(0));
if (platform != null) {
diagnosticsTable.addRow("Target Platform", platform.getName());
}
// ----- establish the launch Options for the Application -----
// add the platform options
OptionsByType launchOptions = OptionsByType.of(platform.getOptions().asArray());
// add the meta-class options
metaClass.onLaunching(platform, launchOptions);
// add the launch specific options
launchOptions.addAll(optionsByType);
// ----- establish an identity for the application -----
// add a unique runtime id for expression support
launchOptions.add(Variable.with("bedrock.runtime.id", UUID.randomUUID()));
// ----- establish default Profiles for this Platform (and Builder) -----
// java applications can automatically detect the following profiles
launchOptions.get(RemoteDebugging.class);
launchOptions.get(CommercialFeatures.class);
// auto-detect and add externally defined profiles
launchOptions.addAll(Profiles.getProfiles());
for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
profile.onLaunching(platform, metaClass, launchOptions);
}
// ----- give the MetaClass a last chance to manipulate any options -----
metaClass.onLaunch(platform, launchOptions);
// ----- determine the display name for the application -----
DisplayName displayName = getDisplayName(launchOptions);
// ----- establish the underlying ProcessBuilder -----
// determine the Executable, defaulting to "java" if not defined
Executable executable = launchOptions.getOrSetDefault(Executable.class, Executable.named("java"));
// we'll use the native operating system process builder to create
// and manage the local application process
LocalProcessBuilder processBuilder = createProcessBuilder(executable.getName());
// ----- establish the working directory -----
// set the working directory for the Process
WorkingDirectory workingDirectory = launchOptions.getOrSetDefault(WorkingDirectory.class, WorkingDirectory.currentDirectory());
File directory = workingDirectory.resolve(platform, launchOptions);
// set the resolved working directory back into the options
launchOptions.add(WorkingDirectory.at(directory));
if (directory != null) {
processBuilder.directory(directory);
diagnosticsTable.addRow("Working Directory", directory.toString());
}
// ----- establish environment variables -----
EnvironmentVariables environmentVariables = launchOptions.get(EnvironmentVariables.class);
switch(environmentVariables.getSource()) {
case Custom:
processBuilder.environment().clear();
diagnosticsTable.addRow("Environment Variables", "(cleared)");
break;
case ThisApplication:
Map<String, String> map = System.getenv();
processBuilder.environment().clear();
processBuilder.environment().putAll(map);
diagnosticsTable.addRow("Environment Variables", "(based on parent process)");
break;
case TargetPlatform:
diagnosticsTable.addRow("Environment Variables", "(based on platform defaults)");
break;
}
// add the optionally defined environment variables
Properties variables = environmentVariables.realize(platform, launchOptions.asArray());
for (String variableName : variables.stringPropertyNames()) {
processBuilder.environment().put(variableName, variables.getProperty(variableName));
}
if (variables.size() > 0) {
Table table = Tabularize.tabularize(variables);
diagnosticsTable.addRow("", table.toString());
}
// ----- establish java specific environment variables -----
// by default we use the java home defined by the schema. if that's not
// defined we'll attempt to use the java home defined by this builder.
JavaHome javaHome = launchOptions.get(JavaHome.class);
// (using the system property)
if (javaHome == null) {
javaHome = JavaHome.at(System.getProperty("java.home", null));
}
if (javaHome != null) {
processBuilder.environment().put("JAVA_HOME", StringHelper.doubleQuoteIfNecessary(javaHome.get()));
}
// ----- establish the command to start java -----
String javaExecutable;
if (javaHome == null) {
// when we don't have a java home we just use the defined executable
javaExecutable = StringHelper.doubleQuoteIfNecessary(executable.getName());
} else {
// when we have a java home, we prefix the executable name with the java.home/bin/
String javaHomePath = javaHome.get();
javaHomePath = javaHomePath.trim();
diagnosticsTable.addRow("Java Home", javaHomePath);
if (!javaHomePath.endsWith(File.separator)) {
javaHomePath = javaHomePath + File.separator;
}
javaExecutable = StringHelper.doubleQuoteIfNecessary(javaHomePath + "bin" + File.separator + executable.getName());
}
processBuilder.command(javaExecutable);
diagnosticsTable.addRow("Java Executable", javaExecutable);
// ----- establish the class path -----
JavaModules modular = launchOptions.get(JavaModules.class);
boolean useModules = modular.isEnabled();
// determine the predefined class path based on the launch options
ClassPath classPath = launchOptions.get(ClassPath.class);
try {
// include the ClassPath of the Platform
classPath = new ClassPath(classPath, ClassPath.ofClass(platform.getClass()));
// include the ClassPath of each of the Options
for (Option option : launchOptions.getInstancesOf(Option.class)) {
classPath = new ClassPath(classPath, ClassPath.ofClass(option.getClass()));
}
// include the application runner (if defined)
BedrockRunner bedrockRunner = optionsByType.get(BedrockRunner.class);
if (bedrockRunner != null && bedrockRunner.isEnabled()) {
// include the JavaApplicationLauncher
classPath = new ClassPath(classPath, ClassPath.ofClass(bedrockRunner.getClassOfRunner()));
}
// add the updated ClassPath back into the launch options
launchOptions.add(classPath);
} catch (IOException e) {
throw new RuntimeException("Failed to locate required classes for the class path", e);
}
processBuilder.command().add(useModules ? "--module-path" : "-cp");
processBuilder.command().add(classPath.toString(launchOptions.asArray()));
if (useModules) {
Table modulePathTable = classPath.getTable();
modulePathTable.getOptions().add(Cell.Separator.of(""));
diagnosticsTable.addRow("Module Path", modulePathTable.toString());
ClassPath path = modular.getClassPath();
if (path != null && !path.isEmpty()) {
processBuilder.command().add("-cp");
processBuilder.command().add(path.toString(launchOptions.asArray()));
Table classPathTable = path.getTable();
classPathTable.getOptions().add(Cell.Separator.of(""));
diagnosticsTable.addRow("Class Path", classPathTable.toString());
}
} else {
Table classPathTable = classPath.getTable();
classPathTable.getOptions().add(Cell.Separator.of(""));
diagnosticsTable.addRow("Class Path", classPathTable.toString());
}
String applicationName = displayName.resolve(launchOptions);
// ----- establish Bedrock specific system properties -----
// configure a server channel to communicate with the native process
final SocketBasedRemoteChannelServer server = new SocketBasedRemoteChannelServer(applicationName);
// register the defined RemoteEventListeners with the server so that when the application starts
// the listeners can immediately start receiving RemoteEvents
RemoteEvents remoteEvents = launchOptions.get(RemoteEvents.class);
remoteEvents.forEach((remoteEventListener, listenerOptions) -> server.addListener(remoteEventListener, listenerOptions));
try {
// NOTE: this listens on the wildcard address on an ephemeral port
server.open();
} catch (IOException e) {
throw new RuntimeException("Failed to create remote execution server for the application", e);
}
// add Bedrock specific System Properties
// NOTE: the Bedrock parent address for locally created applications is always "loopback" as
// i). they are always running locally,
// ii). they only need to connect locally, and
// iii). the "loopback" interface should work regardless of the network we're on.
InetAddress parentAddress;
IPv4Preferred iPv4Preferred = launchOptions.get(IPv4Preferred.class);
if (iPv4Preferred.isPreferred()) {
// we have to provide the schema with an IPv4 address!
try {
parentAddress = InetAddress.getByName("127.0.0.1");
} catch (UnknownHostException e) {
// TODO: log that we couldn't determine the loopback address!
parentAddress = InetAddress.getLoopbackAddress();
}
} else {
// when the schema doesn't care, we can default to what this platform chooses
parentAddress = InetAddress.getLoopbackAddress();
}
Table systemPropertiesTable = new Table();
systemPropertiesTable.getOptions().add(Table.orderByColumn(0));
systemPropertiesTable.getOptions().add(Cell.Separator.of(""));
// establish the URI for this (parent) process
String parentURI = "//" + parentAddress.getHostAddress() + ":" + server.getPort();
systemPropertiesTable.addRow(Settings.PARENT_URI, parentURI.toString());
processBuilder.command().add("-D" + Settings.PARENT_URI + "=" + parentURI);
// add Orphanable configuration
Orphanable orphanable = launchOptions.get(Orphanable.class);
processBuilder.command().add("-D" + Settings.ORPHANABLE + "=" + orphanable.isOrphanable());
systemPropertiesTable.addRow(Settings.ORPHANABLE, Boolean.toString(orphanable.isOrphanable()));
// ----- establish the system properties for the java application -----
// define the system properties based on those defined by the launch options
Properties systemProperties = launchOptions.get(SystemProperties.class).resolve(platform, launchOptions);
for (String propertyName : systemProperties.stringPropertyNames()) {
String propertyValue = systemProperties.getProperty(propertyName);
// (we don't want to have "parents" applications effect child applications
if (propertyName.startsWith("bedrock.profile.") || !propertyName.startsWith("bedrock")) {
processBuilder.command().add("-D" + propertyName + (propertyValue.isEmpty() ? "" : "=" + propertyValue));
systemPropertiesTable.addRow(propertyName, propertyValue);
}
}
diagnosticsTable.addRow("System Properties", systemPropertiesTable.toString());
// ----- establish Java Virtual Machine options -----
StringBuilder jvmOptions = new StringBuilder();
for (JvmOption jvmOption : launchOptions.getInstancesOf(JvmOption.class)) {
for (String value : jvmOption.resolve(launchOptions)) {
processBuilder.command().add(value);
if (jvmOptions.length() > 0) {
jvmOptions.append(" ");
}
jvmOptions.append(value);
}
}
if (jvmOptions.length() > 0) {
diagnosticsTable.addRow("Java Options", jvmOptions.toString());
}
for (String propertyName : System.getProperties().stringPropertyNames()) {
if (propertyName.startsWith("bedrock.runtime.inherit.")) {
// resolve the property value
String propertyValue = System.getProperty(propertyName);
// evaluate any expressions in the property value
ExpressionEvaluator evaluator = new ExpressionEvaluator(launchOptions.get(Variables.class));
propertyValue = evaluator.evaluate(propertyValue, String.class);
processBuilder.command().add(propertyValue);
}
}
// ----- establish the application command line to execute -----
// use the launcher to launch the application
// (we don't start the application directly itself)
String applicationLauncherClassName = JavaApplicationRunner.class.getName();
if (useModules) {
applicationLauncherClassName = "com.oracle.bedrock.runtime/" + applicationLauncherClassName;
processBuilder.command().add("-m");
}
processBuilder.command().add(applicationLauncherClassName);
// set the Java application class name we need to launch
ClassName className = launchOptions.get(ClassName.class);
if (className == null) {
throw new IllegalArgumentException("Java Application ClassName not specified");
}
String applicationClassName = className.getName();
processBuilder.command().add(applicationClassName);
diagnosticsTable.addRow("Application Launcher", applicationLauncherClassName);
diagnosticsTable.addRow("Application Class", applicationClassName);
diagnosticsTable.addRow("Application", applicationName);
// ----- included the java arguments to the command -----
List<String> argList = launchOptions.get(Arguments.class).resolve(platform, launchOptions);
// Set the actual arguments used back into the options
launchOptions.add(Arguments.of(argList));
String arguments = "";
for (String argument : argList) {
processBuilder.command().add(argument);
arguments += argument + " ";
}
if (arguments.length() > 0) {
diagnosticsTable.addRow("Application Arguments", arguments);
}
// should the standard error be redirected to the standard out?
ErrorStreamRedirection redirection = launchOptions.get(ErrorStreamRedirection.class);
processBuilder.redirectErrorStream(redirection.isEnabled());
diagnosticsTable.addRow("Standard Error Device", redirection.isEnabled() ? "stdout" : "stderr");
diagnosticsTable.addRow("Application Launch Time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
// TODO: add all of the Profile options to the table
// ----- start the local process -----
boolean launchLogging = optionsByType.get(LaunchLogging.class).isEnabled();
if (launchLogging && LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Oracle Bedrock " + Bedrock.getVersion() + ": Starting Application...\n" + "------------------------------------------------------------------------\n" + diagnosticsTable.toString() + "\n" + "------------------------------------------------------------------------\n");
}
// create and start the native process
Process process;
try {
process = processBuilder.start(launchOptions);
} catch (IOException e) {
throw new RuntimeException("Failed to build the underlying native process for the application", e);
}
// ----- create the local process and application -----
// establish a LocalJavaProcess to represent the underlying Process
LocalJavaApplicationProcess localJavaProcess = new LocalJavaApplicationProcess(process, server, systemProperties);
// determine the application class that will represent the running application
Class<? extends A> applicationClass = metaClass.getImplementationClass(platform, launchOptions);
A application;
try {
// attempt to find a constructor(Platform, JavaApplicationProcess, Options)
Constructor<? extends A> constructor = ReflectionHelper.getCompatibleConstructor(applicationClass, platform.getClass(), localJavaProcess.getClass(), launchOptions.getClass());
// create the application
application = constructor.newInstance(platform, localJavaProcess, launchOptions);
} catch (Exception e) {
throw new RuntimeException("Failed to instantiate the Application class specified by the MetaClass:" + metaClass, e);
}
if (JmxFeature.isSupportedBy(application)) {
application.add(new JmxFeature());
}
// ----- wait for the application to start -----
// ensure that the launcher process connects back to the server to
// know that the application has started
WaitToStart waitToStart = launchOptions.get(WaitToStart.class);
if (waitToStart.isEnabled()) {
Timeout timeout = launchOptions.get(Timeout.class);
ensure(new AbstractDeferred<Boolean>() {
@Override
public Boolean get() throws TemporarilyUnavailableException, PermanentlyUnavailableException {
if (!server.getRemoteChannels().iterator().hasNext()) {
throw new TemporarilyUnavailableException(this);
} else {
return true;
}
}
}, within(timeout));
}
// ----- notify the MetaClass that the application has been launched -----
metaClass.onLaunched(platform, application, launchOptions);
for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
profile.onLaunched(platform, application, launchOptions);
}
// notify the ApplicationListener-based Options that the application has been launched
for (ApplicationListener listener : launchOptions.getInstancesOf(ApplicationListener.class)) {
listener.onLaunched(application);
}
return application;
}
use of com.oracle.bedrock.runtime.options.DisplayName in project oracle-bedrock by coherence-community.
the class ContainerBasedJavaApplicationLauncher method launch.
// TODO: think about what to do with sanity check
// /**
// * Performs a sanity check on the specified {@link JavaApplicationSchema}.
// * <p>
// * It's particularly important to perform sanity checks on {@link Options}
// * prior to realizing them in a container as some settings may not be appropriate or
// * achievable.
// *
// * @param options the {@link Options}
// * @param schemaProperties the system {@link Properties} that have been launched for the
// * {@link JavaApplication}
// */
// protected <T extends A, S extends ApplicationSchema<T>> void sanityCheck(Options options,
// Properties schemaProperties)
// {
// // ensure that if JAVA_NET_PREFER_IPV4_STACK is requested by the schema it has also been
// // established at the platform level as this is only where it can actually be achieved with Java 7+.
// String schemaPreferIPv4Stack = schemaProperties.getProperty(JavaApplication.JAVA_NET_PREFER_IPV4_STACK);
//
// schemaPreferIPv4Stack = schemaPreferIPv4Stack == null ? "" : schemaPreferIPv4Stack.trim().toLowerCase();
//
// String systemPreferIPv4Stack = System.getProperty(JavaApplication.JAVA_NET_PREFER_IPV4_STACK);
//
// systemPreferIPv4Stack = systemPreferIPv4Stack == null ? "" : systemPreferIPv4Stack.trim().toLowerCase();
//
// if (systemPreferIPv4Stack.isEmpty() &&!schemaPreferIPv4Stack.isEmpty())
// {
// LOGGER.warning("The schema [" + schema + "] defines the " + JavaApplication.JAVA_NET_PREFER_IPV4_STACK
// + " system property but it is not defined by the current process."
// + "Container-based applications requiring this system property must have it defined at the operating system level."
// + "eg: In your case it should be defined as; -D" + JavaApplication.JAVA_NET_PREFER_IPV4_STACK + "="
// + schemaPreferIPv4Stack);
// }
// else if (!systemPreferIPv4Stack.equals(schemaPreferIPv4Stack))
// {
// LOGGER.warning("The schema [" + schema + "] defines the " + JavaApplication.JAVA_NET_PREFER_IPV4_STACK
// + " system property but it is not defined by the current process in the same manner."
// + "Container-based applications requiring this system property must have it in the same manner at the operating system level."
// + "eg: In your case it should be defined as; -D" + JavaApplication.JAVA_NET_PREFER_IPV4_STACK + "="
// + schemaPreferIPv4Stack);
// }
//
// // TODO: check that the JavaHome is not set or not different from the current platform setting
// }
@Override
public A launch(Platform platform, MetaClass<A> metaClass, OptionsByType optionsByType) {
// establish the diagnostics output table
Table diagnosticsTable = new Table();
diagnosticsTable.getOptions().add(Table.orderByColumn(0));
if (platform != null) {
diagnosticsTable.addRow("Target Platform", platform.getName());
}
// ----- establish the launch Options for the Application -----
// add the platform options
OptionsByType launchOptions = OptionsByType.of(platform.getOptions().asArray());
// add the meta-class options
metaClass.onLaunching(platform, launchOptions);
// add the launch specific options
launchOptions.addAll(optionsByType);
// ----- establish an identity for the application -----
// add a unique runtime id for expression support
launchOptions.add(Variable.with("bedrock.runtime.id", UUID.randomUUID()));
// ----- establish default Profiles for this Platform (and Builder) -----
// java applications can automatically detect the following profiles
launchOptions.get(RemoteDebugging.class);
launchOptions.get(CommercialFeatures.class);
// auto-detect and add externally defined profiles
launchOptions.addAll(Profiles.getProfiles());
for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
profile.onLaunching(platform, metaClass, launchOptions);
}
// ----- give the MetaClass a last chance to manipulate any options -----
metaClass.onLaunch(platform, launchOptions);
// ----- determine the display name for the application -----
DisplayName displayName = getDisplayName(launchOptions);
// ----- create and start the application in it's own classloader -----
try {
Table systemPropertiesTable = new Table();
systemPropertiesTable.getOptions().add(Table.orderByColumn(0));
systemPropertiesTable.getOptions().add(Cell.Separator.of(""));
// establish the System Properties for the ContainerBasedJavaApplication
Properties systemProperties = launchOptions.get(SystemProperties.class).resolve(platform, launchOptions);
for (String propertyName : systemProperties.stringPropertyNames()) {
String propertyValue = systemProperties.getProperty(propertyName);
systemPropertiesTable.addRow(propertyName, propertyValue);
}
diagnosticsTable.addRow("System Properties", systemPropertiesTable.toString());
// determine the predefined class path based on the launch options
ClassPath classPath = launchOptions.get(ClassPath.class);
Table classPathTable = classPath.getTable();
classPathTable.getOptions().add(Cell.Separator.of(""));
diagnosticsTable.addRow("Class Path", classPathTable.toString());
// establish the ContainerClassLoader for the application
ContainerClassLoader classLoader = ContainerClassLoader.newInstance(displayName.resolve(launchOptions), classPath, systemProperties);
// Get the command line arguments
List<String> argList = launchOptions.get(Arguments.class).resolve(platform, launchOptions);
// Set the actual arguments used back into the options
launchOptions.add(Arguments.of(argList));
// determine the application class that we'll start
ClassName className = launchOptions.get(ClassName.class);
if (className == null) {
throw new IllegalArgumentException("Java Application ClassName not specified");
}
String applicationClassName = className.getName();
// determine the ApplicationController to use to control the process in the container
// (either an ApplicationController provided as an Option or use the MetaClass if it's appropriate)
ApplicationController controller = launchOptions.getOrSetDefault(ApplicationController.class, metaClass instanceof ApplicationController ? (ApplicationController) metaClass : null);
if (controller == null) {
// when an ApplicationController isn't defined, we default to using the
// standard approach of executing the "main" method on the
// specified Application Class
controller = new StandardController(applicationClassName, argList);
// as a courtesy let's make sure the application class is accessible via the classloader
Class<?> applicationClass = classLoader.loadClass(applicationClassName);
}
diagnosticsTable.addRow("Application Class", applicationClassName);
diagnosticsTable.addRow("Application", displayName.resolve(launchOptions));
String arguments = "";
for (String argument : argList) {
arguments += argument + " ";
}
if (arguments.length() > 0) {
diagnosticsTable.addRow("Application Arguments", arguments);
}
diagnosticsTable.addRow("Application Launch Time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Oracle Bedrock " + Bedrock.getVersion() + ": Starting Application...\n" + "------------------------------------------------------------------------\n" + diagnosticsTable.toString() + "\n" + "------------------------------------------------------------------------\n");
}
// establish the ContainerBasedJavaProcess
ContainerBasedJavaApplicationProcess process = new ContainerBasedJavaApplicationProcess(classLoader, controller, systemProperties);
// register the defined RemoteEventListeners before the application starts so they can
// immediately start receiving RemoteEvents
RemoteEvents remoteEvents = launchOptions.get(RemoteEvents.class);
remoteEvents.forEach((remoteEventListener, listenerOptions) -> process.addListener(remoteEventListener, listenerOptions));
// notify the container of the scope to manage
Container.manage(classLoader.getContainerScope());
// start the process
process.start(launchOptions);
// the environment variables for the ContainerBasedJavaApplication
// will be the environment variables for the Java Virtual Machine
Properties environmentVariables = PropertiesBuilder.fromCurrentEnvironmentVariables().realize();
diagnosticsTable.addRow("Environment Variables", "(based on this Java Virtual Machine)");
// determine the application class that will represent the running application
Class<? extends A> applicationClass = metaClass.getImplementationClass(platform, launchOptions);
A application;
try {
// attempt to find a constructor(Platform, JavaApplicationProcess, Options)
Constructor<? extends A> constructor = ReflectionHelper.getCompatibleConstructor(applicationClass, platform.getClass(), process.getClass(), launchOptions.getClass());
// create the application
application = constructor.newInstance(platform, process, launchOptions);
} catch (Exception e) {
throw new RuntimeException("Failed to instantiate the Application class specified by the MetaClass:" + metaClass);
}
if (JmxFeature.isSupportedBy(application)) {
application.add(new JmxFeature());
}
// ----- notify the MetaClass that the application has been launched -----
metaClass.onLaunched(platform, application, launchOptions);
for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
profile.onLaunched(platform, application, launchOptions);
}
// notify the ApplicationListener-based Options that the application has been launched
for (ApplicationListener listener : launchOptions.getInstancesOf(ApplicationListener.class)) {
listener.onLaunched(application);
}
return application;
} catch (Exception e) {
throw new RuntimeException("Failed to start ContainerBasedJavaProcess", e);
}
}
Aggregations