Source Code Cross Referenced for Introspector.java in  » UML » AndroMDA-3.2 » org » andromda » core » common » 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 » UML » AndroMDA 3.2 » org.andromda.core.common 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package org.andromda.core.common;
002:
003:        import java.beans.PropertyDescriptor;
004:        import java.lang.reflect.Method;
005:        import java.util.Collection;
006:        import java.util.HashMap;
007:        import java.util.Map;
008:
009:        import org.apache.commons.lang.StringUtils;
010:        import org.apache.commons.lang.exception.ExceptionUtils;
011:
012:        /**
013:         * A simple class providing the ability to manipulate properties on java bean objects.
014:         *
015:         * @author Chad Brandon
016:         */
017:        public final class Introspector {
018:            /**
019:             * The shared instance.
020:             */
021:            private static Introspector instance = null;
022:
023:            /**
024:             * Gets the shared instance.
025:             *
026:             * @return the shared introspector instance.
027:             */
028:            public static Introspector instance() {
029:                if (instance == null) {
030:                    instance = new Introspector();
031:                }
032:                return instance;
033:            }
034:
035:            /**
036:             * <p> Indicates whether or not the given <code>object</code> contains a
037:             * valid property with the given <code>name</code> and <code>value</code>.
038:             * </p>
039:             * <p>
040:             * A valid property means the following:
041:             * <ul>
042:             * <li>It exists on the object</li>
043:             * <li>It is not null on the object</li>
044:             * <li>If its a boolean value, then it evaluates to <code>true</code></li>
045:             * <li>If value is not null, then the property matches the given </code>.value</code></li>
046:             * </ul>
047:             * All other possibilities return <code>false</code>
048:             * </p>
049:             *
050:             * @param object the object to test for the valid property.
051:             * @param name the name of the propery for which to test.
052:             * @param value the value to evaluate against.
053:             * @return true/false
054:             */
055:            public boolean containsValidProperty(final Object object,
056:                    final String name, final String value) {
057:                boolean valid;
058:
059:                try {
060:                    final Object propertyValue = this .getProperty(object, name);
061:                    valid = propertyValue != null;
062:
063:                    // if valid is still true, and the propertyValue
064:                    // is not null
065:                    if (valid) {
066:                        // if it's a collection then we check to see if the
067:                        // collection is not empty
068:                        if (propertyValue instanceof  Collection) {
069:                            valid = !((Collection) propertyValue).isEmpty();
070:                        } else {
071:                            final String valueAsString = String
072:                                    .valueOf(propertyValue);
073:                            if (StringUtils.isNotEmpty(value)) {
074:                                valid = valueAsString.equals(value);
075:                            } else if (propertyValue instanceof  Boolean) {
076:                                valid = Boolean.valueOf(valueAsString)
077:                                        .booleanValue();
078:                            }
079:                        }
080:                    }
081:                } catch (final Throwable throwable) {
082:                    valid = false;
083:                }
084:                return valid;
085:            }
086:
087:            /**
088:             * Sets the property having the given <code>name</code> on the <code>object</code>
089:             * with the given <code>value</code>.
090:             *
091:             * @param object the object on which to set the property.
092:             * @param name the name of the property to populate.
093:             * @param value the value to give the property.
094:             */
095:            public void setProperty(final Object object, final String name,
096:                    final Object value) {
097:                this .setNestedProperty(object, name, value);
098:            }
099:
100:            /**
101:             * The delimiter used for seperating nested properties.
102:             */
103:            private static final char NESTED_DELIMITER = '.';
104:
105:            /**
106:             * Attempts to set the nested property with the given
107:             * name of the given object.
108:             * @param object the object on which to populate the property.
109:             * @param name the name of the object.
110:             * @param value the value to populate.
111:             */
112:            private void setNestedProperty(final Object object, String name,
113:                    final Object value) {
114:                if (object != null && name != null && name.length() > 0) {
115:                    final int dotIndex = name.indexOf(NESTED_DELIMITER);
116:                    if (dotIndex >= name.length()) {
117:                        throw new IntrospectorException(
118:                                "Invalid property call --> '" + name + "'");
119:                    }
120:                    String[] names = name.split("\\" + NESTED_DELIMITER);
121:                    Object objectToPopulate = object;
122:                    for (int ctr = 0; ctr < names.length; ctr++) {
123:                        name = names[ctr];
124:                        if (ctr == names.length - 1) {
125:                            break;
126:                        }
127:                        objectToPopulate = this .internalGetProperty(
128:                                objectToPopulate, name);
129:                    }
130:                    this .internalSetProperty(objectToPopulate, name, value);
131:                }
132:            }
133:
134:            /**
135:             * Attempts to retrieve the property with the given <code>name</code> on the <code>object</code>.
136:             *
137:             * @param object the object to which the property belongs.
138:             * @param name the name of the property
139:             * @return the value of the property.
140:             */
141:            public final Object getProperty(final Object object,
142:                    final String name) {
143:                Object result;
144:
145:                try {
146:                    result = this .getNestedProperty(object, name);
147:                } catch (final IntrospectorException throwable) {
148:                    // Dont catch our own exceptions.
149:                    // Otherwise get Exception/Cause chain which
150:                    // can hide the original exception.
151:                    throw throwable;
152:                } catch (Throwable throwable) {
153:                    throwable = ExceptionUtils.getRootCause(throwable);
154:
155:                    // If cause is an IntrospectorException re-throw that exception
156:                    // rather than creating a new one.
157:                    if (throwable instanceof  IntrospectorException) {
158:                        throw (IntrospectorException) throwable;
159:                    }
160:                    throw new IntrospectorException(throwable);
161:                }
162:                return result;
163:            }
164:
165:            /**
166:             * Gets a nested property, that is it gets the properties
167:             * seperated by '.'.
168:             *
169:             * @param object the object from which to retrieve the nested property.
170:             * @param name the name of the property
171:             * @return the property value or null if one couldn't be retrieved.
172:             */
173:            private Object getNestedProperty(final Object object,
174:                    final String name) {
175:                Object property = null;
176:                if (object != null && name != null && name.length() > 0) {
177:                    int dotIndex = name.indexOf(NESTED_DELIMITER);
178:                    if (dotIndex == -1) {
179:                        property = this .internalGetProperty(object, name);
180:                    } else {
181:                        if (dotIndex >= name.length()) {
182:                            throw new IntrospectorException(
183:                                    "Invalid property call --> '" + name + "'");
184:                        }
185:                        final Object nextInstance = this .internalGetProperty(
186:                                object, name.substring(0, dotIndex));
187:                        property = getNestedProperty(nextInstance, name
188:                                .substring(dotIndex + 1));
189:                    }
190:                }
191:                return property;
192:            }
193:
194:            /**
195:             * Cache for a class's write methods.
196:             */
197:            private final Map writeMethodsCache = new HashMap();
198:
199:            /**
200:             * Gets the writable method for the property.
201:             *
202:             * @param object the object from which to retrieve the property method.
203:             * @param name the name of the property.
204:             * @return the property method or null if one wasn't found.
205:             */
206:            private Method getWriteMethod(final Object object, final String name) {
207:                Method writeMethod = null;
208:                final Class objectClass = object.getClass();
209:                Map classWriteMethods = (Map) this .writeMethodsCache
210:                        .get(objectClass);
211:                if (classWriteMethods == null) {
212:                    classWriteMethods = new HashMap();
213:                } else {
214:                    writeMethod = (Method) classWriteMethods.get(name);
215:                }
216:                if (writeMethod == null) {
217:                    final PropertyDescriptor descriptor = this 
218:                            .getPropertyDescriptor(object.getClass(), name);
219:                    writeMethod = descriptor != null ? descriptor
220:                            .getWriteMethod() : null;
221:                    if (writeMethod != null) {
222:                        classWriteMethods.put(name, writeMethod);
223:                        this .writeMethodsCache.put(objectClass,
224:                                classWriteMethods);
225:                    }
226:                }
227:                return writeMethod;
228:            }
229:
230:            /**
231:             * Indicates if the <code>object</code> has a property that
232:             * is <em>readable</em> with the given <code>name</code>.
233:             *
234:             * @param object the object to check.
235:             * @param name the property to check for.
236:             */
237:            public boolean isReadable(final Object object, final String name) {
238:                return this .getReadMethod(object, name) != null;
239:            }
240:
241:            /**
242:             * Indicates if the <code>object</code> has a property that
243:             * is <em>writable</em> with the given <code>name</code>.
244:             *
245:             * @param object the object to check.
246:             * @param name the property to check for.
247:             */
248:            public boolean isWritable(final Object object, final String name) {
249:                return this .getWriteMethod(object, name) != null;
250:            }
251:
252:            /**
253:             * Cache for a class's read methods.
254:             */
255:            private final Map readMethodsCache = new HashMap();
256:
257:            /**
258:             * Gets the readable method for the property.
259:             *
260:             * @param object the object from which to retrieve the property method.
261:             * @param name the name of the property.
262:             * @return the property method or null if one wasn't found.
263:             */
264:            private Method getReadMethod(final Object object, final String name) {
265:                Method readMethod = null;
266:                final Class objectClass = object.getClass();
267:                Map classReadMethods = (Map) this .readMethodsCache
268:                        .get(objectClass);
269:                if (classReadMethods == null) {
270:                    classReadMethods = new HashMap();
271:                } else {
272:                    readMethod = (Method) classReadMethods.get(name);
273:                }
274:                if (readMethod == null) {
275:                    final PropertyDescriptor descriptor = this 
276:                            .getPropertyDescriptor(object.getClass(), name);
277:                    readMethod = descriptor != null ? descriptor
278:                            .getReadMethod() : null;
279:                    if (readMethod != null) {
280:                        classReadMethods.put(name, readMethod);
281:                        this .readMethodsCache
282:                                .put(objectClass, classReadMethods);
283:                    }
284:                }
285:                return readMethod;
286:            }
287:
288:            /**
289:             * The cache of property descriptors.
290:             */
291:            private final Map propertyDescriptorsCache = new HashMap();
292:
293:            /**
294:             * Retrives the property descriptor for the given type and name of
295:             * the property.
296:             *
297:             * @param type the Class of which we'll attempt to retrieve the property
298:             * @param name the name of the property.
299:             * @return the found property descriptor
300:             */
301:            private PropertyDescriptor getPropertyDescriptor(final Class type,
302:                    final String name) {
303:                PropertyDescriptor propertyDescriptor = null;
304:                Map classPropertyDescriptors = (Map) this .propertyDescriptorsCache
305:                        .get(type);
306:                if (classPropertyDescriptors == null) {
307:                    classPropertyDescriptors = new HashMap();
308:                } else {
309:                    propertyDescriptor = (PropertyDescriptor) classPropertyDescriptors
310:                            .get(name);
311:                }
312:
313:                if (propertyDescriptor == null) {
314:                    try {
315:                        final PropertyDescriptor[] descriptors = java.beans.Introspector
316:                                .getBeanInfo(type).getPropertyDescriptors();
317:                        final int descriptorNumber = descriptors.length;
318:                        for (int ctr = 0; ctr < descriptorNumber; ctr++) {
319:                            final PropertyDescriptor descriptor = descriptors[ctr];
320:
321:                            // - handle names that start with a lowercased letter and have an uppercase as the second letter
322:                            final String compareName = name
323:                                    .matches("\\p{Lower}\\p{Upper}.*") ? StringUtils
324:                                    .capitalize(name)
325:                                    : name;
326:                            if (descriptor.getName().equals(compareName)) {
327:                                propertyDescriptor = descriptor;
328:                                break;
329:                            }
330:                        }
331:                        if (propertyDescriptor == null
332:                                && name.indexOf(NESTED_DELIMITER) != -1) {
333:                            int dotIndex = name.indexOf(NESTED_DELIMITER);
334:                            if (dotIndex >= name.length()) {
335:                                throw new IntrospectorException(
336:                                        "Invalid property call --> '" + name
337:                                                + "'");
338:                            }
339:                            final PropertyDescriptor nextInstance = this 
340:                                    .getPropertyDescriptor(type, name
341:                                            .substring(0, dotIndex));
342:                            propertyDescriptor = this .getPropertyDescriptor(
343:                                    nextInstance.getPropertyType(), name
344:                                            .substring(dotIndex + 1));
345:                        }
346:                    } catch (final java.beans.IntrospectionException exception) {
347:                        throw new IntrospectorException(exception);
348:                    }
349:                    classPropertyDescriptors.put(name, propertyDescriptor);
350:                    this .propertyDescriptorsCache.put(type,
351:                            classPropertyDescriptors);
352:                }
353:                return propertyDescriptor;
354:            }
355:
356:            /**
357:             * Prevents stack-over-flows by storing the objects that
358:             * are currently being evaluted within {@link #internalGetProperty(Object, String)}.
359:             */
360:            private final Map evaluatingObjects = new HashMap();
361:
362:            /**
363:             * Attempts to get the value of the property with <code>name</code> on the
364:             * given <code>object</code> (throws an exception if the property
365:             * is not readable on the object).
366:             *
367:             * @param object the object from which to retrieve the property.
368:             * @param name the name of the property
369:             * @return the resulting property value
370:             */
371:            private Object internalGetProperty(final Object object,
372:                    final String name) {
373:                Object property = null;
374:
375:                // - prevent stack-over-flows by checking to make sure
376:                //   we aren't entering any circular evalutions
377:                final Object value = this .evaluatingObjects.get(object);
378:                if (value == null || !value.equals(name)) {
379:                    this .evaluatingObjects.put(object, name);
380:                    if (object != null || name != null || name.length() > 0) {
381:                        final Method method = this .getReadMethod(object, name);
382:                        if (method == null) {
383:                            throw new IntrospectorException(
384:                                    "No readable property named '" + name
385:                                            + "', exists on object '" + object
386:                                            + "'");
387:                        }
388:                        try {
389:                            property = method.invoke(object, (Object[]) null);
390:                        } catch (final Throwable throwable) {
391:                            throw new IntrospectorException(throwable);
392:                        }
393:                    }
394:                    this .evaluatingObjects.remove(object);
395:                }
396:                return property;
397:            }
398:
399:            /**
400:             * Attempts to sets the value of the property with <code>name</code> on the
401:             * given <code>object</code> (throws an exception if the property
402:             * is not writable on the object).
403:             *
404:             * @param object the object from which to retrieve the property.
405:             * @param name the name of the property to set.
406:             * @param value the value of the property to set.
407:             */
408:            private void internalSetProperty(final Object object,
409:                    final String name, Object value) {
410:                if (object != null || name != null || name.length() > 0) {
411:                    Class expectedType = null;
412:                    if (value != null) {
413:                        final PropertyDescriptor descriptor = this 
414:                                .getPropertyDescriptor(object.getClass(), name);
415:                        if (descriptor != null) {
416:                            expectedType = this .getPropertyDescriptor(
417:                                    object.getClass(), name).getPropertyType();
418:                            value = Converter.convert(value, expectedType);
419:                        }
420:                    }
421:                    final Method method = this .getWriteMethod(object, name);
422:                    if (method == null) {
423:                        throw new IntrospectorException(
424:                                "No writeable property named '" + name
425:                                        + "', exists on object '" + object
426:                                        + "'");
427:                    }
428:                    try {
429:                        method.invoke(object, new Object[] { value });
430:                    } catch (final Throwable throwable) {
431:                        throw new IntrospectorException(throwable);
432:                    }
433:                }
434:            }
435:
436:            /**
437:             * Shuts this instance down and reclaims
438:             * any resouces used by this instance.
439:             */
440:            public void shutdown() {
441:                this.propertyDescriptorsCache.clear();
442:                this.writeMethodsCache.clear();
443:                this.readMethodsCache.clear();
444:                this.evaluatingObjects.clear();
445:                instance = null;
446:            }
447:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.