KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ws > jaxme > util > Configurator


1 /*
2  * Copyright 2003, 2004 The Apache Software Foundation
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  */

17 package org.apache.ws.jaxme.util;
18
19 import java.lang.reflect.Constructor JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.List JavaDoc;
24
25 import javax.xml.namespace.QName JavaDoc;
26
27 import org.xml.sax.Attributes JavaDoc;
28 import org.xml.sax.ContentHandler JavaDoc;
29 import org.xml.sax.Locator JavaDoc;
30 import org.xml.sax.SAXException JavaDoc;
31 import org.xml.sax.SAXParseException JavaDoc;
32
33
34 /** <p>The Configurator is an idea borrowed by the Ant project.
35  * It is a SAX2 handler that reads a config file which is
36  * represented by a hierarchy of Java beans. For example:</p>
37  * <pre>
38  * &lt;outerBean foo="true" bar="Quite right"&gt;
39  * &lt;innerBean whatever="57"&gt;
40  * &lt;/innerBean
41  * &lt;/outerBean&gt;
42  * </pre>
43  * The example would create an object outerBean and call its
44  * methods <code>setFoo(boolean)</code> and
45  * <code>setBar(String)</code> to process the attributes.
46  * It would also create a bean innerBean by calling the
47  * outerBeans method <code>createInnerBean()</code>.
48  * Finally the innerBean is configured by calling
49  * <code>setWhatever(int)</code>.</p>
50  *
51  * @author <a HREF="mailto:joe@ispsoft.de">Jochen Wiedmann</a>
52  * @version $Id: Configurator.java,v 1.4 2005/03/10 10:14:03 jochen Exp $
53  */

54 public class Configurator implements ContentHandler JavaDoc, NamespaceResolver {
55   private static final Class JavaDoc[] zeroClasses = new Class JavaDoc[0];
56   private static final Object JavaDoc[] zeroObjects = new Object JavaDoc[0];
57   private static final Class JavaDoc[] oneClassString = new Class JavaDoc[]{String JavaDoc.class};
58   private static final Class JavaDoc[] oneClassAttributes = new Class JavaDoc[]{Attributes JavaDoc.class};
59
60   private String JavaDoc[] namespaces;
61   private List JavaDoc beans = new ArrayList JavaDoc();
62   private List JavaDoc names = new ArrayList JavaDoc();
63   private Object JavaDoc currentBean;
64   private String JavaDoc currentName;
65   private Locator JavaDoc locator;
66   private Object JavaDoc beanFactory;
67   private Object JavaDoc rootObject;
68   private Object JavaDoc resultBean;
69   private int ignoreLevel = 0;
70   private NamespaceSupport nss = new NamespaceSupport();
71   boolean nssNeedsContext;
72
73   /** <p>Sets the namespace handled by the configurator. Defaults
74    * to no namespace. Shortcut for
75    * <code>setNamespace(new String[]{pNamespace})</code>.</p>
76    *
77    * @param pNamespace The namespace being set
78    */

79   public void setNamespace(String JavaDoc pNamespace) {
80     setNamespaces(new String JavaDoc[]{pNamespace});
81   }
82
83   /** <p>Sets the namespaces handled by the configurator. Defaults
84    * to no namespace.</p>
85    *
86    * @param pNamespaces The namespaces being set
87    */

88   public void setNamespaces(String JavaDoc[] pNamespaces) {
89     namespaces = pNamespaces;
90   }
91
92   /** <p>Returns the namespaces handled by the configurator. Defaults
93    * to no namespace.</p>
94    */

95   public String JavaDoc[] getNamespaces() {
96     return namespaces;
97   }
98
99   /** <p>Sets the Locator being used in error messages.</p>
100    */

101   public void setDocumentLocator(Locator JavaDoc pLocator) {
102     locator = pLocator;
103   }
104
105   /** <p>Returns the Locator being used in error messages.</p>
106    */

107   public Locator JavaDoc getDocumentLocator() {
108     return locator;
109   }
110
111   /** <p>Sets the bean factory, creating the outermost element.
112    * The bean factory must have a matching <code>createElementName()</code>
113    * method, with <samp>ElementName</samp> being the element name
114    * of the document element.</p>
115    */

116   public void setBeanFactory(Object JavaDoc pFactory) {
117     beanFactory = pFactory;
118   }
119
120   /** <p>Returns the bean factory, creating the outermost element.
121    * The bean factory must have a matching <code>createElementName()</code>
122    * method, with <samp>ElementName</samp> being the element name
123    * of the document element.</p>
124    */

125   public Object JavaDoc getBeanFactory() {
126     return beanFactory == null ? this : beanFactory;
127   }
128
129   /** <p>An alternative to using the bean factory. This object
130    * is used as the root object, regardless of its name.</p>
131    */

132   public void setRootObject(Object JavaDoc pRootObject) {
133     rootObject = pRootObject;
134   }
135
136   /** <p>An alternative to using the bean factory. This object
137    * is used as the root object, regardless of its name.</p>
138    */

139   public Object JavaDoc getRootObject() {
140     return rootObject;
141   }
142
143   public void startDocument() throws SAXException JavaDoc {
144     currentBean = null;
145     currentName = null;
146     beans.clear();
147     names.clear();
148     ignoreLevel = 0;
149     nss.reset();
150     nssNeedsContext = true;
151   }
152   public void endDocument() throws SAXException JavaDoc {}
153
154   public void startPrefixMapping(String JavaDoc pPrefix, String JavaDoc pURI)
155       throws SAXException JavaDoc {
156     nss.declarePrefix(pPrefix, pURI);
157   }
158
159   public void endPrefixMapping(String JavaDoc pPrefix)
160       throws SAXException JavaDoc {
161     nss.undeclarePrefix(pPrefix);
162   }
163
164   /** <p>Returns whether a namespace is matching the configured
165    * namespace.</p>
166    */

167   protected boolean isNamespaceMatching(String JavaDoc pNamespace) {
168     if (pNamespace == null) {
169       pNamespace = "";
170     }
171     String JavaDoc[] myNamespaces = getNamespaces();
172     if (myNamespaces == null || myNamespaces.length == 0) {
173       return pNamespace.length() == 0;
174     } else {
175       for (int i = 0; i < myNamespaces.length; i++) {
176         String JavaDoc s = myNamespaces[i];
177         if (s == null) {
178           s = "";
179         }
180         if (s.equals(pNamespace)) {
181           return true;
182         }
183       }
184       return false;
185     }
186   }
187
188   /** <p>Given a prefix and a name, creates a method name matching
189    * the prefix and the name.</p>
190    */

191   protected String JavaDoc getMethodNameFor(String JavaDoc pPrefix, String JavaDoc pName) {
192     StringBuffer JavaDoc result = new StringBuffer JavaDoc(pPrefix);
193     for (int i = 0; i < pName.length(); i++) {
194       char c = pName.charAt(i);
195       if (i == 0) {
196         if (Character.isJavaIdentifierStart(c)) {
197           result.append(Character.toUpperCase(c));
198         } else {
199           result.append('_');
200         }
201       } else {
202         if (Character.isJavaIdentifierPart(c)) {
203           result.append(c);
204         } else {
205           result.append('_');
206         }
207       }
208     }
209     return result.toString();
210   }
211
212   /** <p>Creates a new bean, matching the element name <code>pLocalName</code>.
213    * If this is the outermost bean, calls the bean factorys
214    * <code>createBeanName()</code> method, otherwise calls the current beans
215    * <code>createBeanName()</code> method, with <samp>beanName</samp>
216    * being the value of the <code>pLocalName</code> parameter.</p>
217    */

218   public void startElement(String JavaDoc pNamespaceURI, String JavaDoc pQName,
219                             String JavaDoc pLocalName, Attributes JavaDoc pAttr) throws SAXException JavaDoc {
220     if (ignoreLevel > 0) {
221       ++ignoreLevel;
222       return;
223     }
224     
225     if (!isNamespaceMatching(pNamespaceURI)) {
226       if (currentBean == null) {
227         String JavaDoc[] myNamespaces = getNamespaces();
228         if (myNamespaces == null || myNamespaces.length == 0) {
229           throw new SAXParseException JavaDoc("The document element must have the default namespace.",
230                                        getDocumentLocator());
231         } else {
232           StringBuffer JavaDoc sb = new StringBuffer JavaDoc("The document element must have either of the namespaces: ");
233           for (int i = 0; i < myNamespaces.length; i++) {
234             if (i > 0) sb.append(",");
235             String JavaDoc s = myNamespaces[i];
236             if (s == null) {
237               s = "";
238             }
239             sb.append('"').append(s).append('"');
240           }
241           throw new SAXParseException JavaDoc(sb.toString(), getDocumentLocator());
242         }
243       }
244
245       ++ignoreLevel;
246       return; // Namespace not matching, ignore this element
247
}
248
249     Object JavaDoc o;
250     if (currentBean == null && rootObject != null) {
251       o = rootObject;
252     } else {
253       o = null;
254       Object JavaDoc factory = (currentBean == null) ? beanFactory : currentBean;
255       String JavaDoc methodName = getMethodNameFor("create", pLocalName);
256       try {
257         o = invokeMethod(methodName, factory, oneClassAttributes,
258                          new Object JavaDoc[]{pAttr});
259       } catch (SAXParseException JavaDoc e) {
260         if (e.getException() != null &&
261             e.getException() instanceof NoSuchMethodException JavaDoc) {
262           try {
263             o = invokeMethod(methodName, factory, zeroClasses, zeroObjects);
264             e = null;
265           } catch (SAXParseException JavaDoc f) {
266             if (f.getException() != null &&
267                 f.getException() instanceof NoSuchMethodException JavaDoc) {
268               if (currentBean == null) {
269                 throw new SAXParseException JavaDoc("Invalid document element: " + pQName,
270                                              getDocumentLocator());
271               } else {
272                 throw new SAXParseException JavaDoc("Invalid child element name: " + pQName,
273                                              getDocumentLocator());
274               }
275             }
276             throw f;
277           }
278         }
279         if (e != null) {
280            throw e;
281         }
282       }
283       if (o == null) {
284         throw new SAXParseException JavaDoc("Method " + methodName + " of class " +
285                                      factory.getClass().getName() +
286                                      " did not return an object.",
287                                      getDocumentLocator());
288       }
289     }
290
291     if (currentBean == null) {
292       resultBean = o;
293     } else {
294       beans.add(currentBean);
295       names.add(currentName);
296     }
297     currentBean = o;
298     currentName = pQName;
299
300     if (pAttr != null) {
301       for (int i = 0; i < pAttr.getLength(); i++) {
302         String JavaDoc uri = pAttr.getURI(i);
303         if (uri == null || uri.length() == 0 || isNamespaceMatching(uri)) {
304           String JavaDoc value = pAttr.getValue(i);
305           String JavaDoc qName = pAttr.getQName(i);
306           String JavaDoc setMethodName = getMethodNameFor("set", pAttr.getLocalName(i));
307           Method JavaDoc[] methods = currentBean.getClass().getMethods();
308           for (int j = 0; j < methods.length; j++) {
309             Method JavaDoc method = methods[j];
310             if (!setMethodName.equals(method.getName())) {
311               continue;
312             }
313             Class JavaDoc[] argClasses = method.getParameterTypes();
314             if (argClasses.length != 1) {
315               continue;
316             }
317             Object JavaDoc[] args = null;
318             if (argClasses[0] == String JavaDoc.class) {
319               args = new Object JavaDoc[]{value};
320             } else if (argClasses[0] == Integer JavaDoc.class ||
321                         argClasses[0] == Integer.TYPE) {
322               try {
323                 args = new Object JavaDoc[]{new Integer JavaDoc(value)};
324               } catch (Exception JavaDoc e) {
325                 throw new SAXParseException JavaDoc("Attribute " + qName +
326                                              " contains an invalid Integer value: " +
327                                              value, getDocumentLocator());
328               }
329             } else if (argClasses[0] == Long JavaDoc.class ||
330                         argClasses[0] == Long.TYPE) {
331               try {
332                 args = new Object JavaDoc[]{new Long JavaDoc(value)};
333               } catch (Exception JavaDoc e) {
334                 throw new SAXParseException JavaDoc("Attribute " + qName +
335                                              " contains an invalid Long value: " +
336                                              value, getDocumentLocator());
337               }
338             } else if (argClasses[0] == Short JavaDoc.class ||
339                         argClasses[0] == Short.TYPE) {
340               try {
341                 args = new Object JavaDoc[]{new Short JavaDoc(value)};
342               } catch (Exception JavaDoc e) {
343                 throw new SAXParseException JavaDoc("Attribute " + qName +
344                                              " contains an invalid Short value: " +
345                                              value, getDocumentLocator());
346               }
347             } else if (argClasses[0] == Byte JavaDoc.class ||
348                         argClasses[0] == Byte.TYPE) {
349               try {
350                 args = new Object JavaDoc[]{new Byte JavaDoc(value)};
351               } catch (Exception JavaDoc e) {
352                 throw new SAXParseException JavaDoc("Attribute " + qName +
353                                              " contains an invalid Byte value: " +
354                                              value, getDocumentLocator());
355               }
356             } else if (argClasses[0] == Boolean JavaDoc.class ||
357                         argClasses[0] == Boolean.TYPE) {
358               try {
359                 args = new Object JavaDoc[]{Boolean.valueOf(value)};
360               } catch (Exception JavaDoc e) {
361                 throw new SAXParseException JavaDoc("Attribute " + qName +
362                                              " contains an invalid Boolean value: " +
363                                              value, getDocumentLocator());
364               }
365             } else if (argClasses[0] == Character JavaDoc.class ||
366                         argClasses[0] == Character.TYPE) {
367               if (value.length() != 1) {
368                 throw new SAXParseException JavaDoc("Attribute " + qName +
369                                              " contains an invalid Character value: " +
370                                              value, getDocumentLocator());
371               }
372               args = new Object JavaDoc[]{new Character JavaDoc(value.charAt(0))};
373             } else if (argClasses[0] == Class JavaDoc.class) {
374               Class JavaDoc c;
375               try {
376                 c = ClassLoader.getClass(value);
377               } catch (Exception JavaDoc e) {
378                 throw new SAXParseException JavaDoc("Failed to load class " + value,
379                                              getDocumentLocator(), e);
380               }
381               args = new Object JavaDoc[]{c};
382             } else if (argClasses[0] == QName JavaDoc.class) {
383               try {
384                 QName JavaDoc name = QName.valueOf(value);
385                 args = new Object JavaDoc[]{name};
386               } catch (Exception JavaDoc e) {
387                 throw new SAXParseException JavaDoc("Failed to parse QName " + value,
388                                              getDocumentLocator());
389               }
390             } else {
391               // Try a constructor class(String)
392
try {
393                 Constructor JavaDoc con = argClasses[0].getConstructor(oneClassString);
394                 args = new Object JavaDoc[]{con.newInstance(new Object JavaDoc[]{value})};
395               } catch (InvocationTargetException JavaDoc e) {
396                 Throwable JavaDoc t = e.getTargetException();
397                 throw new SAXParseException JavaDoc("Failed to invoke constructor of class " +
398                                              argClasses[0].getClass().getName(),
399                                              getDocumentLocator(),
400                                              (t instanceof Exception JavaDoc) ? ((Exception JavaDoc) t) : e);
401               } catch (NoSuchMethodException JavaDoc e) {
402                 throw new SAXParseException JavaDoc("Attribute " + qName +
403                                              " has an invalid type: " +
404                                              argClasses[0].getClass().getName(),
405                                              getDocumentLocator());
406               } catch (IllegalAccessException JavaDoc e) {
407                 throw new SAXParseException JavaDoc("Illegal access to constructor of class " +
408                                              argClasses[0].getClass().getName(),
409                                              getDocumentLocator(), e);
410               } catch (InstantiationException JavaDoc e) {
411                 throw new SAXParseException JavaDoc("Failed to instantiate class " +
412                                              argClasses[0].getClass().getName(),
413                                              getDocumentLocator(), e);
414               }
415             }
416
417             try {
418               method.invoke(currentBean, args);
419             } catch (IllegalAccessException JavaDoc e) {
420               throw new SAXParseException JavaDoc("Illegal access to method " + setMethodName +
421                                              " of class " + currentBean.getClass().getName(),
422                                              getDocumentLocator(), e);
423             } catch (InvocationTargetException JavaDoc e) {
424               Throwable JavaDoc t = e.getTargetException();
425               throw new SAXParseException JavaDoc("Failed to invoke method " + setMethodName +
426                                            " of class " + currentBean.getClass().getName(),
427                                            getDocumentLocator(),
428                                            (t instanceof Exception JavaDoc) ? ((Exception JavaDoc) t) : e);
429             }
430           }
431         }
432       }
433     }
434   }
435
436   protected Object JavaDoc invokeMethod(String JavaDoc pMethodName, Object JavaDoc pBean,
437                                  Class JavaDoc[] pSignature, Object JavaDoc[] pArgs)
438      throws SAXException JavaDoc {
439     try {
440       Method JavaDoc m = pBean.getClass().getMethod(pMethodName, pSignature);
441       return m.invoke(pBean, pArgs);
442     } catch (IllegalAccessException JavaDoc e) {
443       throw new SAXParseException JavaDoc("Illegal access to method " + pMethodName +
444                                    " of class " + pBean.getClass().getName(),
445                                    getDocumentLocator(), e);
446     } catch (NoSuchMethodException JavaDoc e) {
447       throw new SAXParseException JavaDoc("No such method in class " +
448                                    pBean.getClass().getName() + ": " + pMethodName,
449                                    getDocumentLocator(), e);
450     } catch (InvocationTargetException JavaDoc e) {
451       Throwable JavaDoc t = e.getTargetException();
452       throw new SAXParseException JavaDoc("Failed to invoke method " + pMethodName +
453                                    " of class " + pBean.getClass().getName(),
454                                    getDocumentLocator(),
455                                    (t instanceof Exception JavaDoc) ? ((Exception JavaDoc) t) : e);
456     }
457   }
458
459   /** <p>Terminates parsing the current bean by calling its
460    * <code>finish()</code> method, if any.</p>
461    */

462   public void endElement(String JavaDoc namespaceURI, String JavaDoc qName, String JavaDoc localName)
463       throws SAXException JavaDoc {
464     if (ignoreLevel > 0) {
465       --ignoreLevel;
466       return;
467     }
468
469     Object JavaDoc previousBean = currentBean;
470     if (beans.size() > 0) {
471       currentBean = beans.remove(beans.size()-1);
472       currentName = names.remove(names.size()-1).toString();
473     } else {
474       currentBean = null;
475       currentName = null;
476     }
477     try {
478       invokeMethod("finish", previousBean, zeroClasses, zeroObjects);
479     } catch (SAXParseException JavaDoc e) {
480       if (e.getException() == null ||
481           !(e.getException() instanceof NoSuchMethodException JavaDoc)) {
482         throw e;
483       }
484     }
485   }
486
487   /** <p>Handles atomic child elements by invoking their method
488    * <code>addText(String pText)</code>. Note that it may happen,
489    * that this method is invoked multiple times, if the parser
490    * splits a piece of text into multiple SAX events.</p>
491    */

492   public void characters(char[] ch, int start, int length)
493       throws SAXException JavaDoc {
494     if (ignoreLevel > 0) {
495       return;
496     }
497
498     String JavaDoc s = new String JavaDoc(ch, start, length);
499     try {
500       invokeMethod("addText", currentBean, oneClassString, new String JavaDoc[]{s});
501     } catch (SAXParseException JavaDoc e) {
502       if (e.getException() != null &&
503           (e.getException() instanceof NoSuchMethodException JavaDoc)) {
504         boolean allWhitespace = true;
505         for (int i = 0; i < length; i++) {
506           if (!Character.isWhitespace(ch[start+i])) {
507             allWhitespace = false;
508             break;
509           }
510         }
511         if (allWhitespace) {
512           // Ignore this
513
} else {
514           throw new SAXParseException JavaDoc("Element " + currentName +
515                                        " doesn't support embedded text.",
516                                        getDocumentLocator());
517         }
518       } else {
519         throw e;
520       }
521     }
522   }
523
524   public void ignorableWhitespace(char[] ch, int start, int length)
525     throws SAXException JavaDoc {
526   }
527
528   public void processingInstruction(String JavaDoc target, String JavaDoc data)
529     throws SAXException JavaDoc {
530   }
531
532   public void skippedEntity(String JavaDoc name) throws SAXException JavaDoc {
533   }
534
535   /** Returns the parsed result bean.
536    */

537   public Object JavaDoc getResult() { return resultBean; }
538
539   public boolean processName(String JavaDoc pName, String JavaDoc[] parts) {
540     int offset = pName.indexOf(':');
541     if (offset == -1) {
542       String JavaDoc uri = nss.getNamespaceURI("");
543       if (uri == null) {
544         parts[0] = "";
545       } else {
546         parts[0] = uri;
547       }
548       parts[1] = pName;
549       parts[2] = pName;
550       return true;
551     } else {
552       String JavaDoc uri = nss.getNamespaceURI(pName.substring(0, offset));
553       if (uri == null) {
554         return false;
555       } else {
556         parts[0] = uri;
557         parts[1] = pName.substring(offset+1);
558         parts[2] = pName;
559         return true;
560       }
561     }
562   }
563 }
564
Popular Tags