Source Code Cross Referenced for AnnotateDataBinder.java in  » Ajax » zk » org » zkoss » zkplus » databind » 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 » Ajax » zk » org.zkoss.zkplus.databind 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /* AnnotateDataBinder.java
002:
003:        {{IS_NOTE
004:        	Purpose:
005:        		
006:        	Description:
007:        		
008:        	History:
009:        		Thu Nov 16 13:22:37     2006, Created by Henri Chen
010:        }}IS_NOTE
011:
012:        Copyright (C) 2006 Potix Corporation. All Rights Reserved.
013:
014:        {{IS_RIGHT
015:        }}IS_RIGHT
016:         */
017:        package org.zkoss.zkplus.databind;
018:
019:        import org.zkoss.zk.ui.Path;
020:        import org.zkoss.zk.ui.Page;
021:        import org.zkoss.zk.ui.Desktop;
022:        import org.zkoss.zk.ui.Component;
023:        import org.zkoss.zk.ui.UiException;
024:        import org.zkoss.zk.ui.sys.ComponentCtrl;
025:        import org.zkoss.zk.ui.metainfo.Annotation;
026:
027:        import java.util.Map;
028:        import java.util.List;
029:        import java.util.ArrayList;
030:        import java.util.Map.Entry;
031:        import java.util.Iterator;
032:
033:        /**
034:         * <p>The DataBinder that reads ZUML annotations to create binding info. The ZUML page must declare the 
035:         * XML namespace, xmlns:a="http://www.zkoss.org/2005/zk/annotation", to use the ZUML annotations. 
036:         * The annotation is declared before each Component or specified directly on the Component attributes. 
037:         * For example, the following annotation associates the 
038:         * attibute "value" of the component "textbox" to the bean's value "person.address.city".</p>
039:         * <pre>
040:         * &lt;a:bind value="person.address.city"/>
041:         * &lt;textbox/>
042:         * </pre>
043:         * <p>Or since ZK 2.4 you can annotate directly on the attribute "value" of the component "textbox" like this.</p>
044:         * <pre>
045:         * &lt;textbox value="@{person.address.city}"/>
046:         * </pre>
047:         * <p>The @{...} pattern tells the ZUML parser that this is for annotation.</p>
048:         *
049:         * <p>The AnnotateDataBinder knows "a:bind" annotation only. The complete format is like this if you declared it 
050:         * before the Component.
051:         * <pre>
052:         * &lt;a:bind attrY="bean's value;[tag:expression]..."/>
053:         * &lt;componentX/>
054:         * </pre>
055:         *
056:         * <p>You can also specify directly on the Component attribute, the complete format is like this:
057:         * <pre>
058:         * &lt;componentX attrY="@{bean's value,[tag='expression']...}"/>
059:         * </pre>
060:         *
061:         * <p>This associates the componentX's attribute attrY to the bean's value. The bean's value is something
062:         * in the form of beanid.field1.field2... You can either call {@link DataBinder#bindBean} to bind the beanid to a
063:         * real bean object or you can neglect it and this DataBinder would try to find it from the variables map via
064:         * ({@link org.zkoss.zk.ui.Component#getVariable} method. That is, all those variables defined in zscript are 
065:         * accessible by this DataBinder. Note that you can choose either two formats of annotaion as your will and you 
066:         * can even hybrid them together though it is generaly not a good practice.</p>
067:         *
068:         * <p>The tag:expression or tag='expression' is a generic form to bind more metainfo to the attrY of the componentX. 
069:         * The currently supported tag includes "load-when", "save-when", "access", and "converter"</p>
070:         *
071:         * <ul>
072:         * <li>load-when. You can specify the events concerned when to load the attribute of the component from the bean.
073:         * Multiple definition is allowed and would be called one by one.
074:         * For example, the following code snip tells DataBinder that the attribute "value" of Label "fullName" will load 
075:         * from "person.fullName" when the Textbox "firstName" or "lastName" fire "onChange" event.
076:         *
077:         * <p>Declare in front of the Component:</p>
078:         * <pre>
079:         * &lt;a:bind value="person.firstName"/>
080:         * &lt;textbox id="firstname"/>
081:         *
082:         * &lt;a:bind value="person.lastName"/>
083:         * &lt;textbox id="lastname"/>
084:         *
085:         * &lt;a:bind value="person.fullName; load-when:firstname.onChange; load-when:lastname.onChange"/>
086:         * &lt;label id="fullname"/>
087:         * </pre>
088:         * <p>Or specify directly on the Component's attribute:</p>
089:         * <pre>
090:         * &lt;textbox id="firstname" value="@{person.firstName}"/>
091:         * &lt;textbox id="lastname" value="@{person.lastName}"/>
092:         * &lt;label id="fullname" value="@{person.fullName, load-when='firstname.onChange,lastname.onChange'}"/>
093:         * </pre>
094:         * </li>
095:         *
096:         * <li>save-when. You can specify the events concerned when to save the attribute of the component into the bean.
097:         * Since ZK version 3.0.0, you can specify multiple events in save-when tag (i.e. before ZK 3.0.0, you can specify only
098:         * one event). The events specified, if fired, will trigger
099:         * this DataBinder to save the attribute of the component into bean. For example, the following code snip tells 
100:         * DataBinder that the attribute "value" of Textbox "firstName" will 
101:         * save into "person.firstName" when the Textbox itself fire "onChange" event.
102:         *
103:         * <p>Declare in front of the Component:</p>
104:         * <pre>
105:         * &lt;a:bind value="person.firstName; save-when:self.onChange"/>
106:         * &lt;textbox id="firstName"/>
107:         * </pre>
108:         *
109:         * <p>Or specify directly on the Component's attribute:</p>
110:         * <pre>
111:         * &lt;textbox id="firstName" value="@{person.firstName, save-when='self.onChange'}"/>
112:         * </pre>
113:         *
114:         * <p>However, you don't generally specify the save-when tag. If you don't specify it, the default events are used
115:         * depends on the natural charactieric of the component's attribute as defined in lang-addon.xml. For example, 
116:         * the save-when of Label.value is default to none while that of Textbox.value is default to self.onChange. 
117:         * That is, the following example is the same as the above one.</p>
118:         * <p>Declare in front of the Component:</p>
119:         * <pre>
120:         * &lt;a:bind value="person.firstName"/>
121:         * &lt;textbox id="firstName"/>
122:         * </pre>
123:         * <p>Or specifies directly on the Component's attribute:</p>
124:         * <pre>
125:         * &lt;textbox id="firstName" value="@{person.firstName}"/>
126:         * </pre>
127:         *
128:         * <p>On the other hand, you might not specify the save-when tag nor you want the default events to be used. Then you
129:         * can specify a "none" keyword or simply leave empty to indicate such cases.</p>
130:         * <pre>
131:         * &lt;a:bind value="person.firstName; save-when:none;"/>
132:         * &lt;textbox id="firstName"/>
133:         * </pre>
134:         * or
135:         * <pre>
136:         * &lt;a:bind value="person.firstName; save-when: ;"/>
137:         * &lt;textbox id="firstName"/>
138:         * </pre>
139:         * or
140:         * <pre>
141:         * &lt;textbox id="firstName" value="@{person.firstName, save-when='none'}"/>
142:         * </pre>
143:         * or
144:         * <pre>
145:         * &lt;textbox id="firstName" value="@{person.firstName, save-when=''}"/>
146:         * </pre>
147:         * </li>
148:         *
149:         * <p>Since 3.0.0, DataBinder supports validation phase before saving attribute content into bean property when 
150:         * triggered by the specified event in save-when tag. It will fire onBindingSave event to the data-binding component and
151:         * then fire onBindingValidate to the triggering component before really saving component attribute contents into bean's 
152:         * property. So application developers get the chance to handle the value validatiion before saving. In the following example
153:         * when end user click the "savebtn" button, an "onBindingSave" is first fired to "firtName" and "lastName" textboxes and 
154:         * then an "onBindingValidate" is fired to "savebtn" button. Application developers can register proper event handlers to do 
155:         * what they want to do.</p>
156:         * <pre>
157:         * &lt;textbox id="firstName" value="@{person.firstName, save-when="savebtn.onClick"}" onBindingSave="..."/>
158:         * &lt;textbox id="lastName" value="@{person.lastName, save-when="savebtn.onClick"}" onBindingSave="..."/>
159:         * &lt;button id="savebtn" label="save" onBindingValidate="..."/>
160:         * </pre>
161:         * 
162:         * <p>Note that the original textbox constraint mechanism is still there. This DataBinder validation phase is an 
163:         * add-on feature that can be applied to all components and attributes that use data binding mechanism.</p>
164:         *
165:         * <li>access. You can set the access mode of the attrY of the componentX to be "both"(load/save),  
166:         * "load"(load Only), "save"(save Only), or "none"(neither).  Multiple definition is NOT allowed 
167:         * and the later defined would 
168:         * override the previous defined one. The access mode would affects the behavior of the DataBinder's loadXxx
169:         * and saveXxx methods.
170:         * The {@link DataBinder#loadAll} and {@link DataBinder#loadComponent} would load only those attributes
171:         * with "both" or "load" access mode. The {@link DataBinder#saveAll} and 
172:         * {@link DataBinder#saveComponent} would save only those attributes with "both" or "save" access mode. If you
173:         * don't specify it, the default access mode depends on the natural characteristic of the component's attribute
174:         * as defined in lang-addon.xml. For example, Label.value is default to "load" access mode while Textbox.value 
175:         * is default to "both" access mode. For example, the following code snips tells DataBinder that Textbox "firstName" 
176:         * would allowing doing save into bean only not the other way.
177:         *
178:         * <p>Declare in front of the Component:</p>
179:         * <pre>
180:         * &lt;a:bind value="person.firstName;access:save;"/>
181:         * &lt;textbox id="firstName"/>
182:         * </pre>
183:         *
184:         * <p>Or specify directly on the Component's attribute:</p>
185:         * <pre>
186:         * &lt;textbox id="firstName" value="@{person.firstName, access='save'}"/>
187:         * </pre>
188:         * </li>
189:         *
190:         * <li>converter. You can specify the class name of the converter that implments the {@link TypeConverter} interface.
191:         * It is used to convert the value between component attribute and bean field.  Multiple definition is NOT allowed 
192:         * and the later defined would override the previous defined one.
193:         * Most of the time you don't have to specify this since this DataBinder supports converting most commonly 
194:         * used types. However, if you specify the TypeConverter class name, this DataBinder will new an instance and use 
195:         * it to cast the class.
196:         * </li>
197:         * </ul>
198:         * 
199:         * @since 2.4.0 Supporting @{...} annotations.
200:         * @since 3.0.0 Supporting multiple events of save-when tag and validation phase.
201:         * @author Henri Chen
202:         * @see AnnotateDataBinderInit
203:         * @see DataBinder
204:         */
205:        public class AnnotateDataBinder extends DataBinder {
206:            /**
207:             * Constructor that read all binding annotations of the components inside the specified desktop.
208:             * @param desktop the ZUML desktop.
209:             */
210:            public AnnotateDataBinder(Desktop desktop) {
211:                this (desktop, true);
212:            }
213:
214:            /**
215:             * Constructor that read all binding annotations of the components inside the specified page.
216:             * @param page the ZUML page.
217:             */
218:            public AnnotateDataBinder(Page page) {
219:                this (page, true);
220:            }
221:
222:            /**
223:             * Constructor that read all binding annotations in the components inside the specified component (inclusive).
224:             * @param comp the ZUML component.
225:             */
226:            public AnnotateDataBinder(Component comp) {
227:                this (comp, true);
228:            }
229:
230:            /**
231:             * Constructor that read all binding annotations of the given components array.
232:             * @param comps the Component array.
233:             * @since 3.0.0
234:             */
235:            public AnnotateDataBinder(Component[] comps) {
236:                this (comps, true);
237:            }
238:
239:            /**
240:             * Constructor that read all binding annotations of the components inside the specified desktop.
241:             * @param desktop the ZUML desktop.
242:             * @param defaultConfig whether load default binding configuration defined in lang-addon.xml
243:             */
244:            public AnnotateDataBinder(Desktop desktop, boolean defaultConfig) {
245:                setDefaultConfig(defaultConfig);
246:                for (final Iterator it = desktop.getComponents().iterator(); it
247:                        .hasNext();) {
248:                    loadAnnotations((Component) it.next());
249:                }
250:            }
251:
252:            /**
253:             * Constructor that read all binding annotations of the components inside the specified page.
254:             * @param page the ZUML page.
255:             * @param defaultConfig whether load default binding configuration defined in lang-addon.xml
256:             */
257:            public AnnotateDataBinder(Page page, boolean defaultConfig) {
258:                setDefaultConfig(defaultConfig);
259:                for (final Iterator it = page.getRoots().iterator(); it
260:                        .hasNext();) {
261:                    loadAnnotations((Component) it.next());
262:                }
263:            }
264:
265:            /**
266:             * Constructor that read all binding annotations of the given component array.
267:             * @param comps the Component array
268:             * @param defaultConfig whether load default binding configuration defined in lang-addon.xml
269:             * @since 3.0.0
270:             */
271:            public AnnotateDataBinder(Component[] comps, boolean defaultConfig) {
272:                setDefaultConfig(defaultConfig);
273:                for (int j = 0; j < comps.length; ++j) {
274:                    loadAnnotations(comps[j]);
275:                }
276:            }
277:
278:            /**
279:             * Constructor that read all binding annotations in the components inside the specified component (inclusive).
280:             * @param comp the ZUML component.
281:             * @param defaultConfig whether load default binding configuration defined in lang-addon.xml
282:             */
283:            public AnnotateDataBinder(Component comp, boolean defaultConfig) {
284:                setDefaultConfig(defaultConfig);
285:                loadAnnotations(comp);
286:            }
287:
288:            private void loadAnnotations(Component comp) {
289:                loadComponentAnnotation(comp);
290:                loadComponentPropertyAnnotation(comp);
291:
292:                final List children = comp.getChildren();
293:                for (final Iterator it = children.iterator(); it.hasNext();) {
294:                    loadAnnotations((Component) it.next()); //recursive back
295:                }
296:            }
297:
298:            private void loadComponentPropertyAnnotation(Component comp) {
299:                loadComponentPropertyAnnotationByAnnotName(comp, "default");
300:                loadComponentPropertyAnnotationByAnnotName(comp, "bind");
301:            }
302:
303:            private void loadComponentPropertyAnnotationByAnnotName(
304:                    Component comp, String annotName) {
305:                ComponentCtrl compCtrl = (ComponentCtrl) comp;
306:                final List props = compCtrl.getAnnotatedPropertiesBy(annotName);
307:                for (final Iterator it = props.iterator(); it.hasNext();) {
308:                    final String propName = (String) it.next();
309:                    //[0] value, [1] loadWhenEvents, [2] saveWhenEvents, [3] access, [4] converter
310:                    final Object[] objs = loadPropertyAnnotation(comp,
311:                            propName, annotName);
312:                    addBinding(comp, propName, (String) objs[0],
313:                            (List) objs[1], (List) objs[2], (String) objs[3],
314:                            (String) objs[4]);
315:                }
316:            }
317:
318:            private void loadComponentAnnotation(Component comp) {
319:                loadComponentAnnotation(comp, "default");
320:                loadComponentAnnotation(comp, "bind");
321:            }
322:
323:            private void loadComponentAnnotation(Component comp,
324:                    String annotName) {
325:                ComponentCtrl compCtrl = (ComponentCtrl) comp;
326:                Annotation ann = compCtrl.getAnnotation(annotName);
327:                if (ann != null) {
328:                    Map attrs = ann.getAttributes();
329:                    for (final Iterator it = attrs.entrySet().iterator(); it
330:                            .hasNext();) {
331:                        Entry me = (Entry) it.next();
332:                        String attr = (String) me.getKey();
333:                        //[0] bean value, [1 ~ *] tag:expression
334:                        List expr = parseExpression((String) me.getValue(), ";");
335:                        if (expr == null || expr.get(0) == null) {
336:                            throw new UiException(
337:                                    "Cannot find any bean value in the annotation <a:bind "
338:                                            + attr + "=\"\"/> for component "
339:                                            + comp + ", id=" + comp.getId());
340:                        } else {
341:                            List tags = parseExpression((String) expr.get(0),
342:                                    ":");
343:                            if (tags.size() > 1) {
344:                                throw new UiException(
345:                                        "bean value must be defined as the first statement in the annotation <a:bind "
346:                                                + attr
347:                                                + "=\"\"/> for component "
348:                                                + comp + ", id=" + comp.getId());
349:                            }
350:                        }
351:
352:                        List loadWhenEvents = null;
353:                        List saveWhenEvents = null;
354:                        String access = null;
355:                        String converter = null;
356:
357:                        //process tags
358:                        for (int j = 1; j < expr.size(); ++j) {
359:                            List tags = parseExpression((String) expr.get(j),
360:                                    ":");
361:                            if (tags == null) {
362:                                continue; //skip
363:                            }
364:                            if ("load-when".equals(tags.get(0))) {
365:                                if (tags.size() > 1 && tags.get(1) != null) {
366:                                    loadWhenEvents = parseExpression(
367:                                            (String) tags.get(1), ",");
368:                                } else {
369:                                    loadWhenEvents.add(NULLIFY);
370:                                }
371:                            } else if ("save-when".equals(tags.get(0))) {
372:                                if (tags.size() > 1 && tags.get(1) != null) {
373:                                    saveWhenEvents = parseExpression(
374:                                            (String) tags.get(1), ",");
375:                                } else {
376:                                    saveWhenEvents.add(NULLIFY);
377:                                }
378:                            } else if ("access".equals(tags.get(0))) {
379:                                access = tags.size() > 1 ? (String) tags.get(1)
380:                                        : NULLIFY;
381:                            } else if ("converter".equals(tags.get(0))) {
382:                                converter = tags.size() > 1 ? (String) tags
383:                                        .get(1) : NULLIFY;
384:                            }
385:                        }
386:
387:                        if (loadWhenEvents != null && loadWhenEvents.isEmpty()) {
388:                            loadWhenEvents = null;
389:                        }
390:                        if (saveWhenEvents != null && saveWhenEvents.isEmpty()) {
391:                            saveWhenEvents = null;
392:                        }
393:
394:                        addBinding(comp, attr, (String) expr.get(0),
395:                                loadWhenEvents, saveWhenEvents, access,
396:                                converter);
397:                    }
398:                }
399:            }
400:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.