Advertisement
Guest User

Untitled

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