Source Code Cross Referenced for QueryTreeResolver.java in  » Database-ORM » db-ojb » org » apache » ojb » jdo » jdoql » 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 » Database ORM » db ojb » org.apache.ojb.jdo.jdoql 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package org.apache.ojb.jdo.jdoql;
002:
003:        /* Copyright 2003-2005 The Apache Software Foundation
004:         *
005:         * Licensed under the Apache License, Version 2.0 (the "License");
006:         * you may not use this file except in compliance with the License.
007:         * You may obtain a copy of the License at
008:         *
009:         *     http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:
018:        import java.math.BigDecimal;
019:        import java.math.BigInteger;
020:        import java.util.Collection;
021:        import java.util.Date;
022:        import java.util.HashMap;
023:        import java.util.Iterator;
024:        import java.util.Map;
025:
026:        import javax.jdo.JDOUserException;
027:
028:        import org.apache.ojb.broker.metadata.*;
029:        import org.apache.ojb.broker.util.ClassHelper;
030:        import org.apache.ojb.jdo.QueryImpl;
031:
032:        /**
033:         * Resolves and checks the query trees. This involves the following things:<br/>
034:         * <ul>
035:         * <li>Replace {@link NameExpression NameExpression} with {@link LocalVariableAccess VariableAccess},
036:         *     {@link FieldAccess FieldAccess}, or {@link TypeAccess TypeAccess}</li>
037:         * <li>Resolve types referenced by {@link Type Type} and {@link TypeAccess TypeAccess}</li>
038:         * <li>Resolve features/variables referenced by {@link LocalVariableAccess VariableAccess},
039:         *     {@link FieldAccess FieldAccess}, and {@link MethodInvocation MethodInvocation}</li>
040:         * <li>Check that expression types are valid, e.g. that the types of the two sides of a binary
041:         *     expression are compatible to each other and that this binary operator can be applied
042:         *     to them</li>
043:         * <li>Check that the accessed methods are allowed to be accessed as per JDO spec (or
044:         *     extensions allowed by OJB)</li>
045:         * <li>Check that for each accessed variable there is a variable or parameter defined</li>
046:         * <li>Check that each accessed field is persistent</li>
047:         * </ul> 
048:         * 
049:         * @author <a href="mailto:tomdz@apache.org">Thomas Dudziak</a>
050:         */
051:        public class QueryTreeResolver extends VisitorBase {
052:            // TODO: Integrate position info into the exceptions
053:
054:            /** Defines the ordering of primitive types */
055:            private static HashMap _primitiveTypes = new HashMap();
056:
057:            static {
058:                _primitiveTypes.put(byte.class, new Integer(0));
059:                _primitiveTypes.put(char.class, new Integer(1));
060:                _primitiveTypes.put(short.class, new Integer(2));
061:                _primitiveTypes.put(int.class, new Integer(3));
062:                _primitiveTypes.put(long.class, new Integer(4));
063:                _primitiveTypes.put(BigInteger.class, new Integer(5));
064:                _primitiveTypes.put(float.class, new Integer(6));
065:                _primitiveTypes.put(double.class, new Integer(7));
066:                _primitiveTypes.put(BigDecimal.class, new Integer(8));
067:            }
068:
069:            /** The currently resolved query */
070:            private QueryImpl _query;
071:
072:            /**
073:             * Resolves and checks the given query. Results from a previous resolving are
074:             * overwritten.
075:             *  
076:             * @param query The query
077:             * @exception JDOUserException If the query is invalid
078:             */
079:            public void resolveAndCheck(QueryImpl query)
080:                    throws JDOUserException {
081:                _query = query;
082:                try {
083:                    checkImports(query.getImports());
084:                    visit(query.getVariables());
085:                    visit(query.getParameters());
086:                    if (query.getFilterExpression() != null) {
087:                        query.getFilterExpression().accept(this );
088:                    }
089:                    visit(query.getOrderings());
090:                } finally {
091:                    _query = null;
092:                }
093:            }
094:
095:            /**
096:             * Checks the imports. We're a bit more foregiving as the JDO Spec because
097:             * we don't demand that all imported types/packages exists as long as they
098:             * are not used.
099:             * 
100:             * @param imports The imports to check
101:             * @throws JDOUserException If two direct imports imports types with the same
102:             *                          short name
103:             */
104:            private void checkImports(Collection imports)
105:                    throws JDOUserException {
106:                // It is an error if two direct imports import classes with the same short name
107:                HashMap directlyImportedClasses = new HashMap();
108:                Import importDecl;
109:                String shortName;
110:
111:                for (Iterator it = imports.iterator(); it.hasNext();) {
112:                    importDecl = (Import) it.next();
113:                    if (!importDecl.isOnDemand()) {
114:                        shortName = importDecl.getSpec().substring(
115:                                importDecl.getSpec().lastIndexOf('.'));
116:                        if (directlyImportedClasses.containsKey(shortName)) {
117:                            throw new JDOUserException(
118:                                    "Multiple direct imports of classes with the same unqualified name "
119:                                            + shortName);
120:                        } else {
121:                            directlyImportedClasses.put(shortName, null);
122:                        }
123:                    }
124:                }
125:            }
126:
127:            /**
128:             * Visits all elements of the given map.
129:             * 
130:             * @param objects The objects
131:             * @exception JDOUserException If one of the elements is invalid
132:             */
133:            private void visit(Map objects) throws JDOUserException {
134:                if (objects != null) {
135:                    for (Iterator it = objects.values().iterator(); it
136:                            .hasNext();) {
137:                        ((Acceptor) it.next()).accept(this );
138:                    }
139:                }
140:            }
141:
142:            /**
143:             * Visits all elements of the given collection.
144:             * 
145:             * @param objects The objects
146:             * @exception JDOUserException If one of the elements is invalid
147:             */
148:            private void visit(Collection objects) throws JDOUserException {
149:                if (objects != null) {
150:                    for (Iterator it = objects.iterator(); it.hasNext();) {
151:                        ((Acceptor) it.next()).accept(this );
152:                    }
153:                }
154:            }
155:
156:            /* (non-Javadoc)
157:             * @see org.apache.ojb.jdo.jdoql.Visitor#visit(org.apache.ojb.jdo.jdoql.BinaryExpression)
158:             */
159:            public void visit(BinaryExpression binExpr) throws JDOUserException {
160:                super .visit(binExpr);
161:
162:                // for the types of the left and right expressions one of the following must hold:
163:                // * the operator is '+' and both are String
164:                // * the operator is arithmethic and both are numeric (Character, Long or Double)
165:                // * the operator is bitwise and both are Character or Long
166:                // * the operator is logic and both are Boolean
167:                // * the operator is comparative and the both are String, or both are Date, or both are Numeric
168:                Class leftType = binExpr.getLeftSide().getType();
169:                Class rightType = binExpr.getRightSide().getType();
170:                boolean typeWasSet = false;
171:
172:                switch (binExpr.getOperator()) {
173:                case BinaryExpression.OPERATOR_MULTIPLY:
174:                case BinaryExpression.OPERATOR_DIVIDE:
175:                case BinaryExpression.OPERATOR_PLUS:
176:                case BinaryExpression.OPERATOR_MINUS:
177:                    if (binExpr.getOperator() == BinaryExpression.OPERATOR_PLUS) {
178:                        if ((leftType == String.class)
179:                                && (rightType == String.class)) {
180:                            binExpr.setType(String.class);
181:                            typeWasSet = true;
182:                            break;
183:                        }
184:                    }
185:                    if (isNumeric(leftType) && isNumeric(rightType)) {
186:                        binExpr.setType(getBroaderType(leftType, rightType));
187:                        typeWasSet = true;
188:                    }
189:                    break;
190:                case BinaryExpression.OPERATOR_BITWISE_AND:
191:                case BinaryExpression.OPERATOR_BITWISE_XOR:
192:                case BinaryExpression.OPERATOR_BITWISE_OR:
193:                    if (isInteger(leftType) && isInteger(rightType)) {
194:                        binExpr.setType(getBroaderType(leftType, rightType));
195:                        typeWasSet = true;
196:                    } else if ((leftType == boolean.class)
197:                            && (rightType == boolean.class)) {
198:                        binExpr.setType(boolean.class);
199:                        typeWasSet = true;
200:                    }
201:                    break;
202:                case BinaryExpression.OPERATOR_LOWER:
203:                case BinaryExpression.OPERATOR_GREATER:
204:                case BinaryExpression.OPERATOR_LOWER_OR_EQUAL:
205:                case BinaryExpression.OPERATOR_GREATER_OR_EQUAL:
206:                    if (isNumeric(leftType) && isNumeric(rightType)) {
207:                        binExpr.setType(boolean.class);
208:                        typeWasSet = true;
209:                    } else if ((leftType == String.class)
210:                            && (rightType == String.class)) {
211:                        binExpr.setType(boolean.class);
212:                        typeWasSet = true;
213:                    } else if ((leftType == Date.class)
214:                            && (rightType == Date.class)) {
215:                        binExpr.setType(boolean.class);
216:                        typeWasSet = true;
217:                    }
218:                    break;
219:                case BinaryExpression.OPERATOR_EQUAL:
220:                case BinaryExpression.OPERATOR_NOT_EQUAL:
221:                    if (isNumeric(leftType) && isNumeric(rightType)) {
222:                        binExpr.setType(boolean.class);
223:                        typeWasSet = true;
224:                    } else if ((leftType == boolean.class)
225:                            && (rightType == boolean.class)) {
226:                        binExpr.setType(boolean.class);
227:                        typeWasSet = true;
228:                    } else if (!leftType.isPrimitive()
229:                            && !rightType.isPrimitive()) {
230:                        binExpr.setType(boolean.class);
231:                        typeWasSet = true;
232:                    }
233:                    break;
234:                case BinaryExpression.OPERATOR_AND:
235:                case BinaryExpression.OPERATOR_OR:
236:                    if ((leftType == boolean.class)
237:                            && (rightType == boolean.class)) {
238:                        binExpr.setType(boolean.class);
239:                        typeWasSet = true;
240:                    }
241:                    break;
242:                }
243:                if (!typeWasSet) {
244:                    throw new JDOUserException(
245:                            "Binary expression cannot be applied to expressions of types "
246:                                    + leftType.getName() + " and "
247:                                    + rightType.getName());
248:                }
249:            }
250:
251:            /* (non-Javadoc)
252:             * @see org.apache.ojb.jdo.jdoql.Visitor#visit(org.apache.ojb.jdo.jdoql.MethodInvocation)
253:             */
254:            public void visit(MethodInvocation methodInvoc)
255:                    throws JDOUserException {
256:                super .visit(methodInvoc);
257:
258:                Class type = methodInvoc.getBaseExpression().getType();
259:                String name = methodInvoc.getName();
260:
261:                if (Collection.class.isAssignableFrom(type)) {
262:                    if ("contains".equals(name)) {
263:                        if (methodInvoc.getArguments().size() != 1) {
264:                            throw new JDOUserException(
265:                                    "Illegal number of arguments to method Collection.contains");
266:                        }
267:                    } else if ("isEmpty".equals(name)) {
268:                        if (!methodInvoc.getArguments().isEmpty()) {
269:                            throw new JDOUserException(
270:                                    "Illegal number of arguments to method Collection.isEmpty");
271:                        }
272:                    } else {
273:                        throw new JDOUserException(
274:                                "Only methods 'contains' and 'isEmpty' are allowed to be called at collection objects");
275:                    }
276:                    methodInvoc.setType(boolean.class);
277:                } else if (type == String.class) {
278:                    if (!"startsWith".equals(name) && !"endsWith".equals(name)) {
279:                        throw new JDOUserException(
280:                                "Only methods 'contains' and 'isEmpty' are allowed to be called at collection objects");
281:                    }
282:                    if (methodInvoc.getArguments().size() != 1) {
283:                        throw new JDOUserException(
284:                                "Illegal number of arguments to method String."
285:                                        + name);
286:                    }
287:                    if (((Expression) methodInvoc.getArguments().get(0))
288:                            .getType() != String.class) {
289:                        throw new JDOUserException(
290:                                "Illegal argument to method Collection." + name);
291:                    }
292:                    methodInvoc.setType(boolean.class);
293:                } else {
294:                    throw new JDOUserException("Invocation of method "
295:                            + methodInvoc.getName() + " at type "
296:                            + type.getName() + " is not allowed");
297:                }
298:            }
299:
300:            /* (non-Javadoc)
301:             * @see org.apache.ojb.jdo.jdoql.Visitor#visit(org.apache.ojb.jdo.jdoql.NameExpression)
302:             */
303:            public void visit(NameExpression nameExpr) throws JDOUserException {
304:                super .visit(nameExpr);
305:
306:                Expression newExpr = null;
307:                Class baseType = null;
308:
309:                // we search in this order (which corresponds to Java's name resolution order):
310:                //   * variables (only if without base expression)
311:                //   * parameters (only if without base expression)
312:                //   * fields/references/collections (at searched type if without base expression)
313:                // types are currently not searched for as they are not allowed to appear directly
314:                // except in casts
315:                if (!nameExpr.hasBaseExpression()) {
316:                    // no base expressiom
317:                    LocalVariable var = _query.getVariable(nameExpr.getName());
318:
319:                    if (var == null) {
320:                        var = _query.getParameter(nameExpr.getName());
321:                    }
322:                    if (var != null) {
323:                        LocalVariableAccess varAccess = new LocalVariableAccess(
324:                                nameExpr.getName());
325:
326:                        varAccess.setAccessedVariable(var);
327:                        newExpr = varAccess;
328:                    } else {
329:                        // neither a variable nor parameter, so we must search in the class
330:                        // whose objects the query searches for
331:                        baseType = _query.getSearchedClass();
332:                    }
333:                } else {
334:                    // we have a base expression which means that we follow a reference
335:                    baseType = nameExpr.getBaseExpression().getType();
336:                }
337:                if (newExpr == null) {
338:                    // so we determine the persistent type of the base expression
339:                    ClassDescriptor classDesc = findClassDescriptorFor(baseType);
340:
341:                    if (classDesc == null) {
342:                        throw new JDOUserException(
343:                                "Access to type "
344:                                        + baseType.getName()
345:                                        + " is not allowed because the type is not persistent");
346:                    }
347:
348:                    FieldAccess fieldAccess = new FieldAccess(nameExpr
349:                            .getBaseExpression(), nameExpr.getName());
350:
351:                    // it may be either a field, reference or collection descriptor -
352:                    // this depends on whether the name expression is a base expression
353:                    // to another name expression (not a method invocation or other expression)
354:                    ObjectReferenceDescriptor refDesc = classDesc
355:                            .getObjectReferenceDescriptorByName(nameExpr
356:                                    .getName());
357:
358:                    if (refDesc != null) {
359:                        fieldAccess.setFieldDescriptor(refDesc);
360:                    } else if (nameExpr.hasParent()
361:                            && (nameExpr.getParent() instanceof  NameExpression)) {
362:                        // if we are the base expression of another name expression, then it must be a reference
363:                        throw new JDOUserException(
364:                                "Cannot find reference "
365:                                        + nameExpr.getName()
366:                                        + " in type "
367:                                        + baseType.getName()
368:                                        + " because it is not defined, not persistent or not a reference");
369:                    } else {
370:                        // it can be a field or collection
371:                        CollectionDescriptor collDesc = classDesc
372:                                .getCollectionDescriptorByName(nameExpr
373:                                        .getName());
374:                        if (collDesc != null) {
375:                            fieldAccess.setFieldDescriptor(collDesc);
376:                        } else {
377:                            FieldDescriptor fieldDesc = classDesc
378:                                    .getFieldDescriptorByName(nameExpr
379:                                            .getName());
380:
381:                            if (fieldDesc == null) {
382:                                throw new JDOUserException(
383:                                        "Cannot find feature "
384:                                                + nameExpr.getName()
385:                                                + " in type "
386:                                                + baseType.getName()
387:                                                + " because it is not defined or not persistent");
388:                            }
389:                            fieldAccess.setFieldDescriptor(fieldDesc);
390:                        }
391:                    }
392:                    newExpr = fieldAccess;
393:                }
394:
395:                if (nameExpr.hasParent()) {
396:                    nameExpr.getParent().replaceChild(nameExpr, newExpr);
397:                }
398:            }
399:
400:            /* (non-Javadoc)
401:             * @see org.apache.ojb.jdo.jdoql.Visitor#visit(org.apache.ojb.jdo.jdoql.NullLiteral)
402:             */
403:            public void visit(NullLiteral nullLit) {
404:                Expression parent = nullLit.getParent();
405:
406:                if (parent == null) {
407:                    return;
408:                }
409:
410:                // the only interesting case is if the parent is a binary expression (e.g.
411:                // a '==' expression) in which case the null literal shall have the same
412:                // type as the other operand
413:                if (parent instanceof  BinaryExpression) {
414:                    Class type = null;
415:
416:                    if (((BinaryExpression) parent).getLeftSide() == nullLit) {
417:                        type = ((BinaryExpression) parent).getRightSide()
418:                                .getType();
419:                    } else {
420:                        type = ((BinaryExpression) parent).getLeftSide()
421:                                .getType();
422:                    }
423:                    if (type.isPrimitive()) {
424:                        throw new JDOUserException(
425:                                "Illegal binary expression with a 'null' and a primitive operand");
426:                    }
427:                    nullLit.setType(type);
428:                }
429:            }
430:
431:            /* (non-Javadoc)
432:             * @see org.apache.ojb.jdo.jdoql.Visitor#visit(org.apache.ojb.jdo.jdoql.ThisExpression)
433:             */
434:            public void visit(ThisExpression this Expr) {
435:                super .visit(this Expr);
436:                this Expr.setType(_query.getSearchedClass());
437:            }
438:
439:            /* (non-Javadoc)
440:             * @see org.apache.ojb.jdo.jdoql.Visitor#visit(org.apache.ojb.jdo.jdoql.Type)
441:             */
442:            public void visit(Type type) throws JDOUserException {
443:                ClassLoader loader = ClassHelper.getClassLoader();
444:                Class result = null;
445:                String name = type.getName();
446:                int pos = name.indexOf('.');
447:
448:                if (pos >= 0) {
449:                    // its either a qualified name or refers to an inner class
450:                    // we ignore inner classes here as they are handled by the import
451:                    // resolution below
452:                    // [tomdz] we might have to resolve inner/nested classes manually
453:                    //         if the query should be executed in the scope of the
454:                    //         searched class (which makes private/protected/friendly
455:                    //         inner/nested classes visible)
456:                    //         for now we assume that this is not the case
457:                    try {
458:                        result = Class.forName(name, true, loader);
459:                    } catch (ClassNotFoundException ex) {
460:                        // ignored
461:                    }
462:                }
463:                if (result == null) {
464:                    result = resolveUnqualifiedClassName(loader, name);
465:                }
466:                if (result == null) {
467:                    throw new JDOUserException("No such class " + name);
468:                } else {
469:                    type.setType(result);
470:                }
471:            }
472:
473:            /**
474:             * Resolves the given unqualified class name against the imports of the query.
475:             * 
476:             * @param loader          The class loader to use
477:             * @param unqualifiedName The unqualified class name
478:             * @return The class if it has been found
479:             * @exception JDOUserException If a direct import declaration is invalid
480:             */
481:            private Class resolveUnqualifiedClassName(ClassLoader loader,
482:                    String unqualifiedName) throws JDOUserException {
483:                // A direct import has precedence over on-demand imports of packages that contain
484:                // a class of the same short name (JLS 7.5.1)
485:                // If multiple on-demand imports import packages that have a class with a given
486:                // short name, then the last such import defines the class to be used
487:                Import importDecl;
488:                Class result = null;
489:                int pos;
490:
491:                // we first try to resolve it against java.lang
492:                try {
493:                    result = Class.forName("java.lang." + unqualifiedName,
494:                            true, loader);
495:                } catch (ClassNotFoundException ex) {
496:                    // ignored
497:                }
498:                for (Iterator it = _query.getImports().iterator(); it.hasNext();) {
499:                    importDecl = (Import) it.next();
500:                    if (importDecl.isOnDemand()) {
501:                        try {
502:                            result = Class.forName(importDecl.getSpec() + "."
503:                                    + unqualifiedName, true, loader);
504:                        } catch (ClassNotFoundException ex) {
505:                            // ignored
506:                        }
507:                    } else {
508:                        pos = importDecl.getSpec().lastIndexOf('.');
509:                        if (unqualifiedName.equals(importDecl.getSpec()
510:                                .substring(pos + 1))) {
511:                            try {
512:                                // there can only be one direct import of a class with this
513:                                // unqualified name (imports have already been checked), and
514:                                // no on-demand import can shadow it, so we can simply return it
515:                                return Class.forName(importDecl.getSpec() + "."
516:                                        + unqualifiedName, true, loader);
517:                            } catch (ClassNotFoundException ex) {
518:                                // we have a direct import for the class but the import is invalid
519:                                throw new JDOUserException("The import "
520:                                        + importDecl.getSpec() + " is invalid");
521:                            }
522:                        }
523:                    }
524:                }
525:                return result;
526:            }
527:
528:            /* (non-Javadoc)
529:             * @see org.apache.ojb.jdo.jdoql.Visitor#visit(org.apache.ojb.jdo.jdoql.UnaryExpression)
530:             */
531:            public void visit(UnaryExpression unaryExpr)
532:                    throws JDOUserException {
533:                super .visit(unaryExpr);
534:
535:                // one of the following must hold:
536:                // * the operator is arithmetic and the inner type is numeric
537:                // * the operator is bitwise and the inner type is Character or Long
538:                // * the operator is logic and the inner type is Boolean
539:                // * it is a cast and the cast type is assignment compatible to the inner type
540:                Class innerType = unaryExpr.getInnerExpression().getType();
541:                boolean typeWasSet = false;
542:
543:                switch (unaryExpr.getOperator()) {
544:                case UnaryExpression.OPERATOR_PLUS:
545:                case UnaryExpression.OPERATOR_MINUS:
546:                    if (isNumeric(innerType)) {
547:                        unaryExpr.setType(innerType);
548:                        typeWasSet = true;
549:                    }
550:                    break;
551:                case UnaryExpression.OPERATOR_BITWISE_COMPLEMENT:
552:                    if (isInteger(innerType)) {
553:                        unaryExpr.setType(innerType);
554:                        typeWasSet = true;
555:                    }
556:                    break;
557:                case UnaryExpression.OPERATOR_NOT:
558:                    if (innerType == boolean.class) {
559:                        unaryExpr.setType(innerType);
560:                        typeWasSet = true;
561:                    }
562:                    break;
563:                case UnaryExpression.OPERATOR_CAST:
564:                    Class castType = unaryExpr.getCastType().getType();
565:
566:                    if (isNumeric(castType) && isNumeric(innerType)) {
567:                        unaryExpr.setType(castType);
568:                        typeWasSet = true;
569:                    } else {
570:                        // check for narrowing or widening reference conversion
571:                        if (castType.isAssignableFrom(innerType)
572:                                || innerType.isAssignableFrom(castType)) {
573:                            unaryExpr.setType(castType);
574:                            typeWasSet = true;
575:                        }
576:                    }
577:                    break;
578:
579:                }
580:                if (!typeWasSet) {
581:                    if (unaryExpr.getOperator() == UnaryExpression.OPERATOR_CAST) {
582:                        throw new JDOUserException(
583:                                "Invalid cast expression because inner expression of type "
584:                                        + innerType.getName()
585:                                        + " cannot be cast to "
586:                                        + unaryExpr.getCastType().getName());
587:                    } else {
588:                        throw new JDOUserException("Invalid unary expression");
589:                    }
590:                }
591:            }
592:
593:            // Helper methods
594:
595:            /**
596:             * Retrieves OJB's class descriptor for the given type.
597:             * 
598:             * @param The type to lookup
599:             * @return The class descriptor or <code>null</code> if the class is not persistent
600:             */
601:            private ClassDescriptor findClassDescriptorFor(Class type) {
602:                return MetadataManager.getInstance().getRepository()
603:                        .getDescriptorFor(type);
604:            }
605:
606:            /**
607:             * Determines whether the given class denotes an integer primitive type.
608:             * 
609:             * @param type The type
610:             * @return <code>true</code> if the type is an integer type
611:             */
612:            private static boolean isInteger(Class type) {
613:                if (type.isPrimitive()) {
614:                    return (type != boolean.class) && (type != float.class)
615:                            && (type != double.class);
616:                } else {
617:                    return type == BigInteger.class;
618:                }
619:            }
620:
621:            /**
622:             * Determines whether the given class denotes a floating point primitive type.
623:             * 
624:             * @param type The type
625:             * @return <code>true</code> if the type is a floating point type
626:             */
627:            private static boolean isFloatingPoint(Class type) {
628:                if (type.isPrimitive()) {
629:                    return (type == float.class) || (type == double.class);
630:                } else {
631:                    return type == BigDecimal.class;
632:                }
633:            }
634:
635:            /**
636:             * Determines whether the given class denotes a numeric primitive type.
637:             * 
638:             * @param type The type
639:             * @return <code>true</code> if the type is a numeric type
640:             */
641:            private static boolean isNumeric(Class type) {
642:                if (type.isPrimitive()) {
643:                    return type != boolean.class;
644:                } else {
645:                    return (type == BigDecimal.class)
646:                            || (type == BigInteger.class);
647:                }
648:            }
649:
650:            /**
651:             * Determines the broader of the two given numeric types.
652:             * 
653:             * @param typeA The first type
654:             * @param typeB The seconf type
655:             * @return The broader of the two types
656:             */
657:            private static Class getBroaderType(Class typeA, Class typeB) {
658:                Integer numA = (Integer) _primitiveTypes.get(typeA);
659:                Integer numB = (Integer) _primitiveTypes.get(typeB);
660:
661:                return numA.intValue() < numB.intValue() ? typeB : typeA;
662:            }
663:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.