KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > directwebremoting > impl > DwrXmlConfigurator


1 /*
2  * Copyright 2005 Joe Walker
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.directwebremoting.impl;
17
18 import java.io.IOException JavaDoc;
19 import java.io.InputStream JavaDoc;
20 import java.lang.reflect.Method JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.StringTokenizer JavaDoc;
26
27 import javax.servlet.ServletContext JavaDoc;
28 import javax.xml.parsers.DocumentBuilder JavaDoc;
29 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
30 import javax.xml.parsers.ParserConfigurationException JavaDoc;
31
32 import org.directwebremoting.AjaxFilter;
33 import org.directwebremoting.Container;
34 import org.directwebremoting.WebContextFactory;
35 import org.directwebremoting.extend.AccessControl;
36 import org.directwebremoting.extend.AjaxFilterManager;
37 import org.directwebremoting.extend.Configurator;
38 import org.directwebremoting.extend.ConverterManager;
39 import org.directwebremoting.extend.Creator;
40 import org.directwebremoting.extend.CreatorManager;
41 import org.directwebremoting.extend.TypeHintContext;
42 import org.directwebremoting.util.LocalUtil;
43 import org.directwebremoting.util.LogErrorHandler;
44 import org.directwebremoting.util.Logger;
45 import org.directwebremoting.util.Messages;
46 import org.w3c.dom.Document JavaDoc;
47 import org.w3c.dom.Element JavaDoc;
48 import org.w3c.dom.NamedNodeMap JavaDoc;
49 import org.w3c.dom.Node JavaDoc;
50 import org.w3c.dom.NodeList JavaDoc;
51 import org.xml.sax.SAXException JavaDoc;
52
53 /**
54  * A configurator that gets its configuration by reading a dwr.xml file.
55  * @author Joe Walker [joe at getahead dot ltd dot uk]
56  */

57 public class DwrXmlConfigurator implements Configurator
58 {
59     /**
60      * Setter for the resource name that we can use to read a file from the
61      * servlet context
62      * @param servletResourceName The name to lookup
63      * @throws IOException On file read failure
64      * @throws ParserConfigurationException On XML setup failure
65      * @throws SAXException On XML parse failure
66      */

67     public void setServletResourceName(String JavaDoc servletResourceName) throws IOException JavaDoc, ParserConfigurationException JavaDoc, SAXException JavaDoc
68     {
69         this.servletResourceName = servletResourceName;
70
71         ServletContext JavaDoc servletContext = WebContextFactory.get().getServletContext();
72         if (servletContext == null)
73         {
74             throw new IOException JavaDoc(Messages.getString("DwrXmlConfigurator.MissingServletContext"));
75         }
76
77         InputStream JavaDoc in = null;
78         try
79         {
80             in = servletContext.getResourceAsStream(servletResourceName);
81             if (in == null)
82             {
83                 throw new IOException JavaDoc(Messages.getString("DwrXmlConfigurator.MissingConfigFile", servletResourceName));
84             }
85
86             log.debug("Configuring from servlet resource: " + servletResourceName);
87             setInputStream(in);
88         }
89         finally
90         {
91             LocalUtil.close(in);
92         }
93     }
94
95     /**
96      * Setter for a classpath based lookup
97      * @param classResourceName The resource to lookup in the classpath
98      * @throws IOException On file read failure
99      * @throws ParserConfigurationException On XML setup failure
100      * @throws SAXException On XML parse failure
101      */

102     public void setClassResourceName(String JavaDoc classResourceName) throws IOException JavaDoc, ParserConfigurationException JavaDoc, SAXException JavaDoc
103     {
104         this.classResourceName = classResourceName;
105
106         InputStream JavaDoc in = getClass().getResourceAsStream(classResourceName);
107         if (in == null)
108         {
109             throw new IOException JavaDoc(Messages.getString("DwrXmlConfigurator.MissingConfigFile", classResourceName));
110         }
111
112         log.debug("Configuring from class resource: " + classResourceName);
113         setInputStream(in);
114     }
115
116     /**
117      * Setter for a direct input stream to configure from
118      * @param in The input stream to read from.
119      * @throws IOException On file read failure
120      * @throws ParserConfigurationException On XML setup failure
121      * @throws SAXException On XML parse failure
122      */

123     public void setInputStream(InputStream JavaDoc in) throws ParserConfigurationException JavaDoc, SAXException JavaDoc, IOException JavaDoc
124     {
125         DocumentBuilderFactory JavaDoc dbf = DocumentBuilderFactory.newInstance();
126         dbf.setValidating(true);
127
128         DocumentBuilder JavaDoc db = dbf.newDocumentBuilder();
129         db.setEntityResolver(new DTDEntityResolver());
130         db.setErrorHandler(new LogErrorHandler());
131
132         document = db.parse(in);
133     }
134
135     /**
136      * To set the configuration document directly
137      * @param document The new configuration document
138      */

139     public void setDocument(Document JavaDoc document)
140     {
141         this.document = document;
142     }
143
144     /* (non-Javadoc)
145      * @see org.directwebremoting.Configurator#configure(org.directwebremoting.Container)
146      */

147     public void configure(Container container)
148     {
149         accessControl = (AccessControl) container.getBean(AccessControl.class.getName());
150         ajaxFilterManager = (AjaxFilterManager) container.getBean(AjaxFilterManager.class.getName());
151         converterManager = (ConverterManager) container.getBean(ConverterManager.class.getName());
152         creatorManager = (CreatorManager) container.getBean(CreatorManager.class.getName());
153
154         Element JavaDoc root = document.getDocumentElement();
155
156         NodeList JavaDoc rootChildren = root.getChildNodes();
157         for (int i = 0; i < rootChildren.getLength(); i++)
158         {
159             Node JavaDoc node = rootChildren.item(i);
160             if (node.getNodeType() == Node.ELEMENT_NODE)
161             {
162                 Element JavaDoc child = (Element JavaDoc) node;
163
164                 if (child.getNodeName().equals(ELEMENT_INIT))
165                 {
166                     loadInits(child);
167                 }
168                 else if (child.getNodeName().equals(ELEMENT_ALLOW))
169                 {
170                     loadAllows(child);
171                 }
172                 else if (child.getNodeName().equals(ELEMENT_SIGNATURES))
173                 {
174                     loadSignature(child);
175                 }
176             }
177         }
178     }
179
180     /**
181      * Internal method to load the inits element
182      * @param child The element to read
183      */

184     private void loadInits(Element JavaDoc child)
185     {
186         NodeList JavaDoc inits = child.getChildNodes();
187         for (int j = 0; j < inits.getLength(); j++)
188         {
189             if (inits.item(j).getNodeType() == Node.ELEMENT_NODE)
190             {
191                 Element JavaDoc initer = (Element JavaDoc) inits.item(j);
192
193                 if (initer.getNodeName().equals(ATTRIBUTE_CREATOR))
194                 {
195                     String JavaDoc id = initer.getAttribute(ATTRIBUTE_ID);
196                     String JavaDoc className = initer.getAttribute(ATTRIBUTE_CLASS);
197                     creatorManager.addCreatorType(id, className);
198                 }
199                 else if (initer.getNodeName().equals(ATTRIBUTE_CONVERTER))
200                 {
201                     String JavaDoc id = initer.getAttribute(ATTRIBUTE_ID);
202                     String JavaDoc className = initer.getAttribute(ATTRIBUTE_CLASS);
203                     converterManager.addConverterType(id, className);
204                 }
205             }
206         }
207     }
208
209     /**
210      * Internal method to load the create/convert elements
211      * @param child The element to read
212      */

213     private void loadAllows(Element JavaDoc child)
214     {
215         NodeList JavaDoc allows = child.getChildNodes();
216         for (int j = 0; j < allows.getLength(); j++)
217         {
218             if (allows.item(j).getNodeType() == Node.ELEMENT_NODE)
219             {
220                 Element JavaDoc allower = (Element JavaDoc) allows.item(j);
221
222                 if (allower.getNodeName().equals(ELEMENT_CREATE))
223                 {
224                     loadCreate(allower);
225                 }
226                 else if (allower.getNodeName().equals(ELEMENT_CONVERT))
227                 {
228                     loadConvert(allower);
229                 }
230                 else if (allower.getNodeName().equals(ELEMENT_FILTER))
231                 {
232                     loadFilter(allower);
233                 }
234             }
235         }
236     }
237
238     /**
239      * Internal method to load the convert element
240      * @param allower The element to read
241      */

242     private void loadConvert(Element JavaDoc allower)
243     {
244         String JavaDoc match = allower.getAttribute(ATTRIBUTE_MATCH);
245         String JavaDoc type = allower.getAttribute(ATTRIBUTE_CONVERTER);
246
247         try
248         {
249             Map JavaDoc params = createSettingMap(allower);
250             converterManager.addConverter(match, type, params);
251         }
252         catch (NoClassDefFoundError JavaDoc ex)
253         {
254             log.info("Convertor '" + type + "' not loaded due to NoClassDefFoundError. (match='" + match + "'). Cause: " + ex.getMessage());
255         }
256         catch (Exception JavaDoc ex)
257         {
258             log.error("Failed to add convertor: match=" + match + ", type=" + type, ex);
259         }
260     }
261
262     /**
263      * Internal method to load the create element
264      * @param allower The element to read
265      */

266     private void loadCreate(Element JavaDoc allower)
267     {
268         String JavaDoc type = allower.getAttribute(ATTRIBUTE_CREATOR);
269         String JavaDoc javascript = allower.getAttribute(ATTRIBUTE_JAVASCRIPT);
270
271         try
272         {
273             Map JavaDoc params = createSettingMap(allower);
274             creatorManager.addCreator(javascript, type, params);
275
276             processPermissions(javascript, allower);
277             processAuth(javascript, allower);
278             processParameters(javascript, allower);
279             processAjaxFilters(javascript, allower);
280         }
281         catch (NoClassDefFoundError JavaDoc ex)
282         {
283             log.info("Creator '" + type + "' not loaded due to NoClassDefFoundError. (javascript='" + javascript + "'). Cause: " + ex.getMessage());
284         }
285         catch (Exception JavaDoc ex)
286         {
287             log.error("Failed to add creator: type=" + type + ", javascript=" + javascript, ex);
288         }
289     }
290
291     /**
292      * Internal method to load the convert element
293      * @param allower The element to read
294      */

295     private void loadFilter(Element JavaDoc allower)
296     {
297         String JavaDoc type = allower.getAttribute(ATTRIBUTE_CLASS);
298
299         try
300         {
301             Class JavaDoc impl = LocalUtil.classForName(type);
302             AjaxFilter object = (AjaxFilter) impl.newInstance();
303
304             LocalUtil.setParams(object, createSettingMap(allower), ignore);
305
306             ajaxFilterManager.addAjaxFilter(object);
307         }
308         catch (ClassCastException JavaDoc ex)
309         {
310             log.error(type + " does not implement " + AjaxFilter.class.getName(), ex);
311         }
312         catch (NoClassDefFoundError JavaDoc ex)
313         {
314             log.info("Missing class for filter (class='" + type + "'). Cause: " + ex.getMessage());
315         }
316         catch (Exception JavaDoc ex)
317         {
318             log.error("Failed to add filter: class=" + type, ex);
319         }
320     }
321
322     /**
323      * Create a parameter map from nested <param name="foo" value="blah"/>
324      * elements
325      * @param parent The parent element
326      * @return A map of parameters
327      */

328     private static Map JavaDoc createSettingMap(Element JavaDoc parent)
329     {
330         Map JavaDoc params = new HashMap JavaDoc();
331
332         // Go through the attributes in the allower element, adding to the param map
333
NamedNodeMap JavaDoc attrs = parent.getAttributes();
334         for (int i = 0; i < attrs.getLength(); i++)
335         {
336             Node JavaDoc node = attrs.item(i);
337             String JavaDoc name = node.getNodeName();
338             String JavaDoc value = node.getNodeValue();
339             params.put(name, value);
340         }
341
342         // Go through the param elements in the allower element, adding to the param map
343
NodeList JavaDoc locNodes = parent.getElementsByTagName(ELEMENT_PARAM);
344         for (int i = 0; i < locNodes.getLength(); i++)
345         {
346             // Since this comes from getElementsByTagName we can assume that
347
// all the nodes are elements.
348
Element JavaDoc element = (Element JavaDoc) locNodes.item(i);
349
350             // But getElementsByTagName(ELEMENT_PARAM) includes param nodes that
351
// are nested down inside filters, so we need to check that the
352
// parent node is 'parent'. $&*?! DOM!
353
if (element.getParentNode() != parent)
354             {
355                 continue;
356             }
357
358             String JavaDoc name = element.getAttribute(ATTRIBUTE_NAME);
359             if (name != null)
360             {
361                 String JavaDoc value = element.getAttribute(ATTRIBUTE_VALUE);
362                 if (value == null || value.length() == 0)
363                 {
364                     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
365                     NodeList JavaDoc textNodes = element.getChildNodes();
366
367                     for (int j = 0; j < textNodes.getLength(); j++)
368                     {
369                         buffer.append(textNodes.item(j).getNodeValue());
370                     }
371
372                     value = buffer.toString();
373                 }
374
375                 params.put(name, value);
376             }
377         }
378
379         return params;
380     }
381
382     /**
383      * Process the include and exclude elements, passing them on to the creator
384      * manager.
385      * @param javascript The name of the creator
386      * @param parent The container of the include and exclude elements.
387      */

388     private void processPermissions(String JavaDoc javascript, Element JavaDoc parent)
389     {
390         NodeList JavaDoc incNodes = parent.getElementsByTagName(ELEMENT_INCLUDE);
391         for (int i = 0; i < incNodes.getLength(); i++)
392         {
393             Element JavaDoc include = (Element JavaDoc) incNodes.item(i);
394             String JavaDoc method = include.getAttribute(ATTRIBUTE_METHOD);
395             accessControl.addIncludeRule(javascript, method);
396         }
397
398         NodeList JavaDoc excNodes = parent.getElementsByTagName(ELEMENT_EXCLUDE);
399         for (int i = 0; i < excNodes.getLength(); i++)
400         {
401             Element JavaDoc include = (Element JavaDoc) excNodes.item(i);
402             String JavaDoc method = include.getAttribute(ATTRIBUTE_METHOD);
403             accessControl.addExcludeRule(javascript, method);
404         }
405     }
406
407     /**
408      * J2EE role based method level security added here.
409      * @param javascript The name of the creator
410      * @param parent The container of the include and exclude elements.
411      */

412     private void processAuth(String JavaDoc javascript, Element JavaDoc parent)
413     {
414         NodeList JavaDoc nodes = parent.getElementsByTagName(ELEMENT_AUTH);
415         for (int i = 0; i < nodes.getLength(); i++)
416         {
417             Element JavaDoc include = (Element JavaDoc) nodes.item(i);
418
419             String JavaDoc method = include.getAttribute(ATTRIBUTE_METHOD);
420             String JavaDoc role = include.getAttribute(ATTRIBUTE_ROLE);
421
422             accessControl.addRoleRestriction(javascript, method, role);
423         }
424     }
425
426     /**
427      * J2EE role based method level security added here.
428      * @param javascript The name of the creator
429      * @param parent The container of the include and exclude elements.
430      */

431     private void processAjaxFilters(String JavaDoc javascript, Element JavaDoc parent)
432     {
433         NodeList JavaDoc nodes = parent.getElementsByTagName(ELEMENT_FILTER);
434         for (int i = 0; i < nodes.getLength(); i++)
435         {
436             Element JavaDoc include = (Element JavaDoc) nodes.item(i);
437
438             String JavaDoc type = include.getAttribute(ATTRIBUTE_CLASS);
439             AjaxFilter filter = (AjaxFilter) LocalUtil.classNewInstance(javascript, type, AjaxFilter.class);
440             if (filter != null)
441             {
442                 LocalUtil.setParams(filter, createSettingMap(include), ignore);
443                 ajaxFilterManager.addAjaxFilter(filter, javascript);
444             }
445         }
446     }
447
448     /**
449      * Parse and extra type info from method signatures
450      * @param element The element to read
451      */

452     private void loadSignature(Element JavaDoc element)
453     {
454         StringBuffer JavaDoc sigtext = new StringBuffer JavaDoc();
455
456         // This coagulates text nodes, not sure if we need to do this?
457
element.normalize();
458
459         NodeList JavaDoc nodes = element.getChildNodes();
460         for (int i = 0; i < nodes.getLength(); i++)
461         {
462             Node JavaDoc node = nodes.item(i);
463             short type = node.getNodeType();
464             if (type != Node.TEXT_NODE && type != Node.CDATA_SECTION_NODE)
465             {
466                 log.warn("Ignoring illegal node type: " + type);
467                 continue;
468             }
469
470             sigtext.append(node.getNodeValue());
471         }
472
473         SignatureParser sigp = new SignatureParser(converterManager, creatorManager);
474         sigp.parse(sigtext.toString());
475     }
476
477     /**
478      * Collections often have missing information. This helps fill the missing
479      * data in.
480      * @param javascript The name of the creator
481      * @param parent The container of the include and exclude elements.
482      * @throws ClassNotFoundException If the type attribute can't be converted into a Class
483      */

484     private void processParameters(String JavaDoc javascript, Element JavaDoc parent) throws ClassNotFoundException JavaDoc
485     {
486         NodeList JavaDoc nodes = parent.getElementsByTagName(ELEMENT_PARAMETER);
487         for (int i = 0; i < nodes.getLength(); i++)
488         {
489             Element JavaDoc include = (Element JavaDoc) nodes.item(i);
490
491             String JavaDoc methodName = include.getAttribute(ATTRIBUTE_METHOD);
492
493             // Try to find the method that we are annotating
494
Creator creator = creatorManager.getCreator(javascript);
495             Class JavaDoc dest = creator.getType();
496
497             Method JavaDoc method = null;
498             Method JavaDoc[] methods = dest.getMethods();
499             for (int j = 0; j < methods.length; j++)
500             {
501                 Method JavaDoc test = methods[j];
502                 if (test.getName().equals(methodName))
503                 {
504                     if (method == null)
505                     {
506                         method = test;
507                     }
508                     else
509                     {
510                         log.warn("Setting extra type info to overloaded methods may fail with <parameter .../>");
511                     }
512                 }
513             }
514
515             if (method == null)
516             {
517                 log.error("Unable to find method called: " + methodName + " on type: " + dest.getName() + " from creator: " + javascript);
518                 continue;
519             }
520
521             String JavaDoc number = include.getAttribute(ATTRIBUTE_NUMBER);
522             int paramNo = Integer.parseInt(number);
523
524             String JavaDoc types = include.getAttribute(ATTRIBUTE_TYPE);
525             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(types, ",");
526
527             int j = 0;
528             while (st.hasMoreTokens())
529             {
530                 String JavaDoc type = st.nextToken();
531                 Class JavaDoc clazz = LocalUtil.classForName(type.trim());
532                 TypeHintContext thc = new TypeHintContext(converterManager, method, paramNo).createChildContext(j++);
533                 converterManager.setExtraTypeInfo(thc, clazz);
534             }
535         }
536     }
537
538     /* (non-Javadoc)
539      * @see java.lang.Object#toString()
540      */

541     public String JavaDoc toString()
542     {
543         if (servletResourceName != null)
544         {
545             return "DwrXmlConfigurator[ServletResource:" + servletResourceName + "]";
546         }
547         else
548         {
549             return "DwrXmlConfigurator[ClassResource:" + classResourceName + "]";
550         }
551     }
552
553     /**
554      * The parsed document
555      */

556     private Document JavaDoc document;
557
558     /**
559      * The properties that we don't warn about if they don't exist.
560      */

561     private static List JavaDoc ignore = Arrays.asList(new String JavaDoc[] { "class", });
562
563     /**
564      * The log stream
565      */

566     public static final Logger log = Logger.getLogger(DwrXmlConfigurator.class);
567
568     /**
569      * What AjaxFilters apply to which Ajax calls?
570      */

571     private AjaxFilterManager ajaxFilterManager = null;
572
573     /**
574      * The converter manager that decides how parameters are converted
575      */

576     private ConverterManager converterManager = null;
577
578     /**
579      * The DefaultCreatorManager to which we delegate creation of new objects.
580      */

581     private CreatorManager creatorManager = null;
582
583     /**
584      * The security manager
585      */

586     private AccessControl accessControl = null;
587
588     /**
589      * For debug purposes, the classResourceName that we were configured with.
590      * Either this or {@link #servletResourceName} will be null
591      */

592     private String JavaDoc classResourceName;
593
594     /**
595      * For debug purposes, the servletResourceName that we were configured with
596      * Either this or {@link #classResourceName} will be null
597      */

598     private String JavaDoc servletResourceName;
599
600     /*
601      * The element names
602      */

603     private static final String JavaDoc ELEMENT_INIT = "init";
604
605     private static final String JavaDoc ELEMENT_ALLOW = "allow";
606
607     private static final String JavaDoc ELEMENT_CREATE = "create";
608
609     private static final String JavaDoc ELEMENT_CONVERT = "convert";
610
611     private static final String JavaDoc ELEMENT_PARAM = "param";
612
613     private static final String JavaDoc ELEMENT_INCLUDE = "include";
614
615     private static final String JavaDoc ELEMENT_EXCLUDE = "exclude";
616
617     private static final String JavaDoc ELEMENT_PARAMETER = "parameter";
618
619     private static final String JavaDoc ELEMENT_AUTH = "auth";
620
621     private static final String JavaDoc ELEMENT_SIGNATURES = "signatures";
622
623     private static final String JavaDoc ELEMENT_FILTER = "filter";
624
625     /*
626      * The attribute names
627      */

628     private static final String JavaDoc ATTRIBUTE_ID = "id";
629
630     private static final String JavaDoc ATTRIBUTE_CLASS = "class";
631
632     private static final String JavaDoc ATTRIBUTE_CONVERTER = "converter";
633
634     private static final String JavaDoc ATTRIBUTE_MATCH = "match";
635
636     private static final String JavaDoc ATTRIBUTE_JAVASCRIPT = "javascript";
637
638     private static final String JavaDoc ATTRIBUTE_CREATOR = "creator";
639
640     private static final String JavaDoc ATTRIBUTE_NAME = "name";
641
642     private static final String JavaDoc ATTRIBUTE_VALUE = "value";
643
644     private static final String JavaDoc ATTRIBUTE_METHOD = "method";
645
646     private static final String JavaDoc ATTRIBUTE_ROLE = "role";
647
648     private static final String JavaDoc ATTRIBUTE_NUMBER = "number";
649
650     private static final String JavaDoc ATTRIBUTE_TYPE = "type";
651 }
652
Popular Tags