Source Code Cross Referenced for _ComponentAttributesMap.java in  » J2EE » myfaces-core-1.2.0 » javax » faces » component » 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 » J2EE » myfaces core 1.2.0 » javax.faces.component 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2004 The Apache Software Foundation.
003:         *
004:         * Licensed under the Apache License, Version 2.0 (the "License");
005:         * you may not use this file except in compliance with the License.
006:         * You may obtain a copy of the License at
007:         *
008:         *      http://www.apache.org/licenses/LICENSE-2.0
009:         *
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS,
012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         * See the License for the specific language governing permissions and
014:         * limitations under the License.
015:         */
016:        package javax.faces.component;
017:
018:        import java.beans.BeanInfo;
019:        import java.beans.IntrospectionException;
020:        import java.beans.Introspector;
021:        import java.beans.PropertyDescriptor;
022:        import java.io.Serializable;
023:        import java.lang.reflect.Method;
024:        import java.util.Collection;
025:        import java.util.HashMap;
026:        import java.util.Iterator;
027:        import java.util.Map;
028:        import java.util.Set;
029:
030:        import javax.el.ValueExpression;
031:        import javax.faces.FacesException;
032:        import javax.faces.context.FacesContext;
033:
034:        /**
035:         * A custom implementation of the Map interface, where get and put calls
036:         * try to access getter/setter methods of an associated UIComponent before
037:         * falling back to accessing a real Map object.
038:         * <p>
039:         * Some of the behaviours of this class don't really comply with the
040:         * definitions of the Map class; for example the key parameter to all
041:         * methods is required to be of type String only, and after clear(),
042:         * calls to get can return non-null values. However the JSF spec
043:         * requires that this class behave in the way implemented below. See
044:         * UIComponent.getAttributes for more details.
045:         * <p>
046:         * The term "property" is used here to refer to real javabean properties
047:         * on the underlying UIComponent, while "attribute" refers to an entry
048:         * in the associated Map.
049:         *
050:         * @author Manfred Geiler (latest modification by $Author: mbr $)
051:         * @version $Revision: 518783 $ $Date: 2007-03-15 23:23:53 +0100 (Do, 15 Mrz 2007) $
052:         */
053:        class _ComponentAttributesMap implements  Map, Serializable {
054:            private static final long serialVersionUID = -9106832179394257866L;
055:
056:            private static final Object[] EMPTY_ARGS = new Object[0];
057:
058:            // The component that is read/written via this map.
059:            private UIComponent _component;
060:
061:            // We delegate instead of derive from HashMap, so that we can later
062:            // optimize Serialization
063:            private Map<Object, Object> _attributes = null;
064:
065:            // A cached hashmap of propertyName => PropertyDescriptor object for all
066:            // the javabean properties of the associated component. This is built by
067:            // introspection on the associated UIComponent. Don't serialize this as
068:            // it can always be recreated when needed.
069:            private transient Map<String, PropertyDescriptor> _propertyDescriptorMap = null;
070:
071:            /**
072:             * Create a map backed by the specified component.
073:             * <p>
074:             * This method is expected to be called when a component is first created.
075:             */
076:            _ComponentAttributesMap(UIComponent component) {
077:                _component = component;
078:                _attributes = new HashMap<Object, Object>();
079:            }
080:
081:            /**
082:             * Create a map backed by the specified component. Attributes already
083:             * associated with the component are provided in the specified Map
084:             * class. A reference to the provided map is kept; this object's contents
085:             * are updated during put calls on this instance.
086:             * <p>
087:             * This method is expected to be called during the "restore view" phase. 
088:             */
089:            _ComponentAttributesMap(UIComponent component,
090:                    Map<Object, Object> attributes) {
091:                _component = component;
092:                _attributes = attributes;
093:            }
094:
095:            /**
096:             * Return the number of <i>attributes</i> in this map. Properties of the
097:             * underlying UIComponent are not counted.
098:             * <p>
099:             * Note that because the get method can read properties of the
100:             * UIComponent and evaluate value-bindings, it is possible to have
101:             * size return zero while calls to the get method return non-null
102:             * values.
103:             */
104:            public int size() {
105:                return _attributes.size();
106:            }
107:
108:            /**
109:             * Clear all the <i>attributes</i> in this map. Properties of the
110:             * underlying UIComponent are not modified.
111:             * <p>
112:             * Note that because the get method can read properties of the
113:             * UIComponent and evaluate value-bindings, it is possible to have
114:             * calls to the get method return non-null values immediately after
115:             * a call to clear.
116:             */
117:            public void clear() {
118:                _attributes.clear();
119:            }
120:
121:            /**
122:             * Return true if there are no <i>attributes</i> in this map. Properties
123:             * of the underlying UIComponent are not counted.
124:             * <p>
125:             * Note that because the get method can read properties of the
126:             * UIComponent and evaluate value-bindings, it is possible to have
127:             * isEmpty return true, while calls to the get method return non-null
128:             * values.
129:             */
130:            public boolean isEmpty() {
131:                return _attributes.isEmpty();
132:            }
133:
134:            /**
135:             * Return true if there is an <i>attribute</i> with the specified name,
136:             * but false if there is a javabean <i>property</i> of that name on the
137:             * associated UIComponent.
138:             * <p>
139:             * Note that it should be impossible for the attributes map to contain
140:             * an entry with the same name as a javabean property on the associated
141:             * UIComponent.
142:             * 
143:             * @param key <i>must</i> be a String. Anything else will cause a
144:             * ClassCastException to be thrown.
145:             */
146:            public boolean containsKey(Object key) {
147:                checkKey(key);
148:
149:                return getPropertyDescriptor((String) key) == null ? _attributes
150:                        .containsKey(key)
151:                        : false;
152:            }
153:
154:            /**
155:             * Returns true if there is an <i>attribute</i> with the specified
156:             * value. Properties of the underlying UIComponent aren't examined,
157:             * nor value-bindings.
158:             * 
159:             * @param value null is allowed
160:             */
161:            public boolean containsValue(Object value) {
162:                return _attributes.containsValue(value);
163:            }
164:
165:            /**
166:             * Return a collection of the values of all <i>attributes</i>. Property
167:             * values are not included, nor value-bindings.
168:             */
169:            public Collection<Object> values() {
170:                return _attributes.values();
171:            }
172:
173:            /**
174:             * Call put(key, value) for each entry in the provided map.
175:             */
176:            public void putAll(Map t) {
177:                for (Iterator it = t.entrySet().iterator(); it.hasNext();) {
178:                    Map.Entry entry = (Entry) it.next();
179:                    put(entry.getKey(), entry.getValue());
180:                }
181:            }
182:
183:            /**
184:             * Return a set of all <i>attributes</i>. Properties of the underlying
185:             * UIComponent are not included, nor value-bindings.
186:             */
187:            public Set entrySet() {
188:                return _attributes.entrySet();
189:            }
190:
191:            /**
192:             * Return a set of the keys for all <i>attributes</i>. Properties of the
193:             * underlying UIComponent are not included, nor value-bindings.
194:             */
195:            public Set<Object> keySet() {
196:                return _attributes.keySet();
197:            }
198:
199:            /**
200:             * In order: get the value of a <i>property</i> of the underlying
201:             * UIComponent, read an <i>attribute</i> from this map, or evaluate
202:             * the component's value-binding of the specified name.
203:             * 
204:             * @param key must be a String. Any other type will cause ClassCastException.
205:             */
206:            public Object get(Object key) {
207:                checkKey(key);
208:
209:                // is there a javabean property to read?
210:                PropertyDescriptor propertyDescriptor = getPropertyDescriptor((String) key);
211:                if (propertyDescriptor != null) {
212:                    return getComponentProperty(propertyDescriptor);
213:                }
214:
215:                // is there a literal value to read?
216:                Object mapValue = _attributes.get(key);
217:                if (mapValue != null) {
218:                    return mapValue;
219:                }
220:
221:                // is there a value-binding to read?
222:                ValueExpression ve = _component
223:                        .getValueExpression((String) key);
224:                if (ve != null) {
225:                    return ve.getValue(FacesContext.getCurrentInstance()
226:                            .getELContext());
227:                }
228:
229:                // no value found
230:                return null;
231:            }
232:
233:            /**
234:             * Remove the attribute with the specified name. An attempt to
235:             * remove an entry whose name is that of a <i>property</i> on
236:             * the underlying UIComponent will cause an IllegalArgumentException.
237:             * Value-bindings for the underlying component are ignored. 
238:             * 
239:             * @param key must be a String. Any other type will cause ClassCastException.
240:             */
241:            public Object remove(Object key) {
242:                checkKey(key);
243:                PropertyDescriptor propertyDescriptor = getPropertyDescriptor((String) key);
244:                if (propertyDescriptor != null) {
245:                    throw new IllegalArgumentException(
246:                            "Cannot remove component property attribute");
247:                }
248:                return _attributes.remove(key);
249:            }
250:
251:            /**
252:             * Store the provided value as a <i>property</i> on the underlying
253:             * UIComponent, or as an <i>attribute</i> in a Map if no such property
254:             * exists. Value-bindings associated with the component are ignored; to
255:             * write to a value-binding, the value-binding must be explicitly
256:             * retrieved from the component and evaluated.
257:             * <p>
258:             * Note that this method is different from the get method, which
259:             * does read from a value-binding if one exists. When a value-binding
260:             * exists for a non-property, putting a value here essentially "masks"
261:             * the value-binding until that attribute is removed.
262:             * <p>
263:             * The put method is expected to return the previous value of the
264:             * property/attribute (if any). Because UIComponent property getter
265:             * methods typically try to evaluate any value-binding expression of
266:             * the same name this can cause an EL expression to be evaluated,
267:             * thus invoking a getter method on the user's model. This is fine
268:             * when the returned value will be used; Unfortunately this is quite
269:             * pointless when initialising a freshly created component with whatever
270:             * attributes were specified in the view definition (eg JSP tag
271:             * attributes). Because the UIComponent.getAttributes method
272:             * only returns a Map class and this class must be package-private,
273:             * there is no way of exposing a "putNoReturn" type method.
274:             *  
275:             * @param key String, null is not allowed
276:             * @param value null is allowed
277:             */
278:            public Object put(Object key, Object value) {
279:                checkKeyAndValue(key, value);
280:
281:                PropertyDescriptor propertyDescriptor = getPropertyDescriptor((String) key);
282:                if (propertyDescriptor != null) {
283:                    if (propertyDescriptor.getReadMethod() != null) {
284:                        Object oldValue = getComponentProperty(propertyDescriptor);
285:                        setComponentProperty(propertyDescriptor, value);
286:                        return oldValue;
287:                    }
288:                    setComponentProperty(propertyDescriptor, value);
289:                    return null;
290:                }
291:                return _attributes.put(key, value);
292:            }
293:
294:            /**
295:             * Retrieve info about getter/setter methods for the javabean property
296:             * of the specified name on the underlying UIComponent object.
297:             * <p>
298:             * This method optimises access to javabean properties of the underlying
299:             * UIComponent by maintaining a cache of ProperyDescriptor objects for
300:             * that class.
301:             * <p>
302:             * TODO: Consider making the cache shared between component instances;
303:             * currently 100 UIInputText components means performing introspection
304:             * on the UIInputText component 100 times.
305:             */
306:            private PropertyDescriptor getPropertyDescriptor(String key) {
307:                if (_propertyDescriptorMap == null) {
308:                    BeanInfo beanInfo;
309:                    try {
310:                        beanInfo = Introspector.getBeanInfo(_component
311:                                .getClass());
312:                    } catch (IntrospectionException e) {
313:                        throw new FacesException(e);
314:                    }
315:                    PropertyDescriptor[] propertyDescriptors = beanInfo
316:                            .getPropertyDescriptors();
317:                    _propertyDescriptorMap = new HashMap<String, PropertyDescriptor>();
318:                    for (int i = 0; i < propertyDescriptors.length; i++) {
319:                        PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
320:                        if (propertyDescriptor.getReadMethod() != null) {
321:                            _propertyDescriptorMap.put(propertyDescriptor
322:                                    .getName(), propertyDescriptor);
323:                        }
324:                    }
325:                }
326:                return _propertyDescriptorMap.get(key);
327:            }
328:
329:            /**
330:             * Execute the getter method of the specified property on the underlying
331:             * component.
332:             * 
333:             * @param propertyDescriptor specifies which property to read.
334:             * @return the value returned by the getter method.
335:             * @throws IllegalArgumentException if the property is not readable.
336:             * @throws FacesException if any other problem occurs while invoking
337:             *  the getter method. 
338:             */
339:            private Object getComponentProperty(
340:                    PropertyDescriptor propertyDescriptor) {
341:                Method readMethod = propertyDescriptor.getReadMethod();
342:                if (readMethod == null) {
343:                    throw new IllegalArgumentException("Component property "
344:                            + propertyDescriptor.getName() + " is not readable");
345:                }
346:                try {
347:                    return readMethod.invoke(_component, EMPTY_ARGS);
348:                } catch (Exception e) {
349:                    FacesContext facesContext = FacesContext
350:                            .getCurrentInstance();
351:                    throw new FacesException("Could not get property "
352:                            + propertyDescriptor.getName() + " of component "
353:                            + _component.getClientId(facesContext), e);
354:                }
355:            }
356:
357:            /**
358:             * Execute the setter method of the specified property on the underlying
359:             * component.
360:             * 
361:             * @param propertyDescriptor specifies which property to write.
362:             * @throws IllegalArgumentException if the property is not writable.
363:             * @throws FacesException if any other problem occurs while invoking
364:             *  the getter method. 
365:             */
366:            private void setComponentProperty(
367:                    PropertyDescriptor propertyDescriptor, Object value) {
368:                Method writeMethod = propertyDescriptor.getWriteMethod();
369:                if (writeMethod == null) {
370:                    throw new IllegalArgumentException("Component property "
371:                            + propertyDescriptor.getName() + " is not writable");
372:                }
373:                try {
374:                    writeMethod.invoke(_component, new Object[] { value });
375:                } catch (Exception e) {
376:                    FacesContext facesContext = FacesContext
377:                            .getCurrentInstance();
378:                    throw new FacesException("Could not set property "
379:                            + propertyDescriptor.getName()
380:                            + " of component "
381:                            + _component.getClientId(facesContext)
382:                            + " to value : "
383:                            + value
384:                            + " with type : "
385:                            + (value == null ? "null" : value.getClass()
386:                                    .getName()), e);
387:                }
388:            }
389:
390:            private void checkKeyAndValue(Object key, Object value) {
391:                //http://issues.apache.org/jira/browse/MYFACES-458: obviously, the spec is a little unclear here,
392:                // but value == null should be allowed - if there is a TCK-test failing due to this, we should
393:                // apply for getting the TCK-test dropped
394:                if (value == null)
395:                    throw new NullPointerException("value");
396:                checkKey(key);
397:            }
398:
399:            private void checkKey(Object key) {
400:                if (key == null)
401:                    throw new NullPointerException("key");
402:                if (!(key instanceof  String))
403:                    throw new ClassCastException("key is not a String");
404:            }
405:
406:            /**
407:             * Return the map containing the attributes.
408:             * <p>
409:             * This method is package-scope so that the UIComponentBase class can access it
410:             * directly when serializing the component.
411:             */
412:            Map<Object, Object> getUnderlyingMap() {
413:                return _attributes;
414:            }
415:
416:            /**
417:             * TODO: Document why this method is necessary, and why it doesn't try to
418:             * compare the _component field.
419:             */
420:            public boolean equals(Object obj) {
421:                return _attributes.equals(obj);
422:            }
423:
424:            public int hashCode() {
425:                return _attributes.hashCode();
426:            }
427:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.