/** * The contents of this file are subject to the OpenMRS Public License * Version 1.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://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.module.web; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Vector; import java.util.jar.JarEntry; import java.util.jar.JarFile; import javax.servlet.Filter; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.log4j.xml.DOMConfigurator; import org.openmrs.api.context.Context; import org.openmrs.module.Module; import org.openmrs.module.ModuleException; import org.openmrs.module.ModuleFactory; import org.openmrs.module.ModuleUtil; import org.openmrs.module.web.filter.ModuleFilterConfig; import org.openmrs.module.web.filter.ModuleFilterDefinition; import org.openmrs.module.web.filter.ModuleFilterMapping; import org.openmrs.util.OpenmrsUtil; import org.openmrs.util.PrivilegeConstants; import org.openmrs.web.DispatcherServlet; import org.openmrs.web.dwr.OpenmrsDWRServlet; import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.context.support.XmlWebApplicationContext; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class WebModuleUtil { private static Log log = LogFactory.getLog(WebModuleUtil.class); private static DispatcherServlet dispatcherServlet = null; private static OpenmrsDWRServlet dwrServlet = null; // caches all of the modules' mapped servlets private static Map<String, HttpServlet> moduleServlets = Collections.synchronizedMap(new HashMap<String, HttpServlet>()); // caches all of the module loaded filters and filter-mappings private static Map<Module, Collection<Filter>> moduleFilters = Collections .synchronizedMap(new HashMap<Module, Collection<Filter>>()); private static Map<String, Filter> moduleFiltersByName = Collections.synchronizedMap(new HashMap<String, Filter>()); private static List<ModuleFilterMapping> moduleFilterMappings = Collections .synchronizedList(new Vector<ModuleFilterMapping>()); /** * Performs the webapp specific startup needs for modules Normal startup is done in * {@link ModuleFactory#startModule(Module)} If delayContextRefresh is true, the spring context * is not rerun. This will save a lot of time, but it also means that the calling method is * responsible for restarting the context if necessary (the calling method will also have to * call {@link #loadServlets(Module, ServletContext)} and * {@link #loadFilters(Module, ServletContext)}).<br/> * <br/> * If delayContextRefresh is true and this module should have caused a context refresh, a true * value is returned. Otherwise, false is returned * * @param mod Module to start * @param ServletContext the current ServletContext * @param delayContextRefresh true/false whether or not to do the context refresh * @return boolean whether or not the spring context need to be refreshed */ public static boolean startModule(Module mod, ServletContext servletContext, boolean delayContextRefresh) { //register the module loggers if (mod.getLog4j() != null) { DOMConfigurator.configure(mod.getLog4j().getDocumentElement()); } if (log.isDebugEnabled()) log.debug("trying to start module " + mod); // only try and start this module if the api started it without a // problem. if (ModuleFactory.isModuleStarted(mod) && !mod.hasStartupError()) { String realPath = servletContext.getRealPath(""); // copy the messages into the webapp String path = "/WEB-INF/module_messages@LANG@.properties"; for (Entry<String, Properties> entry : mod.getMessages().entrySet()) { if (log.isDebugEnabled()) log.debug("Copying message property file: " + entry.getKey()); String lang = "_" + entry.getKey(); if (lang.equals("_en") || lang.equals("_")) lang = ""; String currentPath = path.replace("@LANG@", lang); String absolutePath = realPath + currentPath; File file = new File(absolutePath); try { if (!file.exists()) file.createNewFile(); } catch (IOException ioe) { log.error("Unable to create new file " + file.getAbsolutePath() + " " + ioe); } Properties props = entry.getValue(); // set all properties to start with 'moduleName.' if not already List<Object> keys = new Vector<Object>(); keys.addAll(props.keySet()); for (Object obj : keys) { String key = (String) obj; if (!key.startsWith(mod.getModuleId())) { props.put(mod.getModuleId() + "." + key, props.get(key)); props.remove(key); } } // append the properties to the appropriate messages file OpenmrsUtil.storeProperties(props, file, "Module: " + mod.getName() + " v" + mod.getVersion()); } log.debug("Done copying messages"); // flag to tell whether we added any xml/dwr/etc changes that necessitate a refresh // of the web application context boolean moduleNeedsContextRefresh = false; // copy the html files into the webapp (from /web/module/ in the module) // also looks for a spring context file. If found, schedules spring to be restarted JarFile jarFile = null; try { File modFile = mod.getFile(); jarFile = new JarFile(modFile); Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName(); log.debug("Entry name: " + name); if (name.startsWith("web/module/")) { // trim out the starting path of "web/module/" String filepath = name.substring(11); StringBuffer absPath = new StringBuffer(realPath + "/WEB-INF"); // If this is within the tag file directory, copy it into /WEB-INF/tags/module/moduleId/... if (filepath.startsWith("tags/")) { filepath = filepath.substring(5); absPath.append("/tags/module/"); } // Otherwise, copy it into /WEB-INF/view/module/moduleId/... else { absPath.append("/view/module/"); } // if a module id has a . in it, we should treat that as a /, i.e. files in the module // ui.springmvc should go in folder names like .../ui/springmvc/... absPath.append(mod.getModuleIdAsPath() + "/" + filepath); if (log.isDebugEnabled()) log.debug("Moving file from: " + name + " to " + absPath); // get the output file File outFile = new File(absPath.toString().replace("/", File.separator)); if (entry.isDirectory()) { if (!outFile.exists()) { outFile.mkdirs(); } } else { // make the parent directories in case it doesn't exist File parentDir = outFile.getParentFile(); if (!parentDir.exists()) { parentDir.mkdirs(); } //if (outFile.getName().endsWith(".jsp") == false) // outFile = new File(absPath.replace("/", File.separator) + MODULE_NON_JSP_EXTENSION); // copy the contents over to the webapp for non directories OutputStream outStream = new FileOutputStream(outFile, false); InputStream inStream = jarFile.getInputStream(entry); OpenmrsUtil.copyFile(inStream, outStream); inStream.close(); outStream.close(); } } else if (name.equals("moduleApplicationContext.xml") || name.equals("webModuleApplicationContext.xml")) { moduleNeedsContextRefresh = true; } else if (name.equals(mod.getModuleId() + "Context.xml")) { String msg = "DEPRECATED: '" + name + "' should be named 'moduleApplicationContext.xml' now. Please update/upgrade. "; throw new ModuleException(msg, mod.getModuleId()); } } } catch (IOException io) { log.warn("Unable to copy files from module " + mod.getModuleId() + " to the web layer", io); } finally { if (jarFile != null) { try { jarFile.close(); } catch (IOException io) { log.warn("Couldn't close jar file: " + jarFile.getName(), io); } } } // find and add the dwr code to the dwr-modules.xml file (if defined) InputStream inputStream = null; try { Document config = mod.getConfig(); Element root = config.getDocumentElement(); if (root.getElementsByTagName("dwr").getLength() > 0) { // get the dwr-module.xml file that we're appending our code to File f = new File(realPath + "/WEB-INF/dwr-modules.xml".replace("/", File.separator)); inputStream = new FileInputStream(f); Document dwrmodulexml = getDWRModuleXML(inputStream, realPath); Element outputRoot = dwrmodulexml.getDocumentElement(); // loop over all of the children of the "dwr" tag Node node = root.getElementsByTagName("dwr").item(0); Node current = node.getFirstChild(); while (current != null) { if ("allow".equals(current.getNodeName()) || "signatures".equals(current.getNodeName()) || "init".equals(current.getNodeName())) { ((Element) current).setAttribute("moduleId", mod.getModuleId()); outputRoot.appendChild(dwrmodulexml.importNode(current, true)); } current = current.getNextSibling(); } moduleNeedsContextRefresh = true; // save the dwr-modules.xml file. OpenmrsUtil.saveDocument(dwrmodulexml, f); } } catch (FileNotFoundException e) { throw new ModuleException(realPath + "/WEB-INF/dwr-modules.xml file doesn't exist.", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException io) { log.error("Error while closing input stream", io); } } } // mark to delete the entire module web directory on exit // this will usually only be used when an improper shutdown has occurred. String folderPath = realPath + "/WEB-INF/view/module/" + mod.getModuleIdAsPath(); File outFile = new File(folderPath.replace("/", File.separator)); outFile.deleteOnExit(); // additional checks on module needing a context refresh if (moduleNeedsContextRefresh == false) { // AOP advice points are only loaded during the context refresh now. // if the context hasn't been marked to be refreshed yet, mark it // now if this module defines some advice if (mod.getAdvicePoints() != null && mod.getAdvicePoints().size() > 0) { moduleNeedsContextRefresh = true; } } // refresh the spring web context to get the just-created xml // files into it (if we copied an xml file) if (moduleNeedsContextRefresh && delayContextRefresh == false) { if (log.isDebugEnabled()) log.debug("Refreshing context for module" + mod); try { refreshWAC(servletContext, false, mod); try { if (mod.getModuleActivator() != null)// if extends BaseModuleActivator mod.getModuleActivator().started(); } catch (Throwable t) { log.warn("Unable to call module's Activator.started() method", t); } log.debug("Done Refreshing WAC"); } catch (Exception e) { String msg = "Unable to refresh the WebApplicationContext"; mod.setStartupErrorMessage(msg, e); if (log.isWarnEnabled()) log.warn(msg + " for module: " + mod.getModuleId(), e); try { ModuleFactory.stopModule(mod, true, true); //remove jar from classloader play stopModule(mod, servletContext, true); } catch (Exception e2) { // exception expected with most modules here if (log.isWarnEnabled()) log.warn("Error while stopping a module that had an error on refreshWAC", e2); } notifySuperUsersAboutModuleFailure(mod); // try starting the application context again refreshWAC(servletContext, false, mod); } } if (!delayContextRefresh) { // only loading the servlets/filters if spring is refreshed because one // might depend on files being available in spring // if the caller wanted to delay the refresh then they are responsible for // calling these two methods on the module // find and cache the module's servlets //(only if the module started successfully previously) if (ModuleFactory.isModuleStarted(mod)) { log.debug("Loading servlets and filters for module: " + mod); loadServlets(mod, servletContext); loadFilters(mod, servletContext); } } // return true if the module needs a context refresh and we didn't do it here return (moduleNeedsContextRefresh && delayContextRefresh == true); } // we aren't processing this module, so a context refresh is not necessary return false; } /** * Send an Alert to all super users that the given module did not start successfully. * * @param mod The Module that failed */ private static void notifySuperUsersAboutModuleFailure(Module mod) { try { // Add the privileges necessary for notifySuperUsers Context.addProxyPrivilege(PrivilegeConstants.MANAGE_ALERTS); Context.addProxyPrivilege(PrivilegeConstants.VIEW_USERS); // Send an alert to all administrators Context.getAlertService().notifySuperUsers("Module.startupError.notification.message", null, mod.getName()); } finally { // Remove added privileges Context.removeProxyPrivilege(PrivilegeConstants.VIEW_USERS); Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_ALERTS); } } /** * This method will find and cache this module's servlets (so that it doesn't have to look them * up every time) * * @param mod * @param servletContext the servlet context * @return this module's servlet map */ public static void loadServlets(Module mod, ServletContext servletContext) { Element rootNode = mod.getConfig().getDocumentElement(); NodeList servletTags = rootNode.getElementsByTagName("servlet"); for (int i = 0; i < servletTags.getLength(); i++) { Node node = servletTags.item(i); NodeList childNodes = node.getChildNodes(); String name = "", className = ""; for (int j = 0; j < childNodes.getLength(); j++) { Node childNode = childNodes.item(j); if ("servlet-name".equals(childNode.getNodeName())) { if (childNode.getTextContent() != null) name = childNode.getTextContent().trim(); } else if ("servlet-class".equals(childNode.getNodeName())) { if (childNode.getTextContent() != null) className = childNode.getTextContent().trim(); } } if (name.length() == 0 || className.length() == 0) { log.warn("both 'servlet-name' and 'servlet-class' are required for the 'servlet' tag. Given '" + name + "' and '" + className + "' for module " + mod.getName()); continue; } HttpServlet httpServlet = null; try { httpServlet = (HttpServlet) ModuleFactory.getModuleClassLoader(mod).loadClass(className).newInstance(); } catch (ClassNotFoundException e) { log.warn("Class not found for servlet " + name + " for module " + mod.getName(), e); continue; } catch (IllegalAccessException e) { log.warn("Class cannot be accessed for servlet " + name + " for module " + mod.getName(), e); continue; } catch (InstantiationException e) { log.warn("Class cannot be instantiated for servlet " + name + " for module " + mod.getName(), e); continue; } try { log.debug("Initializing " + name + " servlet. - " + httpServlet + "."); ServletConfig servletConfig = new ModuleServlet.SimpleServletConfig(name, servletContext); httpServlet.init(servletConfig); } catch (Throwable t) { log.warn("Unable to initialize servlet: ", t); throw new ModuleException("Unable to initialize servlet: " + httpServlet, mod.getModuleId(), t); } // don't allow modules to overwrite servlets of other modules. HttpServlet otherServletUsingSameName = moduleServlets.get(name); if (otherServletUsingSameName != null) { //log.debug("A servlet mapping with name " + name + " already exists. " + mod.getModuleId() + "'s servlet is overwriting it"); String otherServletName = otherServletUsingSameName.getClass().getPackage() + "." + otherServletUsingSameName.getClass().getName(); throw new ModuleException("A servlet mapping with name " + name + " is already in use and pointing at: " + otherServletName + " from another installed module and this module is trying" + " to use that same name. Either the module attempting to be installed (" + mod.getModuleId() + ") will not work or the other one will not. Please consult the developers of these two" + " modules to sort this out."); } log.debug("Caching the " + name + " servlet."); moduleServlets.put(name, httpServlet); } } /** * Remove all of the servlets defined for this module * * @param mod the module that is being stopped that needs its servlets removed */ public static void unloadServlets(Module mod) { Element rootNode = mod.getConfig().getDocumentElement(); NodeList servletTags = rootNode.getElementsByTagName("servlet"); for (int i = 0; i < servletTags.getLength(); i++) { Node node = servletTags.item(i); NodeList childNodes = node.getChildNodes(); String name = ""; for (int j = 0; j < childNodes.getLength(); j++) { Node childNode = childNodes.item(j); if ("servlet-name".equals(childNode.getNodeName())) { if (childNode.getTextContent() != null) { name = childNode.getTextContent().trim(); HttpServlet servlet = moduleServlets.get(name); if (servlet != null) { servlet.destroy(); // shut down the servlet moduleServlets.remove(name); } } } } } } /** * This method will initialize and store this module's filters * * @param module - The Module to load and register Filters * @param servletContext - The servletContext within which this method is called */ public static void loadFilters(Module module, ServletContext servletContext) { // Load Filters Map<String, Filter> filters = new HashMap<String, Filter>(); try { for (ModuleFilterDefinition def : ModuleFilterDefinition.retrieveFilterDefinitions(module)) { if (moduleFiltersByName.containsKey(def.getFilterName())) { throw new ModuleException("A filter with name <" + def.getFilterName() + "> has already been registered."); } ModuleFilterConfig config = ModuleFilterConfig.getInstance(def, servletContext); Filter f = (Filter) ModuleFactory.getModuleClassLoader(module).loadClass(def.getFilterClass()).newInstance(); f.init(config); filters.put(def.getFilterName(), f); } } catch (ModuleException e) { throw e; } catch (Exception e) { throw new ModuleException("An error occurred initializing Filters for module: " + module.getModuleId(), e); } moduleFilters.put(module, filters.values()); moduleFiltersByName.putAll(filters); log.debug("Module: " + module.getModuleId() + " successfully loaded " + filters.size() + " filters."); // Load Filter Mappings List<ModuleFilterMapping> modMappings = ModuleFilterMapping.retrieveFilterMappings(module); moduleFilterMappings.addAll(modMappings); log.debug("Module: " + module.getModuleId() + " successfully loaded " + modMappings.size() + " filter mappings."); } /** * This method will destroy and remove all filters that were registered by the passed * {@link Module} * * @param module - The Module for which you want to remove and destroy filters. */ public static void unloadFilters(Module module) { // Unload Filter Mappings for (java.util.Iterator<ModuleFilterMapping> mapIter = moduleFilterMappings.iterator(); mapIter.hasNext();) { ModuleFilterMapping mapping = mapIter.next(); if (module.equals(mapping.getModule())) { mapIter.remove(); log.debug("Removed ModuleFilterMapping: " + mapping); } } // unload Filters Collection<Filter> filters = moduleFilters.get(module); if (filters != null) { try { for (Filter f : filters) { f.destroy(); } } catch (Exception e) { log.warn("An error occurred while trying to destroy and remove module Filter.", e); } log.debug("Module: " + module.getModuleId() + " successfully unloaded " + filters.size() + " filters."); moduleFilters.remove(module); for (Iterator<String> i = moduleFiltersByName.keySet().iterator(); i.hasNext();) { String filterName = i.next(); Filter filterVal = moduleFiltersByName.get(filterName); if (filters.contains(filterVal)) { i.remove(); } } } } /** * This method will return all Filters that have been registered a module * * @return A Collection of {@link Filter}s that have been registered by a module */ public static Collection<Filter> getFilters() { return moduleFiltersByName.values(); } /** * This method will return all Filter Mappings that have been registered by a module * * @return A Collection of all {@link ModuleFilterMapping}s that have been registered by a * Module */ public static Collection<ModuleFilterMapping> getFilterMappings() { return moduleFilterMappings; } /** * Return List of Filters that have been loaded through Modules that have mappings that pass for * the passed request * * @param request - The request to check for matching {@link Filter}s * @return List of all {@link Filter}s that have filter mappings that match the passed request */ public static List<Filter> getFiltersForRequest(ServletRequest request) { List<Filter> filters = new Vector<Filter>(); if (request != null) { HttpServletRequest httpRequest = (HttpServletRequest) request; String requestPath = httpRequest.getRequestURI(); if (requestPath != null) { if (requestPath.startsWith(httpRequest.getContextPath())) requestPath = requestPath.substring(httpRequest.getContextPath().length()); for (ModuleFilterMapping filterMapping : WebModuleUtil.getFilterMappings()) { if (ModuleFilterMapping.filterMappingPasses(filterMapping, requestPath)) { Filter passedFilter = moduleFiltersByName.get(filterMapping.getFilterName()); if (passedFilter != null) { filters.add(passedFilter); } else { log.warn("Unable to retrieve filter that has a name of " + filterMapping.getFilterName() + " in filter mapping."); } } } } } return filters; } /** * @param inputStream * @param realPath * @return */ private static Document getDWRModuleXML(InputStream inputStream, String realPath) { Document dwrmodulexml = null; try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); db.setEntityResolver(new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { // When asked to resolve external entities (such as a DTD) we return an InputSource // with no data at the end, causing the parser to ignore the DTD. return new InputSource(new StringReader("")); } }); dwrmodulexml = db.parse(inputStream); } catch (Exception e) { throw new ModuleException("Error parsing dwr-modules.xml file", e); } return dwrmodulexml; } /** * Reverses all activities done by startModule(org.openmrs.module.Module) Normal stop/shutdown * is done by ModuleFactory */ public static void shutdownModules(ServletContext servletContext) { String realPath = servletContext.getRealPath(""); // clear the module messages String messagesPath = realPath + "/WEB-INF/"; File folder = new File(messagesPath.replace("/", File.separator)); if (folder.exists()) { Properties emptyProperties = new Properties(); for (File f : folder.listFiles()) { if (f.getName().startsWith("module_messages")) { OpenmrsUtil.storeProperties(emptyProperties, f, ""); } } } // call web shutdown for each module for (Module mod : ModuleFactory.getLoadedModules()) { stopModule(mod, servletContext, true); } } /** * Reverses all visible activities done by startModule(org.openmrs.module.Module) * * @param mod * @param servletContext */ public static void stopModule(Module mod, ServletContext servletContext) { stopModule(mod, servletContext, false); } /** * Reverses all visible activities done by startModule(org.openmrs.module.Module) * * @param mod * @param servletContext * @param skipRefresh */ private static void stopModule(Module mod, ServletContext servletContext, boolean skipRefresh) { String moduleId = mod.getModuleId(); String modulePackage = mod.getPackageName(); // stop all dependent modules for (Module dependentModule : ModuleFactory.getStartedModules()) { if (!dependentModule.equals(mod) && dependentModule.getRequiredModules().contains(modulePackage)) stopModule(dependentModule, servletContext, skipRefresh); } String realPath = servletContext.getRealPath(""); // delete the web files from the webapp String absPath = realPath + "/WEB-INF/view/module/" + moduleId; File moduleWebFolder = new File(absPath.replace("/", File.separator)); if (moduleWebFolder.exists()) { try { OpenmrsUtil.deleteDirectory(moduleWebFolder); } catch (IOException io) { log.warn("Couldn't delete: " + moduleWebFolder.getAbsolutePath(), io); } } // (not) deleting module message properties // remove the module's servlets unloadServlets(mod); // remove the module's filters and filter mappings unloadFilters(mod); // remove this module's entries in the dwr xml file InputStream inputStream = null; try { Document config = mod.getConfig(); Element root = config.getDocumentElement(); // if they defined any xml element if (root.getElementsByTagName("dwr").getLength() > 0) { // get the dwr-module.xml file that we're appending our code to File f = new File(realPath + "/WEB-INF/dwr-modules.xml".replace("/", File.separator)); inputStream = new FileInputStream(f); Document dwrmodulexml = getDWRModuleXML(inputStream, realPath); Element outputRoot = dwrmodulexml.getDocumentElement(); // loop over all of the children of the "dwr" tag // and remove all "allow" and "signature" tags that have the // same moduleId attr as the module being stopped NodeList nodeList = outputRoot.getChildNodes(); int i = 0; while (i < nodeList.getLength()) { Node current = nodeList.item(i); if ("allow".equals(current.getNodeName()) || "signatures".equals(current.getNodeName())) { NamedNodeMap attrs = current.getAttributes(); Node attr = attrs.getNamedItem("moduleId"); if (attr != null && moduleId.equals(attr.getNodeValue())) { outputRoot.removeChild(current); } else i++; } else i++; } // save the dwr-modules.xml file. OpenmrsUtil.saveDocument(dwrmodulexml, f); } } catch (FileNotFoundException e) { throw new ModuleException(realPath + "/WEB-INF/dwr-modules.xml file doesn't exist.", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException io) { log.error("Error while closing input stream", io); } } } if (skipRefresh == false) { //try { // if (dispatcherServlet != null) // dispatcherServlet.reInitFrameworkServlet(); // if (dwrServlet != null) // dwrServlet.reInitServlet(); //} //catch (ServletException se) { // log.warn("Unable to reinitialize webapplicationcontext for dispatcherservlet for module: " + mod.getName(), se); //} refreshWAC(servletContext, false, null); } } /** * Stops, closes, and refreshes the Spring context for the given <code>servletContext</code> * * @param servletContext * @param isOpenmrsStartup if this refresh is being done at application startup * @param startedModule the module that was just started and waiting on the context refresh * @return The newly refreshed webApplicationContext */ public static XmlWebApplicationContext refreshWAC(ServletContext servletContext, boolean isOpenmrsStartup, Module startedModule) { XmlWebApplicationContext wac = (XmlWebApplicationContext) WebApplicationContextUtils .getWebApplicationContext(servletContext); if (log.isDebugEnabled()) log.debug("Refreshing web applciation Context of class: " + wac.getClass().getName()); XmlWebApplicationContext newAppContext = (XmlWebApplicationContext) ModuleUtil.refreshApplicationContext(wac, isOpenmrsStartup, startedModule); try { // must "refresh" the spring dispatcherservlet as well to add in //the new handlerMappings if (dispatcherServlet != null) dispatcherServlet.reInitFrameworkServlet(); } catch (ServletException se) { log.warn("Caught a servlet exception while refreshing the dispatcher servlet", se); } try { if (dwrServlet != null) dwrServlet.reInitServlet(); } catch (ServletException se) { log.warn("Cause a servlet exception while refreshing the dwr servlet", se); } return newAppContext; } /** * Save the dispatcher servlet for use later (reinitializing things) * * @param ds */ public static void setDispatcherServlet(DispatcherServlet ds) { log.debug("Setting dispatcher servlet: " + ds); dispatcherServlet = ds; } /** * Save the dwr servlet for use later (reinitializing things) * * @param ds */ public static void setDWRServlet(OpenmrsDWRServlet ds) { log.debug("Setting dwr servlet: " + ds); dwrServlet = ds; //new NewCreator(); //SessionFactoryUtils.processDeferredClose(null); } /** * Finds the servlet defined by the servlet name * * @param servletName the name of the servlet out of the path * @return the current servlet or null if none defined */ public static HttpServlet getServlet(String servletName) { return moduleServlets.get(servletName); } }