Clean up web.xml and create a unit test to keep it clean.

VIVO-19
This commit is contained in:
j2blake 2013-02-04 17:22:29 -05:00
parent 9bba099882
commit 7c2de3a6f2
2 changed files with 310 additions and 184 deletions

View file

@ -0,0 +1,307 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpServlet;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.sun.net.httpserver.HttpServer;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
/**
* Check to see that web.xml doesn't include any constructs that are permitted
* by Tomcat but prohibited by the Servlet 2.4 Specification.
*
* These are things that might not be noticed when testing Vitro on Tomcat, but
* might show up as problems on other containers like GlassFish or WebLogic.
* <ul>
* <li>
* The contents of <dispatcher/> elements must be upper-case. Tomcat permits
* lower-case, but the specification does not.</li>
* <li>
* All <servlet-class/> tags must point to existing classes. Tomcat does not try
* to load a servlet until it is necessary to service a request, but WebLogic
* loads them on startup. Either method is permitted by the specification.</li>
* </ul>
*
* As long as we're here, let's check some things that would cause Vitro to fail
* in any servlet container.
* <ul>
* <li>
* All <listener-class/> tags must point to existing classes.</li>
* <li>
* All <filter-class/> tags must point to existing classes.</li>
* <li>
* All <taglib-location/> tags must point to existing files.</li>
* </ul>
*/
@RunWith(value = Parameterized.class)
public class WebXmlTest extends AbstractTestClass {
private static final Log log = LogFactory.getLog(WebXmlTest.class);
@Parameters
public static Collection<Object[]> findWebXmlFiles() {
IOFileFilter fileFilter = new NameFileFilter("web.xml");
IOFileFilter dirFilter = new NotFileFilter(new NameFileFilter(".build"));
Collection<File> files = FileUtils.listFiles(new File("."), fileFilter,
dirFilter);
if (files.isEmpty()) {
System.out.println("WARNING: could not find web.xml");
} else {
if (files.size() > 1) {
System.out
.println("WARNING: testing more than one web.xml file: "
+ files);
}
}
Collection<Object[]> parameters = new ArrayList<Object[]>();
for (File file : files) {
parameters.add(new Object[] { file });
}
return parameters;
}
private static DocumentBuilder docBuilder = createDocBuilder();
private static XPath xpath = createXPath();
private static DocumentBuilder createDocBuilder() {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
factory.setNamespaceAware(true); // never forget this!
return factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
}
}
private static XPath createXPath() {
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new StupidNamespaceContext());
return xp;
}
private File webXmlFile;
private Document webXmlDoc;
private List<String> messages = new ArrayList<String>();
public WebXmlTest(File file) {
this.webXmlFile = file;
}
@Before
public void parseWebXml() throws SAXException, IOException {
if (webXmlDoc == null) {
webXmlDoc = docBuilder.parse(webXmlFile);
}
}
@Test
public void checkAll() throws IOException {
checkDispatcherValues();
checkServletClasses();
checkListenerClasses();
checkFilterClasses();
checkTaglibLocations();
if (!messages.isEmpty()) {
for (String message : messages) {
System.out.println(message);
}
fail("Found these problems with '" + webXmlFile.getCanonicalPath()
+ "'\n " + StringUtils.join(messages, "\n "));
}
}
private void checkDispatcherValues() {
List<String> okValues = Arrays.asList(new String[] { "FORWARD",
"REQUEST", "INCLUDE", "ERROR" });
for (Node n : findNodes("//j2ee:dispatcher")) {
String text = n.getTextContent();
if (!okValues.contains(text)) {
messages.add("<dispatcher>" + text
+ "</dispatcher> is not valid. Acceptable values are "
+ okValues);
}
}
}
private void checkServletClasses() {
for (Node n : findNodes("//j2ee:servlet-class")) {
String text = n.getTextContent();
String problem = confirmClassNameIsValid(text, HttpServlet.class);
if (problem != null) {
messages.add("<servlet-class>" + text
+ "</servlet-class> is not valid: " + problem);
}
}
}
private void checkListenerClasses() {
for (Node n : findNodes("//j2ee:listener-class")) {
String text = n.getTextContent();
String problem = confirmClassNameIsValid(text,
ServletContextListener.class);
if (problem != null) {
messages.add("<listener-class>" + text
+ "</listener-class> is not valid: " + problem);
}
}
}
private void checkFilterClasses() {
for (Node n : findNodes("//j2ee:filter-class")) {
String text = n.getTextContent();
String problem = confirmClassNameIsValid(text, Filter.class);
if (problem != null) {
messages.add("<filter-class>" + text
+ "</filter-class> is not valid: " + problem);
}
}
}
private void checkTaglibLocations() {
// TODO Don't know how to do this one. Where do we look for the taglibs?
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
/**
* Search for an Xpath, returning a handy list.
*/
private List<Node> findNodes(String pattern) {
try {
XPathExpression xpe = xpath.compile(pattern);
NodeList nodes = (NodeList) xpe.evaluate(
webXmlDoc.getDocumentElement(), XPathConstants.NODESET);
List<Node> list = new ArrayList<Node>();
for (int i = 0; i < nodes.getLength(); i++) {
list.add(nodes.item(i));
}
return list;
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
}
}
/**
* Check that the supplied className can be instantiated with a
* zero-argument constructor, and assigned to a variable of the target
* class.
*/
private String confirmClassNameIsValid(String className,
Class<?> targetClass) {
try {
Class<?> specifiedClass = Class.forName(className);
Object o = specifiedClass.newInstance();
if (!targetClass.isInstance(o)) {
return specifiedClass.getSimpleName()
+ " is not a subclass of "
+ targetClass.getSimpleName() + ".";
}
} catch (ClassNotFoundException e) {
return "The class does not exist.";
} catch (InstantiationException | IllegalAccessException e) {
return "The class does not have a public constructor "
+ "that takes zero arguments.";
}
return null;
}
/**
* Dump the first 20 nodes of an XML context, excluding comments and blank
* text nodes.
*/
@SuppressWarnings("unused")
private int dumpXml(Node xmlNode, int... parms) {
int remaining = (parms.length == 0) ? 20 : parms[0];
int level = (parms.length < 2) ? 1 : parms[1];
Node n = xmlNode;
if (Node.COMMENT_NODE == n.getNodeType()) {
return 0;
}
if (Node.TEXT_NODE == n.getNodeType()) {
if (StringUtils.isBlank(n.getTextContent())) {
return 0;
}
}
int used = 1;
System.out.println(StringUtils.repeat("-->", level) + n);
NodeList nl = n.getChildNodes();
for (int i = 0; (i < nl.getLength() && remaining > used); i++) {
used += dumpXml(nl.item(i), remaining - used, level + 1);
}
return used;
}
// ----------------------------------------------------------------------
// Helper classes
// ----------------------------------------------------------------------
private static class StupidNamespaceContext implements NamespaceContext {
@Override
public String getNamespaceURI(String prefix) {
if ("j2ee".equals(prefix)) {
return "http://java.sun.com/xml/ns/j2ee";
} else {
throw new UnsupportedOperationException();
}
}
@Override
public String getPrefix(String namespaceURI) {
throw new UnsupportedOperationException();
}
@Override
public Iterator<?> getPrefixes(String namespaceURI) {
throw new UnsupportedOperationException();
}
}
}

View file

@ -122,8 +122,8 @@
<filter-mapping> <filter-mapping>
<filter-name>VitroRequestPrep</filter-name> <filter-name>VitroRequestPrep</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
<dispatcher>request</dispatcher> <dispatcher>REQUEST</dispatcher>
<dispatcher>forward</dispatcher> <dispatcher>FORWARD</dispatcher>
</filter-mapping> </filter-mapping>
<filter> <filter>
@ -133,7 +133,7 @@
<filter-mapping> <filter-mapping>
<filter-name>PageRoutingFilter</filter-name> <filter-name>PageRoutingFilter</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
<dispatcher>request</dispatcher> <dispatcher>REQUEST</dispatcher>
</filter-mapping> </filter-mapping>
<!-- Spring setup **************************************************** --> <!-- Spring setup **************************************************** -->
@ -164,25 +164,6 @@
--> -->
<!-- Servlets ********************************************************** --> <!-- Servlets ********************************************************** -->
<servlet>
<!--adding only trimSpaces param to defaults to clean up html output-->
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>trimSpaces</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet> <servlet>
<servlet-name>IndexController</servlet-name> <servlet-name>IndexController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.search.controller.IndexController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.search.controller.IndexController</servlet-class>
@ -201,15 +182,6 @@
<url-pattern>/RecomputeInferences</url-pattern> <url-pattern>/RecomputeInferences</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>SDBSetupController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.SDBSetupController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SDBSetupController</servlet-name>
<url-pattern>/sdbsetup</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>MenuManagementEdit</servlet-name> <servlet-name>MenuManagementEdit</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.MenuManagementEdit</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.MenuManagementEdit</servlet-class>
@ -228,24 +200,6 @@
<url-pattern>/ajax/sparqlQuery</url-pattern> <url-pattern>/ajax/sparqlQuery</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- This is the new navigation controller. It is not ready for the 1.1 release
see http://issues.library.cornell.edu/browse/NIHVIVO-597
<servlet>
<servlet-name>NavigationController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.NavigationController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>NavigationController</servlet-name>
<url-pattern>/nav/*</url-pattern>
</servlet-mapping>
-->
<servlet>
<servlet-name>fetch</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.QueryServlet</servlet-class>
<!--load-on-startup>2</load-on-startup-->
</servlet>
<servlet> <servlet>
<servlet-name>AboutController</servlet-name> <servlet-name>AboutController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.AboutController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.AboutController</servlet-class>
@ -389,15 +343,6 @@
<url-pattern>/editRequestAJAX</url-pattern> <url-pattern>/editRequestAJAX</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>FlagUpdateController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.FlagUpdateController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FlagUpdateController</servlet-name>
<url-pattern>/flagUpdate</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>RDFUploadFormController</servlet-name> <servlet-name>RDFUploadFormController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.jena.RDFUploadFormController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.jena.RDFUploadFormController</servlet-class>
@ -452,24 +397,6 @@
<url-pattern>/jenaXmlFileUpload/*</url-pattern> <url-pattern>/jenaXmlFileUpload/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>OwlImportController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.owl.OwlImportController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OwlImportController</servlet-name>
<url-pattern>/owl</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>OwlImportServlet</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.owl.ProtegeOwlImportServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OwlImportServlet</servlet-name>
<url-pattern>/importOwl</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>JenaAdminServlet</servlet-name> <servlet-name>JenaAdminServlet</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.jena.JenaAdminActions</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.jena.JenaAdminActions</servlet-class>
@ -569,16 +496,6 @@
<url-pattern>/datapropEdit</url-pattern> <url-pattern>/datapropEdit</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>KeywordEditController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.KeywordEditController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>KeywordEditController</servlet-name>
<url-pattern>/keywordEdit</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>OntologyEditController</servlet-name> <servlet-name>OntologyEditController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.OntologyEditController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.OntologyEditController</servlet-class>
@ -777,24 +694,6 @@
<url-pattern>/admin/wait</url-pattern> <url-pattern>/admin/wait</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>StatementChangeListingController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.listing.jena.StatementChangeListingController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>StatementChangeListingController</servlet-name>
<url-pattern>/statementHistory</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>WriteOutChangesController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.listing.jena.WriteOutChangesController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WriteOutChangesController</servlet-name>
<url-pattern>/writeOutChanges</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>ListVClassWebappsController</servlet-name> <servlet-name>ListVClassWebappsController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.ListVClassWebappsController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.ListVClassWebappsController</servlet-class>
@ -957,15 +856,6 @@
<url-pattern>/edit/reorder</url-pattern> <url-pattern>/edit/reorder</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>AdminController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.AdminController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AdminController</servlet-name>
<url-pattern>/adminCon</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>TermsOfUseController</servlet-name> <servlet-name>TermsOfUseController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.TermsOfUseController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.TermsOfUseController</servlet-class>
@ -1105,32 +995,6 @@
<url-pattern>/browse</url-pattern> <url-pattern>/browse</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>pubsbyorg</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.vclass.PubsByDepartmentServlet</servlet-class>
<init-param>
<param-name>workspaceDir</param-name>
<param-value>/usr/local/services/vivo/logs</param-value>
</init-param>
<!--load-on-startup>2</load-on-startup-->
</servlet>
<servlet>
<servlet-name>coauthors</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.vclass.CoAuthorServlet</servlet-class>
<init-param>
<param-name>workspaceDir</param-name>
<param-value>/usr/local/services/vivo/logs</param-value>
</init-param>
<!--load-on-startup>2</load-on-startup-->
</servlet>
<servlet>
<servlet-name>generic_create</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.GenericDBCreate</servlet-class>
<!--load-on-startup>2</load-on-startup-->
</servlet>
<servlet> <servlet>
<servlet-name>serveFiles</servlet-name> <servlet-name>serveFiles</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.filestorage.serving.FileServingServlet</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.filestorage.serving.FileServingServlet</servlet-class>
@ -1140,21 +1004,6 @@
<url-pattern>/file/*</url-pattern> <url-pattern>/file/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>generic_editprep</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.GenericDBEditPrep</servlet-class>
</servlet>
<servlet>
<servlet-name>generic_update</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.GenericDBUpdate</servlet-class>
</servlet>
<servlet>
<servlet-name>generic_delete</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.GenericDBDelete</servlet-class>
</servlet>
<servlet> <servlet>
<servlet-name>SparqlQuery</servlet-name> <servlet-name>SparqlQuery</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.SparqlQueryServlet</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.SparqlQueryServlet</servlet-class>
@ -1165,16 +1014,6 @@
<url-pattern>/admin/sparqlquery</url-pattern> <url-pattern>/admin/sparqlquery</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>VisualizationController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>VisualizationController</servlet-name>
<url-pattern>/visualization</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>primitiveRdfEdit</servlet-name> <servlet-name>primitiveRdfEdit</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.PrimitiveRdfEdit</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.PrimitiveRdfEdit</servlet-class>
@ -1194,10 +1033,6 @@
</servlet-mapping> </servlet-mapping>
<!-- ============================== servlet-mappings ======================== --> <!-- ============================== servlet-mappings ======================== -->
<servlet-mapping>
<servlet-name>fetch</servlet-name>
<url-pattern>/fetch</url-pattern>
</servlet-mapping>
<servlet-mapping> <servlet-mapping>
<servlet-name>mailusers</servlet-name> <servlet-name>mailusers</servlet-name>
<url-pattern>/mailusers</url-pattern> <url-pattern>/mailusers</url-pattern>
@ -1256,22 +1091,6 @@
<servlet-name>coauthors</servlet-name> <servlet-name>coauthors</servlet-name>
<url-pattern>/coauthors</url-pattern> <url-pattern>/coauthors</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet-mapping>
<servlet-name>generic_create</servlet-name>
<url-pattern>/generic_create</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>generic_editprep</servlet-name>
<url-pattern>/generic_editprep</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>generic_update</servlet-name>
<url-pattern>/generic_update</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>generic_delete</servlet-name>
<url-pattern>/generic_delete</url-pattern>
</servlet-mapping>
<!-- ==================== sparql query builder ==================== --> <!-- ==================== sparql query builder ==================== -->