
org.sakaiproject.component.impl.SpringCompMgr Maven / Gradle / Ivy
/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/kernel/tags/sakai-10.7/component-manager/src/main/java/org/sakaiproject/component/impl/SpringCompMgr.java $
* $Id: SpringCompMgr.java 105077 2012-02-24 22:54:29Z [email protected] $
***********************************************************************************
*
* Copyright (c) 2005, 2006, 2007, 2008 Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.component.impl;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.component.api.ComponentManager;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.component.api.ServerConfigurationService.ConfigData;
import org.sakaiproject.util.ComponentsLoader;
import org.sakaiproject.util.SakaiApplicationContext;
import org.sakaiproject.util.SakaiComponentEvent;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ConfigurableApplicationContext;
/**
*
* SpringCompMgr manages API implementation components using the Springframework
* ApplicationContext.
*
*
* See the {@link org.sakaiproject.api.kernel.component.ComponentManager}interface
* for details.
*
*/
public class SpringCompMgr implements ComponentManager {
/** Our log (commons). */
private static Log M_log = LogFactory.getLog(SpringCompMgr.class);
/**
* System property to control if we close on jvm shutdown (if set) or on the
* loss of our last child (if not set).
*/
protected final static String CLOSE_ON_SHUTDOWN = "sakai.component.closeonshutdown";
/**
* System property to control if we close the jvm on a error occurring at startup.
* This is useful to set in development so that it's clearer when the component manager
* failed to startup.
*/
protected final static String SHUTDOWN_ON_ERROR = "sakai.component.shutdownonerror";
/**
* The Sakai configuration component package, which must be the last
* defined.
*/
protected final static String CONFIGURATION_COMPONENT_PACKAGE = "sakai-component-pack";
/** The Sakai configuration components, which must be the first loaded. */
protected final static String[] CONFIGURATION_COMPONENTS = {
"org.sakaiproject.component.SakaiPropertyPromoter",
"org.sakaiproject.log.api.LogConfigurationManager" };
protected final static String DEFAULT_CONFIGURATION_FILE = "classpath:/org/sakaiproject/config/sakai-configuration.xml";
protected final static String CONFIGURATION_FILE_NAME = "sakai-configuration.xml";
/** The Spring Application Context. */
protected SakaiApplicationContext m_ac = null;
/** The already created components given to manage (their interface names). */
protected Set m_loadedComponents = new HashSet();
/** A count of the # of child AC's that call us parent. */
protected int m_childCount = 0;
/** Records that close has been called. */
protected boolean m_hasBeenClosed = false;
/**
* Initialize.
*
* @param parent
* A ComponentManager in which this one gets nested, or NULL if
* this is this top one.
*/
public SpringCompMgr(ComponentManager parent) {
// Note: don't init here, init after it's fully constructed
// (and if it's being constructed by the cover, after the cover has set
// it's instance variable).
// othewise when singletons are instantiated, if they call a Cover or
// Discovery in the init(),
// the component manager cover will not yet have this object! -ggolden
}
/**
* Initialize the component manager.
*
* @param lateRefresh If true
then don't refresh the application context
* but leave it up to the caller, this is useful when running tests as it means you
* can change the application context before everything gets setup. In production
* systems it should be false
.
*/
public void init(boolean lateRefresh) {
if (m_ac != null)
return;
// Make sure a "sakai.home" system property is set.
ensureSakaiHome();
checkSecurityPath();
m_ac = new SakaiApplicationContext();
m_ac.setInitialSingletonNames(CONFIGURATION_COMPONENTS);
List configLocationList = new ArrayList();
configLocationList.add(DEFAULT_CONFIGURATION_FILE);
String localConfigLocation = System.getProperty("sakai.home")
+ CONFIGURATION_FILE_NAME;
File configFile = new File(localConfigLocation);
if (configFile.exists()) {
configLocationList.add("file:" + localConfigLocation);
}
m_ac.setConfigLocations(configLocationList.toArray(new String[0]));
// load component packages
loadComponents();
// if configured (with the system property CLOSE_ON_SHUTDOWN set),
// create a shutdown task to close when the JVM closes
// (otherwise we will close in removeChildAc() when the last child is gone)
if (System.getProperty(CLOSE_ON_SHUTDOWN) != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
close();
}
});
}
if (!lateRefresh) {
try {
// get the singletons loaded
m_ac.refresh();
m_ac.publishEvent(new SakaiComponentEvent(this, SakaiComponentEvent.Type.STARTED));
} catch (Exception e) {
if (Boolean.valueOf(System.getProperty(SHUTDOWN_ON_ERROR, "false"))) {
M_log.fatal(e.getMessage(), e);
M_log.fatal("Shutting down JVM");
System.exit(1);
} else {
M_log.warn(e.getMessage(), e);
}
}
}
// dump the configuration values out
try {
final ServerConfigurationService scs = (ServerConfigurationService) this.get(ServerConfigurationService.class);
if (scs != null) {
ConfigData cd = scs.getConfigData();
M_log.info("Configuration loaded "+cd.getTotalConfigItems()+" values, "+cd.getRegisteredConfigItems()+" registered");
if (scs.getBoolean("config.dump.to.log", false)) {
// output the config logs now and then output then again in 120 seconds
M_log.info("Configuration values:\n" + cd.toString());
Timer timer = new Timer(true);
timer.schedule(new TimerTask() {
@Override
public void run() {
M_log.info("Configuration values: (delay 1):\n" + scs.getConfigData().toString());
}
}, 120*1000);
timer.schedule(new TimerTask() {
@Override
public void run() {
M_log.info("Configuration values: (delay 2):\n" + scs.getConfigData().toString());
}
}, 300*1000);
}
} else {
// probably testing so just say we cannot dump the config
M_log.warn("Configuration: Unable to get and dump out the registered server config values because no ServerConfigurationService is available - this is OK if this is part of a test, this is very bad otherwise");
}
} catch (Exception e) {
M_log.error("Configuration: Unable to get and dump out the registered server config values (config.dump.to.log): "+e, e);
}
}
/**
* Access the ApplicationContext
*
* @return the ApplicationContext
*/
public ConfigurableApplicationContext getApplicationContext() {
return m_ac;
}
/**
* {@inheritDoc}
*/
public Object get(Class iface) {
Object component = null;
try {
component = m_ac.getBean(iface.getName(), iface);
} catch (NoSuchBeanDefinitionException e) {
// This is an expected outcome, we don't usually want logs
if (M_log.isDebugEnabled()) {
M_log.debug("get(" + iface.getName() + "): " + e, e);
}
} catch (Exception e) {
M_log.warn("get(" + iface.getName() + "): ", e);
}
return component;
}
/**
* {@inheritDoc}
*/
public Object get(String ifaceName) {
Object component = null;
try {
component = m_ac.getBean(ifaceName);
} catch (NoSuchBeanDefinitionException e) {
// This is an expected outcome, we don't usually want logs
if (M_log.isDebugEnabled()) {
M_log.debug("get(" + ifaceName + "): " + e, e);
}
} catch (Exception e) {
M_log.warn("get(" + ifaceName + "): ", e);
}
return component;
}
/**
* {@inheritDoc}
*/
public boolean contains(Class iface) {
boolean found = m_ac.containsBeanDefinition(iface.getName());
return found;
}
/**
* {@inheritDoc}
*/
public boolean contains(String ifaceName) {
boolean found = m_ac.containsBeanDefinition(ifaceName);
return found;
}
/**
* {@inheritDoc}
*/
public Set getRegisteredInterfaces() {
Set rv = new HashSet();
// get the registered ones
String[] names = m_ac.getBeanDefinitionNames();
for (int i = 0; i < names.length; i++) {
rv.add(names[i]);
}
// add the loaded ones
for (Iterator iLoaded = m_loadedComponents.iterator(); iLoaded
.hasNext();) {
String loaded = (String) iLoaded.next();
rv.add(loaded);
}
return rv;
}
/**
* {@inheritDoc}
*/
public void close() {
m_hasBeenClosed = true;
if(m_ac.isActive()) {
m_ac.publishEvent(new SakaiComponentEvent(this, SakaiComponentEvent.Type.STOPPING));
}
m_ac.close();
}
/**
* {@inheritDoc}
*/
public void loadComponent(Class iface, Object component) {
// Spring doesn't list these in getBeanDefinitionNames, so we keep track
m_loadedComponents.add(iface.getName());
m_ac.getBeanFactory().registerSingleton(iface.getName(), component);
}
/**
* {@inheritDoc}
*/
public void loadComponent(String ifaceName, Object component) {
// Spring doesn't list these in getBeanDefinitionNames, so we keep track
m_loadedComponents.add(ifaceName);
m_ac.getBeanFactory().registerSingleton(ifaceName, component);
}
/**
* Locate the component loader, and load any available components.
*/
protected void loadComponents() {
ComponentsLoader loader = new ComponentsLoader();
// locate the components root
// if we have our system property set, use it
String componentsRoot = System
.getProperty(SAKAI_COMPONENTS_ROOT_SYS_PROP);
if (componentsRoot == null) {
// if we are in Catalina, place it at ${catalina.home}/components/
String catalina = getCatalina();
if (catalina != null) {
componentsRoot = catalina + File.separatorChar + "components"
+ File.separatorChar;
}
}
if (componentsRoot == null) {
M_log
.warn("loadComponents: cannot estabish a root directory for the components packages");
return;
}
// make sure this is set
System.setProperty(SAKAI_COMPONENTS_ROOT_SYS_PROP, componentsRoot);
// load components
loader.load(m_ac, componentsRoot);
}
/**
* Increment the count of ACs that call this one parent.
*/
public synchronized void addChildAc() {
m_childCount++;
}
/**
* Decrement the count of ACs that call this one parent.
*/
public synchronized void removeChildAc() {
m_childCount--;
// if we are not using the shutdown hook, close() when the m_childCount
// == 0
if ((m_childCount == 0)
&& (System.getProperty(CLOSE_ON_SHUTDOWN) == null)) {
close();
}
}
/**
* Check the environment for catalina's base or home directory.
*
* @return Catalina's base or home directory.
*/
protected String getCatalina() {
String catalina = System.getProperty("catalina.base");
if (catalina == null) {
catalina = System.getProperty("catalina.home");
}
return catalina;
}
/**
* @inheritDoc
*/
public Properties getConfig() {
if (M_log.isErrorEnabled())
M_log
.error(
"getConfig called; ServerConfigurationService should be used instead",
new Exception());
return null;
}
/**
* @inheritDoc
*/
public void waitTillConfigured() {
// Nothing really to do - the cover takes care of this -ggolden
}
/**
* @inheritDoc
*/
public boolean hasBeenClosed() {
return m_hasBeenClosed;
}
private void ensureSakaiHome() {
// find a path to sakai files on the app server - if not set, set it
String sakaiHomePath = System.getProperty("sakai.home");
if (sakaiHomePath == null) {
String catalina = getCatalina();
if (catalina != null) {
sakaiHomePath = catalina + File.separatorChar + "sakai"
+ File.separatorChar;
}
}
// strange case...
if (sakaiHomePath == null) {
sakaiHomePath = File.separatorChar + "usr" + File.separatorChar
+ "local" + File.separatorChar + "sakai"
+ File.separatorChar;
}
if (!sakaiHomePath.endsWith(File.separator))
sakaiHomePath = sakaiHomePath + File.separatorChar;
final File sakaiHomeDirectory = new File(sakaiHomePath);
if (!sakaiHomeDirectory.exists()) // no sakai.home directory exists,
// try to create one
{
if (sakaiHomeDirectory.mkdir()) {
M_log
.debug("Created sakai.home directory at: "
+ sakaiHomePath);
} else {
M_log.warn("Could not create sakai.home directory at: "
+ sakaiHomePath);
}
}
// make sure it's set properly
System.setProperty("sakai.home", sakaiHomePath);
}
private void checkSecurityPath() {
// check for the security home
String securityPath = System.getProperty("sakai.security");
if (securityPath != null) {
// make sure it's properly slashed
if (!securityPath.endsWith(File.separator))
securityPath = securityPath + File.separatorChar;
System.setProperty("sakai.security", securityPath);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy