com.sun.enterprise.v3.server.ApplicationLoaderService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2006-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2017-2022] [Payara Foundation and/or its affiliates]
package com.sun.enterprise.v3.server;
import com.sun.enterprise.config.serverbeans.*;
import com.sun.enterprise.deploy.shared.ArchiveFactory;
import com.sun.enterprise.util.io.FileUtils;
import com.sun.enterprise.admin.report.HTMLActionReporter;
import com.sun.enterprise.v3.bootstrap.BootCommandService;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Provider;
import fish.payara.internal.api.DeployPreviousApplicationsRunLevel;
import org.glassfish.api.ActionReport;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.deployment.DeployCommandParameters;
import org.glassfish.api.deployment.UndeployCommandParameters;
import org.glassfish.api.deployment.archive.ArchiveHandler;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.api.event.EventListener.Event;
import org.glassfish.api.event.EventTypes;
import org.glassfish.api.event.Events;
import org.glassfish.deployment.common.ApplicationConfigInfo;
import org.glassfish.deployment.common.DeploymentContextImpl;
import org.glassfish.deployment.common.DeploymentUtils;
import org.glassfish.deployment.common.InstalledLibrariesResolver;
import org.glassfish.deployment.monitor.DeploymentLifecycleStatsProvider;
import org.glassfish.external.probe.provider.PluginPoint;
import org.glassfish.external.probe.provider.StatsProviderManager;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.runlevel.RunLevel;
import org.glassfish.hk2.utilities.BuilderHelper;
import org.glassfish.internal.data.ApplicationInfo;
import org.glassfish.internal.data.ApplicationRegistry;
import org.glassfish.internal.data.ContainerRegistry;
import org.glassfish.internal.data.EngineInfo;
import org.glassfish.internal.deployment.*;
import org.glassfish.internal.deployment.analysis.StructuredDeploymentTracing;
import org.glassfish.kernel.KernelLoggerInfo;
import org.glassfish.security.services.impl.AuthenticationServiceImpl;
import org.jvnet.hk2.annotations.Optional;
import org.jvnet.hk2.annotations.Service;
/**
* This service is responsible for loading all deployed applications...
*
* @author Jerome Dochez
*/
@Service(name="ApplicationLoaderService")
@RunLevel(value = DeployPreviousApplicationsRunLevel.VAL, mode = RunLevel.RUNLEVEL_MODE_NON_VALIDATING)
// In the wake of the introduction of PostBootRunLevel and DeployPreviousApplicationsRunLevel, should this still be non-validating?
public class ApplicationLoaderService implements org.glassfish.hk2.api.PreDestroy, org.glassfish.hk2.api.PostConstruct {
final Logger logger = KernelLoggerInfo.getLogger();
// During the authentication service's PostConstruct the javax.security.auth.login.Configuration class is constructed.
// During the Configuration initialization a static variable is set to the current thread's context class loader.
// When applications are loaded via this (ApplicationLoaderService) the current thread's context class loader
// is temporarily set. When an application is loaded it will access the authentication service. If the
// authentication service gets initialized at this time then the Configuration construction will happen and its
// static variable will be set to the thread's temporarily set context class loader. Therefore by making
// a reference to the authentication service here we guarantee that it will be created before this
// (ApplicationLoaderService) service is created.
@Inject @Optional
private AuthenticationServiceImpl authenticationService;
@Inject
Deployment deployment;
@Inject
Provider archiveFactoryProvider;
@Inject
SnifferManager snifferManager;
@Inject
ContainerRegistry containerRegistry;
@Inject
ApplicationRegistry appRegistry;
// Explicit dependency, boot command file can contain setup for already deployed applications
@Inject
private BootCommandService bootCommandService;
@Inject
Events events;
@Inject
protected Applications applications;
protected SystemApplications systemApplications;
protected Domain domain;
@Inject @Named( ServerEnvironment.DEFAULT_INSTANCE_NAME)
Server server;
@Inject
ServerEnvironment env;
@Inject
ServiceLocator habitat;
private String deploymentTracingEnabled = null;
private Map appOrderInfoMap = new HashMap();
private int appOrder = 0;
/**
* Starts the application loader service.
*
* Look at the list of applications installed in our local repository
* Get a Deployer capable for each application found
* Invoke the deployer load() method for each application.
*/
@Override
public void postConstruct() {
assert env!=null;
try{
logger.fine("Satisfying Optional Packages dependencies...");
InstalledLibrariesResolver.initializeInstalledLibRegistry(env.getLibPath().getAbsolutePath());
}catch(Exception e){
logger.log(Level.WARNING, KernelLoggerInfo.exceptionOptionalDepend, e);
}
DeploymentLifecycleStatsProvider dlsp = new DeploymentLifecycleStatsProvider();
StatsProviderManager.register("deployment", PluginPoint.SERVER,
"deployment/lifecycle", dlsp);
deploymentTracingEnabled = System.getProperty(
"org.glassfish.deployment.trace");
domain = habitat.getService(Domain.class);
/*
* Build a map that associates an application with its
* order in domain.xml. If the deployment-order attribute
* is not used for any application, then the applications
* are loaded in the order they occur in domain.xml. Also, for
* applications with the same deployment-order attribute,
* the applications are loaded in the order they occur in domain.xml.
* Otherwise, applications are loaded according to the
* deploynment-order attribute.
*/
systemApplications = domain.getSystemApplications();
for (Application systemApp : systemApplications.getApplications()) {
appOrderInfoMap.put(systemApp.getName(), Integer.valueOf(appOrder++));
}
List standaloneAdapters =
applications.getApplicationsWithSnifferType(ServerTags.CONNECTOR, true);
for (Application standaloneAdapter : standaloneAdapters) {
appOrderInfoMap.put(standaloneAdapter.getName(), Integer.valueOf(appOrder++));
}
List allApplications = applications.getApplications();
for (Application app : allApplications) {
appOrderInfoMap.put(app.getName(), Integer.valueOf(appOrder++));
}
for (Application systemApp : systemApplications.getApplications()) {
// check to see if we need to load up this system application
if (Boolean.valueOf(systemApp.getDeployProperties().getProperty
(ServerTags.LOAD_SYSTEM_APP_ON_STARTUP))) {
if (deployment.isAppEnabled(systemApp) || loadAppOnDAS(systemApp.getName())) {
Integer order = appOrderInfoMap.get(systemApp.getName());
ApplicationOrderInfo info = new ApplicationOrderInfo(systemApp, order);
DeploymentOrder.addApplicationDeployment(info);
}
}
}
// load standalone resource adapters first
for (Application standaloneAdapter : standaloneAdapters) {
// load the referenced enabled applications on this instance
// and always (partially) load on DAS when application is
// referenced by non-DAS target so the application
// information is available on DAS
if (deployment.isAppEnabled(standaloneAdapter) || loadAppOnDAS(standaloneAdapter.getName())) {
DeploymentOrder.addApplicationDeployment(new ApplicationOrderInfo(standaloneAdapter, appOrderInfoMap.get(standaloneAdapter.getName()).intValue()));
}
}
// then the rest of the applications
for (Application app : allApplications) {
if (app.isStandaloneModule() &&
app.containsSnifferType(ServerTags.CONNECTOR)) {
continue;
}
ApplicationInfo appDeployment = deployment.get(app.getName());
if (appDeployment != null && appDeployment.isRunning()) {
// skip applications loaded via deploy in postbootcommand file
continue;
}
// load the referenced enabled applications on this instance
// and always (partially) load on DAS when application is
// referenced by non-DAS target so the application
// information is available on DAS
if (Boolean.valueOf(app.getEnabled()) || loadAppOnDAS(app.getName())) {
DeploymentOrder.addApplicationDeployment(new ApplicationOrderInfo(app, appOrderInfoMap.get(app.getName()).intValue()));
}
}
List appDeployments = new ArrayList<>();
// process the deployed applications
Iterator iter = DeploymentOrder.getApplicationDeployments();
while (iter.hasNext()) {
Application app = (Application)iter.next();
ApplicationRef appRef = server.getApplicationRef(app.getName());
if (appRef != null) {
// Does the application need to be run on this instance?
appDeployments.addAll(processApplication(app, appRef));
}
}
// does the user want us to run a particular application
String defaultParam = env.getStartupContext().getArguments().getProperty("default");
if (defaultParam!=null) {
initializeRuntimeDependencies();
File sourceFile;
if (defaultParam.equals(".")) {
sourceFile = new File(System.getProperty("user.dir"));
} else {
sourceFile = new File(defaultParam);
}
if (sourceFile.exists()) {
sourceFile = sourceFile.getAbsoluteFile();
ReadableArchive sourceArchive=null;
try {
sourceArchive = archiveFactoryProvider.get().openArchive(sourceFile);
DeployCommandParameters parameters = new DeployCommandParameters(sourceFile);
parameters.name = sourceFile.getName();
parameters.enabled = Boolean.TRUE;
parameters.origin = DeployCommandParameters.Origin.deploy;
ActionReport report = new HTMLActionReporter();
if (!sourceFile.isDirectory()) {
// ok we need to explode the directory somwhere and remember to delete it on shutdown
final File tmpFile = File.createTempFile(sourceFile.getName(),"");
final String path = tmpFile.getAbsolutePath();
if (!tmpFile.delete()) {
logger.log(Level.WARNING, KernelLoggerInfo.cantDeleteTempFile, path);
}
File tmpDir = new File(path);
FileUtils.deleteOnExit(tmpDir);
events.register(new org.glassfish.api.event.EventListener() {
public void event(Event event) {
if (event.is(EventTypes.SERVER_SHUTDOWN)) {
if (tmpFile.exists()) {
FileUtils.whack(tmpFile);
}
}
}
});
if (tmpDir.mkdirs()) {
ArchiveHandler handler = deployment.getArchiveHandler(sourceArchive);
final String appName = handler.getDefaultApplicationName(sourceArchive);
DeploymentContextImpl dummyContext = new DeploymentContextImpl(report, logger, sourceArchive, parameters, env);
handler.expand(sourceArchive, archiveFactoryProvider.get().createArchive(tmpDir), dummyContext);
sourceArchive =
archiveFactoryProvider.get().openArchive(tmpDir);
logger.log(Level.INFO, KernelLoggerInfo.sourceNotDirectory, tmpDir.getAbsolutePath());
parameters.name = appName;
}
}
ExtendedDeploymentContext depContext = deployment.getBuilder(logger, parameters, report).source(sourceArchive).build();
Deployment.ApplicationDeployment appDeployment = deployment.prepare(null, depContext);
if (appDeployment==null) {
logger.log(Level.SEVERE, KernelLoggerInfo.cantFindApplicationInfo, sourceFile.getAbsolutePath());
}
else {
appDeployments.add(appDeployment);
}
} catch(RuntimeException | IOException e) {
logger.log(Level.SEVERE, KernelLoggerInfo.deployException, e);
} finally {
if (sourceArchive!=null) {
try {
sourceArchive.close();
} catch (IOException ioe) {
// ignore
}
}
}
}
}
events.send(new Event<>(Deployment.ALL_APPLICATIONS_LOADED, null), false);
for (Deployment.ApplicationDeployment depl : appDeployments) {
deployment.initialize(depl.appInfo, depl.appInfo.getSniffers(), depl.context);
}
events.send(new Event<>(Deployment.ALL_APPLICATIONS_PROCESSED, null));
}
private void initializeRuntimeDependencies() {
// ApplicationLoaderService needs to be initialized after
// ManagedBeanManagerImpl. By injecting ManagedBeanManagerImpl,
// we guarantee the initialization order.
habitat.getAllServices(BuilderHelper.createNameFilter("ManagedBeanManagerImpl"));
// ApplicationLoaderService needs to be initialized after
// ResourceManager. By injecting ResourceManager, we guarantee the
// initialization order.
// See https://glassfish.dev.java.net/issues/show_bug.cgi?id=7179
habitat.getAllServices(BuilderHelper.createNameFilter("ResourceManager"));
// Application scoped resource is loaded after ResourceManager
// http://java.net/jira/browse/GLASSFISH-19161
habitat.getAllServices(BuilderHelper.createNameFilter("ApplicationScopedResourcesManager"));
}
public List processApplication(Application app, ApplicationRef appRef) {
long operationStartTime = Calendar.getInstance().getTimeInMillis();
initializeRuntimeDependencies();
String source = app.getLocation();
final String appName = app.getName();
// lifecycle modules are loaded separately
if (Boolean.valueOf(app.getDeployProperties().getProperty(ServerTags.IS_LIFECYCLE))) {
return Collections.emptyList();
}
URI uri;
try {
uri = new URI(source);
} catch (URISyntaxException e) {
logger.log(Level.SEVERE, KernelLoggerInfo.cantDetermineLocation, e.getLocalizedMessage());
return Collections.emptyList();
}
List appDeployments = new ArrayList<>();
File sourceFile = new File(uri);
if (sourceFile.exists()) {
try {
ReadableArchive archive = null;
try {
StructuredDeploymentTracing structuredTracing = deploymentTracingEnabled != null
? StructuredDeploymentTracing.create(app.getName())
: StructuredDeploymentTracing.createDisabled(app.getName());
DeploymentTracing tracing = null;
DeployCommandParameters deploymentParams =
app.getDeployParameters(appRef);
deploymentParams.target = server.getName();
deploymentParams.origin = DeployCommandParameters.Origin.load;
deploymentParams.command = DeployCommandParameters.Command.startup_server;
if (domain.isAppReferencedByPaaSTarget(appName)) {
if (server.isDas()) {
// for loading PaaS application on DAS
// we set it to the real PaaS target
deploymentParams.target = deployment.getDefaultTarget(appName, deploymentParams.origin, deploymentParams._classicstyle);
}
}
archive = archiveFactoryProvider.get().openArchive(sourceFile, deploymentParams);
ActionReport report = new HTMLActionReporter();
ExtendedDeploymentContext depContext = deployment.getBuilder(logger, deploymentParams, report).source(archive).build();
tracing = structuredTracing.register(depContext);
depContext.getAppProps().putAll(app.getDeployProperties());
depContext.setModulePropsMap(app.getModulePropertiesMap());
new ApplicationConfigInfo(app).store(depContext.getAppProps());
appDeployments.add(deployment.prepare(deployment.getSniffersFromApp(app), depContext));
appDeployments.addAll(loadApplicationForTenants(app, appRef, report));
if (report.getActionExitCode().equals(ActionReport.ExitCode.SUCCESS)) {
if (tracing!=null) {
tracing.print(System.out);
}
logger.log(Level.INFO, KernelLoggerInfo.loadingApplicationTime, new Object[] {
appName, (Calendar.getInstance().getTimeInMillis() - operationStartTime)});
} else {
logger.log(Level.SEVERE, KernelLoggerInfo.deployFail, report.getMessage());
}
} finally {
if (archive!=null) {
try {
archive.close();
} catch(IOException e) {
logger.log(Level.FINE, KernelLoggerInfo.deployException, e);
}
}
}
} catch (IOException e) {
logger.log(Level.SEVERE, KernelLoggerInfo.exceptionOpenArtifact, e);
}
} else {
logger.log(Level.SEVERE, KernelLoggerInfo.notFoundInOriginalLocation, source);
}
appDeployments.removeIf(t -> t == null);
return appDeployments;
}
public String toString() {
return "Application Loader";
}
/**
* Stopped all loaded applications
*/
public void preDestroy() {
// stop all running applications including user and system applications
// which are registered in the domain.xml
List allApplications = new ArrayList();
List standaloneAdapters =
applications.getApplicationsWithSnifferType(ServerTags.CONNECTOR, true);
allApplications.addAll(applications.getApplications());
allApplications.addAll(systemApplications.getApplications());
//stop applications that are not of type "standalone" connectors
for (Application app : allApplications) {
if (app.isStandaloneModule() &&
app.containsSnifferType(ServerTags.CONNECTOR)) {
continue;
}
ApplicationInfo appInfo = deployment.get(app.getName());
stopApplication(app, appInfo);
}
//stop applications that are "standalone" connectors
for (Application app : standaloneAdapters) {
ApplicationInfo appInfo = deployment.get(app.getName());
stopApplication(app, appInfo);
}
// now stop the applications which are not registered in the
// domain.xml like timer service application
Set allAppNames = new HashSet();
allAppNames.addAll(appRegistry.getAllApplicationNames());
for (String appName : allAppNames) {
ApplicationInfo appInfo = appRegistry.get(appName);
stopApplication(null, appInfo);
}
// stop all the containers
for (EngineInfo engineInfo : containerRegistry.getContainers()) {
engineInfo.stop(logger);
}
events.send(new Event<>(Deployment.ALL_APPLICATIONS_STOPPED, null), false);
}
private void stopApplication(Application app, ApplicationInfo appInfo) {
final ActionReport dummy = new HTMLActionReporter();
if (appInfo!=null) {
UndeployCommandParameters parameters = new UndeployCommandParameters(appInfo.getName());
parameters.origin = UndeployCommandParameters.Origin.unload;
parameters.command = UndeployCommandParameters.Command.shutdown_server;
try {
deployment.disable(parameters, app, appInfo, dummy, logger);
} catch (Exception e) {
logger.log(Level.SEVERE, KernelLoggerInfo.loadingApplicationErrorDisable, e);
}
unloadApplicationForTenants(app, dummy);
appRegistry.remove(appInfo.getName());
}
}
private void unloadApplicationForTenants(Application app, ActionReport report) {
if (app == null || app.getAppTenants() == null) {
return;
}
for (AppTenant tenant : app.getAppTenants().getAppTenant()) {
UndeployCommandParameters parameters = new UndeployCommandParameters();
parameters.name = DeploymentUtils.getInternalNameForTenant(app.getName(), tenant.getTenant());
parameters.origin = UndeployCommandParameters.Origin.unload;
parameters.target = server.getName();
ApplicationInfo appInfo = deployment.get(parameters.name);
if (appInfo == null) {
continue;
}
ActionReport subReport = report.addSubActionsReport();
try {
ExtendedDeploymentContext deploymentContext = deployment.getBuilder(KernelLoggerInfo.getLogger(), parameters, subReport).source(appInfo.getSource()).build();
deploymentContext.getAppProps().putAll(
app.getDeployProperties());
deploymentContext.getAppProps().putAll(
tenant.getDeployProperties());
deploymentContext.setModulePropsMap(
app.getModulePropertiesMap());
deploymentContext.setTenant(tenant.getTenant(), app.getName());
deployment.unload(appInfo, deploymentContext);
} catch(Throwable e) {
subReport.setActionExitCode(ActionReport.ExitCode.FAILURE);
subReport.setMessage(e.getMessage());
subReport.setFailureCause(e);
}
appRegistry.remove(appInfo.getName());
}
}
private List loadApplicationForTenants(Application app, ApplicationRef appRef, ActionReport report) {
if (app.getAppTenants() == null) {
return Collections.unmodifiableList(Collections.emptyList());
}
List appDeployments = new ArrayList<>();
for (AppTenant tenant : app.getAppTenants().getAppTenant()) {
DeployCommandParameters commandParams = app.getDeployParameters(appRef);
commandParams.contextroot = tenant.getContextRoot();
commandParams.target = server.getName();
commandParams.name = DeploymentUtils.getInternalNameForTenant(app.getName(), tenant.getTenant());
commandParams.enabled = Boolean.TRUE;
commandParams.origin = DeployCommandParameters.Origin.load;
ActionReport subReport = report.addSubActionsReport();
ReadableArchive archive = null;
try {
URI uri = new URI(app.getLocation());
File file = new File(uri);
if (file.exists()) {
archive = archiveFactoryProvider.get().openArchive(file);
ExtendedDeploymentContext deploymentContext =
deployment.getBuilder(KernelLoggerInfo.getLogger(), commandParams, subReport).source(archive).build();
deploymentContext.getAppProps().putAll(app.getDeployProperties());
deploymentContext.getAppProps().putAll(tenant.getDeployProperties());
deploymentContext.setModulePropsMap(app.getModulePropertiesMap());
deploymentContext.setTenant(tenant.getTenant(), app.getName());
appDeployments.add(deployment.prepare(deployment.getSniffersFromApp(app), deploymentContext));
} else {
logger.log(Level.SEVERE, KernelLoggerInfo.notFoundInOriginalLocation, app.getLocation());
}
} catch(Throwable e) {
subReport.setActionExitCode(ActionReport.ExitCode.FAILURE);
subReport.setMessage(e.getMessage());
subReport.setFailureCause(e);
} finally {
try {
if (archive != null) {
archive.close();
}
} catch(IOException e) {
// ignore
}
}
}
return Collections.unmodifiableList(appDeployments);
}
private boolean loadAppOnDAS(String appName) {
if (server.isDas()) {
List targets = domain.getAllReferencedTargetsForApplication(appName);
for (String target : targets) {
if (!DeploymentUtils.isDASTarget(target)) {
// if application is referenced by any non-DAS target
// we need to partially load it on DAS
return true;
}
}
}
return false;
}
}