1 package org.astrogrid.common.j2ee.environment;
2
3 import java.net.URL;
4 import javax.xml.parsers.DocumentBuilder;
5 import javax.xml.parsers.DocumentBuilderFactory;
6 import org.apache.commons.logging.Log;
7 import org.apache.commons.logging.LogFactory;
8 import org.w3c.dom.Document;
9 import org.w3c.dom.Node;
10 import org.w3c.dom.NodeList;
11 import org.xml.sax.EntityResolver;
12 import org.xml.sax.InputSource;
13
14 /***
15 * A Java bean representing the environment of a web application
16 * as initialized from the deployment descriptor (web.xml).
17 * Servlets and JSPs can use this bean to display and edit the
18 * environment.
19 * <p>
20 * The bean has five properties: deploymentDescriptor,
21 * contextPath, tomcatContextFileName and envEntries.
22 * <p>
23 * The deploymentDescriptor property holds a URI (written out as
24 * a String) by which the web application can access web.xml. This
25 * parameter must be written by the client to initialize the bean;
26 * setting the parameter causes the bean to parse web.xml and to
27 * store the relevant parts of the environment description. This
28 * property may not be read back by the client.
29 * <p>
30 * The contextPath property holds the context path of the root of
31 * the web-application (i.e. the path to the application front page).
32 * The context path always begins with a slash.
33 * <p>
34 * The tomcatContextFileName property holds the unqualified file-name
35 * of the file which could be used to configure the Tomcat context if
36 * the web application is running in the Tomcat web-container. If the
37 * context path is /myWebApp then the Tomcat context can be set by
38 * writing the file $CATALINA_HOME/conf/Catalina/myWebApp.xml and
39 * the property is set to myWebApp.xml.
40 * <p>
41 * The envEntry property, which is indexed, holds the collection of
42 * {@link org.astrogrid.common.j2ee.environemnt.EnvEntry} beans
43 * derived from the env-entry elements in web.xml.
44 *
45 * @author Guy Rixon
46 */
47 public class Environment {
48 private static Log log = LogFactory.getLog(Environment.class);
49
50 /*** Creates a new instance of Environment */
51 public Environment() {}
52
53 /***
54 * The context path of the web application.
55 */
56 private String contextPath;
57
58 /***
59 * Gets the context path.
60 */
61 public String getContextPath() {
62 return this.contextPath;
63 }
64
65 /***
66 * Sets the context path. Also sets the
67 * tomcatContextFileName property.
68 */
69 public void setContextPath(String path) {
70 this.contextPath = path;
71 this.tomcatContextFileName = this.contextPath.substring(1) + ".xml";
72 }
73
74 /***
75 * The Tomcat context-file name for this application.
76 */
77 private String tomcatContextFileName;
78
79 /***
80 * Gets the context-file name.
81 */
82 public String getTomcatContextFileName() {
83 return this.tomcatContextFileName;
84 }
85
86 /***
87 * The environment entries required by this application.
88 */
89 private EnvEntry[] envEntries;
90
91 /***
92 * Gets all the environment entries.
93 */
94 public EnvEntry getEnvEntry(int index) {
95 return this.envEntries[index];
96 }
97
98 /***
99 * Gets all the environment entries.
100 */
101 public EnvEntry[] getEnvEntry() {
102 return this.envEntries;
103 }
104
105 /***
106 * Sets the URL for the deployment descriptor (web.xml).
107 * This causes the bean to parse the descriptor and thus
108 * to extract the environment entries.
109 */
110 public void setDeploymentDescriptor(String webDotXmlUri) throws Exception {
111 log.debug("Parsing the deployment descriptor at " + webDotXmlUri);
112
113
114 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
115 factory.setValidating(false);
116 factory.setCoalescing(true);
117 factory.setExpandEntityReferences(false);
118 factory.setNamespaceAware(false);
119 DocumentBuilder domParser = factory.newDocumentBuilder();
120 domParser.setEntityResolver(new DtdResolver());
121 Document webDotXmlDoc = domParser.parse(webDotXmlUri);
122 log.debug("Now we have a DOM for the deployment descriptor.");
123
124
125 NodeList envEntryNodes = webDotXmlDoc.getElementsByTagName("env-entry");
126 int nBeans = envEntryNodes.getLength();
127 this.envEntries = new EnvEntry[nBeans];
128 for (int i = 0; i < nBeans; i++) {
129 this.envEntries[i] = this.parseEnvEntry(envEntryNodes.item(i));
130 }
131 }
132
133 /***
134 * Parses an env-entry element represented as a DOM fragment.
135 *
136 * @param envEntryNode The Element node representng the env-entry element.
137 * @return A bean representing the env-entry element.
138 */
139 private EnvEntry parseEnvEntry(Node envEntryNode) throws Exception {
140 EnvEntry envEntry = new EnvEntry();
141
142
143
144
145
146 NodeList childNodes = envEntryNode.getChildNodes();
147 for (int i = 0; i < childNodes.getLength(); i++) {
148 Node childNode = childNodes.item(i);
149 String nodeName = childNode.getNodeName();
150 if (nodeName.equals("env-entry-name")) {
151 envEntry.setName(this.getElementValue(childNode));
152 }
153 else if (nodeName.equals("env-entry-type")) {
154 envEntry.setType(this.getElementValue(childNode));
155 }
156 else if (nodeName.equals("env-entry-value")) {
157 envEntry.setDefaultValue(this.getElementValue(childNode));
158 }
159 else if (nodeName.equals("description")) {
160 envEntry.setDescription(this.getElementValue(childNode));
161 }
162
163 }
164 return envEntry;
165 }
166
167 /***
168 * Gets the value of an XML element represented by a DOM node.
169 * The element must be of a simple type with a text nodes in the
170 * DOM fragment. This method gets the concatenated value of the text nodes.
171 *
172 * @param node The DOM node representing the element.
173 * @return The value of the text-node child, or null if there is no text node.
174 */
175 private String getElementValue(Node node) {
176
177 try {
178
179
180 node.normalize();
181
182
183
184 NodeList children = node.getChildNodes();
185 for (int i = 0; i < children.getLength(); i++) {
186 Node child = children.item(i);
187 if (child.getNodeType() == Node.TEXT_NODE) {
188 return child.getNodeValue();
189 }
190 }
191
192
193
194 return null;
195 }
196 catch (Throwable t) {
197 return null;
198 }
199 }
200
201
202 /***
203 * A resolver for the DTDs governing the deployment descriptor.
204 * This resolver forces the parser to use local copies of the DTDs.
205 * It stops the parser crashing due to lack of DTDs when the copies on
206 * the web are not available.
207 */
208 protected class DtdResolver implements EntityResolver {
209
210 /***
211 * Locates the DTD for the deployment descriptor.
212 * The given public-ID of the DTD is resolved to a local copy
213 * of the DTD text. The given system-ID is not used. This class
214 * can only resolve the DTDs for the servlet 2.2 and 2.3 specifications.
215 *
216 * @param publicId The public id of the DTD in the instance document.
217 * @param systemId The system ID for the DTD in the instance document.
218 * @return A source based on the local copy of the DTD.
219 */
220 public InputSource resolveEntity(String publicId, String systemId) {
221 log.debug("Resolving " + publicId);
222 if (publicId.equals("-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN")) {
223 URL u = this.getClass().getResource("web-app_2_2.dtd");
224 log.debug("Resolved to " + u);
225 return new InputSource(u.toString());
226 }
227 else if (publicId.equals("-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN")) {
228 URL u = this.getClass().getResource("web-app_2_3.dtd");
229 log.debug("Resolved to " + u);
230 return new InputSource(u.toString());
231 }
232 else {
233 log.debug("Not resolved.");
234 return null;
235 }
236 }
237 }
238
239
240 }