001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.pageflow.internal;
020:
021: import org.apache.beehive.netui.core.urltemplates.URLTemplate;
022: import org.apache.beehive.netui.core.urltemplates.URLTemplates;
023: import org.apache.beehive.netui.core.urltemplates.URLTemplatesFactory;
024: import org.apache.beehive.netui.util.logging.Logger;
025: import org.apache.beehive.netui.util.xml.DomUtils;
026: import org.apache.beehive.netui.util.xml.XmlInputStreamResolver;
027:
028: import java.io.InputStream;
029: import java.io.IOException;
030: import java.util.HashMap;
031: import java.util.List;
032: import javax.servlet.ServletContext;
033: import javax.xml.parsers.DocumentBuilder;
034: import javax.xml.parsers.DocumentBuilderFactory;
035: import javax.xml.parsers.ParserConfigurationException;
036:
037: import org.w3c.dom.Document;
038: import org.w3c.dom.Element;
039: import org.xml.sax.EntityResolver;
040: import org.xml.sax.ErrorHandler;
041: import org.xml.sax.InputSource;
042: import org.xml.sax.SAXException;
043: import org.xml.sax.SAXParseException;
044:
045: /**
046: * Methods for configuring and retrieving the URLTemplate object.
047: */
048: public class DefaultURLTemplatesFactory extends URLTemplatesFactory {
049: private static final Logger _log = Logger
050: .getInstance(DefaultURLTemplatesFactory.class);
051:
052: // Constants for schema elements
053: private static final String KEY = "key";
054: private static final String NAME = "name";
055: private static final String TEMPLATE_NAME = "template-name";
056: private static final String URL_TEMPLATE = "url-template";
057: private static final String URL_TEMPLATE_REF = "url-template-ref";
058: private static final String URL_TEMPLATE_REF_GROUP = "url-template-ref-group";
059: private static final String VALUE = "value";
060:
061: private static final String CONFIG_SCHEMA = "org/apache/beehive/netui/core/urltemplates/schema/url-template-config.xsd";
062:
063: private static final XmlInputStreamResolver SCHEMA_RESOLVER = new XmlInputStreamResolver() {
064: public String getResourcePath() {
065: return CONFIG_SCHEMA;
066: }
067:
068: public InputStream getInputStream() {
069: return DefaultURLTemplatesFactory.class.getClassLoader()
070: .getResourceAsStream(getResourcePath());
071: }
072: };
073:
074: // The actual URL templates and template ref groups
075: private URLTemplates _urlTemplates;
076:
077: /**
078: * Returns an array of the URL templates.
079: *
080: * <p>
081: * Always returns a copy of a URLTemplate with the same
082: * parsed template data but its own cleared set of
083: * token values for the substitue() methods.
084: * This allows multiple client requests access to
085: * the same parsed template structure, without requiring
086: * it to be parsed for each request.
087: * </p>
088: *
089: * @return the URL templates
090: */
091: public URLTemplate[] getURLTemplates() {
092: if (_urlTemplates == null) {
093: return null;
094: }
095:
096: return _urlTemplates.getTemplates();
097: }
098:
099: /**
100: * Returns URL template given the name of the template.
101: *
102: * @param name name of the template
103: * @return template
104: */
105: public URLTemplate getURLTemplate(String name) {
106: assert _urlTemplates != null : "The template config file has not been loaded.";
107:
108: if (_urlTemplates == null) {
109: return null;
110: }
111:
112: return _urlTemplates.getTemplate(name);
113: }
114:
115: /**
116: * Returns URL template name of the given type (by key) from the
117: * desired reference group.
118: *
119: * @param refGroupName name of a group of templates from the config file.
120: * @param key type of the template
121: * @return template name
122: */
123: public String getTemplateNameByRef(String refGroupName, String key) {
124: assert _urlTemplates != null : "The template config file has not been loaded.";
125:
126: if (_urlTemplates == null) {
127: return null;
128: }
129:
130: String ref = _urlTemplates.getTemplateNameByRef(refGroupName,
131: key);
132: if (ref == null) {
133: // If the template is a secure template, look for the secure default
134: // before resolving to the default
135: if (key.equals(URLTemplatesFactory.SECURE_RENDER_TEMPLATE)
136: || key
137: .equals(URLTemplatesFactory.SECURE_ACTION_TEMPLATE)
138: || key
139: .equals(URLTemplatesFactory.SECURE_RESOURCE_TEMPLATE)) {
140: ref = _urlTemplates.getTemplateNameByRef(refGroupName,
141: URLTemplatesFactory.SECURE_DEFAULT_TEMPLATE);
142: }
143: }
144:
145: return ref;
146: }
147:
148: /**
149: * Initialization method that parses the URL template config file to
150: * get the URL templates and template reference groups.
151: *
152: * @param servletContext the current ServletContext.
153: */
154: public void load(ServletContext servletContext) {
155: _urlTemplates = new URLTemplates();
156: InputStream xmlInputStream = null;
157: InputStream xsdInputStream = null;
158:
159: try {
160: xmlInputStream = servletContext
161: .getResourceAsStream(_configFilePath);
162: if (xmlInputStream != null) {
163: /* load the XSD input stream */
164: xsdInputStream = SCHEMA_RESOLVER.getInputStream();
165:
166: final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
167: final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
168: final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
169:
170: DocumentBuilderFactory dbf = DocumentBuilderFactory
171: .newInstance();
172: dbf.setValidating(true);
173: dbf.setNamespaceAware(true);
174: dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
175: dbf.setAttribute(JAXP_SCHEMA_SOURCE, xsdInputStream);
176:
177: DocumentBuilder db = dbf.newDocumentBuilder();
178:
179: /* add an ErrorHandler that just logs validation problems */
180: db.setErrorHandler(new ErrorHandler() {
181: public void warning(SAXParseException exception) {
182: _log
183: .info("Validation warning validating config file \""
184: + _configFilePath
185: + "\" against XML Schema \""
186: + SCHEMA_RESOLVER
187: .getResourcePath());
188: }
189:
190: public void error(SAXParseException exception) {
191: _log.error(
192: "Validation errors occurred parsing the config file \""
193: + _configFilePath
194: + "\". Cause: " + exception,
195: exception);
196: }
197:
198: public void fatalError(SAXParseException exception) {
199: _log.error(
200: "Validation errors occurred parsing the config file \""
201: + _configFilePath
202: + "\". Cause: " + exception,
203: exception);
204: }
205: });
206:
207: db.setEntityResolver(new EntityResolver() {
208: public InputSource resolveEntity(String publicId,
209: String systemId) {
210: if (systemId
211: .endsWith("/url-template-config.xsd")) {
212: InputStream inputStream = DefaultURLTemplatesFactory.class
213: .getClassLoader()
214: .getResourceAsStream(CONFIG_SCHEMA);
215: return new InputSource(inputStream);
216: } else
217: return null;
218: }
219: });
220:
221: Document document = db.parse(xmlInputStream);
222: Element root = document.getDocumentElement();
223: loadTemplates(root);
224: loadTemplateRefGroups(root);
225: } else {
226: if (_log.isInfoEnabled())
227: _log
228: .info("Running without URL template descriptor, "
229: + _configFilePath);
230: }
231: } catch (ParserConfigurationException pce) {
232: _log.error("Problem loading URL template descriptor file "
233: + _configFilePath, pce);
234: } catch (SAXException se) {
235: _log.error("Problem parsing URL template descriptor in "
236: + _configFilePath, se);
237: } catch (IOException ioe) {
238: _log.error("Problem reading URL template descriptor file "
239: + _configFilePath, ioe);
240: } finally {
241: // Close the streams
242: try {
243: if (xmlInputStream != null)
244: xmlInputStream.close();
245: } catch (Exception ignore) {
246: }
247: try {
248: if (xsdInputStream != null)
249: xsdInputStream.close();
250: } catch (IOException ignore) {
251: }
252: }
253: }
254:
255: /**
256: * Loads the templates from a URL template config document.
257: *
258: * @param parent
259: */
260: private void loadTemplates(Element parent) {
261: // Load templates
262: List templates = DomUtils.getChildElementsByName(parent,
263: URL_TEMPLATE);
264: for (int i = 0; i < templates.size(); i++) {
265: Element template = (Element) templates.get(i);
266: String name = getElementText(template, NAME);
267: if (name == null) {
268: _log.error("Malformed URL template descriptor in "
269: + _configFilePath
270: + ". The url-template name is missing.");
271: continue;
272: }
273:
274: String value = getElementText(template, VALUE);
275: if (value == null) {
276: _log
277: .error("Malformed URL template descriptor in "
278: + _configFilePath
279: + ". The url-template value is missing for template "
280: + name);
281: continue;
282: }
283:
284: if (_log.isDebugEnabled()) {
285: _log.debug("[URLTemplate] " + name + " = " + value);
286: }
287:
288: URLTemplate urlTemplate = new URLTemplate(value, name);
289: if (urlTemplate.verify(_knownTokens, _requiredTokens)) {
290: _urlTemplates.addTemplate(name, urlTemplate);
291: }
292: }
293: }
294:
295: /**
296: * Loads the template reference groups from a URL template config document.
297: *
298: * @param parent
299: */
300: private void loadTemplateRefGroups(Element parent) {
301: // Load template refs
302: List templateRefGroups = DomUtils.getChildElementsByName(
303: parent, URL_TEMPLATE_REF_GROUP);
304: ;
305: for (int i = 0; i < templateRefGroups.size(); i++) {
306: Element refGroupElement = (Element) templateRefGroups
307: .get(i);
308: String refGroupName = getElementText(refGroupElement, NAME);
309: if (refGroupName == null) {
310: _log
311: .error("Malformed URL template descriptor in "
312: + _configFilePath
313: + ". The url-template-ref-group name is missing.");
314: continue;
315: }
316:
317: HashMap refGroup = new HashMap();
318: List templateRefs = DomUtils.getChildElementsByName(
319: refGroupElement, URL_TEMPLATE_REF);
320: ;
321: for (int j = 0; j < templateRefs.size(); j++) {
322: Element templateRefElement = (Element) templateRefs
323: .get(j);
324: String key = getElementText(templateRefElement, KEY);
325: if (key == null) {
326: _log
327: .error("Malformed URL template descriptor in "
328: + _configFilePath
329: + ". The url-template-ref key is missing in url-template-ref-group "
330: + refGroupName);
331: continue;
332: }
333:
334: String name = getElementText(templateRefElement,
335: TEMPLATE_NAME);
336: if (name != null) {
337: refGroup.put(key, name);
338: if (_log.isDebugEnabled()) {
339: _log
340: .debug("[" + refGroupName
341: + " URLTemplate] " + key
342: + " = " + name);
343: }
344: } else {
345: _log
346: .error("Malformed URL template descriptor in "
347: + _configFilePath
348: + ". The url-template-ref template-name is missing in url-template-ref-group "
349: + refGroupName);
350: }
351: }
352:
353: if (refGroup.size() != 0) {
354: _urlTemplates.addTemplateRefGroup(refGroupName,
355: refGroup);
356: }
357: }
358: }
359:
360: private String getElementText(Element parent, String elementName) {
361: Element child = DomUtils.getChildElementByName(parent,
362: elementName);
363: if (child != null) {
364: String text = DomUtils.getElementText(child);
365: if (text != null) {
366: text = text.trim();
367: return text.length() == 0 ? null : text;
368: }
369: }
370:
371: return null;
372: }
373: }
|