KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > ext > dom > JaxenXPathSupport


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52  
53 package freemarker.ext.dom;
54
55 import freemarker.template.*;
56 import freemarker.template.utility.Collections12;
57 import freemarker.template.utility.UndeclaredThrowableException;
58 import freemarker.cache.TemplateCache;
59 import freemarker.core.CustomAttribute;
60 import freemarker.core.Environment;
61 import org.jaxen.*;
62 import org.jaxen.dom.DocumentNavigator;
63 import org.w3c.dom.Document JavaDoc;
64 import org.xml.sax.EntityResolver JavaDoc;
65 import org.xml.sax.InputSource JavaDoc;
66 import org.xml.sax.SAXException JavaDoc;
67
68 import java.io.IOException JavaDoc;
69 import java.io.StringReader JavaDoc;
70 import java.io.StringWriter JavaDoc;
71 import java.util.*;
72
73 import javax.xml.parsers.DocumentBuilder JavaDoc;
74 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
75
76
77 /**
78  * @author Jonathan Revusky
79  * @version $Id: JaxenXPathSupport.java,v 1.30 2003/12/20 01:17:30 ddekany Exp $
80  */

81 class JaxenXPathSupport implements XPathSupport {
82     
83     private static final CustomAttribute cache =
84         new CustomAttribute(CustomAttribute.SCOPE_TEMPLATE) {
85             protected Object JavaDoc create() {
86                 return new HashMap();
87             }
88         };
89
90     private final static ArrayList EMPTY_ARRAYLIST = new ArrayList();
91
92     public TemplateModel executeQuery(Object JavaDoc context, String JavaDoc xpathQuery) throws TemplateModelException {
93         try {
94             BaseXPath xpath;
95             Map xpathCache = (Map)cache.get();
96             synchronized(xpathCache) {
97                 xpath = (BaseXPath) xpathCache.get(xpathQuery);
98                 if (xpath == null) {
99                     xpath = new BaseXPath(xpathQuery, fmDomNavigator);
100                     xpath.setNamespaceContext(customNamespaceContext);
101                     xpath.setFunctionContext(fmFunctionContext);
102                     xpath.setVariableContext(fmVariableContext);
103                     xpathCache.put(xpathQuery, xpath);
104                 }
105             }
106             List result = xpath.selectNodes(context != null ? context : EMPTY_ARRAYLIST);
107             if (result.size() == 1) {
108                 return ObjectWrapper.DEFAULT_WRAPPER.wrap(result.get(0));
109             }
110             NodeListModel nlm = new NodeListModel(result, null);
111             nlm.xpathSupport = this;
112             return nlm;
113         } catch (UndeclaredThrowableException e) {
114             Throwable JavaDoc t = e.getUndeclaredThrowable();
115             if(t instanceof TemplateModelException) {
116                 throw (TemplateModelException)t;
117             }
118             throw e;
119         } catch (JaxenException je) {
120             throw new TemplateModelException(je);
121         }
122     }
123
124     static private final NamespaceContext customNamespaceContext = new NamespaceContext() {
125         
126         public String JavaDoc translateNamespacePrefixToUri(String JavaDoc prefix) {
127             if (prefix.equals(Template.DEFAULT_NAMESPACE_PREFIX)) {
128                 return Environment.getCurrentEnvironment().getDefaultNS();
129             }
130             return Environment.getCurrentEnvironment().getNamespaceForPrefix(prefix);
131         }
132     };
133
134     private static final VariableContext fmVariableContext = new VariableContext() {
135         public Object JavaDoc getVariableValue(String JavaDoc namespaceURI, String JavaDoc prefix, String JavaDoc localName)
136         throws
137             UnresolvableException
138         {
139             try {
140                 TemplateModel model = Environment.getCurrentEnvironment().getVariable(localName);
141                 if(model == null) {
142                     throw new UnresolvableException("Variable " + localName + " not found.");
143                 }
144                 if(model instanceof TemplateScalarModel) {
145                     return ((TemplateScalarModel)model).getAsString();
146                 }
147                 if(model instanceof TemplateNumberModel) {
148                     return ((TemplateNumberModel)model).getAsNumber();
149                 }
150                 if(model instanceof TemplateDateModel) {
151                     return ((TemplateDateModel)model).getAsDate();
152                 }
153                 if(model instanceof TemplateBooleanModel) {
154                     return ((TemplateBooleanModel)model).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE;
155                 }
156             }
157             catch(TemplateModelException e) {
158                 throw new UndeclaredThrowableException(e);
159             }
160             throw new UnresolvableException("Variable " + localName + " is not a string, number, date, or boolean");
161         }
162     };
163      
164     private static final FunctionContext fmFunctionContext = new XPathFunctionContext() {
165         public Function getFunction(String JavaDoc namespaceURI, String JavaDoc prefix, String JavaDoc localName)
166         throws UnresolvableException {
167             try {
168                 return super.getFunction(namespaceURI, prefix, localName);
169             }
170             catch(UnresolvableException e) {
171                 return super.getFunction(null, null, localName);
172             }
173         }
174     };
175     
176     private static final CustomAttribute cachedTree = new CustomAttribute(CustomAttribute.SCOPE_TEMPLATE);
177      
178     private static final Navigator fmDomNavigator = new DocumentNavigator() {
179         public Object JavaDoc getDocument(String JavaDoc uri) throws FunctionCallException
180         {
181             try
182             {
183                 Template raw = getTemplate(uri);
184                 Document JavaDoc doc = (Document JavaDoc)cachedTree.get(raw);
185                 if(doc == null) {
186                     DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
187                     factory.setNamespaceAware(true);
188                     DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
189                     FmEntityResolver er = new FmEntityResolver();
190                     builder.setEntityResolver(er);
191                     doc = builder.parse(createInputSource(null, raw));
192                     // If the entity resolver got called 0 times, the document
193
// is standalone, so we can safely cache it
194
if(er.getCallCount() == 0) {
195                         cachedTree.set(doc, raw);
196                     }
197                 }
198                 return doc;
199             }
200             catch (Exception JavaDoc e)
201             {
202                 throw new FunctionCallException("Failed to parse document for URI: " + uri, e);
203             }
204         }
205     };
206
207     static Template getTemplate(String JavaDoc systemId) throws IOException JavaDoc {
208         Environment env = Environment.getCurrentEnvironment();
209         String JavaDoc encoding = env.getTemplate().getEncoding();
210         if (encoding == null) {
211             encoding = env.getConfiguration().getEncoding(env.getLocale());
212         }
213         String JavaDoc templatePath = env.getTemplate().getName();
214         int lastSlash = templatePath.lastIndexOf('/');
215         templatePath = lastSlash == -1 ? "" : templatePath.substring(0, lastSlash + 1);
216         systemId = TemplateCache.getFullTemplatePath(env, templatePath, systemId);
217         Template raw = env.getConfiguration().getTemplate(systemId, env.getLocale(), encoding, false);
218         return raw;
219     }
220
221     private static InputSource JavaDoc createInputSource(String JavaDoc publicId, Template raw) throws IOException JavaDoc, SAXException JavaDoc {
222         StringWriter JavaDoc sw = new StringWriter JavaDoc();
223         try {
224             raw.process(Collections12.EMPTY_MAP, sw);
225         }
226         catch(TemplateException e) {
227             throw new SAXException JavaDoc(e);
228         }
229         InputSource JavaDoc is = new InputSource JavaDoc();
230         is.setPublicId(publicId);
231         is.setSystemId(raw.getName());
232         is.setCharacterStream(new StringReader JavaDoc(sw.toString()));
233         return is;
234     }
235
236     private static class FmEntityResolver implements EntityResolver JavaDoc {
237         private int callCount = 0;
238         
239         public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId)
240         throws SAXException JavaDoc, IOException JavaDoc {
241             ++callCount;
242             return createInputSource(publicId, getTemplate(systemId));
243         }
244         
245         int getCallCount() {
246             return callCount;
247         }
248     };
249 }
250
Popular Tags