由于程序的原因,本文件未被完整保存。
在做struts应用的时候,经常学要修改struts-config.xml文件,在每次修改完之后只有重新启动服务器才能让修改生效。因此做了一个Listener,在应用启动的时候开始,每隔一段时间就去检查一下struts-config.xml文件的最后修改时间,如果修改时间变化了,就重新读取struts-config.xml,将对应的配置放到ServletContext中去。
一.LoadResourceListener
import java.util.Timer;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import kick.utils.Constants;
public class LoadResourceListener implements ServletContextListener {
/* (non-Javadoc)
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent event) {
Timer loadResource = new Timer();
//获取ServletContext
ServletContext servletContext = event.getServletContext();
//创建一个LoadResourceTimerTask 的实例
LoadResourceTimerTask loadResourceTimerTask = new LoadResourceTimerTask(servletContext);
//将刚创建的TimerTask的实例的运行计划订为:马上开始,每隔20×1000ms运行一次
loadResource.schedule(loadResourceTimerTask,0,Constants.DELAY_UPDATE_TIME);
}
/* (non-Javadoc)
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent arg0) {
}
}
二.配置LoadResourceListener
在filter的配置下面添加上如下的配置
<listener>
<listener-class>kick.load.resource.LoadResourceListener</listener-class>
</listener>
三.LoadResourceTimerTask类
/*
* Created on 2005-9-6
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package kick.load.resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.TimerTask;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.sql.DataSource;
import kick.utils.Constants;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.FastHashMap;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.Globals;
import org.apache.struts.config.ConfigRuleSet;
import org.apache.struts.config.DataSourceConfig;
import org.apache.struts.config.FormBeanConfig;
import org.apache.struts.config.MessageResourcesConfig;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.config.ModuleConfigFactory;
import org.apache.struts.util.MessageResources;
import org.apache.struts.util.MessageResourcesFactory;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.ServletContextWriter;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class LoadResourceTimerTask extends TimerTask {
private ServletContext context = null;
/**
* <p>
* The resources object for our internal resources.
* </p>
*/
protected MessageResources internal = null;
/**
* <p>
* The Digester used to produce ModuleConfig objects from a Struts
* configuration file.
* </p>
*
* @since Struts 1.1
*/
protected Digester configDigester = null;
/**
* <p>
* The Java base name of our internal resources.
* </p>
*
* @since Struts 1.1
*/
protected String internalName = "org.apache.struts.action.ActionResources";
/**
* <p>
* Commons Logging instance.
* </p>
*
* @since Struts 1.1
*/
protected static Log log = LogFactory.getLog(LoadResourceTimerTask.class);
private List initParams = null;
/**
* <p>
* The set of public identifiers, and corresponding resource names, for the
* versions of the configuration file DTDs that we know about. There
* <strong>MUST </strong> be an even number of Strings in this list!
* </p>
*/
protected String registrations[] = { "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
"/org/apache/struts/resources/struts-config_1_0.dtd",
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN",
"/org/apache/struts/resources/struts-config_1_1.dtd",
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN",
"/org/apache/struts/resources/struts-config_1_2.dtd",
"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", "/org/apache/struts/resources/web-app_2_2.dtd",
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", "/org/apache/struts/resources/web-app_2_3.dtd" };
/**
* <p>
* The JDBC data sources that has been configured for this module, if any,
* keyed by the servlet context attribute under which they are stored.
* </p>
*/
protected FastHashMap dataSources = new FastHashMap();
/**
* <p>
* Comma-separated list of context-relative path(s) to our configuration
* resource(s) for the default module.
* </p>
*/
protected String config = "/WEB-INF/struts-config.xml";
private List resourcesName = new ArrayList();
private Set resourceFiles = new HashSet();
public LoadResourceTimerTask(ServletContext context) {
this.context = context;
try {
initInternal();
parseWeb();
parseConfigFile();
parseResource();
// parseConfigFile();
} catch (ServletException e) {
System.out.println(e.getMessage());
e.printStackTrace();
throw new RuntimeException(e);
}
}
/*
* (non-Javadoc)
*
* @see java.util.TimerTask#run()
*/
public void run() {
try {
reLoadConfigFile();
reLoadResource();
} catch (Exception e) {
}
}
/**
*
*/
private void parseConfigFile() {
InitParam initParam = null;
for (int i = 0; i < initParams.size(); i++) {
initParam = (InitParam) initParams.get(i);
String name = initParam.getName();
if (!name.startsWith("config")) {
continue;
}
String prefix = name.substring(6);
String paths = initParam.getValue();
// Process each specified resource path
while (paths.length() > 0) {
// digester.push(config);
String path = null;
int comma = paths.indexOf(',');
if (comma >= 0) {
path = paths.substring(0, comma).trim();
paths = paths.substring(comma + 1);
} else {
path = paths.trim();
paths = "";
}
if (path.length() < 1) {
break;
}
File file = new File(getServletContext().getRealPath(path));
StrutsConfig s = new StrutsConfig();
Digester d = new Digester();
d.push(s);
d.setNamespaceAware(false);
d.setValidating(false);
for (int j = 0; j < registrations.length; j += 2) {
URL url = this.getClass().getResource(registrations[j + 1]);
if (url != null) {
d.register(registrations[j], url.toString());
}
}
d.addObjectCreate("struts-config/message-resources", Resource.class);
d.addSetProperties("struts-config/message-resources", "parameter", "parameter");
d.addSetNext("struts-config/message-resources", "addResource");
// d.addCallMethod("web-struts-config/message-resources",
// "setParameter", 0);
try {
d.parse(file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// String resourcePath =
// ((Resource)s.getResources()).toFilePaht();
List rs = s.getResources();
for (int ii = 0; ii < rs.size(); ii++) {
resourcesName.add(((Resource) rs.get(ii)).toFilePaht());
}
}
}
}
public void parseResource() {
int index = 0;
String dirName = "";
String resource = "";
String subFileName = "";
for (int i = 0; i < resourcesName.size(); i++) {
resource = (String) resourcesName.get(i);
index = resource.lastIndexOf("/");
dirName = resource.substring(0, index);
subFileName = resource.substring(index + 1, resource.length());
File file = new File(getServletContext().getRealPath("/WEB-INF/classes/" + dirName));
if (file.isDirectory()) {
String[] fileNames = file.list();
if (fileNames != null) {
for (int j = 0; j < fileNames.length; j++) {
if (fileNames[j] != null) {
if (fileNames[j].trim().startsWith(subFileName.trim())) {
resourceFiles.add(dirName + "/" + fileNames[j]);
// System.out.println("The file Name : '" +
// subFileName + "'");
// System.out.println("Add file name : '" +
// fileNames[j] + "'");
}
}
}
}
}
}
}
private void reLoadConfigFile() {
try {
InitParam initParam = null;
for (int i = 0; i < initParams.size(); i++) {
initParam = (InitParam) initParams.get(i);
String name = initParam.getName();
if (!name.startsWith("config")) {
continue;
}
String prefix = name.substring(6);
String paths = initParam.getValue();
// Process each specified resource path
while (paths.length() > 0) {
// digester.push(config);
String path = null;
int comma = paths.indexOf(',');
if (comma >= 0) {
path = paths.substring(0, comma).trim();
paths = paths.substring(comma + 1);
} else {
path = paths.trim();
paths = "";
}
if (path.length() < 1) {
break;
}
File file = new File(getServletContext().getRealPath(path));
if ((System.currentTimeMillis() - file.lastModified()) < Constants.DELAY_UPDATE_TIME) {
log.debug("The struts-config.xml is changed,will be reload into context.");
log.debug("The file name is : '" + path + "'");
log.debug("Refash the resource file config list!");
parseConfigFile();
log.debug("Refash the resource file list!");
parseResource();
ModuleConfig moduleConfig = initModuleConfig(prefix, path);
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
moduleConfig.freeze();
log.debug("Reload the config file success!");
}
this.initModulePrefixes(this.getServletContext());
}
}
} catch (Exception e) {
}
}
private void reLoadConfig(String prefix, String path) {
try {
ModuleConfig moduleConfig = initModuleConfig(prefix, path);
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
moduleConfig.freeze();
} catch (Exception e) {
}
}
private void reLoadResource() {
Iterator it = resourceFiles.iterator();
String fileName = "";
while (it.hasNext()) {
fileName = (String) it.next();
File file = new File(this.getServletContext().getRealPath("/WEB-INF/classes/" + fileName));
if ((System.currentTimeMillis() - file.lastModified()) < Constants.DELAY_UPDATE_TIME) {
log.debug("Update the '" + file.getName() + "' property file!");
updateConfigFile();
}
}
}
/**
*
*/
private void updateConfigFile() {
InitParam initParam = null;
for (int i = 0; i < initParams.size(); i++) {
initParam = (InitParam) initParams.get(i);
String name = initParam.getName();
if (!name.startsWith("config")) {
continue;
}
String prefix = name.substring(6);
String paths = initParam.getValue();
// Process each specified resource path
while (paths.length() > 0) {
// digester.push(config);
String path = null;
int comma = paths.indexOf(',');
if (comma >= 0) {
path = paths.substring(0, comma).trim();
paths = paths.substring(comma + 1);
} else {
path = paths.trim();
paths = "";
}
if (path.length() < 1) {
break;
}
File file = new File(getServletContext().getRealPath(path));
file.setLastModified(System.currentTimeMillis());
}
}
}
/**
*
*/
private void parseWeb() {
InputStream input = getServletContext().getResourceAsStream("/WEB-INF/web.xml");
WebApp w = new WebApp();
Digester d = new Digester();
d.push(w);
d.setNamespaceAware(false);
d.setValidating(false);
for (int i = 0; i < registrations.length; i += 2) {
URL url = this.getClass().getResource(registrations[i + 1]);
if (url != null) {
d.register(registrations[i], url.toString());
}
}
d.addObjectCreate("web-app/servlet", Servlet.class);
d.addSetNext("web-app/servlet", "addServlet");
d.addObjectCreate("web-app/servlet/init-param", InitParam.class);
d.addSetNext("web-app/servlet/init-param", "addInitParams");
d.addCallMethod("web-app/servlet/init-param/param-name", "setName", 0);
d.addCallMethod("web-app/servlet/init-param/param-value", "setValue", 0);
try {
d.parse(input);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
List l = w.getServlets();
if (l.size() > 0) {
initParams = ((Servlet) l.get(0)).getInitParams();
}
initParams = ((Servlet) ((List) w.getServlets()).get(0)).getInitParams();
try {
input.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
/**
* <p>
* Gracefully release any configDigester instance that we have created.
* </p>
*
* @since Struts 1.1
*/
protected void destroyConfigDigester() {
configDigester = null;
}
/**
* <p>
* Saves a String[] of module prefixes in the ServletContext under
* Globals.MODULE_PREFIXES_KEY. <strong>NOTE </strong>- the "" prefix for
* the default module is not included in this list.
* </p>
*
* @param context
* The servlet context.
* @since Struts 1.2
*/
protected void initModulePrefixes(ServletContext context) {
ArrayList prefixList = new ArrayList();
Enumeration names = context.getAttributeNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
if (!name.startsWith(Globals.MODULE_KEY)) {
continue;
}
String prefix = name.substring(Globals.MODULE_KEY.length());
if (prefix.length() > 0) {
prefixList.add(prefix);
}
}
String[] prefixes = (String[]) prefixList.toArray(new String[prefixList.size()]);
context.setAttribute(Globals.MODULE_PREFIXES_KEY, prefixes);
}
/**
* <p>
* Initialize the data sources for the specified module.
* </p>
*
* @param config
* ModuleConfig information for this module
*
* @exception ServletException
* if initialization cannot be performed
* @since Struts 1.1
*/
protected void initModuleDataSources(ModuleConfig config) throws ServletException {
// :FIXME: Document UnavailableException?
if (log.isDebugEnabled()) {
log.debug("Initializing module path '" + config.getPrefix() + "' data sources");
}
ServletContextWriter scw = new ServletContextWriter(getServletContext());
DataSourceConfig dscs[] = config.findDataSourceConfigs();
if (dscs == null) {
dscs = new DataSourceConfig[0];
}
dataSources.setFast(false);
for (int i = 0; i < dscs.length; i++) {
if (log.isDebugEnabled()) {
log.debug("Initializing module path '" + config.getPrefix() + "' data source '" + dscs[i].getKey()
+ "'");
}
DataSource ds = null;
try {
ds = (DataSource) RequestUtils.applicationInstance(dscs[i].getType());
BeanUtils.populate(ds, dscs[i].getProperties());
ds.setLogWriter(scw);
} catch (Exception e) {
log.error(internal.getMessage("dataSource.init", dscs[i].getKey()), e);
throw new UnavailableException(internal.getMessage("dataSource.init", dscs[i].getKey()));
}
getServletContext().setAttribute(dscs[i].getKey() + config.getPrefix(), ds);
dataSources.put(dscs[i].getKey(), ds);
}
dataSources.setFast(true);
}
/**
* <p>
* Initialize the application <code>MessageResources</code> for the
* specified module.
* </p>
*
* @param config
* ModuleConfig information for this module
*
* @exception ServletException
* if initialization cannot be performed
* @since Struts 1.1
*/
protected void initModuleMessageResources(ModuleConfig config) throws ServletException {
MessageResourcesConfig mrcs[] = config.findMessageResourcesConfigs();
for (int i = 0; i < mrcs.length; i++) {
if ((mrcs[i].getFactory() == null) || (mrcs[i].getParameter() == null)) {
continue;
}
if (log.isDebugEnabled()) {
log.debug("Initializing module path '" + config.getPrefix() + "' message resources from '"
+ mrcs[i].getParameter() + "'");
}
String factory = mrcs[i].getFactory();
MessageResourcesFactory.setFactoryClass(factory);
MessageResourcesFactory factoryObject = MessageResourcesFactory.createFactory();
MessageResources resources = factoryObject.createResources(mrcs[i].getParameter());
resources.setReturnNull(mrcs[i].getNull());
getServletContext().setAttribute(mrcs[i].getKey() + config.getPrefix(), resources);
}
}
/**
* <p>
* Initialize the module configuration information for the specified module.
* </p>
*
* @param prefix
* Module prefix for this module
* @param paths
* Comma-separated list of context-relative resource path(s) for
* this modules's configuration resource(s)
*
* @exception ServletException
* if initialization cannot be performed
* @since Struts 1.1
*/
protected ModuleConfig initModuleConfig(String prefix, String paths) throws ServletException {
// :FIXME: Document UnavailableException? (Doesn't actually throw
// anything)
if (log.isDebugEnabled()) {
log.debug("Initializing module path '" + prefix + "' configuration from '" + paths + "'");
}
// Parse the configuration for this module
ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory();
ModuleConfig config = factoryObject.createModuleConfig(prefix);
// Configure the Digester instance we will use
Digester digester = initConfigDigester();
// Process each specified resource path
while (paths.length() > 0) {
digester.push(config);
String path = null;
int comma = paths.indexOf(',');
if (comma >= 0) {
path = paths.substring(0, comma).trim();
paths = paths.substring(comma + 1);
} else {
path = paths.trim();
paths = "";
}
if (path.length() < 1) {
break;
}
this.parseModuleConfigFile(digester, path);
}
getServletContext().setAttribute(Globals.MODULE_KEY + config.getPrefix(), config);
// Force creation and registration of DynaActionFormClass instances
// for all dynamic form beans we wil be using
FormBeanConfig fbs[] = config.findFormBeanConfigs();
for (int i = 0; i < fbs.length; i++) {
if (fbs[i].getDynamic()) {
fbs[i].getDynaActionFormClass();
}
}
return config;
}
/**
* <p>
* Create (if needed) and return a new <code>Digester</code> instance that
* has been initialized to process Struts module configuration files and
* configure a corresponding <code>ModuleConfig</code> object (which must
* be pushed on to the evaluation stack before parsing begins).
* </p>
*
* @exception ServletException
* if a Digester cannot be configured
* @since Struts 1.1
*/
protected Digester initConfigDigester() throws ServletException {
// :FIXME: Where can ServletException be thrown?
// Do we have an existing instance?
if (configDigester != null) {
return (configDigester);
}
// Create a new Digester instance with standard capabilities
configDigester = new Digester();
configDigester.setNamespaceAware(true);
configDigester.setValidating(false);
configDigester.setUseContextClassLoader(true);
configDigester.addRuleSet(new ConfigRuleSet());
for (int i = 0; i < registrations.length; i += 2) {
URL url = this.getClass().getResource(registrations[i + 1]);
if (url != null) {
configDigester.register(registrations[i], url.toString());
}
}
this.addRuleSets();
// Return the completely configured Digester instance
return (configDigester);
}
/**
* <p>
* Add any custom RuleSet instances to configDigester that have been
* specified in the <code>rulesets</code> init parameter.
* </p>
*
* @throws ServletException
*/
private void addRuleSets() throws ServletException {
String rulesets = null;
if (rulesets == null) {
rulesets = "";
}
rulesets = rulesets.trim();
String ruleset = null;
while (rulesets.length() > 0) {
int comma = rulesets.indexOf(",");
if (comma < 0) {
ruleset = rulesets.trim();
rulesets = "";
} else {
ruleset = rulesets.substring(0, comma).trim();
rulesets = rulesets.substring(comma + 1).trim();
}
if (log.isDebugEnabled()) {
log.debug("Configuring custom Digester Ruleset of type " + ruleset);
}
try {
RuleSet instance = (RuleSet) RequestUtils.applicationInstance(ruleset);
this.configDigester.addRuleSet(instance);
} catch (Exception e) {
log.error("Exception configuring custom Digester RuleSet", e);
throw new ServletException(e);
}
}
}
/**
* <p>
* Parses one module config file.
* </p>
*
* @param digester
* Digester instance that does the parsing
* @param path
* The path to the config file to parse.
*
* @throws UnavailableException
* if file cannot be read or parsed
* @since Struts 1.2
*/
protected void parseModuleConfigFile(Digester digester, String path) throws UnavailableException {
InputStream input = null;
try {
URL url = getServletContext().getResource(path);
// If the config isn't in the servlet context, try the class loader
// which allows the config files to be stored in a jar
if (url == null) {
url = getClass().getResource(path);
}
if (url == null) {
String msg = internal.getMessage("configMissing", path);
log.error(msg);
throw new UnavailableException(msg);
}
InputSource is = new InputSource(url.toExternalForm());
input = url.openStream();
is.setByteStream(input);
digester.parse(is);
} catch (MalformedURLException e) {
handleConfigException(path, e);
} catch (IOException e) {
handleConfigException(path, e);
} catch (SAXException e) {
handleConfigException(path, e);
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
throw new UnavailableException(e.getMessage());
}
}
}
}
/**
* <p>
* Simplifies exception handling in the <code>parseModuleConfigFile</code>
* method.
* <p>
*
* @param path
* @param e
* @throws UnavailableException
* as a wrapper around Exception
*/
private void handleConfigException(String path, Exception e) throws UnavailableException {
String msg = internal.getMessage("configParse", path);
log.error(msg, e);
throw new UnavailableException(msg);
}
/**
* <p>
* Initialize our internal MessageResources bundle.
* </p>
*
* @exception ServletException
* if we cannot initialize these resources
*/
protected void initInternal() throws ServletException {
// :FIXME: Document UnavailableException
try {
internal = MessageResources.getMessageResources(internalName);
} catch (MissingResourceException e) {
log.error("Cannot load internal resources from '" + internalName + "'", e);
throw new UnavailableException("Cannot load internal resources from '" + internalName + "'");
}
}
/**
* @return
*/
private ServletContext getServletContext() {
return (this.context);
}
}
四.另外还有几个Digester用来解析web.xml和struts-config.xml文件的类
/*
* Created on 2005-9-6
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package kick.load.resource;
import java.util.ArrayList;
import java.util.List;
public class WebApp {
private List servlets = new ArrayList();
public void addServlet(Servlet servlet){
servlets.add(servlet);
}
/**
* @return Returns the servlets.
*/
public List getServlets() {
return servlets;
}
/**
* @param servlets The servlets to set.
*/
public void setServlets(List servlets) {
this.servlets = servlets;
}
public void print(){
for(int i = 0;i<servlets.size();i++){
((Servlet)servlets.get(i)).print();
}
}
}
/*
* Created on 2005-9-6
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package kick.load.resource;
import java.util.ArrayList;
import java.util.List;
public class Servlet {
private List initParams = new ArrayList();
public void addInitParams(InitParam i){
initParams.add(i);
}
public void print(){
for(int i = 0;i<initParams.size();i++){
((InitParam)initParams.get(i)).print();
}
}
/**
* @return Returns the initParams.
*/
public List getInitParams() {
return initParams;
}
/**
* @param initParams The initParams to set.
*/
public void setInitParams(List initParams) {
this.initParams = initParams;
}
}