modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java | 11 modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/authentication/LogoutAction.java | 3 modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/SessionCacheListener.java | 22 + modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesBase.java | 13 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCache.java | 139 -------- modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCacheBean.java | 171 ++++++++++ modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCacheLocal.java | 38 ++ modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java | 36 +- modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java | 31 - modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/LookupUtil.java | 8 10 files changed, 287 insertions(+), 185 deletions(-)
New commits: commit b19c778b7fae320ed14a155602556d083af782c0 Author: John Mazzitelli mazz@redhat.com Date: Thu Sep 13 12:03:20 2012 -0400
fix subject preference cache - making it a ejb singleton also made ShutdownListener a ejb singleton with PreDestroy method
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java index bbdd102..52cae1d 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java @@ -28,7 +28,7 @@ import org.rhq.core.domain.util.PageList; import org.rhq.enterprise.gui.coregui.client.gwt.SubjectGWTService; import org.rhq.enterprise.gui.coregui.server.util.SerialUtility; import org.rhq.enterprise.server.auth.SubjectManagerLocal; -import org.rhq.enterprise.server.auth.prefs.SubjectPreferencesCache; +import org.rhq.enterprise.server.auth.prefs.SubjectPreferencesCacheLocal; import org.rhq.enterprise.server.exception.LoginException; import org.rhq.enterprise.server.util.LookupUtil;
@@ -40,6 +40,7 @@ public class SubjectGWTServiceImpl extends AbstractGWTServiceImpl implements Sub private static final long serialVersionUID = 1L;
private SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager(); + private SubjectPreferencesCacheLocal prefsCache = LookupUtil.getSubjectPreferencesCache(); private Object subjectLock = new Object(); // used to lock out concurrent subject updates
public void createPrincipal(String username, String password) throws RuntimeException { @@ -106,7 +107,7 @@ public class SubjectGWTServiceImpl extends AbstractGWTServiceImpl implements Sub Subject subject = SerialUtility.prepare(modifiedSubject, "SubjectManager.updateSubjectPW"); // Clear the prefs for this subject from the user prefs cache that portal-war uses, in case we just // changed any prefs; otherwise the cache would contain stale prefs. - SubjectPreferencesCache.getInstance().clearConfiguration(subject.getId()); + LookupUtil.getSubjectPreferencesCache().clearConfiguration(subject.getId()); return subject; } catch (Throwable t) { throw getExceptionToThrowToClient(t); @@ -170,8 +171,8 @@ public class SubjectGWTServiceImpl extends AbstractGWTServiceImpl implements Sub subjectToModify = subjectManager.getSubjectById(subjectToModify.getId()); subjectToModify.setUserConfiguration(prefs); } - - Configuration persistedPrefs = SubjectPreferencesCache.getInstance().getPreferences(subjectToModify.getId()); + + Configuration persistedPrefs = prefsCache.getPreferences(subjectToModify.getId());
if (updatePrefs && changedPrefs != null) { Configuration userPrefs = subjectToModify.getUserConfiguration(); @@ -191,7 +192,7 @@ public class SubjectGWTServiceImpl extends AbstractGWTServiceImpl implements Sub
if (updatePrefs) { //clear the prefs cache so that JSF UI refreshes it - SubjectPreferencesCache.getInstance().clearConfiguration(subjectToModify.getId()); + prefsCache.clearConfiguration(subjectToModify.getId()); } }
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/authentication/LogoutAction.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/authentication/LogoutAction.java index b86acae..1a0cfd5 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/authentication/LogoutAction.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/authentication/LogoutAction.java @@ -37,7 +37,6 @@ import org.rhq.enterprise.gui.legacy.WebUser; import org.rhq.enterprise.gui.legacy.util.RequestUtils; import org.rhq.enterprise.gui.legacy.util.SessionUtils; import org.rhq.enterprise.server.auth.SubjectManagerLocal; -import org.rhq.enterprise.server.auth.prefs.SubjectPreferencesCache; import org.rhq.enterprise.server.util.LookupUtil;
public class LogoutAction extends Action { @@ -72,7 +71,7 @@ public class LogoutAction extends Action { if (webUser != null) { Subject subject = webUser.getSubject(); if (subject != null) { - SubjectPreferencesCache.getInstance().clearConfiguration(subject.getId()); + LookupUtil.getSubjectPreferencesCache().clearConfiguration(subject.getId()); } } } diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/SessionCacheListener.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/SessionCacheListener.java index faa8873..caa58b5 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/SessionCacheListener.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/SessionCacheListener.java @@ -1,3 +1,21 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ package org.rhq.enterprise.gui.startup;
import javax.servlet.http.HttpSessionEvent; @@ -6,7 +24,7 @@ import javax.servlet.http.HttpSessionListener; import org.rhq.core.domain.auth.Subject; import org.rhq.enterprise.gui.legacy.WebUser; import org.rhq.enterprise.gui.legacy.util.SessionUtils; -import org.rhq.enterprise.server.auth.prefs.SubjectPreferencesCache; +import org.rhq.enterprise.server.util.LookupUtil;
public class SessionCacheListener implements HttpSessionListener {
@@ -19,7 +37,7 @@ public class SessionCacheListener implements HttpSessionListener { if (webUser != null) { Subject subject = webUser.getSubject(); if (subject != null) { - SubjectPreferencesCache.getInstance().clearConfiguration(subject.getId()); + LookupUtil.getSubjectPreferencesCache().clearConfiguration(subject.getId()); } } } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesBase.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesBase.java index 5b1b980..e8ef7c3 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesBase.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesBase.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. + * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -20,9 +20,7 @@ package org.rhq.enterprise.server.auth.prefs;
import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -30,6 +28,7 @@ import org.apache.commons.logging.LogFactory; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.util.StringUtil; +import org.rhq.enterprise.server.util.LookupUtil;
public abstract class SubjectPreferencesBase {
@@ -41,11 +40,9 @@ public abstract class SubjectPreferencesBase { protected static final String PREF_ITEM_DELIM_REGEX = "\|";
private int subjectId; - private Set<String> changed;
public SubjectPreferencesBase(Subject subject) { this.subjectId = subject.getId(); - this.changed = new HashSet<String>(); }
/** @@ -117,7 +114,7 @@ public abstract class SubjectPreferencesBase { }
protected String getPreference(String key) throws IllegalArgumentException { - PropertySimple prop = SubjectPreferencesCache.getInstance().getUserProperty(subjectId, key); + PropertySimple prop = LookupUtil.getSubjectPreferencesCache().getUserProperty(subjectId, key);
if (prop == null) { if (this.subjectId == 0) { @@ -239,10 +236,10 @@ public abstract class SubjectPreferencesBase { val = value.toString(); }
- SubjectPreferencesCache.getInstance().setUserProperty(subjectId, key, val); + LookupUtil.getSubjectPreferencesCache().setUserProperty(subjectId, key, val); }
protected void unsetPreference(String key) { - SubjectPreferencesCache.getInstance().unsetUserProperty(subjectId, key); + LookupUtil.getSubjectPreferencesCache().unsetUserProperty(subjectId, key); } } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCache.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCache.java deleted file mode 100644 index d88bd85..0000000 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCache.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.rhq.enterprise.server.auth.prefs; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.rhq.core.domain.auth.Subject; -import org.rhq.core.domain.configuration.Configuration; -import org.rhq.core.domain.configuration.Property; -import org.rhq.core.domain.configuration.PropertySimple; -import org.rhq.enterprise.server.auth.SubjectManagerLocal; -import org.rhq.enterprise.server.common.EntityManagerFacadeLocal; -import org.rhq.enterprise.server.configuration.ConfigurationManagerLocal; -import org.rhq.enterprise.server.util.LookupUtil; - -public class SubjectPreferencesCache { - - protected final Log log = LogFactory.getLog(SubjectPreferencesCache.class); - - private Map<Integer, Configuration> subjectPreferences; - - private static final SubjectPreferencesCache instance = new SubjectPreferencesCache(); - - private SubjectManagerLocal subjectManager; - private EntityManagerFacadeLocal entityManagerFacade; - private ConfigurationManagerLocal configurationManager; - - private SubjectPreferencesCache() { - subjectPreferences = new HashMap<Integer, Configuration>(); - subjectManager = LookupUtil.getSubjectManager(); - entityManagerFacade = LookupUtil.getEntityManagerFacade(); - configurationManager = LookupUtil.getConfigurationManager(); - } - - public static SubjectPreferencesCache getInstance() { - return instance; - } - - private void load(int subjectId) { - // if subject ID is 0, it probably means this is a new LDAP user that needs to be registered - if (subjectId != 0 && !subjectPreferences.containsKey(subjectId)) { - try { - Subject subject = subjectManager.loadUserConfiguration(subjectId); - Configuration configuration = subject.getUserConfiguration(); - subjectPreferences.put(subjectId, configuration); - } catch (Throwable t) { - log.warn("Can not get preferences for subject[id=" + subjectId + "], subject does not exist yet"); - } - } - } - - public synchronized PropertySimple getUserProperty(int subjectId, String propertyName) { - load(subjectId); - - Configuration config = subjectPreferences.get(subjectId); - if (config == null) { - return null; - } - - PropertySimple prop = config.getSimple(propertyName); - if (prop == null) { - return null; - } - - return new PropertySimple(propertyName, prop.getStringValue()); - } - - public synchronized void setUserProperty(int subjectId, String propertyName, String value) { - load(subjectId); - - Configuration config = subjectPreferences.get(subjectId); - if (config == null) { - return; - } - - PropertySimple prop = config.getSimple(propertyName); - if (prop == null) { - prop = new PropertySimple(propertyName, value); - config.put(prop); // add new to collection - mergeProperty(prop); - } else if (prop.getStringValue() == null || !prop.getStringValue().equals(value)) { - prop.setStringValue(value); - mergeProperty(prop); - } - } - - private void mergeProperty(PropertySimple prop) { - // merge will persist if property doesn't exist (i.e., id = 0) - PropertySimple mergedProperty = entityManagerFacade.merge(prop); // only merge changes - if (prop.getId() == 0) { - // so subsequent merges do not continue re-persisting property as new - prop.setId(mergedProperty.getId()); - } - } - - public synchronized void unsetUserProperty(int subjectId, String propertyName) { - load(subjectId); - - Configuration config = subjectPreferences.get(subjectId); - if (config == null) { - return; - } - - Property property = config.remove(propertyName); - // it's possible property was already removed, and thus this operation becomes a no-op to the backing store - if (property != null && property.getId() != 0) { - try { - configurationManager.deleteProperties(new int[] { property.getId() }); - } catch (Throwable t) { - log.error("Could not remove " + property, t); - } - } - } - - /** - * @param subjectId the subject to get preferences of - * @return the <b>COPY</b> of the configuration object - changes done to that instance will not be reflected in the persisted - * preferences - */ - public synchronized Configuration getPreferences(int subjectId) { - load(subjectId); - - Configuration config = subjectPreferences.get(subjectId); - if (config == null) { - return new Configuration(); - } else { - return config.deepCopy(); - } - } - - public synchronized void clearConfiguration(int subjectId) { - if (log.isTraceEnabled()) { - log.trace("Removing PreferencesCache For " + subjectId); - } - subjectPreferences.remove(subjectId); - } -} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCacheBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCacheBean.java new file mode 100644 index 0000000..d196d07 --- /dev/null +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCacheBean.java @@ -0,0 +1,171 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.enterprise.server.auth.prefs; + +import java.util.HashMap; +import java.util.Map; + +import javax.ejb.ConcurrencyManagement; +import javax.ejb.ConcurrencyManagementType; +import javax.ejb.EJB; +import javax.ejb.Lock; +import javax.ejb.LockType; +import javax.ejb.Singleton; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.rhq.core.domain.auth.Subject; +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.Property; +import org.rhq.core.domain.configuration.PropertySimple; +import org.rhq.enterprise.server.auth.SubjectManagerLocal; +import org.rhq.enterprise.server.common.EntityManagerFacadeLocal; +import org.rhq.enterprise.server.configuration.ConfigurationManagerLocal; + +@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) +@Singleton +public class SubjectPreferencesCacheBean implements SubjectPreferencesCacheLocal { + + protected final Log log = LogFactory.getLog(SubjectPreferencesCacheBean.class); + + private Map<Integer, Configuration> subjectPreferences; + + @EJB + private SubjectManagerLocal subjectManager; + + @EJB + private EntityManagerFacadeLocal entityManagerFacade; + + @EJB + private ConfigurationManagerLocal configurationManager; + + private SubjectPreferencesCacheBean() { + subjectPreferences = new HashMap<Integer, Configuration>(); + } + + private void load(int subjectId) { + // if subject ID is 0, it probably means this is a new LDAP user that needs to be registered + if (subjectId != 0 && !subjectPreferences.containsKey(subjectId)) { + try { + Subject subject = subjectManager.loadUserConfiguration(subjectId); + Configuration configuration = subject.getUserConfiguration(); + subjectPreferences.put(subjectId, configuration); + } catch (Throwable t) { + log.warn("Can not get preferences for subject[id=" + subjectId + "], subject does not exist yet"); + } + } + } + + @Override + @Lock(LockType.READ) + public PropertySimple getUserProperty(int subjectId, String propertyName) { + load(subjectId); + + Configuration config = subjectPreferences.get(subjectId); + if (config == null) { + return null; + } + + PropertySimple prop = config.getSimple(propertyName); + if (prop == null) { + return null; + } + + return new PropertySimple(propertyName, prop.getStringValue()); + } + + @Override + @Lock(LockType.WRITE) + public void setUserProperty(int subjectId, String propertyName, String value) { + load(subjectId); + + Configuration config = subjectPreferences.get(subjectId); + if (config == null) { + return; + } + + PropertySimple prop = config.getSimple(propertyName); + if (prop == null) { + prop = new PropertySimple(propertyName, value); + config.put(prop); // add new to collection + mergeProperty(prop); + } else if (prop.getStringValue() == null || !prop.getStringValue().equals(value)) { + prop.setStringValue(value); + mergeProperty(prop); + } + } + + private void mergeProperty(PropertySimple prop) { + // merge will persist if property doesn't exist (i.e., id = 0) + PropertySimple mergedProperty = entityManagerFacade.merge(prop); // only merge changes + if (prop.getId() == 0) { + // so subsequent merges do not continue re-persisting property as new + prop.setId(mergedProperty.getId()); + } + } + + @Override + @Lock(LockType.WRITE) + public void unsetUserProperty(int subjectId, String propertyName) { + load(subjectId); + + Configuration config = subjectPreferences.get(subjectId); + if (config == null) { + return; + } + + Property property = config.remove(propertyName); + // it's possible property was already removed, and thus this operation becomes a no-op to the backing store + if (property != null && property.getId() != 0) { + try { + configurationManager.deleteProperties(new int[] { property.getId() }); + } catch (Throwable t) { + log.error("Could not remove " + property, t); + } + } + } + + /** + * @param subjectId the subject to get preferences of + * @return the <b>COPY</b> of the configuration object - changes done to that instance will not be reflected in the persisted + * preferences + */ + @Override + @Lock(LockType.READ) + public Configuration getPreferences(int subjectId) { + load(subjectId); + + Configuration config = subjectPreferences.get(subjectId); + if (config == null) { + return new Configuration(); + } else { + return config.deepCopy(); + } + } + + @Override + @Lock(LockType.WRITE) + public void clearConfiguration(int subjectId) { + if (log.isTraceEnabled()) { + log.trace("Removing PreferencesCache For " + subjectId); + } + subjectPreferences.remove(subjectId); + } +} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCacheLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCacheLocal.java new file mode 100644 index 0000000..73e82e7 --- /dev/null +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/prefs/SubjectPreferencesCacheLocal.java @@ -0,0 +1,38 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.enterprise.server.auth.prefs; + +import javax.ejb.Local; + +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.PropertySimple; + +@Local +public interface SubjectPreferencesCacheLocal { + + PropertySimple getUserProperty(int subjectId, String propertyName); + + void setUserProperty(int subjectId, String propertyName, String value); + + void unsetUserProperty(int subjectId, String propertyName); + + Configuration getPreferences(int subjectId); + + void clearConfiguration(int subjectId); +} \ No newline at end of file diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java index 5194fb6..f8dca66 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java @@ -23,9 +23,10 @@ import java.sql.SQLException; import java.sql.Statement;
import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import javax.ejb.EJB; import javax.ejb.Singleton; import javax.ejb.Startup; -import javax.management.Notification; import javax.sql.DataSource;
import org.apache.commons.logging.Log; @@ -34,7 +35,10 @@ import org.apache.commons.logging.LogFactory; import org.rhq.core.domain.cloud.Server; import org.rhq.core.domain.cloud.Server.OperationMode; import org.rhq.core.util.jdbc.JDBCUtil; -import org.rhq.enterprise.server.util.LookupUtil; +import org.rhq.enterprise.server.RHQConstants; +import org.rhq.enterprise.server.cloud.CloudManagerLocal; +import org.rhq.enterprise.server.cloud.instance.ServerManagerLocal; +import org.rhq.enterprise.server.scheduler.SchedulerLocal;
/** * This listens for the RHQ server's shutdown notification and when it hears it, will start shutting down RHQ components @@ -47,13 +51,22 @@ import org.rhq.enterprise.server.util.LookupUtil; @Singleton @Startup public class ShutdownListener { - /** - * Logger - */ private final Log log = LogFactory.getLog(ShutdownListener.class);
private final String RHQ_DB_TYPE_MAPPING_PROPERTY = "rhq.server.database.type-mapping";
+ @EJB + private SchedulerLocal schedulerBean; + + @EJB + private ServerManagerLocal serverManager; + + @EJB + private CloudManagerLocal cloudManager; + + @Resource(name = "RHQ_DS", mappedName = RHQConstants.DATASOURCE_JNDI_NAME) + private DataSource dataSource; + /** * This is called when the shutdown notification is received from the JBoss server. This gives a chance for us to * cleanly shutdown our application in an orderly fashion. @@ -61,12 +74,14 @@ public class ShutdownListener { * @see javax.management.NotificationListener#handleNotification(Notification, Object) */ @PreDestroy - public void handleNotification(Notification notification, Object handback) { + public void handleNotification() { // JBossAS 4.2.3 used to send us this JMX notification on shutdown - AS7 does not have shutdown notifications. // So we are using the @PreDestroy mechanism on a singleton EJB to attempt to clean up the application before it is shutdown + log.info("Shutdown listener has been told we are shutting down - starting to clean up now..."); stopScheduler(); updateServerOperationMode(); stopEmbeddedDatabase(); + log.info("Shutdown listener completed its shutdown tasks. It is safe to shutdown now."); }
/** @@ -75,7 +90,7 @@ public class ShutdownListener { private void stopScheduler() { try { log.info("Shutting down the scheduler gracefully - currently running jobs will be allowed to finish..."); - LookupUtil.getSchedulerBean().shutdown(true); + schedulerBean.shutdown(true); log.info("The scheduler has been shutdown and all jobs are done."); } catch (Throwable t) { // only show ugly stack traces if the user runs the server in debug mode @@ -90,9 +105,9 @@ public class ShutdownListener { private void updateServerOperationMode() { try { // Set the server operation mode to DOWN unless in MM - Server server = LookupUtil.getServerManager().getServer(); + Server server = serverManager.getServer(); if (Server.OperationMode.MAINTENANCE != server.getOperationMode()) { - LookupUtil.getCloudManager().updateServerMode(new Integer[] { server.getId() }, OperationMode.DOWN); + cloudManager.updateServerMode(new Integer[] { server.getId() }, OperationMode.DOWN); } } catch (Throwable t) { // only show ugly stack traces if the user runs the server in debug mode @@ -113,8 +128,7 @@ public class ShutdownListener { Connection connection = null; Statement statement = null; try { - DataSource ds = LookupUtil.getDataSource(); - connection = ds.getConnection(); + connection = dataSource.getConnection(); statement = connection.createStatement(); statement.execute("shutdown"); log.info("Embedded database closed cleanly"); diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java index c5b0823..e1ef4a8 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Properties;
import javax.annotation.PostConstruct; +import javax.annotation.Resource; import javax.ejb.EJB; import javax.ejb.Singleton; import javax.ejb.Startup; @@ -49,10 +50,10 @@ import org.rhq.core.domain.resource.Agent; import org.rhq.core.util.ObjectNameFactory; import org.rhq.enterprise.communications.ServiceContainerConfigurationConstants; import org.rhq.enterprise.communications.util.SecurityUtil; +import org.rhq.enterprise.server.RHQConstants; import org.rhq.enterprise.server.alert.engine.internal.AlertConditionCacheCoordinator; import org.rhq.enterprise.server.auth.SessionManager; import org.rhq.enterprise.server.auth.SubjectManagerLocal; -import org.rhq.enterprise.server.auth.prefs.SubjectPreferencesCache; import org.rhq.enterprise.server.cloud.CloudManagerLocal; import org.rhq.enterprise.server.cloud.instance.CacheConsistencyManagerLocal; import org.rhq.enterprise.server.cloud.instance.ServerManagerLocal; @@ -84,6 +85,8 @@ import org.rhq.enterprise.server.util.concurrent.AvailabilityReportSerializer; * This startup singleton EJB performs the rest of the RHQ Server startup initialization. * In order for it to do its work properly, we must ensure everything has been deployed and started; * specifically, all EJBs must have been deployed and available. + * + * This bean is not meant for client consumption - it is only for startup initialization. */ @Singleton @Startup @@ -116,6 +119,9 @@ public class StartupBean { @EJB private SubjectManagerLocal subjectManager;
+ @Resource(name = "RHQ_DS", mappedName = RHQConstants.DATASOURCE_JNDI_NAME) + private DataSource dataSource; + /** * Performs the final RHQ Server initialization work that needs to talk place. EJBs are available in this method. * @@ -133,7 +139,6 @@ public class StartupBean { // get singletons right now so we load the classes immediately into our classloader AlertConditionCacheCoordinator.getInstance(); SessionManager.getInstance(); - SubjectPreferencesCache.getInstance(); AlertSerializer.getSingleton(); AvailabilityReportSerializer.getSingleton();
@@ -179,8 +184,7 @@ public class StartupBean { // Ensure the class is loaded and the dbType is set for our current db Connection conn = null; try { - DataSource ds = LookupUtil.getDataSource(); - conn = ds.getConnection(); + conn = dataSource.getConnection(); DatabaseTypeFactory.setDefaultDatabaseType(DatabaseTypeFactory.getDatabaseType(conn)); } catch (Exception e) { log.error("Could not initialize server.", e); @@ -683,24 +687,17 @@ public class StartupBean { }
/** - * Registers a listener to the JBoss server's shutdown notification so some components can be cleaned up in an + * Registers a listener to the system shutdown notification so some components can be cleaned up in an * orderly fashion when the server is shutdown. * - * @throws RuntimeException if cannot register this service as a shutdown listener + * @throws RuntimeException if cannot register a shutdown listener */ private void registerShutdownListener() throws RuntimeException { // as of JBossAS 4.0.5, this is the known MBean name of the service that notifies when the server is shutting down - // TODO: find out how AS7 can notify us when its going down - right now, this code won't work on AS7 - /* - try { - ObjectName jbossServerName = new ObjectName("jboss.system:type=Server"); - MBeanServer jbossServer = ManagementFactory.getPlatformMBeanServer(); - jbossServer.addNotificationListener(jbossServerName, new ShutdownListener(), null, null); - } catch (Exception e) { - throw new RuntimeException("Failed to register the Server Shutdown Listener", e); - } - */ - log.warn("!!! TODO: REGISTER OUR SHUTDOWN LISTENER!!!"); + // AS7 today does not have notifications like this. So we have a new EJB singleton ShutdownListener with a PreDestroy method. + // If that doesn't work, we can try to create a system shutdown hook in here. Thus I'm leaving this method in here in case + // we need it later. Just add a Runtime.addShutdownHook call in here that calls our ShutdownListener. + return; }
/** diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/LookupUtil.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/LookupUtil.java index 313f295..183fc3e 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/LookupUtil.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/LookupUtil.java @@ -53,6 +53,8 @@ import org.rhq.enterprise.server.alert.engine.jms.CachedConditionProducerBean; import org.rhq.enterprise.server.alert.engine.jms.CachedConditionProducerLocal; import org.rhq.enterprise.server.auth.SubjectManagerBean; import org.rhq.enterprise.server.auth.SubjectManagerLocal; +import org.rhq.enterprise.server.auth.prefs.SubjectPreferencesCacheBean; +import org.rhq.enterprise.server.auth.prefs.SubjectPreferencesCacheLocal; import org.rhq.enterprise.server.authz.AuthorizationManagerBean; import org.rhq.enterprise.server.authz.AuthorizationManagerLocal; import org.rhq.enterprise.server.authz.RoleManagerBean; @@ -604,7 +606,11 @@ public final class LookupUtil { public static PlatformUtilizationManagerLocal getPlatformUtilizationManager() { return lookupLocal(PlatformUtilizationManagerBean.class); } - + + public static SubjectPreferencesCacheLocal getSubjectPreferencesCache() { + return lookupLocal(SubjectPreferencesCacheBean.class); + } + public static CoreServerMBean getCoreServer() { CoreServerMBean rhqServer; try {
rhq-commits@lists.fedorahosted.org