/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2010-2012 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. */ 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 javax.inject.Inject; import javax.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); } } }