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