Source Code Cross Referenced for TypeCoercerImpl.java in  » Web-Framework » Tapestry » org » apache » tapestry » ioc » internal » services » 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 » Tapestry » org.apache.tapestry.ioc.internal.services 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // Copyright 2006, 2007 The Apache Software Foundation
002:        //
003:        // Licensed under the Apache License, Version 2.0 (the "License");
004:        // you may not use this file except in compliance with the License.
005:        // You may obtain a copy of the License at
006:        //
007:        //     http://www.apache.org/licenses/LICENSE-2.0
008:        //
009:        // Unless required by applicable law or agreed to in writing, software
010:        // distributed under the License is distributed on an "AS IS" BASIS,
011:        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012:        // See the License for the specific language governing permissions and
013:        // limitations under the License.
014:
015:        package org.apache.tapestry.ioc.internal.services;
016:
017:        import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newLinkedList;
018:        import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
019:        import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
020:        import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
021:        import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newConcurrentMap;
022:        import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
023:
024:        import java.util.Collection;
025:        import java.util.LinkedList;
026:        import java.util.List;
027:        import java.util.Map;
028:        import java.util.Set;
029:
030:        import org.apache.tapestry.ioc.internal.util.InheritanceSearch;
031:        import org.apache.tapestry.ioc.internal.util.InternalUtils;
032:        import org.apache.tapestry.ioc.services.ClassFabUtils;
033:        import org.apache.tapestry.ioc.services.Coercion;
034:        import org.apache.tapestry.ioc.services.CoercionTuple;
035:        import org.apache.tapestry.ioc.services.TypeCoercer;
036:
037:        public class TypeCoercerImpl implements  TypeCoercer {
038:            // Read only after constructor
039:
040:            private final Map<Class, List<CoercionTuple>> _sourceTypeToTuple = newMap();
041:
042:            // Access to the cache must be thread safe
043:
044:            private final Map<CacheKey, Coercion> _cache = newConcurrentMap();
045:
046:            static class CacheKey {
047:                private final Class _sourceClass;
048:
049:                private final Class _targetClass;
050:
051:                CacheKey(final Class sourceClass, final Class targetClass) {
052:                    _sourceClass = sourceClass;
053:                    _targetClass = targetClass;
054:                }
055:
056:                @Override
057:                public boolean equals(Object obj) {
058:                    if (obj == null)
059:                        return false;
060:
061:                    if (!(obj instanceof  CacheKey))
062:                        return false;
063:
064:                    CacheKey other = (CacheKey) obj;
065:
066:                    return _sourceClass.equals(other._sourceClass)
067:                            && _targetClass.equals(other._targetClass);
068:                }
069:
070:                @Override
071:                public int hashCode() {
072:                    return _sourceClass.hashCode() * 27
073:                            % _targetClass.hashCode();
074:                }
075:
076:                @Override
077:                public String toString() {
078:                    return String.format("CacheKey[%s --> %s]", _sourceClass
079:                            .getName(), _targetClass.getName());
080:                }
081:            }
082:
083:            private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>() {
084:                public Object coerce(Void input) {
085:                    return null;
086:                }
087:
088:                @Override
089:                public String toString() {
090:                    return "null --> null";
091:                }
092:            };
093:
094:            public TypeCoercerImpl(Collection<CoercionTuple> tuples) {
095:                for (CoercionTuple tuple : tuples) {
096:                    Class key = tuple.getSourceType();
097:
098:                    addTuple(key, tuple);
099:                }
100:            }
101:
102:            @SuppressWarnings({"unchecked","unchecked"})
103:            private void addTuple(Class key, CoercionTuple tuple) {
104:                List<CoercionTuple> list = _sourceTypeToTuple.get(key);
105:
106:                if (list == null) {
107:                    list = newList();
108:                    _sourceTypeToTuple.put(key, list);
109:                }
110:
111:                list.add(tuple);
112:            }
113:
114:            @SuppressWarnings("unchecked")
115:            public Object coerce(Object input, Class targetType) {
116:                notNull(targetType, "targetType");
117:
118:                // Treat null as void in terms of locating a coercion.
119:
120:                Class sourceType = input != null ? input.getClass()
121:                        : void.class;
122:
123:                // The caller may ask for the value in a primitive type, but the best we can do is the
124:                // equivalent wrapper type.
125:
126:                Class effectiveTargetType = ClassFabUtils
127:                        .getWrapperType(targetType);
128:
129:                // Is a coercion even necessary? Not if the target type is assignable from the
130:                // input value.
131:
132:                if (effectiveTargetType.isAssignableFrom(sourceType))
133:                    return input;
134:
135:                Coercion coercion = findCoercion(sourceType,
136:                        effectiveTargetType);
137:
138:                Object result;
139:
140:                try {
141:                    result = coercion.coerce(input);
142:                } catch (Exception ex) {
143:                    throw new RuntimeException(ServiceMessages.failedCoercion(
144:                            input, targetType, coercion, ex), ex);
145:                }
146:
147:                // Double check that the coercer provided a result of the correct type
148:
149:                return effectiveTargetType.cast(result);
150:            }
151:
152:            @SuppressWarnings("unchecked")
153:            public <S, T> String explain(Class<S> inputType, Class<T> targetType) {
154:                notNull(inputType, "inputType");
155:                notNull(targetType, "targetType");
156:
157:                Class effectiveTargetType = ClassFabUtils
158:                        .getWrapperType(targetType);
159:
160:                // Is a coercion even necessary? Not if the target type is assignable from the
161:                // input value.
162:
163:                if (effectiveTargetType.isAssignableFrom(inputType))
164:                    return "";
165:
166:                Coercion coercion = findCoercion(inputType, effectiveTargetType);
167:
168:                return coercion.toString();
169:            }
170:
171:            private Coercion findCoercion(Class sourceType, Class targetType) {
172:                CacheKey key = new CacheKey(sourceType, targetType);
173:
174:                Coercion result = _cache.get(key);
175:
176:                if (result == null) {
177:                    result = findOrCreateCoercion(sourceType, targetType);
178:                    _cache.put(key, result);
179:                }
180:
181:                return result;
182:            }
183:
184:            public void clearCache() {
185:                _cache.clear();
186:            }
187:
188:            /**
189:             * Here's the real meat; we do a search of the space to find coercions, or a system of
190:             * coercions, that accomplish the desired coercion.
191:             * <p>
192:             * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance
193:             * lists could be cached. Further, there's probably more ways to early prune the search.
194:             * However, even with dozens or perhaps hundreds of tuples, I suspect the search will still
195:             * grind to a conclusion quickly.
196:             * <p>
197:             * The order of operations should help ensure that the most efficient tuple chain is located. If
198:             * you think about how tuples are added to the queue, there are two factors: size (the number of
199:             * steps in the coercion) and "class distance" (that is, number of steps up the inheritance
200:             * hiearchy). All the appropriate 1 step coercions will be considered first, in class distance
201:             * order. Along the way, we'll queue up all the 2 step coercions, again in class distance order.
202:             * By the time we reach some of those, we'll have begun queing up the 3 step coercions, and so
203:             * forth, until we run out of input tuples we can use to fabricate multi-step compound
204:             * coercions, or reach a final response.
205:             * <p>
206:             * This does create a good number of short lived temporary objects (the compound tuples), but
207:             * that's what the GC is really good at.
208:             * 
209:             * @param sourceType
210:             * @param targetType
211:             * @return coercer from sourceType to targetType
212:             */
213:            @SuppressWarnings("unchecked")
214:            private Coercion findOrCreateCoercion(Class sourceType,
215:                    Class targetType) {
216:                // These are instance variables because this method may be called concurrently.
217:                // On a true race, we may go to the work of seeking out and/or fabricating
218:                // a tuple twice, but it's more likely that different threads are looking
219:                // for different source/target coercions.
220:
221:                Set<CoercionTuple> consideredTuples = newSet();
222:                LinkedList<CoercionTuple> queue = newLinkedList();
223:
224:                seedQueue(sourceType, consideredTuples, queue);
225:
226:                while (!queue.isEmpty()) {
227:                    CoercionTuple tuple = queue.removeFirst();
228:
229:                    // If the tuple results in a value type that is assignable to the desired target type,
230:                    // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
231:                    // "quality" (how close is the tuple target type to the desired target type). Cost
232:                    // is currently implicit, as compound tuples are stored deeper in the queue,
233:                    // so simpler coercions will be located earlier.
234:
235:                    Class tupleTargetType = tuple.getTargetType();
236:
237:                    if (targetType.isAssignableFrom(tupleTargetType))
238:                        return tuple.getCoercion();
239:
240:                    // So .. this tuple doesn't get us directly to the target type.
241:                    // However, it *may* get us part of the way. Each of these
242:                    // represents a coercion from the source type to an intermediate type.
243:                    // Now we're going to look for conversions from the intermediate type
244:                    // to some other type.
245:
246:                    queueIntermediates(sourceType, tuple, consideredTuples,
247:                            queue);
248:                }
249:
250:                // A default rule for coercing nulls if nothing better is found.
251:
252:                if (sourceType == void.class)
253:                    return COERCION_NULL_TO_OBJECT;
254:
255:                // Not found anywhere. Identify the source and target type and a (sorted) list of
256:                // all the known coercions.
257:
258:                throw new IllegalArgumentException(ServiceMessages
259:                        .noCoercionFound(sourceType, targetType,
260:                                buildCoercionCatalog()));
261:
262:            }
263:
264:            /**
265:             * Builds a string listing all the coercions configured for the type coercer, sorted
266:             * alphabetically.
267:             */
268:            private String buildCoercionCatalog() {
269:                List<String> descriptions = newList();
270:
271:                for (List<CoercionTuple> list : _sourceTypeToTuple.values()) {
272:                    for (CoercionTuple tuple : list)
273:                        descriptions.add(tuple.toString());
274:                }
275:
276:                return InternalUtils.joinSorted(descriptions);
277:            }
278:
279:            /** Seeds the pool with the initial set of coercions for the given type. */
280:            private void seedQueue(Class sourceType,
281:                    Set<CoercionTuple> consideredTuples,
282:                    LinkedList<CoercionTuple> queue) {
283:                // Work from the source type up looking for tuples
284:
285:                for (Class c : new InheritanceSearch(sourceType)) {
286:                    List<CoercionTuple> tuples = _sourceTypeToTuple.get(c);
287:
288:                    if (tuples == null)
289:                        continue;
290:
291:                    for (CoercionTuple tuple : tuples) {
292:                        queue.addLast(tuple);
293:                        consideredTuples.add(tuple);
294:                    }
295:                }
296:            }
297:
298:            /**
299:             * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
300:             * compound coercion tuples to the end of the queue.
301:             * 
302:             * @param sourceType
303:             *            the source type of the coercion
304:             * @param intermediateTuple
305:             *            a tuple that converts from the source type to some intermediate type (that is not
306:             *            assignable to the target type)
307:             * @param consideredTuples
308:             *            set of tuples that have already been added to the pool (directly, or as a compound
309:             *            coercion)
310:             * @param queue
311:             *            the work queue of tuples
312:             */
313:            @SuppressWarnings("unchecked")
314:            private void queueIntermediates(Class sourceType,
315:                    CoercionTuple intermediateTuple,
316:                    Set<CoercionTuple> consideredTuples,
317:                    LinkedList<CoercionTuple> queue) {
318:                Class intermediateType = intermediateTuple.getTargetType();
319:
320:                for (Class c : new InheritanceSearch(intermediateType)) {
321:                    List<CoercionTuple> tuples = _sourceTypeToTuple.get(c);
322:
323:                    if (tuples == null)
324:                        continue;
325:
326:                    for (CoercionTuple tuple : tuples) {
327:                        if (consideredTuples.contains(tuple))
328:                            continue;
329:
330:                        Class newIntermediateType = tuple.getTargetType();
331:
332:                        // If this tuple is for coercing from an intermediate type back towards our
333:                        // initial source type, then ignore it. This should only be an optimization,
334:                        // as branches that loop back towards the source type will
335:                        // eventually be considered and discarded.
336:
337:                        if (sourceType.isAssignableFrom(newIntermediateType))
338:                            continue;
339:
340:                        // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
341:                        // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
342:                        // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
343:                        // intermediate type, hopefully closer to our eventual target type.
344:
345:                        Coercion compoundCoercer = new CompoundCoercion(
346:                                intermediateTuple.getCoercion(), tuple
347:                                        .getCoercion());
348:
349:                        CoercionTuple compoundTuple = new CoercionTuple(
350:                                sourceType, newIntermediateType,
351:                                compoundCoercer, false);
352:
353:                        // So, every tuple that is added to the queue can take as input the sourceType.
354:                        // The target type may be another intermdiate type, or may be something
355:                        // assignable to the target type, which will bring the search to a succesful
356:                        // conclusion.
357:
358:                        queue.addLast(compoundTuple);
359:                        consideredTuples.add(tuple);
360:                    }
361:                }
362:            }
363:
364:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.