Source Code Cross Referenced for XOD.java in  » Web-Framework » ThinWire » thinwire » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Framework » ThinWire » thinwire.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:        #IFNDEF ALT_LICENSE
003:                                   ThinWire(R) RIA Ajax Framework
004:                         Copyright (C) 2003-2007 Custom Credit Systems
005:
006:          This library is free software; you can redistribute it and/or modify it under
007:          the terms of the GNU Lesser General Public License as published by the Free
008:          Software Foundation; either version 2.1 of the License, or (at your option) any
009:          later version.
010:
011:          This library is distributed in the hope that it will be useful, but WITHOUT ANY
012:          WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
013:          PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
014:
015:          You should have received a copy of the GNU Lesser General Public License along
016:          with this library; if not, write to the Free Software Foundation, Inc., 59
017:          Temple Place, Suite 330, Boston, MA 02111-1307 USA
018:
019:          Users who would rather have a commercial license, warranty or support should
020:          contact the following company who invented, built and supports the technology:
021:          
022:                        Custom Credit Systems, Richardson, TX 75081, USA.
023:           	            email: info@thinwire.com    ph: +1 (888) 644-6405
024:         	                        http://www.thinwire.com
025:        #ENDIF
026:         [ v1.2_RC2 ] 
027:         */
028:        package thinwire.util;
029:
030:        import java.io.File;
031:        import java.io.InputStream;
032:        import java.lang.reflect.Field;
033:        import java.lang.reflect.InvocationTargetException;
034:        import java.lang.reflect.Method;
035:        import java.lang.reflect.Modifier;
036:        import java.util.ArrayList;
037:        import java.util.Collection;
038:        import java.util.Collections;
039:        import java.util.HashMap;
040:        import java.util.List;
041:        import java.util.Map;
042:        import java.util.logging.Level;
043:        import java.util.logging.Logger;
044:        import java.util.regex.Matcher;
045:        import java.util.regex.Pattern;
046:
047:        import javax.xml.parsers.DocumentBuilder;
048:        import javax.xml.parsers.DocumentBuilderFactory;
049:
050:        import org.w3c.dom.DOMException;
051:        import org.w3c.dom.Document;
052:        import org.w3c.dom.NamedNodeMap;
053:        import org.w3c.dom.Node;
054:        import org.w3c.dom.NodeList;
055:
056:        import thinwire.ui.Application;
057:
058:        /**
059:         * Xml Object Document (XOD) generates objects from the XML file, and associates them with a Map.
060:         * XODs can be used to create instances of plain old java objects (POJO). For example, a Dialog can be
061:         * created as follows:<p>
062:         * <h3>Sample File</h3>
063:         * <img src="doc-files/XOD-1.png"> <p>
064:         * <h3>Sample File XML</h3>
065:         * <pre>
066:         * &lt;?xml version="1.0"?&gt;
067:         * &lt;xod&gt;
068:         *     &lt;include file="classes.xml"/&gt;
069:         *     &lt;Dialog id="dialog"&gt;
070:         *         &lt;title&gt;XOD Demo File&lt;/title&gt;
071:         *         &lt;width&gt;300&lt;/width&gt;
072:         *         &lt;height&gt;200&lt;/height&gt;
073:         *         &lt;children&gt;
074:         *             &lt;TextField id="name"&gt;
075:         *                 &lt;x&gt;90&lt;/x&gt;
076:         *                 &lt;y&gt;5&lt;/y&gt;
077:         *                 &lt;width&gt;80&lt;/width&gt;
078:         *                 &lt;height&gt;25&lt;/height&gt;
079:         *             &lt;/TextField&gt;
080:         *             &lt;Label&gt;
081:         *                 &lt;text&gt;Name:&lt;/text&gt;
082:         *                 &lt;labelFor&gt;name&lt;/labelFor&gt;
083:         *                 &lt;alignX&gt;RIGHT&lt;/alignX&gt;
084:         *                 &lt;x&gt;5&lt;/x&gt;
085:         *                 &lt;y&gt;5&lt;/y&gt;
086:         *                 &lt;width&gt;80&lt;/width&gt;
087:         *                 &lt;height&gt;25&lt;/height&gt;
088:         *             &lt;/Label&gt;
089:         *         &lt;/children&gt;
090:         *     &lt;/Dialog&gt;
091:         * &lt;/xod&gt;
092:         * </pre>
093:         * <h3>Sample Java Code Using XOD</h3>
094:         * <pre>
095:         * XOD xod = new XOD();
096:         * xod.execute("dialog.xml");  
097:         * Dialog dialog = (Dialog)xod.getObjectMap().get("dialog");
098:         * dialog.setVisible(true);
099:         * </pre>
100:         *  <h3>Sample Alias XML File</h3>
101:         * The &lt;alias&gt; tag associates a short name with a class name.  This content doesn't
102:         * have to be separate.  Instead of using the &lt;include&gt; tag in the demo file displayed
103:         * above, the demo file could have included it directly.<p>
104:         * <pre>
105:         * &lt;xod&gt;
106:         *     &lt;alias name="Button" class="thinwire.ui.Button"/&gt;
107:         *     &lt;alias name="CheckBox" class="thinwire.ui.CheckBox"/&gt;
108:         *     &lt;alias name="Dialog" class="thinwire.ui.Dialog"/&gt;
109:         *     &lt;alias name="Divider" class="thinwire.ui.Divider"/&gt;
110:         *     &lt;alias name="DropDownGridBox" class="thinwire.ui.DropDownGridBox"/&gt;
111:         *     &lt;alias name="Frame" class="thinwire.ui.Frame"/&gt;
112:         *     &lt;alias name="GridBox" class="thinwire.ui.GridBox"/&gt;
113:         *     &lt;alias name="Image" class="thinwire.ui.Image"/&gt;
114:         *     &lt;alias name="Label" class="thinwire.ui.Label"/&gt;
115:         *     &lt;alias name="Menu" class="thinwire.ui.Menu"/&gt;
116:         *     &lt;alias name="Panel" class="thinwire.ui.Panel"/&gt;
117:         *     &lt;alias name="RadioButton" class="thinwire.ui.RadioButton"/&gt;
118:         *     &lt;alias name="RadioButton.Group" class="thinwire.ui.RadioButton$Group"/&gt;
119:         *     &lt;alias name="TabFolder" class="thinwire.ui.TabFolder"/&gt;
120:         *     &lt;alias name="TabSheet" class="thinwire.ui.TabSheet"/&gt;
121:         *     &lt;alias name="TextArea" class="thinwire.ui.TextArea"/&gt;
122:         *     &lt;alias name="TextField" class="thinwire.ui.TextField"/&gt;
123:         * &lt;/xod&gt;
124:         *</pre>
125:         *<h3>Notes on the XOD Tags</h3>
126:         *<h4>&lt;xod&gt;</h4>
127:         *The &lt;xod&gt; tag is the top level tag.  It occurs once and encloses all other
128:         *tags.
129:         *<h4>&lt;include&gt;</h4>
130:         *The &lt;include&gt; tag allows you to include other XOD XML files within an XOD file.
131:         *Use it to reduce duplication. E.g. You can use it to include an alias file like the
132:         *one shown above.
133:         *<h4>&lt;alias&gt;</h4>
134:         *Many of the tags in the demo listed above can be thought of as
135:         *instruction to construct plain old java objects.  E.g. The &lt;Button&gt; tag can be thought of as
136:         *instruction to build a Button class instance.
137:         *<p>
138:         *In general, an XOD file can contain tags of the form
139:         *<pre>
140:         *  &lt;com.mypackage.XXXX&gt;
141:         *</pre>
142:         *where XXXX is a class, and such a tag can be thought of as an 
143:         *instruction to create an instance of the XXXX class.<p>
144:         *But the full class names are long.  To allow for shorter tags in your xod files, you can define an alias: <br>
145:         *<pre>
146:         *  &lt;alias name="Button" class="thinwire.ui.Button"/&gt;   
147:         *</pre>
148:         *Once you've included this alias in your file, you can construct
149:         *an object using it:<br>
150:         *<pre>
151:         *   &lt;Button id="button_ok"&gt;
152:         *        &lt;text&gt;OK&lt;/text&gt;
153:         *        &lt;x&gt;73&lt;/x&gt;
154:         *        &lt;y&gt;301&lt;/y&gt;
155:         *        &lt;width&gt;84&lt;/width&gt;
156:         *        &lt;height&gt;30&lt;/height&gt;
157:         *   &lt;/Button&gt;
158:         * </pre>
159:         *<h4>&lt;ref&gt;</h4>
160:         *Some objects need to be associated with other objects.
161:         *E.g. We need a means to indicate that the RadioButtons described in a
162:         *container are members of the RadioButton.Group.
163:         *We use the &lt;ref&gt; tag to accomplish this.
164:         *<p>
165:         *<h4>Object Class Tags</h4>
166:         *If there's a class with the name "com.mypackage.XXXX", you can include an
167:         *&lt;com.mypackage.XXXX&gt; element in your XOD definition.  You can also
168:         *create an alias for that class and use it in place of the class name. 
169:         *<p>
170:         *<h4>Component Property Tags - e.g. &lt;width&gt;, &lt;text&gt;, &lt;x&gt;</h4>
171:         *To specify properties - e.g. location, size, and text - for the components you wish
172:         *to build, add property tag elements. In general, if a UI component class has a "setXxxx" method,
173:         *you can include an &lt;xxxx&gt; property tag.<p>
174:         *E.g. Since the thinwire.ui.Button class has a setText method,
175:         *you can specify the text for your button with a &lt;text&gt; element.
176:         *
177:         *<pre>
178:         *   &lt;Button id="button_ok"&gt;
179:         *        ....
180:         *        &lt;text&gt;OK&lt;/text&gt;
181:         *        ....
182:         *   &lt;/Button&gt;
183:         * </pre>
184:         * 
185:         * <h4>Property Tag Values</h4>
186:         * The properties of objects have types. E.g.  The text property of the
187:         * Button class is of type String, and the x property of the Button class is of type
188:         * int. Other standard types are Integer, double, Double, char, Character, long, Long,
189:         * boolean, Boolean, float, Float, byte, and Byte.
190:         * <p>
191:         * In the case of these standard types, the XOD class will make the appropriate conversion
192:         * while processing a xod file. E.g. When it comes across
193:         * <pre>
194:         *   &lt;Button id="Search_btn"&gt;
195:         *        .....
196:         *        &lt;x&gt;73&lt;/x&gt;
197:         *        .....
198:         *   &lt;/Button&gt;
199:         * </pre>
200:         * the XOD engine will convert "73" to an int and assign the x property of the
201:         * new Button that int value.
202:         * <p>
203:         * In the case of non-literal types, XOD has three special strategies.
204:         * First, it will check to see if the class type of the property you are assigning
205:         * to has a 'valueOf' method that returns the appropriate type.  If it does, it
206:         * will call that method and assign the returned value to the property. 
207:         * E.g. The Label class has an alignX property of type thinwire.ui.AlignX.
208:         * This class has a 'valueOf' method.  When XOD processes the above demo file and comes across
209:         * <pre>
210:         * &lt;Label&gt;
211:         *     .....
212:         *     &lt;alignX&gt;RIGHT&lt;/alignX&gt;
213:         *     .....
214:         * &lt;/Label&gt;
215:         * </pre>
216:         * it calls the static 'valueOf' on AlignX, which returns the appropriate constant AlignX.RIGHT.
217:         * Second, it will check to see if the class type has a static final field (i.e. constant) that
218:         * is named the same as the value specified in the property tag.  If it finds a constant, it will
219:         * be assed to the property. 
220:         * Third, it looks for an object defined elsewhere in the XOD, an object
221:         * whose id in the XOD matches the property value. If it finds one, it assigns
222:         * the object as a value for the property. E.g. When it comes across
223:         * <pre>
224:         *  &lt;Label&gt;
225:         *      .....
226:         *      &lt;labelFor&gt;name&lt;/labelFor&gt;
227:         *      .....
228:         *  &lt;/Label&gt;
229:         * </pre>
230:         * then XOD engine discovers that there is a 'name' object defined previously, and it assigns
231:         * this object to the Label's labelFor property.<p> 
232:         * <p>
233:         * <h4>Collection Properties</h4>
234:         * A component may have a property with a Collection type.  E.g. Dialogs have
235:         * a getChildren method, and a children property.  The children of a Dialog form
236:         * a collection.<p>
237:         * When an XML element represents a property with a Collection type, the content of 
238:         * the element represents the members of the collection. E.g.  When XOD comes 
239:         * across 
240:         * <pre>
241:         *  &lt;children&gt;
242:         *      &lt;Label&gt;
243:         *          ....
244:         *      &lt;/Label&gt;
245:         *      &lt;Label&gt;
246:         *          ....
247:         *      &lt;/Label&gt;
248:         *      &lt;Label&gt;
249:         *          ....
250:         *      &lt;/Label&gt;
251:         *      &lt;Divider&gt;
252:         *          ....
253:         *      &lt;/Divider&gt;
254:         *      &lt;Divider&gt;
255:         *          ....
256:         *      &lt;/Divider&gt;
257:         *      &lt;TextField id="name"&gt;
258:         *          .... 
259:         *      &lt;/TextField&gt;
260:         *      ....
261:         *  &lt;/children&gt;
262:         * </pre>
263:         * it constructs Label, Divider, and TextField components and makes these
264:         * components children of the Dialog.
265:         *
266:         * @author Joshua J. Gertzen
267:         */
268:        public final class XOD {
269:            private static final Logger log = Logger.getLogger(XOD.class
270:                    .getName());
271:            private static final Level LEVEL = Level.FINER;
272:
273:            private static File getRelativeFile(String uri) {
274:                Application app = Application.current();
275:                return app == null ? new File(uri) : app.getRelativeFile(uri);
276:            }
277:
278:            private static File getRelativeFile(String parent, String child) {
279:                Application app = Application.current();
280:                return app == null ? new File(parent, child) : app
281:                        .getRelativeFile(parent, child);
282:            }
283:
284:            private Map<String, Object> objectMap;
285:            private Map<Object, String> idMap;
286:            private List<Object> rootObjects;
287:            private List<Object> objects;
288:            private Map<String, Class> aliases;
289:            private Map<String, String> properties;
290:            private Map<Class, Map<String, Object[]>> propertyAliases;
291:            private List<String> uriStack;
292:            private boolean processingInclude;
293:
294:            /**
295:             * Create a new XOD.
296:             */
297:            public XOD() {
298:                this (null);
299:            }
300:
301:            /**
302:             * Create a new XOD.
303:             * @param uri the name of the XML Object Document file to execute.
304:             */
305:            public XOD(String uri) {
306:                rootObjects = new ArrayList<Object>();
307:                objectMap = new HashMap<String, Object>();
308:                objects = new ArrayList<Object>();
309:                aliases = new HashMap<String, Class>();
310:                properties = new HashMap<String, String>();
311:                uriStack = new ArrayList<String>();
312:                if (uri != null)
313:                    execute(uri);
314:            }
315:
316:            public Map<String, Class> getAliasMap() {
317:                return aliases;
318:            }
319:
320:            public Map<String, String> getPropertyMap() {
321:                return properties;
322:            }
323:
324:            /**
325:             * The object map contains references to previously defined objects
326:             * identified by id.  Typically, it will map an ID found in the 
327:             * XOD to an object.
328:             * @return the object Map
329:             */
330:            public Map<String, Object> getObjectMap() {
331:                return objectMap;
332:            }
333:
334:            public List<Object> getObjects() {
335:                return Collections.unmodifiableList(objects);
336:            }
337:
338:            public List<Object> getRootObjects() {
339:                return Collections.unmodifiableList(rootObjects);
340:            }
341:
342:            /**
343:             * Gets the id that is associated to the specified object.
344:             * For this to succeed, the object must be in the object map.
345:             * @param o the object to retrieve the id for.
346:             * @return the id associated to the object, or null if the object is not in the object map.
347:             */
348:            public String getObjectId(Object o) {
349:                return getIdMap().get(o);
350:            }
351:
352:            private Map<Object, String> getIdMap() {
353:                if (idMap == null) {
354:                    idMap = new HashMap<Object, String>();
355:
356:                    for (Map.Entry<String, Object> entry : objectMap.entrySet()) {
357:                        idMap.put(entry.getValue(), entry.getKey());
358:                    }
359:                }
360:
361:                return idMap;
362:            }
363:
364:            /**
365:             * Executes a XOD file, adding the created objects to the map and list.
366:             * @param uri the name of the XML Object Document file.
367:             */
368:            public void execute(String uri) {
369:                processFile(null, uri, 0);
370:            }
371:
372:            private Object processFile(Object parent, String uri, int level) {
373:                Object ret = null;
374:
375:                try {
376:                    DocumentBuilder builder = DocumentBuilderFactory
377:                            .newInstance().newDocumentBuilder();
378:                    uri = uri.replace('\\', '/');
379:                    InputStream is = Application.getResourceAsStream(uri);
380:                    if (is == null)
381:                        throw new IllegalArgumentException(
382:                                "Content for URI was not found:" + uri);
383:                    uriStack.add(uri);
384:                    int index = uri.lastIndexOf('/');
385:                    if (index == -1)
386:                        index = 0;
387:                    properties.put("xod.file", uri.substring(index));
388:                    properties.put("xod.path", index == 0 ? "" : uri.substring(
389:                            0, index));
390:
391:                    Document doc = builder.parse(is);
392:                    is.close();
393:                    ret = processBranch(parent, doc.getChildNodes(), level);
394:                } catch (Exception e) {
395:                    throw new RuntimeException("processing file '" + uri + "'",
396:                            e);
397:                } finally {
398:                    uriStack.remove(uriStack.size() - 1);
399:
400:                    if (uriStack.size() > 0) {
401:                        uri = uriStack.get(uriStack.size() - 1);
402:                        int index = uri.lastIndexOf('/');
403:                        if (index == -1)
404:                            index = 0;
405:                        properties.put("xod.file", uri.substring(index));
406:                        properties.put("xod.path", index == 0 ? "" : uri
407:                                .substring(0, index));
408:                    }
409:                }
410:
411:                return ret;
412:            }
413:
414:            private void appendAttributes(Node n) {
415:                NamedNodeMap nnm = n.getAttributes();
416:                Document doc = n.getOwnerDocument();
417:
418:                for (int i = 0, cnt = nnm.getLength(); i < cnt; i++) {
419:                    Node attribute = nnm.item(i);
420:                    Node tag = doc.createElement(attribute.getNodeName());
421:                    tag.appendChild(doc
422:                            .createTextNode(attribute.getNodeValue()));
423:                    n.appendChild(tag);
424:                }
425:            }
426:
427:            private Object processBranch(Object parent, NodeList nl, int level) {
428:                for (int i = 0, cnt = nl.getLength(); i < cnt; i++) {
429:                    Node n = nl.item(i);
430:
431:                    switch (n.getNodeType()) {
432:                    case Node.COMMENT_NODE:
433:                        //Valid, but just ignored
434:                        break;
435:
436:                    case Node.TEXT_NODE:
437:                        if (n.getNodeValue().trim().length() != 0)
438:                            throw new DOMException(
439:                                    DOMException.NO_DATA_ALLOWED_ERR,
440:                                    "a value for the <" + n.getNodeName()
441:                                            + "> tag is not allowed");
442:                        break;
443:
444:                    case Node.ELEMENT_NODE:
445:                        evaluateNode(parent, n, level);
446:                        break;
447:
448:                    default:
449:                        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
450:                                "node type " + n.getNodeType()
451:                                        + " is not supported");
452:                    }
453:                }
454:
455:                return null;
456:            }
457:
458:            private Object evaluateNode(Object parent, Node n, int level) {
459:                Object ret = null;
460:                String name = n.getNodeName();
461:
462:                if (name.equals("xod")) {
463:                    if (n.getChildNodes().getLength() == 0)
464:                        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
465:                                name + ":n.getChildNodes().getLength() == 0");
466:                    if (level != 0 && !processingInclude)
467:                        throw new DOMException(DOMException.INVALID_STATE_ERR,
468:                                "level != 0");
469:                    if (log.isLoggable(LEVEL))
470:                        log.log(LEVEL, "xod");
471:                    processBranch(parent, n.getChildNodes(), level + 1);
472:                } else if (name.equals("property") && parent == null) {
473:                    if (n.getAttributes().getLength() != 2)
474:                        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
475:                                name + ":n.getAttributes().getLength() != 2");
476:                    String key = (String) n.getAttributes()
477:                            .getNamedItem("name").getNodeValue();
478:                    String value = (String) n.getAttributes().getNamedItem(
479:                            "value").getNodeValue();
480:                    value = this .replaceProperties(value);
481:                    properties.put(key, value);
482:                    if (log.isLoggable(LEVEL))
483:                        log.log(LEVEL, "property[name:" + key + ",value:"
484:                                + value + "]");
485:                } else if (name.equals("alias")) {
486:                    if (n.getAttributes().getLength() != 2)
487:                        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
488:                                name + ":n.getAttributes().getLength() != 2");
489:                    //if (n.getChildNodes().getLength() != 0) throw new DOMException(DOMException.NOT_SUPPORTED_ERR, name + ":n.getChildNodes().getLength() != 0");
490:                    String aliasName = (String) n.getAttributes().getNamedItem(
491:                            "name").getNodeValue();
492:                    String className = this .replaceProperties((String) n
493:                            .getAttributes().getNamedItem("class")
494:                            .getNodeValue());
495:                    Class clazz = getClassForName(aliasName, className);
496:                    if (n.hasChildNodes())
497:                        processBranch(clazz, n.getChildNodes(), level + 1);
498:                    if (log.isLoggable(LEVEL))
499:                        log.log(LEVEL, "alias[name:" + aliasName + ",class:"
500:                                + className + "]");
501:                } else if (name.equals("property") && parent instanceof  Class) {
502:                    if (n.getAttributes().getLength() != 2
503:                            && n.getAttributes().getLength() != 3)
504:                        throw new DOMException(
505:                                DOMException.NOT_SUPPORTED_ERR,
506:                                name
507:                                        + ":n.getAttributes().getLength() != 2 && n.getAttributes().getLength() != 3");
508:                    String propName = this .replaceProperties((String) n
509:                            .getAttributes().getNamedItem("name")
510:                            .getNodeValue());
511:                    String aliasName = this .replaceProperties((String) n
512:                            .getAttributes().getNamedItem("alias")
513:                            .getNodeValue());
514:                    String className = this .replaceProperties((String) n
515:                            .getAttributes().getNamedItem("class")
516:                            .getNodeValue());
517:                    setPropertyAlias((Class) parent, propName, aliasName,
518:                            getClassForName(null, className));
519:                } else if (name.equals("include")) {
520:                    if (n.getAttributes().getLength() != 1)
521:                        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
522:                                name + ":n.getAttributes().getLength() != 1");
523:                    if (n.getChildNodes().getLength() != 0)
524:                        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
525:                                name + ":n.getChildNodes().getLength() != 0");
526:                    String fileUri = this .replaceProperties((String) n
527:                            .getAttributes().getNamedItem("file")
528:                            .getNodeValue());
529:
530:                    if (!getRelativeFile(fileUri).exists()) {
531:                        String curFileUri = uriStack.get(0);
532:                        String newUri = fileUri;
533:
534:                        do {
535:                            File parentFolder = getRelativeFile(curFileUri)
536:                                    .getParentFile();
537:
538:                            if (parentFolder == null) {
539:                                newUri = null;
540:                                break;
541:                            }
542:
543:                            curFileUri = parentFolder.getAbsolutePath();
544:                            newUri = getRelativeFile(curFileUri, fileUri)
545:                                    .getAbsolutePath();
546:                        } while (!getRelativeFile(newUri).exists());
547:
548:                        if (newUri != null)
549:                            fileUri = newUri;
550:                    }
551:
552:                    processingInclude = true;
553:                    processFile(parent, fileUri, level + 1);
554:                    processingInclude = false;
555:                    if (log.isLoggable(LEVEL))
556:                        log.log(LEVEL, "include[file:" + fileUri + "]");
557:                } else if (name.equals("ref")) {
558:                    if (n.getAttributes().getLength() != 1)
559:                        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
560:                                name + ":n.getAttributes().getLength() != 1");
561:                    if (n.getChildNodes().getLength() != 0)
562:                        throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
563:                                name + ":n.getChildNodes().getLength() != 0");
564:                    String id = (String) n.getAttributes().getNamedItem("id")
565:                            .getNodeValue();
566:                    ret = objectMap.get(id);
567:                    if (log.isLoggable(LEVEL))
568:                        log.log(LEVEL, "ref[id:" + id + "]");
569:
570:                    if (parent != null && parent instanceof  Collection) {
571:                        if (log.isLoggable(LEVEL))
572:                            log.log(LEVEL, "adding ref child to collection");
573:                        ((Collection) parent).add(ret);
574:                    }
575:                } else {
576:                    boolean property = false;
577:
578:                    //If there is a parent and the tag name does not contain a period and the first character is lowerCase, then this might be a property
579:                    if (parent != null && name.indexOf('.') == -1
580:                            && Character.isLowerCase(name.charAt(0))) {
581:                        //if (n.getAttributes().getLength() != 0) throw new DOMException(DOMException.NOT_SUPPORTED_ERR, name + ":n.getAttributes().getLength() != 0");
582:
583:                        //Check to see if this property has an Alias.
584:                        Object[] propertyAlias = getPropertyAlias(parent
585:                                .getClass(), name);
586:                        if (propertyAlias != null)
587:                            name = (String) propertyAlias[0];
588:
589:                        //Search for a set method for the property
590:                        String setter = Character.toUpperCase(name.charAt(0))
591:                                + name.substring(1);
592:                        String getter = "get" + setter;
593:                        String istter = "is" + setter;
594:                        setter = "set" + setter;
595:
596:                        Method setMethod = null;
597:                        Method getMethod = null;
598:
599:                        for (Method m : parent.getClass().getMethods()) {
600:                            if (setMethod != null && getMethod != null)
601:                                break;
602:                            String methodName = m.getName();
603:
604:                            if (methodName.equals(setter)) {
605:                                setMethod = m;
606:                            } else if (methodName.equals(getter)
607:                                    || methodName.equals(istter)) {
608:                                getMethod = m;
609:                            }
610:                        }
611:
612:                        if (getMethod != null) {
613:                            if (setMethod == null) {
614:                                Object subObject = invoke(parent, getMethod,
615:                                        (Object[]) null);
616:                                appendAttributes(n);
617:                                processBranch(subObject, n.getChildNodes(),
618:                                        level + 1);
619:                                property = true;
620:                            } else {
621:                                Class[] params = setMethod.getParameterTypes();
622:
623:                                if (params.length == 1) {
624:                                    NodeList propNodes = n.getChildNodes();
625:                                    Node node = null;
626:
627:                                    if (propNodes.getLength() == 1)
628:                                        node = propNodes.item(0);
629:                                    else {
630:                                        for (int i = propNodes.getLength() - 1; i >= 0; i--) {
631:                                            Node item = propNodes.item(i);
632:
633:                                            if (item.getNodeType() == Node.ELEMENT_NODE) {
634:                                                node = item;
635:                                                break;
636:                                            }
637:                                        }
638:                                    }
639:
640:                                    if (node != null) {
641:                                        short nodeType = node.getNodeType();
642:                                        Class paramClass = propertyAlias != null ? (Class) propertyAlias[1]
643:                                                : params[0];
644:                                        Object value;
645:
646:                                        //If there is only one property then this is a simple value assignment
647:                                        //Else if there is three then there is a tag being set as the value
648:                                        if (nodeType == Node.TEXT_NODE) {
649:                                            value = getObjectForTypeFromString(
650:                                                    paramClass, (String) node
651:                                                            .getNodeValue(),
652:                                                    true);
653:                                        } else if (nodeType == Node.ELEMENT_NODE) {
654:                                            value = evaluateNode(null, node,
655:                                                    level + 1);
656:                                            Class valueClass = value.getClass();
657:
658:                                            if (!paramClass
659:                                                    .isAssignableFrom(valueClass)) {
660:                                                value = getObjectForTypeFromString(
661:                                                        paramClass, value
662:                                                                .toString(),
663:                                                        false);
664:                                                if (value == null)
665:                                                    throw new DOMException(
666:                                                            DOMException.NOT_SUPPORTED_ERR,
667:                                                            "no conversion from "
668:                                                                    + valueClass
669:                                                                    + " to "
670:                                                                    + paramClass
671:                                                                    + " is known");
672:                                            }
673:                                        } else {
674:                                            throw new DOMException(
675:                                                    DOMException.NOT_SUPPORTED_ERR,
676:                                                    "a property tag can only contain a value or a single tag");
677:                                        }
678:
679:                                        if (value == null)
680:                                            throw new DOMException(
681:                                                    DOMException.NOT_SUPPORTED_ERR,
682:                                                    "the property tag's value resolved to null which is not valid");
683:
684:                                        invoke(parent, setMethod, value);
685:                                        if (log.isLoggable(LEVEL))
686:                                            log.log(LEVEL, "set property "
687:                                                    + name + " = " + value);
688:                                    }
689:
690:                                    property = true;
691:                                }
692:                            }
693:                        }
694:                    }
695:
696:                    //If this was determined to not be a property, this must be a class instantiation
697:                    if (!property) {
698:                        Class c = aliases.get(name);
699:                        if (c == null)
700:                            c = getClassForName(name, name);
701:
702:                        NodeList children = n.getChildNodes();
703:
704:                        try {
705:                            String id = null;
706:                            NamedNodeMap attrs = n.getAttributes();
707:                            List<Object[]> nonStatic = null;
708:
709:                            for (int cnt = attrs.getLength(); --cnt >= 0;) {
710:                                Node attr = attrs.item(cnt);
711:                                String attrName = attr.getNodeName();
712:                                String attrValue = attr.getNodeValue();
713:
714:                                if (attrName.equals("id")) {
715:                                    id = attrValue;
716:                                } else {
717:                                    String setter = "set"
718:                                            + Character.toUpperCase(attrName
719:                                                    .charAt(0))
720:                                            + attrName.substring(1);
721:                                    boolean found = false;
722:
723:                                    for (Method m : c.getMethods()) {
724:                                        String methodName = m.getName();
725:
726:                                        if (methodName.equals(attrName)
727:                                                || methodName.equals(setter)) {
728:                                            Class[] args = m
729:                                                    .getParameterTypes();
730:
731:                                            if (args.length == 1) {
732:                                                found = true;
733:                                                Object arg = getObjectForTypeFromString(
734:                                                        args[0], attrValue,
735:                                                        true);
736:
737:                                                if (Modifier.isStatic(m
738:                                                        .getModifiers())) {
739:                                                    ret = invoke(null, m, arg);
740:
741:                                                    if (!c.isInstance(ret)) {
742:                                                        if (log
743:                                                                .isLoggable(LEVEL))
744:                                                            log
745:                                                                    .log(
746:                                                                            LEVEL,
747:                                                                            "invoked static id="
748:                                                                                    + id
749:                                                                                    + ":"
750:                                                                                    + c
751:                                                                                            .getName()
752:                                                                                    + "."
753:                                                                                    + methodName
754:                                                                                    + "('"
755:                                                                                    + attrValue
756:                                                                                    + "')");
757:                                                        ret = null;
758:                                                    } else {
759:                                                        if (log
760:                                                                .isLoggable(LEVEL))
761:                                                            log
762:                                                                    .log(
763:                                                                            LEVEL,
764:                                                                            "static factory new id="
765:                                                                                    + id
766:                                                                                    + ":"
767:                                                                                    + c
768:                                                                                            .getName()
769:                                                                                    + "."
770:                                                                                    + methodName
771:                                                                                    + "('"
772:                                                                                    + attrValue
773:                                                                                    + "')");
774:                                                    }
775:                                                } else {
776:                                                    if (nonStatic == null)
777:                                                        nonStatic = new ArrayList<Object[]>(
778:                                                                3);
779:
780:                                                    if (methodName
781:                                                            .equals(attrName)) {
782:                                                        nonStatic
783:                                                                .add(
784:                                                                        0,
785:                                                                        new Object[] {
786:                                                                                m,
787:                                                                                arg });
788:                                                    } else {
789:                                                        nonStatic
790:                                                                .add(new Object[] {
791:                                                                        m, arg });
792:                                                    }
793:                                                }
794:                                            }
795:                                        }
796:                                    }
797:
798:                                    if (!found)
799:                                        throw new DOMException(
800:                                                DOMException.NOT_FOUND_ERR,
801:                                                "no target method found id="
802:                                                        + id + ":"
803:                                                        + c.getName() + "."
804:                                                        + attrName + "('"
805:                                                        + attrValue + "')");
806:                                }
807:                            }
808:
809:                            if (ret == null) {
810:                                ret = c.newInstance();
811:                                if (log.isLoggable(LEVEL))
812:                                    log.log(LEVEL, "new " + c.getName());
813:                            }
814:
815:                            if (nonStatic != null) {
816:                                for (Object[] callMeth : nonStatic) {
817:                                    invoke(ret, (Method) callMeth[0],
818:                                            callMeth[1]);
819:                                    if (log.isLoggable(LEVEL))
820:                                        log.log(LEVEL, "invoked id="
821:                                                + id
822:                                                + ":"
823:                                                + c.getName()
824:                                                + "."
825:                                                + ((Method) callMeth[0])
826:                                                        .getName() + "("
827:                                                + callMeth[1] + ")");
828:                                }
829:                            }
830:
831:                            if (id != null)
832:                                objectMap.put(id, ret);
833:                            objects.add(ret);
834:                            if (level == 1)
835:                                rootObjects.add(ret);
836:
837:                            if (parent != null && parent instanceof  Collection) {
838:                                if (log.isLoggable(LEVEL))
839:                                    log
840:                                            .log(LEVEL,
841:                                                    "adding child to collection");
842:                                ((Collection) parent).add(ret);
843:                            }
844:
845:                            processBranch(ret, children, level + 1);
846:                        } catch (IllegalAccessException e) {
847:                            throw new RuntimeException(e);
848:                        } catch (InstantiationException e) {
849:                            throw new RuntimeException(e);
850:                        }
851:                    }
852:                }
853:
854:                return ret;
855:            }
856:
857:            private static final Pattern REGEX_PROPERTY = Pattern.compile(
858:                    "(.*?)[$][{]([\\w.]+)[}](.*?)", Pattern.DOTALL);
859:
860:            private String replaceProperties(String value) {
861:                if (log.isLoggable(LEVEL))
862:                    log.log(LEVEL, "before replaceProperties:" + value);
863:                if (value != null && value.indexOf("${") >= 0) {
864:                    StringBuffer sb = new StringBuffer();
865:                    Matcher m = REGEX_PROPERTY.matcher(value);
866:
867:                    while (m.find()) {
868:                        String prop = m.group(2);
869:                        String val = properties.get(prop);
870:                        if (val == null)
871:                            val = "${" + prop + "}";
872:                        m.appendReplacement(sb, m.group(1) + val + m.group(3));
873:                    }
874:
875:                    m.appendTail(sb);
876:                    value = sb.toString();
877:                }
878:
879:                if (log.isLoggable(LEVEL))
880:                    log.log(LEVEL, "after replaceProperties:" + value);
881:                return value;
882:            }
883:
884:            private Object getObjectForTypeFromString(Class type, String str,
885:                    boolean performObjectFieldLookup) {
886:                Object value;
887:                str = replaceProperties(str);
888:
889:                if (type == String.class) {
890:                    value = str;
891:                } else if (type == boolean.class || type == Boolean.class) {
892:                    value = Boolean.valueOf(str);
893:                } else if (type == int.class || type == Integer.class) {
894:                    value = new Integer(Double.valueOf(str).intValue());
895:                } else if (type == long.class || type == Long.class) {
896:                    value = new Long(Double.valueOf(str).longValue());
897:                } else if (type == short.class || type == Short.class) {
898:                    value = new Short(Double.valueOf(str).shortValue());
899:                } else if (type == byte.class || type == Byte.class) {
900:                    value = new Byte(Double.valueOf(str).byteValue());
901:                } else if (type == float.class || type == Float.class) {
902:                    value = new Float(Double.valueOf(str).floatValue());
903:                } else if (type == double.class || type == Double.class) {
904:                    value = Double.valueOf(str);
905:                } else if (type == char.class || type == Character.class) {
906:                    value = new Character(str.charAt(0));
907:                } else if (performObjectFieldLookup) {
908:                    //See if there is a constant with the name specified
909:                    try {
910:                        Method method = type.getMethod("valueOf", String.class);
911:                        value = method.invoke(null, str);
912:                    } catch (Exception e) {
913:                        String upperStr = str.toUpperCase();
914:                        value = null;
915:
916:                        for (Field f : type.getFields()) {
917:                            if (f.getName().toUpperCase().equals(upperStr)) {
918:                                try {
919:                                    value = f.get(null);
920:                                } catch (IllegalAccessException e2) {
921:                                    value = null;
922:                                }
923:
924:                                break;
925:                            }
926:                        }
927:
928:                        if (value == null)
929:                            value = objectMap.get(str);
930:                    }
931:                } else
932:                    value = null;
933:
934:                return value == null ? str : value;
935:            }
936:
937:            private Object invoke(Object object, Method method,
938:                    Object... params) {
939:                try {
940:                    if (!method.isAccessible())
941:                        method.setAccessible(true);
942:                    return method.invoke(object, params);
943:                } catch (InvocationTargetException e) {
944:                    throw new RuntimeException("["
945:                            + object.getClass().getName() + "."
946:                            + method.getName() + "]", e);
947:                } catch (IllegalAccessException e) {
948:                    throw new RuntimeException("["
949:                            + object.getClass().getName() + "."
950:                            + method.getName() + "]", e);
951:                }
952:            }
953:
954:            private void setPropertyAlias(Class clazz, String propertyName,
955:                    String aliasName, Class aliasClass) {
956:                if (propertyAliases == null)
957:                    propertyAliases = new HashMap<Class, Map<String, Object[]>>(
958:                            3);
959:                Map<String, Object[]> map = propertyAliases.get(clazz);
960:                if (map == null)
961:                    propertyAliases.put(clazz,
962:                            map = new HashMap<String, Object[]>(1));
963:                map.put(aliasName, new Object[] { propertyName, aliasClass });
964:            }
965:
966:            private Object[] getPropertyAlias(Class clazz, String propertyName) {
967:                if (propertyAliases != null) {
968:                    Map<String, Object[]> map = propertyAliases.get(clazz);
969:                    if (map != null)
970:                        return map.get(propertyName);
971:                }
972:
973:                return null;
974:            }
975:
976:            private Class getClassForName(String name, String className) {
977:                try {
978:                    Class c = Class.forName(className);
979:                    if (name != null)
980:                        aliases.put(name, c);
981:                    return c;
982:                } catch (ClassNotFoundException e) {
983:                    throw new RuntimeException(e);
984:                }
985:            }
986:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.