Advertisement
Guest User

Untitled

a guest
Jan 4th, 2013
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.50 KB | None | 0 0
  1. /**
  2. * The contents of this file are subject to the OpenMRS Public License
  3. * Version 1.0 (the "License"); you may not use this file except in
  4. * compliance with the License. You may obtain a copy of the License at
  5. * http://license.openmrs.org
  6. *
  7. * Software distributed under the License is distributed on an "AS IS"
  8. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  9. * License for the specific language governing rights and limitations
  10. * under the License.
  11. *
  12. * Copyright (C) OpenMRS, LLC. All Rights Reserved.
  13. */
  14. package org.openmrs.module.web;
  15.  
  16. import java.io.File;
  17. import java.io.FileInputStream;
  18. import java.io.FileNotFoundException;
  19. import java.io.FileOutputStream;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.io.OutputStream;
  23. import java.io.StringReader;
  24. import java.util.Collection;
  25. import java.util.Collections;
  26. import java.util.Enumeration;
  27. import java.util.HashMap;
  28. import java.util.Iterator;
  29. import java.util.List;
  30. import java.util.Map;
  31. import java.util.Map.Entry;
  32. import java.util.Properties;
  33. import java.util.Vector;
  34. import java.util.jar.JarEntry;
  35. import java.util.jar.JarFile;
  36.  
  37. import javax.servlet.Filter;
  38. import javax.servlet.ServletConfig;
  39. import javax.servlet.ServletContext;
  40. import javax.servlet.ServletException;
  41. import javax.servlet.ServletRequest;
  42. import javax.servlet.http.HttpServlet;
  43. import javax.servlet.http.HttpServletRequest;
  44. import javax.xml.parsers.DocumentBuilder;
  45. import javax.xml.parsers.DocumentBuilderFactory;
  46.  
  47. import org.apache.commons.logging.Log;
  48. import org.apache.commons.logging.LogFactory;
  49. import org.apache.log4j.xml.DOMConfigurator;
  50. import org.openmrs.api.context.Context;
  51. import org.openmrs.module.Module;
  52. import org.openmrs.module.ModuleException;
  53. import org.openmrs.module.ModuleFactory;
  54. import org.openmrs.module.ModuleUtil;
  55. import org.openmrs.module.web.filter.ModuleFilterConfig;
  56. import org.openmrs.module.web.filter.ModuleFilterDefinition;
  57. import org.openmrs.module.web.filter.ModuleFilterMapping;
  58. import org.openmrs.util.OpenmrsUtil;
  59. import org.openmrs.util.PrivilegeConstants;
  60. import org.openmrs.web.DispatcherServlet;
  61. import org.openmrs.web.dwr.OpenmrsDWRServlet;
  62. import org.springframework.web.context.support.WebApplicationContextUtils;
  63. import org.springframework.web.context.support.XmlWebApplicationContext;
  64. import org.w3c.dom.Document;
  65. import org.w3c.dom.Element;
  66. import org.w3c.dom.NamedNodeMap;
  67. import org.w3c.dom.Node;
  68. import org.w3c.dom.NodeList;
  69. import org.xml.sax.EntityResolver;
  70. import org.xml.sax.InputSource;
  71. import org.xml.sax.SAXException;
  72.  
  73. public class WebModuleUtil {
  74.  
  75. private static Log log = LogFactory.getLog(WebModuleUtil.class);
  76.  
  77. private static DispatcherServlet dispatcherServlet = null;
  78.  
  79. private static OpenmrsDWRServlet dwrServlet = null;
  80.  
  81. // caches all of the modules' mapped servlets
  82. private static Map<String, HttpServlet> moduleServlets = Collections.synchronizedMap(new HashMap<String, HttpServlet>());
  83.  
  84. // caches all of the module loaded filters and filter-mappings
  85. private static Map<Module, Collection<Filter>> moduleFilters = Collections
  86. .synchronizedMap(new HashMap<Module, Collection<Filter>>());
  87.  
  88. private static Map<String, Filter> moduleFiltersByName = Collections.synchronizedMap(new HashMap<String, Filter>());
  89.  
  90. private static List<ModuleFilterMapping> moduleFilterMappings = Collections
  91. .synchronizedList(new Vector<ModuleFilterMapping>());
  92.  
  93. /**
  94. * Performs the webapp specific startup needs for modules Normal startup is done in
  95. * {@link ModuleFactory#startModule(Module)} If delayContextRefresh is true, the spring context
  96. * is not rerun. This will save a lot of time, but it also means that the calling method is
  97. * responsible for restarting the context if necessary (the calling method will also have to
  98. * call {@link #loadServlets(Module, ServletContext)} and
  99. * {@link #loadFilters(Module, ServletContext)}).<br/>
  100. * <br/>
  101. * If delayContextRefresh is true and this module should have caused a context refresh, a true
  102. * value is returned. Otherwise, false is returned
  103. *
  104. * @param mod Module to start
  105. * @param ServletContext the current ServletContext
  106. * @param delayContextRefresh true/false whether or not to do the context refresh
  107. * @return boolean whether or not the spring context need to be refreshed
  108. */
  109. public static boolean startModule(Module mod, ServletContext servletContext, boolean delayContextRefresh) {
  110.  
  111. if (log.isDebugEnabled())
  112. log.debug("trying to start module " + mod);
  113.  
  114. // only try and start this module if the api started it without a
  115. // problem.
  116. if (ModuleFactory.isModuleStarted(mod) && !mod.hasStartupError()) {
  117.  
  118. String realPath = servletContext.getRealPath("");
  119.  
  120. // copy the messages into the webapp
  121. String path = "/WEB-INF/module_messages@LANG@.properties";
  122.  
  123. for (Entry<String, Properties> entry : mod.getMessages().entrySet()) {
  124. if (log.isDebugEnabled())
  125. log.debug("Copying message property file: " + entry.getKey());
  126.  
  127. String lang = "_" + entry.getKey();
  128. if (lang.equals("_en") || lang.equals("_"))
  129. lang = "";
  130.  
  131. String currentPath = path.replace("@LANG@", lang);
  132.  
  133. String absolutePath = realPath + currentPath;
  134. File file = new File(absolutePath);
  135. try {
  136. if (!file.exists())
  137. file.createNewFile();
  138. }
  139. catch (IOException ioe) {
  140. log.error("Unable to create new file " + file.getAbsolutePath() + " " + ioe);
  141. }
  142.  
  143. Properties props = entry.getValue();
  144.  
  145. // set all properties to start with 'moduleName.' if not already
  146. List<Object> keys = new Vector<Object>();
  147. keys.addAll(props.keySet());
  148. for (Object obj : keys) {
  149. String key = (String) obj;
  150. if (!key.startsWith(mod.getModuleId())) {
  151. props.put(mod.getModuleId() + "." + key, props.get(key));
  152. props.remove(key);
  153. }
  154. }
  155.  
  156. try {
  157. //Copy to the module properties file replacing any keys that already exist
  158. Properties allModulesProperties = new Properties();
  159. OpenmrsUtil.loadProperties(allModulesProperties, file);
  160. allModulesProperties.putAll(props);
  161. OpenmrsUtil.storeProperties(allModulesProperties, new FileOutputStream(file), null);
  162. }
  163. catch (FileNotFoundException e) {
  164. throw new ModuleException(file.getAbsolutePath(), e);
  165. }
  166. }
  167. log.debug("Done copying messages");
  168.  
  169. // flag to tell whether we added any xml/dwr/etc changes that necessitate a refresh
  170. // of the web application context
  171. boolean moduleNeedsContextRefresh = false;
  172.  
  173. // copy the html files into the webapp (from /web/module/ in the module)
  174. // also looks for a spring context file. If found, schedules spring to be restarted
  175. JarFile jarFile = null;
  176. try {
  177. File modFile = mod.getFile();
  178. jarFile = new JarFile(modFile);
  179. Enumeration<JarEntry> entries = jarFile.entries();
  180.  
  181. while (entries.hasMoreElements()) {
  182. JarEntry entry = entries.nextElement();
  183. String name = entry.getName();
  184. log.debug("Entry name: " + name);
  185. if (name.startsWith("web/module/")) {
  186. // trim out the starting path of "web/module/"
  187. String filepath = name.substring(11);
  188.  
  189. StringBuffer absPath = new StringBuffer(realPath + "/WEB-INF");
  190.  
  191. // If this is within the tag file directory, copy it into /WEB-INF/tags/module/moduleId/...
  192. if (filepath.startsWith("tags/")) {
  193. filepath = filepath.substring(5);
  194. absPath.append("/tags/module/");
  195. }
  196. // Otherwise, copy it into /WEB-INF/view/module/moduleId/...
  197. else {
  198. absPath.append("/view/module/");
  199. }
  200.  
  201. // if a module id has a . in it, we should treat that as a /, i.e. files in the module
  202. // ui.springmvc should go in folder names like .../ui/springmvc/...
  203. absPath.append(mod.getModuleIdAsPath() + "/" + filepath);
  204. if (log.isDebugEnabled())
  205. log.debug("Moving file from: " + name + " to " + absPath);
  206.  
  207. // get the output file
  208. File outFile = new File(absPath.toString().replace("/", File.separator));
  209. if (entry.isDirectory()) {
  210. if (!outFile.exists()) {
  211. outFile.mkdirs();
  212. }
  213. } else {
  214. // make the parent directories in case it doesn't exist
  215. File parentDir = outFile.getParentFile();
  216. if (!parentDir.exists()) {
  217. parentDir.mkdirs();
  218. }
  219.  
  220. //if (outFile.getName().endsWith(".jsp") == false)
  221. // outFile = new File(absPath.replace("/", File.separator) + MODULE_NON_JSP_EXTENSION);
  222.  
  223. // copy the contents over to the webapp for non directories
  224. OutputStream outStream = new FileOutputStream(outFile, false);
  225. InputStream inStream = jarFile.getInputStream(entry);
  226. OpenmrsUtil.copyFile(inStream, outStream);
  227. inStream.close();
  228. outStream.close();
  229. }
  230. } else if (name.equals("moduleApplicationContext.xml") || name.equals("webModuleApplicationContext.xml")) {
  231. moduleNeedsContextRefresh = true;
  232. } else if (name.equals(mod.getModuleId() + "Context.xml")) {
  233. String msg = "DEPRECATED: '" + name
  234. + "' should be named 'moduleApplicationContext.xml' now. Please update/upgrade. ";
  235. throw new ModuleException(msg, mod.getModuleId());
  236. }
  237. }
  238. }
  239. catch (IOException io) {
  240. log.warn("Unable to copy files from module " + mod.getModuleId() + " to the web layer", io);
  241. }
  242. finally {
  243. if (jarFile != null) {
  244. try {
  245. jarFile.close();
  246. }
  247. catch (IOException io) {
  248. log.warn("Couldn't close jar file: " + jarFile.getName(), io);
  249. }
  250. }
  251. }
  252.  
  253. // find and add the dwr code to the dwr-modules.xml file (if defined)
  254. InputStream inputStream = null;
  255. try {
  256. Document config = mod.getConfig();
  257. Element root = config.getDocumentElement();
  258. if (root.getElementsByTagName("dwr").getLength() > 0) {
  259.  
  260. // get the dwr-module.xml file that we're appending our code to
  261. File f = new File(realPath + "/WEB-INF/dwr-modules.xml".replace("/", File.separator));
  262. inputStream = new FileInputStream(f);
  263. Document dwrmodulexml = getDWRModuleXML(inputStream, realPath);
  264. Element outputRoot = dwrmodulexml.getDocumentElement();
  265.  
  266. // loop over all of the children of the "dwr" tag
  267. Node node = root.getElementsByTagName("dwr").item(0);
  268. Node current = node.getFirstChild();
  269. while (current != null) {
  270. if ("allow".equals(current.getNodeName()) || "signatures".equals(current.getNodeName())
  271. || "init".equals(current.getNodeName())) {
  272. ((Element) current).setAttribute("moduleId", mod.getModuleId());
  273. outputRoot.appendChild(dwrmodulexml.importNode(current, true));
  274. }
  275.  
  276. current = current.getNextSibling();
  277. }
  278.  
  279. moduleNeedsContextRefresh = true;
  280.  
  281. // save the dwr-modules.xml file.
  282. OpenmrsUtil.saveDocument(dwrmodulexml, f);
  283. }
  284. }
  285. catch (FileNotFoundException e) {
  286. throw new ModuleException(realPath + "/WEB-INF/dwr-modules.xml file doesn't exist.", e);
  287. }
  288. finally {
  289. if (inputStream != null) {
  290. try {
  291. inputStream.close();
  292. }
  293. catch (IOException io) {
  294. log.error("Error while closing input stream", io);
  295. }
  296. }
  297. }
  298.  
  299. // mark to delete the entire module web directory on exit
  300. // this will usually only be used when an improper shutdown has occurred.
  301. String folderPath = realPath + "/WEB-INF/view/module/" + mod.getModuleIdAsPath();
  302. File outFile = new File(folderPath.replace("/", File.separator));
  303. outFile.deleteOnExit();
  304.  
  305. // additional checks on module needing a context refresh
  306. if (moduleNeedsContextRefresh == false) {
  307.  
  308. // AOP advice points are only loaded during the context refresh now.
  309. // if the context hasn't been marked to be refreshed yet, mark it
  310. // now if this module defines some advice
  311. if (mod.getAdvicePoints() != null && mod.getAdvicePoints().size() > 0) {
  312. moduleNeedsContextRefresh = true;
  313. }
  314.  
  315. }
  316.  
  317. // refresh the spring web context to get the just-created xml
  318. // files into it (if we copied an xml file)
  319. if (moduleNeedsContextRefresh && delayContextRefresh == false) {
  320. if (log.isDebugEnabled())
  321. log.debug("Refreshing context for module" + mod);
  322.  
  323. try {
  324. refreshWAC(servletContext, false, mod);
  325. log.debug("Done Refreshing WAC");
  326. }
  327. catch (Exception e) {
  328. String msg = "Unable to refresh the WebApplicationContext";
  329. mod.setStartupErrorMessage(msg, e);
  330.  
  331. if (log.isWarnEnabled())
  332. log.warn(msg + " for module: " + mod.getModuleId(), e);
  333.  
  334. try {
  335. stopModule(mod, servletContext, true);
  336. ModuleFactory.stopModule(mod, true, true); //remove jar from classloader play
  337. }
  338. catch (Exception e2) {
  339. // exception expected with most modules here
  340. if (log.isWarnEnabled())
  341. log.warn("Error while stopping a module that had an error on refreshWAC", e2);
  342. }
  343.  
  344. // try starting the application context again
  345. refreshWAC(servletContext, false, mod);
  346.  
  347. notifySuperUsersAboutModuleFailure(mod);
  348. }
  349.  
  350. }
  351.  
  352. if (!delayContextRefresh) {
  353. // only loading the servlets/filters if spring is refreshed because one
  354. // might depend on files being available in spring
  355. // if the caller wanted to delay the refresh then they are responsible for
  356. // calling these two methods on the module
  357.  
  358. // find and cache the module's servlets
  359. //(only if the module started successfully previously)
  360. if (ModuleFactory.isModuleStarted(mod)) {
  361. log.debug("Loading servlets and filters for module: " + mod);
  362. loadServlets(mod, servletContext);
  363. loadFilters(mod, servletContext);
  364. }
  365. }
  366.  
  367. // return true if the module needs a context refresh and we didn't do it here
  368. return (moduleNeedsContextRefresh && delayContextRefresh == true);
  369.  
  370. }
  371.  
  372. // we aren't processing this module, so a context refresh is not necessary
  373. return false;
  374. }
  375.  
  376. /**
  377. * Send an Alert to all super users that the given module did not start successfully.
  378. *
  379. * @param mod The Module that failed
  380. */
  381. private static void notifySuperUsersAboutModuleFailure(Module mod) {
  382. try {
  383. // Add the privileges necessary for notifySuperUsers
  384. Context.addProxyPrivilege(PrivilegeConstants.MANAGE_ALERTS);
  385. Context.addProxyPrivilege(PrivilegeConstants.VIEW_USERS);
  386.  
  387. // Send an alert to all administrators
  388. Context.getAlertService().notifySuperUsers("Module.startupError.notification.message", null, mod.getName());
  389. }
  390. finally {
  391. // Remove added privileges
  392. Context.removeProxyPrivilege(PrivilegeConstants.VIEW_USERS);
  393. Context.removeProxyPrivilege(PrivilegeConstants.MANAGE_ALERTS);
  394. }
  395. }
  396.  
  397. /**
  398. * This method will find and cache this module's servlets (so that it doesn't have to look them
  399. * up every time)
  400. *
  401. * @param mod
  402. * @param servletContext the servlet context
  403. * @return this module's servlet map
  404. */
  405. public static void loadServlets(Module mod, ServletContext servletContext) {
  406. Element rootNode = mod.getConfig().getDocumentElement();
  407. NodeList servletTags = rootNode.getElementsByTagName("servlet");
  408.  
  409. for (int i = 0; i < servletTags.getLength(); i++) {
  410. Node node = servletTags.item(i);
  411. NodeList childNodes = node.getChildNodes();
  412. String name = "", className = "";
  413. for (int j = 0; j < childNodes.getLength(); j++) {
  414. Node childNode = childNodes.item(j);
  415. if ("servlet-name".equals(childNode.getNodeName())) {
  416. if (childNode.getTextContent() != null)
  417. name = childNode.getTextContent().trim();
  418. } else if ("servlet-class".equals(childNode.getNodeName())) {
  419. if (childNode.getTextContent() != null)
  420. className = childNode.getTextContent().trim();
  421. }
  422. }
  423. if (name.length() == 0 || className.length() == 0) {
  424. log.warn("both 'servlet-name' and 'servlet-class' are required for the 'servlet' tag. Given '" + name
  425. + "' and '" + className + "' for module " + mod.getName());
  426. continue;
  427. }
  428.  
  429. HttpServlet httpServlet = null;
  430. try {
  431. httpServlet = (HttpServlet) ModuleFactory.getModuleClassLoader(mod).loadClass(className).newInstance();
  432. }
  433. catch (ClassNotFoundException e) {
  434. log.warn("Class not found for servlet " + name + " for module " + mod.getName(), e);
  435. continue;
  436. }
  437. catch (IllegalAccessException e) {
  438. log.warn("Class cannot be accessed for servlet " + name + " for module " + mod.getName(), e);
  439. continue;
  440. }
  441. catch (InstantiationException e) {
  442. log.warn("Class cannot be instantiated for servlet " + name + " for module " + mod.getName(), e);
  443. continue;
  444. }
  445.  
  446. try {
  447. log.debug("Initializing " + name + " servlet. - " + httpServlet + ".");
  448. ServletConfig servletConfig = new ModuleServlet.SimpleServletConfig(name, servletContext);
  449. httpServlet.init(servletConfig);
  450. }
  451. catch (Throwable t) {
  452. log.warn("Unable to initialize servlet: ", t);
  453. throw new ModuleException("Unable to initialize servlet: " + httpServlet, mod.getModuleId(), t);
  454. }
  455.  
  456. // don't allow modules to overwrite servlets of other modules.
  457. HttpServlet otherServletUsingSameName = moduleServlets.get(name);
  458. if (otherServletUsingSameName != null) {
  459. //log.debug("A servlet mapping with name " + name + " already exists. " + mod.getModuleId() + "'s servlet is overwriting it");
  460. String otherServletName = otherServletUsingSameName.getClass().getPackage() + "."
  461. + otherServletUsingSameName.getClass().getName();
  462. throw new ModuleException("A servlet mapping with name " + name + " is already in use and pointing at: "
  463. + otherServletName + " from another installed module and this module is trying"
  464. + " to use that same name. Either the module attempting to be installed (" + mod.getModuleId()
  465. + ") will not work or the other one will not. Please consult the developers of these two"
  466. + " modules to sort this out.");
  467. }
  468.  
  469. log.debug("Caching the " + name + " servlet.");
  470. moduleServlets.put(name, httpServlet);
  471. }
  472. }
  473.  
  474. /**
  475. * Remove all of the servlets defined for this module
  476. *
  477. * @param mod the module that is being stopped that needs its servlets removed
  478. */
  479. public static void unloadServlets(Module mod) {
  480. Element rootNode = mod.getConfig().getDocumentElement();
  481. NodeList servletTags = rootNode.getElementsByTagName("servlet");
  482.  
  483. for (int i = 0; i < servletTags.getLength(); i++) {
  484. Node node = servletTags.item(i);
  485. NodeList childNodes = node.getChildNodes();
  486. String name = "";
  487. for (int j = 0; j < childNodes.getLength(); j++) {
  488. Node childNode = childNodes.item(j);
  489. if ("servlet-name".equals(childNode.getNodeName())) {
  490. if (childNode.getTextContent() != null) {
  491. name = childNode.getTextContent().trim();
  492. HttpServlet servlet = moduleServlets.get(name);
  493. if (servlet != null) {
  494. servlet.destroy(); // shut down the servlet
  495. moduleServlets.remove(name);
  496. }
  497. }
  498. }
  499. }
  500. }
  501. }
  502.  
  503. /**
  504. * This method will initialize and store this module's filters
  505. *
  506. * @param module - The Module to load and register Filters
  507. * @param servletContext - The servletContext within which this method is called
  508. */
  509. public static void loadFilters(Module module, ServletContext servletContext) {
  510.  
  511. // Load Filters
  512. Map<String, Filter> filters = new HashMap<String, Filter>();
  513. try {
  514. for (ModuleFilterDefinition def : ModuleFilterDefinition.retrieveFilterDefinitions(module)) {
  515. if (moduleFiltersByName.containsKey(def.getFilterName())) {
  516. throw new ModuleException("A filter with name <" + def.getFilterName()
  517. + "> has already been registered.");
  518. }
  519. ModuleFilterConfig config = ModuleFilterConfig.getInstance(def, servletContext);
  520. Filter f = (Filter) ModuleFactory.getModuleClassLoader(module).loadClass(def.getFilterClass()).newInstance();
  521. f.init(config);
  522. filters.put(def.getFilterName(), f);
  523. }
  524. }
  525. catch (ModuleException e) {
  526. throw e;
  527. }
  528. catch (Exception e) {
  529. throw new ModuleException("An error occurred initializing Filters for module: " + module.getModuleId(), e);
  530. }
  531. moduleFilters.put(module, filters.values());
  532. moduleFiltersByName.putAll(filters);
  533. log.debug("Module: " + module.getModuleId() + " successfully loaded " + filters.size() + " filters.");
  534.  
  535. // Load Filter Mappings
  536. List<ModuleFilterMapping> modMappings = ModuleFilterMapping.retrieveFilterMappings(module);
  537. moduleFilterMappings.addAll(modMappings);
  538. log.debug("Module: " + module.getModuleId() + " successfully loaded " + modMappings.size() + " filter mappings.");
  539. }
  540.  
  541. /**
  542. * This method will destroy and remove all filters that were registered by the passed
  543. * {@link Module}
  544. *
  545. * @param module - The Module for which you want to remove and destroy filters.
  546. */
  547. public static void unloadFilters(Module module) {
  548.  
  549. // Unload Filter Mappings
  550. for (java.util.Iterator<ModuleFilterMapping> mapIter = moduleFilterMappings.iterator(); mapIter.hasNext();) {
  551. ModuleFilterMapping mapping = mapIter.next();
  552. if (module.equals(mapping.getModule())) {
  553. mapIter.remove();
  554. log.debug("Removed ModuleFilterMapping: " + mapping);
  555. }
  556. }
  557.  
  558. // unload Filters
  559. Collection<Filter> filters = moduleFilters.get(module);
  560. if (filters != null) {
  561. try {
  562. for (Filter f : filters) {
  563. f.destroy();
  564. }
  565. }
  566. catch (Exception e) {
  567. log.warn("An error occurred while trying to destroy and remove module Filter.", e);
  568. }
  569. log.debug("Module: " + module.getModuleId() + " successfully unloaded " + filters.size() + " filters.");
  570. moduleFilters.remove(module);
  571.  
  572. for (Iterator<String> i = moduleFiltersByName.keySet().iterator(); i.hasNext();) {
  573. String filterName = i.next();
  574. Filter filterVal = moduleFiltersByName.get(filterName);
  575. if (filters.contains(filterVal)) {
  576. i.remove();
  577. }
  578. }
  579. }
  580. }
  581.  
  582. /**
  583. * This method will return all Filters that have been registered a module
  584. *
  585. * @return A Collection of {@link Filter}s that have been registered by a module
  586. */
  587. public static Collection<Filter> getFilters() {
  588. return moduleFiltersByName.values();
  589. }
  590.  
  591. /**
  592. * This method will return all Filter Mappings that have been registered by a module
  593. *
  594. * @return A Collection of all {@link ModuleFilterMapping}s that have been registered by a
  595. * Module
  596. */
  597. public static Collection<ModuleFilterMapping> getFilterMappings() {
  598. return moduleFilterMappings;
  599. }
  600.  
  601. /**
  602. * Return List of Filters that have been loaded through Modules that have mappings that pass for
  603. * the passed request
  604. *
  605. * @param request - The request to check for matching {@link Filter}s
  606. * @return List of all {@link Filter}s that have filter mappings that match the passed request
  607. */
  608. public static List<Filter> getFiltersForRequest(ServletRequest request) {
  609.  
  610. List<Filter> filters = new Vector<Filter>();
  611. if (request != null) {
  612. HttpServletRequest httpRequest = (HttpServletRequest) request;
  613. String requestPath = httpRequest.getRequestURI();
  614.  
  615. if (requestPath != null) {
  616. if (requestPath.startsWith(httpRequest.getContextPath()))
  617. requestPath = requestPath.substring(httpRequest.getContextPath().length());
  618. for (ModuleFilterMapping filterMapping : WebModuleUtil.getFilterMappings()) {
  619. if (ModuleFilterMapping.filterMappingPasses(filterMapping, requestPath)) {
  620. Filter passedFilter = moduleFiltersByName.get(filterMapping.getFilterName());
  621. if (passedFilter != null) {
  622. filters.add(passedFilter);
  623. } else {
  624. log.warn("Unable to retrieve filter that has a name of " + filterMapping.getFilterName()
  625. + " in filter mapping.");
  626. }
  627. }
  628. }
  629. }
  630. }
  631. return filters;
  632. }
  633.  
  634. /**
  635. * @param inputStream
  636. * @param realPath
  637. * @return
  638. */
  639. private static Document getDWRModuleXML(InputStream inputStream, String realPath) {
  640. Document dwrmodulexml = null;
  641. try {
  642. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  643. DocumentBuilder db = dbf.newDocumentBuilder();
  644. db.setEntityResolver(new EntityResolver() {
  645.  
  646. public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
  647. // When asked to resolve external entities (such as a DTD) we return an InputSource
  648. // with no data at the end, causing the parser to ignore the DTD.
  649. return new InputSource(new StringReader(""));
  650. }
  651. });
  652.  
  653. dwrmodulexml = db.parse(inputStream);
  654. }
  655. catch (Exception e) {
  656. throw new ModuleException("Error parsing dwr-modules.xml file", e);
  657. }
  658.  
  659. return dwrmodulexml;
  660. }
  661.  
  662. /**
  663. * Reverses all activities done by startModule(org.openmrs.module.Module) Normal stop/shutdown
  664. * is done by ModuleFactory
  665. */
  666. public static void shutdownModules(ServletContext servletContext) {
  667.  
  668. String realPath = servletContext.getRealPath("");
  669.  
  670. // clear the module messages
  671. String messagesPath = realPath + "/WEB-INF/";
  672. File folder = new File(messagesPath.replace("/", File.separator));
  673.  
  674. if (folder.exists()) {
  675. Properties emptyProperties = new Properties();
  676. for (File f : folder.listFiles()) {
  677. if (f.getName().startsWith("module_messages")) {
  678. OpenmrsUtil.storeProperties(emptyProperties, f, "");
  679. }
  680. }
  681. }
  682.  
  683. // call web shutdown for each module
  684. for (Module mod : ModuleFactory.getLoadedModules()) {
  685. stopModule(mod, servletContext, true);
  686. }
  687.  
  688. }
  689.  
  690. /**
  691. * Reverses all visible activities done by startModule(org.openmrs.module.Module)
  692. *
  693. * @param mod
  694. * @param servletContext
  695. */
  696. public static void stopModule(Module mod, ServletContext servletContext) {
  697. stopModule(mod, servletContext, false);
  698. }
  699.  
  700. /**
  701. * Reverses all visible activities done by startModule(org.openmrs.module.Module)
  702. *
  703. * @param mod
  704. * @param servletContext
  705. * @param skipRefresh
  706. */
  707. private static void stopModule(Module mod, ServletContext servletContext, boolean skipRefresh) {
  708.  
  709. String moduleId = mod.getModuleId();
  710. String modulePackage = mod.getPackageName();
  711.  
  712. // stop all dependent modules
  713. for (Module dependentModule : ModuleFactory.getStartedModules()) {
  714. if (!dependentModule.equals(mod) && dependentModule.getRequiredModules().contains(modulePackage))
  715. stopModule(dependentModule, servletContext, skipRefresh);
  716. }
  717.  
  718. String realPath = servletContext.getRealPath("");
  719.  
  720. // delete the web files from the webapp
  721. String absPath = realPath + "/WEB-INF/view/module/" + moduleId;
  722. File moduleWebFolder = new File(absPath.replace("/", File.separator));
  723. if (moduleWebFolder.exists()) {
  724. try {
  725. OpenmrsUtil.deleteDirectory(moduleWebFolder);
  726. }
  727. catch (IOException io) {
  728. log.warn("Couldn't delete: " + moduleWebFolder.getAbsolutePath(), io);
  729. }
  730. }
  731.  
  732. // (not) deleting module message properties
  733.  
  734. // remove the module's servlets
  735. unloadServlets(mod);
  736.  
  737. // remove the module's filters and filter mappings
  738. unloadFilters(mod);
  739.  
  740. // remove this module's entries in the dwr xml file
  741. InputStream inputStream = null;
  742. try {
  743. Document config = mod.getConfig();
  744. Element root = config.getDocumentElement();
  745. // if they defined any xml element
  746. if (root.getElementsByTagName("dwr").getLength() > 0) {
  747.  
  748. // get the dwr-module.xml file that we're appending our code to
  749. File f = new File(realPath + "/WEB-INF/dwr-modules.xml".replace("/", File.separator));
  750. inputStream = new FileInputStream(f);
  751. Document dwrmodulexml = getDWRModuleXML(inputStream, realPath);
  752. Element outputRoot = dwrmodulexml.getDocumentElement();
  753.  
  754. // loop over all of the children of the "dwr" tag
  755. // and remove all "allow" and "signature" tags that have the
  756. // same moduleId attr as the module being stopped
  757. NodeList nodeList = outputRoot.getChildNodes();
  758. int i = 0;
  759. while (i < nodeList.getLength()) {
  760. Node current = nodeList.item(i);
  761. if ("allow".equals(current.getNodeName()) || "signatures".equals(current.getNodeName())) {
  762. NamedNodeMap attrs = current.getAttributes();
  763. Node attr = attrs.getNamedItem("moduleId");
  764. if (attr != null && moduleId.equals(attr.getNodeValue())) {
  765. outputRoot.removeChild(current);
  766. } else
  767. i++;
  768. } else
  769. i++;
  770. }
  771.  
  772. // save the dwr-modules.xml file.
  773. OpenmrsUtil.saveDocument(dwrmodulexml, f);
  774. }
  775. }
  776. catch (FileNotFoundException e) {
  777. throw new ModuleException(realPath + "/WEB-INF/dwr-modules.xml file doesn't exist.", e);
  778. }
  779. finally {
  780. if (inputStream != null) {
  781. try {
  782. inputStream.close();
  783. }
  784. catch (IOException io) {
  785. log.error("Error while closing input stream", io);
  786. }
  787. }
  788. }
  789.  
  790. if (skipRefresh == false) {
  791. //try {
  792. // if (dispatcherServlet != null)
  793. // dispatcherServlet.reInitFrameworkServlet();
  794. // if (dwrServlet != null)
  795. // dwrServlet.reInitServlet();
  796. //}
  797. //catch (ServletException se) {
  798. // log.warn("Unable to reinitialize webapplicationcontext for dispatcherservlet for module: " + mod.getName(), se);
  799. //}
  800.  
  801. refreshWAC(servletContext, false, null);
  802. }
  803.  
  804. }
  805.  
  806. /**
  807. * Stops, closes, and refreshes the Spring context for the given <code>servletContext</code>
  808. *
  809. * @param servletContext
  810. * @param isOpenmrsStartup if this refresh is being done at application startup
  811. * @param startedModule the module that was just started and waiting on the context refresh
  812. * @return The newly refreshed webApplicationContext
  813. */
  814. public static XmlWebApplicationContext refreshWAC(ServletContext servletContext, boolean isOpenmrsStartup,
  815. Module startedModule) {
  816. XmlWebApplicationContext wac = (XmlWebApplicationContext) WebApplicationContextUtils
  817. .getWebApplicationContext(servletContext);
  818. if (log.isDebugEnabled())
  819. log.debug("Refreshing web applciation Context of class: " + wac.getClass().getName());
  820.  
  821. XmlWebApplicationContext newAppContext = (XmlWebApplicationContext) ModuleUtil.refreshApplicationContext(wac,
  822. isOpenmrsStartup, startedModule);
  823.  
  824. try {
  825. // must "refresh" the spring dispatcherservlet as well to add in
  826. //the new handlerMappings
  827. if (dispatcherServlet != null)
  828. dispatcherServlet.reInitFrameworkServlet();
  829. }
  830. catch (ServletException se) {
  831. log.warn("Caught a servlet exception while refreshing the dispatcher servlet", se);
  832. }
  833.  
  834. try {
  835. if (dwrServlet != null)
  836. dwrServlet.reInitServlet();
  837. }
  838. catch (ServletException se) {
  839. log.warn("Cause a servlet exception while refreshing the dwr servlet", se);
  840. }
  841.  
  842. return newAppContext;
  843. }
  844.  
  845. /**
  846. * Save the dispatcher servlet for use later (reinitializing things)
  847. *
  848. * @param ds
  849. */
  850. public static void setDispatcherServlet(DispatcherServlet ds) {
  851. log.debug("Setting dispatcher servlet: " + ds);
  852. dispatcherServlet = ds;
  853. }
  854.  
  855. /**
  856. * Save the dwr servlet for use later (reinitializing things)
  857. *
  858. * @param ds
  859. */
  860. public static void setDWRServlet(OpenmrsDWRServlet ds) {
  861. log.debug("Setting dwr servlet: " + ds);
  862. dwrServlet = ds;
  863. //new NewCreator();
  864. //SessionFactoryUtils.processDeferredClose(null);
  865. }
  866.  
  867. /**
  868. * Finds the servlet defined by the servlet name
  869. *
  870. * @param servletName the name of the servlet out of the path
  871. * @return the current servlet or null if none defined
  872. */
  873. public static HttpServlet getServlet(String servletName) {
  874. return moduleServlets.get(servletName);
  875. }
  876.  
  877. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement