blob: d637e0278020342eb3fdb49fbaf78ccccb7d3164 [file] [log] [blame]
/*
* Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package com.sun.enterprise.v3.server;
import com.sun.enterprise.config.serverbeans.Application;
import com.sun.enterprise.config.serverbeans.ApplicationRef;
import com.sun.enterprise.config.serverbeans.Applications;
import com.sun.enterprise.config.serverbeans.Cluster;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.config.serverbeans.ServerTags;
import com.sun.enterprise.module.bootstrap.StartupContext;
import com.sun.enterprise.util.LocalStringManagerImpl;
import com.sun.enterprise.v3.common.HTMLActionReporter;
import java.beans.PropertyChangeEvent;
import java.util.Calendar;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.glassfish.api.ActionReport;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.deployment.UndeployCommandParameters;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.runlevel.RunLevel;
import org.glassfish.internal.api.PostStartupRunLevel;
import org.glassfish.internal.data.ApplicationInfo;
import org.glassfish.internal.data.ApplicationRegistry;
import org.glassfish.internal.deployment.Deployment;
import org.glassfish.kernel.KernelLoggerInfo;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.config.TransactionListener;
import org.jvnet.hk2.config.Transactions;
import org.jvnet.hk2.config.UnprocessedChangeEvents;
@Service
@RunLevel(PostStartupRunLevel.VAL)
public class ApplicationConfigListener implements TransactionListener, PostConstruct {
final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ApplicationConfigListener.class);
final private Logger logger = KernelLoggerInfo.getLogger();
@Inject
Transactions transactions;
@Inject
Domain domain;
@Inject
Applications applications;
@Inject
ApplicationRegistry appRegistry;
@Inject
Deployment deployment;
@Inject
StartupContext startupContext;
@Inject @Named( ServerEnvironment.DEFAULT_INSTANCE_NAME)
Server server;
private final static String UPGRADE_PARAM = "-upgrade";
public void transactionCommited( final List<PropertyChangeEvent> changes) {
boolean isUpdatingAttribute = true;
for (PropertyChangeEvent event : changes) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if (event.getSource() instanceof Applications) {
if (event.getPropertyName().equals(ServerTags.APPLICATION)) {
if (oldValue == null || newValue == null) {
// we are adding/removing application element here
// and updating existing attribute
isUpdatingAttribute = false;
break;
}
}
} else if (event.getSource() instanceof Server ||
event.getSource() instanceof Cluster) {
if (event.getPropertyName().equals(
ServerTags.APPLICATION_REF)) {
if (oldValue == null || newValue == null) {
// we are adding/removing application-ref element here
// and updating existing attribute
isUpdatingAttribute = false;
break;
}
}
}
}
if (!isUpdatingAttribute) {
// if we are not updating existing attribute, we should
// skip the config listener
return;
}
for (PropertyChangeEvent event : changes) {
if (event.getSource() instanceof Application ||
event.getSource() instanceof ApplicationRef) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if (oldValue != null && newValue != null &&
oldValue instanceof String &&
newValue instanceof String &&
!((String)oldValue).equals((String)newValue)) {
// if it's an attribute change of the application
// element or application-ref element
Object parent = event.getSource();
String appName = null;
if (parent instanceof Application) {
appName = ((Application)parent).getName();
} else if (parent instanceof ApplicationRef) {
appName = ((ApplicationRef)parent).getRef();
}
// if it's not a user application, let's not do
// anything
if (applications.getApplication(appName) == null) {
return;
}
if (event.getPropertyName().equals(ServerTags.ENABLED)) {
// enable or disable application accordingly
handleAppEnableChange(event.getSource(),
appName, Boolean.valueOf((String)newValue));
} else if (event.getPropertyName().equals(ServerTags.CONTEXT_ROOT) || event.getPropertyName().equals(ServerTags.VIRTUAL_SERVERS) || event.getPropertyName().equals(ServerTags.AVAILABILITY_ENABLED)) {
// for other changes, reload the application
handleOtherAppConfigChanges(event.getSource(),
appName);
}
}
}
}
}
public void unprocessedTransactedEvents(
List<UnprocessedChangeEvents> changes) {
}
public void postConstruct() {
Properties arguments = startupContext.getArguments();
if (arguments != null) {
boolean isUpgrade = Boolean.valueOf(
arguments.getProperty(UPGRADE_PARAM));
if (isUpgrade) {
// we don't want to register this listener for the upgrade
// start up
return;
}
}
transactions.addTransactionsListener(this);
}
private void handleAppEnableChange(Object parent,
String appName, boolean enabled) {
Application application = applications.getApplication(appName);
if (application.isLifecycleModule()) {
return;
}
if (enabled) {
if (isCurrentInstanceMatchingTarget(parent)) {
enableApplication(appName);
}
} else {
if (isCurrentInstanceMatchingTarget(parent)) {
disableApplication(appName);
}
}
}
private void handleOtherAppConfigChanges(Object parent, String appName) {
Application application = applications.getApplication(appName);
if (application.isLifecycleModule()) {
return;
}
// reload the application for other application related
// config changes if the application is in enabled state
if (isCurrentInstanceMatchingTarget(parent) &&
deployment.isAppEnabled(application)) {
disableApplication(appName);
enableApplication(appName);
}
}
private boolean isCurrentInstanceMatchingTarget(Object parent) {
// DAS receive all the events, so we need to figure out
// whether we should take action on DAS depending on the event
if (parent instanceof ApplicationRef) {
Object grandparent = ((ApplicationRef)parent).getParent();
if (grandparent instanceof Server) {
Server gpServer = (Server)grandparent;
if ( ! server.getName().equals(gpServer.getName())) {
return false;
}
} else if (grandparent instanceof Cluster) {
if (server.isDas()) {
return false;
}
}
}
return true;
}
private void enableApplication(String appName) {
Application app = applications.getApplication(appName);
ApplicationRef appRef = domain.getApplicationRefInServer(server.getName(), appName);
// if the application does not exist or application is not referenced
// by the current server instance, do not load
if (app == null || appRef == null) {
return;
}
// if the application is not in enable state, do not load
if (!deployment.isAppEnabled(app)) {
return;
}
ApplicationInfo appInfo = appRegistry.get(appName);
if (appInfo == null || appInfo.isLoaded()) {
return;
}
long operationStartTime =
Calendar.getInstance().getTimeInMillis();
try {
ActionReport report = new HTMLActionReporter();
deployment.enable(server.getName(), app, appRef, report, logger);
if (report.getActionExitCode().equals(ActionReport.ExitCode.SUCCESS)) {
logger.log(Level.INFO, KernelLoggerInfo.loadingApplicationTime,
new Object[] { appName, (Calendar.getInstance().getTimeInMillis() - operationStartTime)});
} else if (report.getActionExitCode().equals(ActionReport.ExitCode.WARNING)){
logger.log(Level.WARNING, KernelLoggerInfo.loadingApplicationWarning,
new Object[] { appName, report.getMessage()});
} else if (report.getActionExitCode().equals(ActionReport.ExitCode.FAILURE)) {
throw new Exception(report.getMessage());
}
} catch(Exception e) {
logger.log(Level.SEVERE, KernelLoggerInfo.loadingApplicationErrorEnable, e);
throw new RuntimeException(e);
}
}
private void disableApplication(String appName) {
Application app = applications.getApplication(appName);
ApplicationRef appRef = domain.getApplicationRefInServer(server.getName(), appName);
// if the application does not exist or application is not referenced
// by the current server instance, do not unload
if (app == null || appRef == null) {
return;
}
ApplicationInfo appInfo = appRegistry.get(appName);
if (appInfo == null || !appInfo.isLoaded()) {
return;
}
try {
ActionReport report = new HTMLActionReporter();
UndeployCommandParameters commandParams =
new UndeployCommandParameters();
commandParams.name = appName;
commandParams.target = server.getName();
commandParams.origin = UndeployCommandParameters.Origin.unload;
commandParams.command = UndeployCommandParameters.Command.disable;
deployment.disable(commandParams, app, appInfo, report, logger);
if (report.getActionExitCode().equals(ActionReport.ExitCode.FAILURE)) {
throw new Exception(report.getMessage());
}
} catch(Exception e) {
logger.log(Level.SEVERE, KernelLoggerInfo.loadingApplicationErrorDisable, e);
throw new RuntimeException(e);
}
}
}