KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensymphony > module > sitemesh > factory > DefaultFactory


1 /*
2  * Title: DefaultFactory
3  * Description:
4  *
5  * This software is published under the terms of the OpenSymphony Software
6  * License version 1.1, of which a copy has been included with this
7  * distribution in the LICENSE.txt file.
8  */

9
10 package com.opensymphony.module.sitemesh.factory;
11
12 import com.opensymphony.module.sitemesh.Config;
13 import com.opensymphony.module.sitemesh.DecoratorMapper;
14 import com.opensymphony.module.sitemesh.PageParser;
15
16 import org.w3c.dom.Document JavaDoc;
17 import org.w3c.dom.Element JavaDoc;
18 import org.w3c.dom.NodeList JavaDoc;
19 import org.w3c.dom.Text JavaDoc;
20 import org.xml.sax.SAXException JavaDoc;
21
22 import javax.xml.parsers.DocumentBuilder JavaDoc;
23 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
24 import javax.xml.parsers.ParserConfigurationException JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.util.*;
29
30 /**
31  * DefaultFactory, reads configuration from <code>/WEB-INF/sitemesh.xml</code>, or uses the
32  * default configuration if <code>sitemesh.xml</code> does not exist.
33  *
34  * @author <a HREF="mailto:joe@truemesh.com">Joe Walnes</a>
35  * @author <a HREF="mailto:pathos@pandora.be">Mathias Bogaert</a>
36  * @version $Revision: 1.3 $
37  */

38 public class DefaultFactory extends BaseFactory {
39     String JavaDoc configFileName = "/WEB-INF/sitemesh.xml";
40     File JavaDoc configFile;
41     long configLastModified;
42     Map configProps = new HashMap();
43
44     String JavaDoc excludesFileName;
45     File JavaDoc excludesFile;
46
47     public DefaultFactory(Config config) {
48         super(config);
49
50         // configFilePath is null if loaded from war file
51
String JavaDoc configFilePath = config.getServletContext().getRealPath(configFileName);
52
53         if (configFilePath != null) { // disable config auto reloading for .war files
54
configFile = new File JavaDoc(configFilePath);
55         }
56
57         loadConfig();
58     }
59
60     /** Refresh config before delegating to superclass. */
61     public DecoratorMapper getDecoratorMapper() {
62         refresh();
63         return super.getDecoratorMapper();
64     }
65
66     /** Refresh config before delegating to superclass. */
67     public PageParser getPageParser(String JavaDoc contentType) {
68         refresh();
69         return super.getPageParser(contentType);
70     }
71
72     /** Refresh config before delegating to superclass. */
73     public boolean shouldParsePage(String JavaDoc contentType) {
74         refresh();
75         return super.shouldParsePage(contentType);
76     }
77
78     /**
79      * Returns <code>true</code> if the supplied path matches one of the exclude
80      * URLs specified in sitemesh.xml, otherwise returns <code>false</code>. This
81      * method refreshes the config before delgating to the superclass.
82      */

83     public boolean isPathExcluded(String JavaDoc path) {
84         refresh();
85         return super.isPathExcluded(path);
86     }
87
88     /** Load configuration from file. */
89     private synchronized void loadConfig() {
90         try {
91             // Load and parse the sitemesh.xml file
92
Element JavaDoc root = loadSitemeshXML();
93
94             NodeList JavaDoc sections = root.getChildNodes();
95             // Loop through child elements of root node
96
for (int i = 0; i < sections.getLength(); i++) {
97                 if (sections.item(i) instanceof Element JavaDoc) {
98                     Element JavaDoc curr = (Element JavaDoc)sections.item(i);
99                     NodeList JavaDoc children = curr.getChildNodes();
100
101                     if ("property".equalsIgnoreCase(curr.getTagName())) {
102                         String JavaDoc name = curr.getAttribute("name");
103                         String JavaDoc value = curr.getAttribute("value");
104                         if (!"".equals(name) && !"".equals(value)) {
105                             configProps.put("${" + name + "}", value);
106                         }
107                     }
108                     else if ("page-parsers".equalsIgnoreCase(curr.getTagName())) {
109                         // handle <page-parsers>
110
loadPageParsers(children);
111                     }
112                     else if ("decorator-mappers".equalsIgnoreCase(curr.getTagName())) {
113                         // handle <decorator-mappers>
114
loadDecoratorMappers(children);
115                     }
116                     else if ("excludes".equalsIgnoreCase(curr.getTagName())) {
117                         // handle <excludes>
118
String JavaDoc fileName = replaceProperties(curr.getAttribute("file"));
119                         if (!"".equals(fileName)) {
120                             excludesFileName = fileName;
121                             loadExcludes();
122                         }
123                     }
124                 }
125             }
126         }
127         catch (ParserConfigurationException JavaDoc e) {
128             report("Could not get XML parser", e);
129         }
130         catch (IOException JavaDoc e) {
131             report("Could not read config file : " + configFileName, e);
132         }
133         catch (SAXException JavaDoc e) {
134             report("Could not parse config file : " + configFileName, e);
135         }
136     }
137
138     private Element JavaDoc loadSitemeshXML()
139             throws ParserConfigurationException JavaDoc, IOException JavaDoc, SAXException JavaDoc
140     {
141         DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
142         DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
143
144         InputStream JavaDoc is = null;
145
146         if (configFile == null) {
147             is = config.getServletContext().getResourceAsStream(configFileName);
148         }
149         else if (configFile.exists() && configFile.canRead()) {
150             is = configFile.toURL().openStream();
151         }
152
153         if (is == null){ // load the default sitemesh configuration
154
is = getClass().getClassLoader().getResourceAsStream("com/opensymphony/module/sitemesh/factory/sitemesh-default.xml");
155         }
156
157         if (is == null){ // load the default sitemesh configuration using another classloader
158
is = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/opensymphony/module/sitemesh/factory/sitemesh-default.xml");
159         }
160
161         if (is == null){
162             throw new IllegalStateException JavaDoc("Cannot load default configuration from jar");
163         }
164
165         if (configFile != null) configLastModified = configFile.lastModified();
166
167         Document JavaDoc doc = builder.parse(is);
168         Element JavaDoc root = doc.getDocumentElement();
169         // Verify root element
170
if (!"sitemesh".equalsIgnoreCase(root.getTagName())) {
171             report("Root element of sitemesh configuration file not <sitemesh>", null);
172         }
173         return root;
174     }
175
176     private void loadExcludes()
177             throws ParserConfigurationException JavaDoc, IOException JavaDoc, SAXException JavaDoc
178     {
179         DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
180         DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
181
182         InputStream JavaDoc is = null;
183
184         if (excludesFile == null) {
185             is = config.getServletContext().getResourceAsStream(excludesFileName);
186         }
187         else if (excludesFile.exists() && excludesFile.canRead()) {
188             is = excludesFile.toURL().openStream();
189         }
190
191         if (is == null){
192             throw new IllegalStateException JavaDoc("Cannot load excludes configuration file from jar");
193         }
194
195         Document JavaDoc document = builder.parse(is);
196         Element JavaDoc root = document.getDocumentElement();
197         NodeList JavaDoc sections = root.getChildNodes();
198
199         // Loop through child elements of root node looking for the <excludes> block
200
for (int i = 0; i < sections.getLength(); i++) {
201             if (sections.item(i) instanceof Element JavaDoc) {
202                 Element JavaDoc curr = (Element JavaDoc)sections.item(i);
203                 if ("excludes".equalsIgnoreCase(curr.getTagName())) {
204                     loadExcludeUrls(curr.getChildNodes());
205                 }
206             }
207         }
208     }
209
210     /** Loop through children of 'page-parsers' element and add all 'parser' mappings. */
211     private void loadPageParsers(NodeList JavaDoc nodes) {
212         clearParserMappings();
213         for (int i = 0; i < nodes.getLength(); i++) {
214             if (nodes.item(i) instanceof Element JavaDoc) {
215                 Element JavaDoc curr = (Element JavaDoc)nodes.item(i);
216
217                 if ("parser".equalsIgnoreCase(curr.getTagName())) {
218                     String JavaDoc className = curr.getAttribute("class");
219                     String JavaDoc contentType = curr.getAttribute("content-type");
220                     mapParser(contentType, className);
221                 }
222             }
223         }
224     }
225
226     private void loadDecoratorMappers(NodeList JavaDoc nodes) {
227         clearDecoratorMappers();
228         Properties emptyProps = new Properties();
229
230         pushDecoratorMapper("com.opensymphony.module.sitemesh.mapper.NullDecoratorMapper", emptyProps);
231
232         // note, this works from the bottom node up.
233
for (int i = nodes.getLength() - 1; i > 0; i--) {
234             if (nodes.item(i) instanceof Element JavaDoc) {
235                 Element JavaDoc curr = (Element JavaDoc)nodes.item(i);
236                 if ("mapper".equalsIgnoreCase(curr.getTagName())) {
237                     String JavaDoc className = curr.getAttribute("class");
238                     Properties props = new Properties();
239                     // build properties from <param> tags.
240
NodeList JavaDoc children = curr.getChildNodes();
241                     for (int j = 0; j < children.getLength(); j++) {
242                         if (children.item(j) instanceof Element JavaDoc) {
243                             Element JavaDoc currC = (Element JavaDoc)children.item(j);
244                             if ("param".equalsIgnoreCase(currC.getTagName())) {
245                                 String JavaDoc value = currC.getAttribute("value");
246                                 props.put(currC.getAttribute("name"), replaceProperties(value));
247                             }
248                         }
249                     }
250                     // add mapper
251
pushDecoratorMapper(className, props);
252                 }
253             }
254         }
255
256         pushDecoratorMapper("com.opensymphony.module.sitemesh.mapper.InlineDecoratorMapper", emptyProps);
257     }
258
259     /**
260      * Reads in all the url patterns to exclude from decoration.
261      */

262     private void loadExcludeUrls(NodeList JavaDoc nodes) {
263         clearExcludeUrls();
264         for (int i = 0; i < nodes.getLength(); i++) {
265             if (nodes.item(i) instanceof Element JavaDoc) {
266                 Element JavaDoc p = (Element JavaDoc) nodes.item(i);
267                 if ("pattern".equalsIgnoreCase(p.getTagName()) || "url-pattern".equalsIgnoreCase(p.getTagName())) {
268                     Text JavaDoc patternText = (Text JavaDoc) p.getFirstChild();
269                     if (patternText != null) {
270                         String JavaDoc pattern = patternText.getData().trim();
271                         if (pattern != null) {
272                             addExcludeUrl(pattern);
273                         }
274                     }
275                 }
276             }
277         }
278     }
279
280     /** Check if configuration file has been modified, and if so reload it. */
281     private void refresh() {
282         if (configFile != null && configLastModified != configFile.lastModified()) loadConfig();
283     }
284
285     /**
286      * Replaces any properties that appear in the supplied string
287      * with their actual values
288      *
289      * @param str the string to replace the properties in
290      * @return the same string but with any properties expanded out to their
291      * actual values
292      */

293     private String JavaDoc replaceProperties(String JavaDoc str) {
294         Set props = configProps.entrySet();
295         for (Iterator it = props.iterator(); it.hasNext();)
296         {
297             Map.Entry entry = (Map.Entry) it.next();
298             String JavaDoc key = (String JavaDoc) entry.getKey();
299             int idx;
300             while ((idx = str.indexOf(key)) >= 0) {
301                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc(100);
302                 buf.append(str.substring(0, idx));
303                 buf.append(entry.getValue());
304                 buf.append(str.substring(idx + key.length()));
305                 str = buf.toString();
306             }
307         }
308         return str;
309     }
310 }
Popular Tags