App Engine 1.8.4.
[gae.git] / java / src / main / com / google / apphosting / utils / config / WebXmlReader.java
blobe45e276f3dd21cc4cb11eaa6a6e027f4da7a826a
1 // Copyright 2009 Google Inc. All Rights Reserved.
3 package com.google.apphosting.utils.config;
5 import com.google.apphosting.utils.config.WebXml.SecurityConstraint;
7 import org.mortbay.xml.XmlParser;
8 import org.mortbay.xml.XmlParser.Node;
10 import java.io.InputStream;
11 import java.net.URL;
12 import java.util.Stack;
14 /**
15 * This reads {@code web.xml}.
19 public class WebXmlReader extends AbstractConfigXmlReader<WebXml> {
21 private static final String[] DEFAULT_WELCOME_FILES = new String[] {
22 "index.html",
23 "index.jsp",
26 public static final String DEFAULT_RELATIVE_FILENAME = "WEB-INF/web.xml";
28 private static final String URLPATTERN_TAG = "url-pattern";
29 private static final String SERVLETMAP_TAG = "servlet-mapping";
30 private static final String FILTERMAP_TAG = "filter-mapping";
31 private static final String SECURITYCONST_TAG = "security-constraint";
32 private static final String AUTHCONST_TAG = "auth-constraint";
33 private static final String ROLENAME_TAG = "role-name";
34 private static final String USERDATACONST_TAG = "user-data-constraint";
35 private static final String TRANSGUARANTEE_TAG = "transport-guarantee";
36 private static final String WELCOME_FILE_LIST_TAG = "welcome-file-list";
37 private static final String WELCOME_FILE_TAG = "welcome-file";
38 private static final String EXTENSION_TAG = "extension";
39 private static final String MIME_TYPE_TAG = "mime-type";
40 private static final String ERROR_CODE_TAG = "error-code";
42 private final String relativeFilename;
44 /**
45 * Creates a reader for web.xml.
47 * @param appDir The directory in which the config file resides.
48 * @param relativeFilename The path to the config file, relative to
49 * {@code appDir}.
51 public WebXmlReader(String appDir, String relativeFilename) {
52 super(appDir, true);
53 this.relativeFilename = relativeFilename;
56 /**
57 * Creates a reader for web.xml.
59 * @param appDir The directory in which the web.xml config file resides. The
60 * path to the config file relative to the directory is assumed to be
61 * {@link #DEFAULT_RELATIVE_FILENAME}.
63 public WebXmlReader(String appDir) {
64 this(appDir, DEFAULT_RELATIVE_FILENAME);
67 @Override
68 protected String getRelativeFilename() {
69 return relativeFilename;
72 /**
73 * Parses the config file.
74 * @return A {@link WebXml} object representing the parsed configuration.
76 public WebXml readWebXml() {
77 return readConfigXml();
80 /**
81 * Instead of creating a default {@link XmlParser}, use the same
82 * logic as Jetty's {@code WebXmlConfiguration} to create one that
83 * is aware of web.xml files. Specifically, this method registers
84 * static versions of all known web.xml DTD's and schemas to avoid
85 * URL retrieval at parse time.
87 @Override
88 protected XmlParser createXmlParser() {
90 XmlParser xmlParser = new XmlParser();
91 URL dtd22 = getClass().getResource("/javax/servlet/resources/web-app_2_2.dtd");
92 URL dtd23 = getClass().getResource("/javax/servlet/resources/web-app_2_3.dtd");
93 URL jsp20xsd = getClass().getResource("/javax/servlet/resources/jsp_2_0.xsd");
94 URL jsp21xsd = getClass().getResource("/javax/servlet/resources/jsp_2_1.xsd");
95 URL j2ee14xsd = getClass().getResource("/javax/servlet/resources/j2ee_1_4.xsd");
96 URL webapp24xsd = getClass().getResource("/javax/servlet/resources/web-app_2_4.xsd");
97 URL webapp25xsd = getClass().getResource("/javax/servlet/resources/web-app_2_5.xsd");
98 URL schemadtd = getClass().getResource("/javax/servlet/resources/XMLSchema.dtd");
99 URL xmlxsd = getClass().getResource("/javax/servlet/resources/xml.xsd");
100 URL webservice11xsd =
101 getClass().getResource("/javax/servlet/resources/j2ee_web_services_client_1_1.xsd");
102 URL webservice12xsd =
103 getClass().getResource("/javax/servlet/resources/javaee_web_services_client_1_2.xsd");
104 URL datatypesdtd = getClass().getResource("/javax/servlet/resources/datatypes.dtd");
105 xmlParser.redirectEntity("web-app_2_2.dtd",dtd22);
106 xmlParser.redirectEntity("-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22);
107 xmlParser.redirectEntity("web.dtd",dtd23);
108 xmlParser.redirectEntity("web-app_2_3.dtd",dtd23);
109 xmlParser.redirectEntity("-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23);
110 xmlParser.redirectEntity("XMLSchema.dtd",schemadtd);
111 xmlParser.redirectEntity("http://www.w3.org/2001/XMLSchema.dtd",schemadtd);
112 xmlParser.redirectEntity("-//W3C//DTD XMLSCHEMA 200102//EN",schemadtd);
113 xmlParser.redirectEntity("jsp_2_0.xsd",jsp20xsd);
114 xmlParser.redirectEntity("http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd",jsp20xsd);
115 xmlParser.redirectEntity("jsp_2_1.xsd",jsp21xsd);
116 xmlParser.redirectEntity("http://java.sun.com/xml/ns/javaee/jsp_2_1.xsd",jsp21xsd);
117 xmlParser.redirectEntity("j2ee_1_4.xsd",j2ee14xsd);
118 xmlParser.redirectEntity("http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd",j2ee14xsd);
119 xmlParser.redirectEntity("web-app_2_4.xsd",webapp24xsd);
120 xmlParser.redirectEntity("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd",webapp24xsd);
121 xmlParser.redirectEntity("web-app_2_5.xsd",webapp25xsd);
122 xmlParser.redirectEntity("http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd",webapp25xsd);
123 xmlParser.redirectEntity("xml.xsd",xmlxsd);
124 xmlParser.redirectEntity("http://www.w3.org/2001/xml.xsd",xmlxsd);
125 xmlParser.redirectEntity("datatypes.dtd",datatypesdtd);
126 xmlParser.redirectEntity("http://www.w3.org/2001/datatypes.dtd",datatypesdtd);
127 xmlParser.redirectEntity("j2ee_web_services_client_1_1.xsd",webservice11xsd);
128 xmlParser.redirectEntity("http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd",
129 webservice11xsd);
130 xmlParser.redirectEntity("javaee_web_services_client_1_2.xsd",webservice12xsd);
131 xmlParser.redirectEntity("http://www.ibm.com/webservices/xsd/javaee_web_services_client_1_2.xsd",
132 webservice12xsd);
134 return xmlParser;
137 @Override
138 protected WebXml processXml(InputStream is) {
139 final WebXml webXml = new WebXml();
140 parse(new ParserCallback() {
142 private WebXml.SecurityConstraint security;
143 private String extension;
145 @Override
146 public void newNode(Node node, Stack<Node> ancestors) {
147 String thisTag = node.getTag().toLowerCase();
148 String parentTag = null;
149 if (ancestors.size() > 0) {
150 parentTag = ancestors.get(ancestors.size() - 1).getTag().toLowerCase();
153 if (URLPATTERN_TAG.equals(thisTag)) {
154 String pattern = getString(node);
155 if (SERVLETMAP_TAG.equals(parentTag) || FILTERMAP_TAG.equals(parentTag)) {
156 String id = node.getAttribute("id");
157 webXml.addServletPattern(pattern, id);
158 } else if (security != null) {
159 security.addUrlPattern(pattern);
161 } else if (ROLENAME_TAG.equals(thisTag) && AUTHCONST_TAG.equals(parentTag)) {
162 if (security == null) {
163 throw new AppEngineConfigException(getFilename() + ": <" + ROLENAME_TAG +
164 "> in <" + AUTHCONST_TAG + "> in unrecognized context");
166 security.setRequiredRole(parseRequiredRole(getString(node)));
167 } else if (TRANSGUARANTEE_TAG.equals(thisTag) && USERDATACONST_TAG.equals(parentTag)) {
168 if (security == null) {
169 throw new AppEngineConfigException(getFilename() + ": <" + TRANSGUARANTEE_TAG +
170 "> in <" + USERDATACONST_TAG + "> in unrecognized context");
172 security.setTransportGuarantee(parseTransportGuarantee(getString(node)));
173 } else if (SECURITYCONST_TAG.equals(thisTag)) {
174 security = webXml.addSecurityConstraint();
175 } else if (WELCOME_FILE_TAG.equals(thisTag)) {
176 if (!WELCOME_FILE_LIST_TAG.equals(parentTag)) {
177 throw new AppEngineConfigException(getFilename() + ": <" + WELCOME_FILE_TAG +
178 "> in unrecognized context");
180 webXml.addWelcomeFile(getString(node));
181 } else if (EXTENSION_TAG.equals(thisTag)) {
182 extension = getString(node);
183 } else if (MIME_TYPE_TAG.equals(thisTag)) {
184 if (extension == null) {
185 throw new AppEngineConfigException(getFilename() + ": <" + MIME_TYPE_TAG +
186 "> without <extension>.");
188 String mimeType = getString(node);
189 webXml.addMimeMapping(extension, mimeType);
190 extension = null;
191 } else if (ERROR_CODE_TAG.equals(thisTag)) {
192 String code = getString(node);
193 if ("404".equals(code)) {
194 webXml.setFallThroughToRuntime(true);
198 }, is);
200 if (webXml.getWelcomeFiles().isEmpty()) {
201 for (String welcomeFile : DEFAULT_WELCOME_FILES) {
202 webXml.addWelcomeFile(welcomeFile);
206 return webXml;
209 private SecurityConstraint.RequiredRole parseRequiredRole(String role) {
210 if ("*".equals(role)) {
211 return SecurityConstraint.RequiredRole.ANY_USER;
212 } else if ("admin".equals(role)) {
213 return SecurityConstraint.RequiredRole.ADMIN;
214 } else {
215 throw new AppEngineConfigException(getFilename() + ": " +
216 "Unknown role-name: must be '*' or 'admin'");
220 private SecurityConstraint.TransportGuarantee parseTransportGuarantee(String transportGuarantee) {
221 if ("NONE".equalsIgnoreCase(transportGuarantee)) {
222 return SecurityConstraint.TransportGuarantee.NONE;
223 } else if ("INTEGRAL".equalsIgnoreCase(transportGuarantee)) {
224 return SecurityConstraint.TransportGuarantee.INTEGRAL;
225 } else if ("CONFIDENTIAL".equalsIgnoreCase(transportGuarantee)) {
226 return SecurityConstraint.TransportGuarantee.CONFIDENTIAL;
227 } else {
228 throw new AppEngineConfigException(getFilename() + ": " +
229 "Unknown transport-guarantee: must be " +
230 "NONE, INTEGRAL, or CONFIDENTIAL.");