Source Code Cross Referenced for ConstraintParser.java in  » Database-ORM » MMBase » org » mmbase » storage » search » legacy » 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 » MMBase » org.mmbase.storage.search.legacy 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:        This software is OSI Certified Open Source Software.
0004:        OSI Certified is a certification mark of the Open Source Initiative.
0005:
0006:        The license (Mozilla version 1.0) can be read at the MMBase site.
0007:        See http://www.MMBase.org/license
0008:
0009:         */
0010:        package org.mmbase.storage.search.legacy;
0011:
0012:        import java.util.*;
0013:        import org.mmbase.bridge.Field;
0014:        import org.mmbase.core.CoreField;
0015:        import org.mmbase.module.core.*;
0016:        import org.mmbase.storage.StorageManagerFactory;
0017:        import org.mmbase.storage.search.*;
0018:        import org.mmbase.storage.search.implementation.*;
0019:        import org.mmbase.util.logging.*;
0020:        import org.mmbase.bridge.NodeQuery;
0021:
0022:        /**
0023:         * Parser, tries to parse a <em>SQL-search-condition</em> for a query to a
0024:         * {@link org.mmbase.storage.search.Constraint Constraint} object.
0025:         * <p>
0026:         * This class is provided for the sole purpose of alignment of old code with
0027:         * the new {@link org.mmbase.storage.search.SearchQuery SearchQuery} framework,
0028:         * and should not be called by new code.
0029:         * <p>
0030:         * A <em>SQL-search-condition</em> can be one of these forms:
0031:         * <ul>
0032:         * <li>[<b>NOT</b>] <b>(</b><em>SQL-search-condition</em><b>)</b>
0033:         * <li>[<b>NOT</b>] <em>simple-SQL-search-condition</em>
0034:         * <li><em>SQL-search-condition</em> <b>AND</b> <em>SQL-search-condition</em>
0035:         * <li><em>SQL-search-condition</em> <b>OR</b> <em>SQL-search-condition</em>
0036:         * </ul>
0037:         * A <em>simple-SQL-search-condition</em> string can be of one of these forms:
0038:         * <ul>
0039:         * <li><em>field</em> [<b>NOT</b>] <b>LIKE</b> <em>value</em>
0040:         * <li><b>UPPER(</b><em>field</em><b>)</b> [<b>NOT</b>] <b>LIKE</b> <em>value</em>
0041:         * <li><b>LOWER(</b><em>field</em><b>)</b> [<b>NOT</b>] <b>LIKE</b> <em>value</em>
0042:         * <li><em>field</em> <b>IS</b> [<b>NOT</b>] <b>NULL</b>
0043:         * <li><em>field</em> [<b>NOT</b>] <b>IN
0044:         *     (</b><em>value1</em><b>,</b> <em>value2</em><b>,</b> ..<b>)</b>
0045:         * <li><em>field</em> [<b>NOT</b>] <b>BETWEEN</b> <em>value1</em> <b>AND</b> <em>value2</em>
0046:         * <li><b>UPPER(</b><em>field</em><b>)</b> [<b>NOT</b>] <b>BETWEEN</b> <em>value1</em> <b>AND</b> <em>value2</em>
0047:         * <li><b>LOWER(</b><em>field</em><b>)</b> [<b>NOT</b>] <b>BETWEEN</b> <em>value1</em> <b>AND</b> <em>value2</em>
0048:         * <li><em>field</em> <b>=</b> <em>value</em>
0049:         * <li><em>field</em> <b>=</b> <em>field2</em>
0050:         * <li><b>UPPER(</b><em>field</em><b>) =</b> <em>value</em>
0051:         * <li><b>LOWER(</b><em>field</em><b>) =</b> <em>value</em>
0052:         * <li><em>field</em> <b>==</b> <em>value</em>
0053:         * <li><em>field</em> <b>==</b> <em>field2</em>
0054:         * <li><em>field</em> <b>&lt;=</b> <em>value</em>
0055:         * <li><em>field</em> <b>&lt;=</b> <em>field2</em>
0056:         * <li><em>field</em> <b>&lt;</b> <em>value</em>
0057:         * <li><em>field</em> <b>&lt;</b> <em>field2</em>
0058:         * <li><em>field</em> <b>&gt;=</b> <em>value</em>
0059:         * <li><em>field</em> <b>&gt;=</b> <em>field2</em>
0060:         * <li><em>field</em> <b>&gt;</b> <em>value</em>
0061:         * <li><em>field</em> <b>&gt;</b> <em>field2</em>
0062:         * <li><em>field</em> <b>&lt;&gt;</b> <em>value</em>
0063:         * <li><em>field</em> <b>&lt;&gt;</b> <em>field2</em>
0064:         * <li><em>field</em> <b>!=</b> <em>value</em>
0065:         * <li><em>field</em> <b>!=</b> <em>field2</em>
0066:         * <li><em>string-search-condition</em>
0067:         * </ul>
0068:         * A <em>field</em> can be one of these forms:
0069:         * <ul>
0070:         * <li><em>stepalias</em><b>.</b><em>fieldname</em>
0071:         * <li><em>fieldname</em> (only when the query has just one step).
0072:         * </ul>
0073:         * A <em>value</em> can be one of these forms:
0074:         * <ul>
0075:         * <li><em>string between single quotes</em> for string fields, example: <code>'A string value'</code>
0076:         * <li><em>numerical value</em> for numerical fields, example: <code>123.456</code>
0077:         * <li><em>numerical value between single quotes</em> for numerical fields, example" <code>'123.456'</code>
0078:         * </ul>
0079:         * A <em>string-search-condition</em> can be of this form:
0080:         * <ul>
0081:         * <li><b>StringSearch(</b><em>field</em><b>,</b>PHRASE|PROXIMITY|WORD<b>,</b>
0082:         *  FUZZY|LITERAL|SYNONYM<b>,</b>
0083:         *  <em>searchterms</em><b>,</b>
0084:         *  <em>casesensitive</em><b>)</b>
0085:         *  [<b>.set(FUZZINESS,</b><em>fuzziness</em><b>)</b>]
0086:         *  [<b>.set(PROXIMITY_LIMIT,</b><em>proximity</em><b>)</b>]
0087:         * </ul>
0088:         * <em>searchterms</em> can be of one of these forms:
0089:         * <ul>
0090:         * <li><b>'</b>term1<b>'</b>
0091:         * <li><b>"</b>term1<b>"</b>
0092:         * <li><b>'</b>term1 term2<b>'</b>
0093:         * <li><b>"</b>term1 term2<b>"</b>
0094:         * <li> etc...
0095:         * </ul>
0096:         * <em>casesensitive</em> can be of one on these forms:
0097:         * <ul>
0098:         * <li><b>true</b>
0099:         * <li><b>false</b>
0100:         * </ul>
0101:         * <em>fuzziness</em> must be a float value between 0.0 and 1.0,
0102:         * <em>proximity</em> must be a int value &gt; 0<br />
0103:         * <p>
0104:         * See {@link org.mmbase.storage.search.StringSearchConstraint
0105:         * StringSearchConstraint} for more info on string-search constraints.
0106:         * <p>
0107:         * A search condition that is not of one of these forms will be converted to a
0108:         * {@link org.mmbase.storage.search.LegacyConstraint LegacyConstraint}, i.e.
0109:         * in that case the search condition string will not be interpreted, but
0110:         * instead be used "as-is".
0111:         * Each time this occurs is logged with priority <code>service</code> to
0112:         * category <code>org.mmbase.storage.search.legacyConstraintParser.fallback</code>.
0113:         *
0114:         * @author  Rob van Maris
0115:         * @version $Id: ConstraintParser.java,v 1.35 2007/11/28 10:17:47 michiel Exp $
0116:         * @since MMBase-1.7
0117:         */
0118:        public class ConstraintParser {
0119:
0120:            private final static Logger log = Logging
0121:                    .getLoggerInstance(ConstraintParser.class);
0122:
0123:            /** Logger instance dedicated to logging fallback to legacy constraint. */
0124:            private final static Logger fallbackLog = Logging
0125:                    .getLoggerInstance(ConstraintParser.class.getName()
0126:                            + ".fallback");
0127:
0128:            /**
0129:             * Converts a constraint by turning all 'quoted' fields into
0130:             * database supported fields.
0131:             * XXX: todo: escape characters for '[' and ']'.
0132:             * @param constraints constraint to convert
0133:             * @return Converted constraint
0134:             * @since MMBase-1.8.1 (moved from org.mmbase.bridge.util.Queries)
0135:             */
0136:            private static String convertClausePartToDBS(String constraints) {
0137:                StorageManagerFactory<?> factory = MMBase.getMMBase()
0138:                        .getStorageManagerFactory();
0139:                StringBuilder result = new StringBuilder();
0140:                int posa = constraints.indexOf('[');
0141:                while (posa > -1) {
0142:                    int posb = constraints.indexOf(']', posa);
0143:                    if (posb == -1) {
0144:                        posa = -1;
0145:                    } else {
0146:                        String fieldName = constraints
0147:                                .substring(posa + 1, posb);
0148:                        int posc = fieldName.indexOf('.');
0149:                        if (posc == -1) {
0150:                            fieldName = factory != null ? factory
0151:                                    .getStorageIdentifier(fieldName).toString()
0152:                                    : fieldName;
0153:                        } else {
0154:                            fieldName = fieldName.substring(0, posc + 1)
0155:                                    + (factory != null ? factory
0156:                                            .getStorageIdentifier(fieldName
0157:                                                    .substring(posc + 1))
0158:                                            : fieldName.substring(posc + 1));
0159:                        }
0160:                        result.append(constraints.substring(0, posa)).append(
0161:                                fieldName);
0162:                        constraints = constraints.substring(posb + 1);
0163:                        posa = constraints.indexOf('[');
0164:                    }
0165:                }
0166:                result.append(constraints);
0167:                return result.toString();
0168:            }
0169:
0170:            /**
0171:             * Converts a constraint by turning all 'quoted' fields into
0172:             * database supported fields.
0173:             * XXX: todo: escape characters for '[' and ']'.
0174:             * @param constraints constraints to convert
0175:             * @return converted constraint
0176:             * @since MMBase-1.8.1 (moved from org.mmbase.bridge.util.Queries)
0177:             */
0178:            public static String convertClauseToDBS(String constraints) {
0179:                if (constraints.startsWith("MMNODE")) {
0180:                    //  wil probably not work
0181:                    // @todo check
0182:                    return constraints;
0183:                } else if (constraints.startsWith("ALTA")) {
0184:                    //  wil probably not work
0185:                    // @todo check
0186:                    return constraints.substring(5);
0187:                }
0188:
0189:                //keesj: what does this code do?
0190:
0191:                StringBuilder result = new StringBuilder();
0192:                //if there is a quote in the constraints posa will not be equals -1
0193:
0194:                int quoteOpen = constraints.indexOf('\'');
0195:                while (quoteOpen > -1) {
0196:                    //keesj: posb can be the same a posa maybe the method should read indexOf("\"",posa) ?
0197:                    int quoteClose = constraints.indexOf('\'', quoteOpen + 1);
0198:                    if (quoteClose == -1) {
0199:                        // unmatching quote?
0200:                        log.warn("unbalanced quote in " + constraints);
0201:                        break;
0202:                    }
0203:
0204:                    //keesj:part is now the first part of the constraints if there is a quote in the query
0205:                    String part = constraints.substring(0, quoteOpen);
0206:
0207:                    //append to the string buffer "part" the first part
0208:                    result.append(convertClausePartToDBS(part));
0209:                    result.append(constraints.substring(quoteOpen,
0210:                            quoteClose + 1));
0211:
0212:                    constraints = constraints.substring(quoteClose + 1);
0213:                    quoteOpen = constraints.indexOf('\'');
0214:
0215:                }
0216:                result.append(convertClausePartToDBS(constraints));
0217:                return result.toString();
0218:            }
0219:
0220:            /**
0221:             * returns false, when escaping wasnt closed, or when a ";" was found outside a escaped part (to prefent spoofing)
0222:             * This is used by createQuery (i wonder if it still makes sense)
0223:             * @param constraints constraint to check
0224:             * @return is valid constraint
0225:             * @since MMBase-1.8.1 (moved from org.mmbase.bridge.util.Queries)
0226:             */
0227:            static public boolean validConstraints(String constraints) {
0228:                // first remove all the escaped "'" ('' occurences) chars...
0229:                String remaining = constraints;
0230:                while (remaining.indexOf("''") != -1) {
0231:                    int start = remaining.indexOf("''");
0232:                    int stop = start + 2;
0233:                    if (stop < remaining.length()) {
0234:                        String begin = remaining.substring(0, start);
0235:                        String end = remaining.substring(stop);
0236:                        remaining = begin + end;
0237:                    } else {
0238:                        remaining = remaining.substring(0, start);
0239:                    }
0240:                }
0241:                // assume we are not escaping... and search the string..
0242:                // Keep in mind that at this point, the remaining string could contain different information
0243:                // than the original string. This doesnt matter for the next sequence...
0244:                // but it is important to realize!
0245:                while (remaining.length() > 0) {
0246:                    if (remaining.indexOf('\'') != -1) {
0247:                        // we still contain a "'"
0248:                        int start = remaining.indexOf('\'');
0249:
0250:                        // escaping started, but no stop
0251:                        if (start == remaining.length()) {
0252:                            log
0253:                                    .warn("reached end, but we are still escaping(you should sql-escape the search query inside the jsp-page?)\noriginal:"
0254:                                            + constraints);
0255:                            return false;
0256:                        }
0257:
0258:                        String notEscaped = remaining.substring(0, start);
0259:                        if (notEscaped.indexOf(';') != -1) {
0260:                            log
0261:                                    .warn("found a ';' outside the constraints(you should sql-escape the search query inside the jsp-page?)\noriginal:"
0262:                                            + constraints
0263:                                            + "\nnot excaped:"
0264:                                            + notEscaped);
0265:                            return false;
0266:                        }
0267:
0268:                        int stop = remaining.substring(start + 1).indexOf('\'');
0269:                        if (stop < 0) {
0270:                            log
0271:                                    .warn("reached end, but we are still escaping(you should sql-escape the search query inside the jsp-page?)\noriginal:"
0272:                                            + constraints
0273:                                            + "\nlast escaping:"
0274:                                            + remaining.substring(start + 1));
0275:                            return false;
0276:                        }
0277:                        // we added one to to start, thus also add this one to stop...
0278:                        stop = start + stop + 1;
0279:
0280:                        // when the last character was the stop of our escaping
0281:                        if (stop == remaining.length()) {
0282:                            return true;
0283:                        }
0284:
0285:                        // cut the escaped part from the string, and continue with resting sting...
0286:                        remaining = remaining.substring(stop + 1);
0287:                    } else {
0288:                        if (remaining.indexOf(';') != -1) {
0289:                            log.warn("found a ';' inside our constrain:"
0290:                                    + constraints);
0291:                            return false;
0292:                        }
0293:                        return true;
0294:                    }
0295:                }
0296:                return true;
0297:            }
0298:
0299:            private SearchQuery query = null;
0300:            private List<? extends Step> steps = null;
0301:
0302:            /**
0303:             * Parses string or numerical value from list of tokens, to match the type
0304:             * of the specified field.
0305:             * If the first token is not "'", it is interpreted as a numerical value,
0306:             * otherwise it is required to be the first token of the sequence
0307:             * "'", "value", "'", representing a string value for string fields, or
0308:             * a numerical value for numerical fields.
0309:             *
0310:             * @param iTokens Tokens iterator, must be positioned before the (first)
0311:             *        token representing the value.
0312:             * @param field The field.
0313:             * @return A <code>String</code> or <code>Double</code> object representing
0314:             *        the value.
0315:             * @throws NumberFormatException when the first token is not (the start of)
0316:             *        a valid value expression (it may be a <em>field</em> instead).
0317:             */
0318:            // package visibility!
0319:            static Object parseValue(Iterator<String> iTokens, StepField field)
0320:                    throws NumberFormatException {
0321:                Object result = null;
0322:                String token = iTokens.next();
0323:                if (token.equals("'")) {
0324:                    // String value.
0325:                    result = iTokens.next();
0326:                    token = iTokens.next();
0327:                    if (!token.equals("'")) {
0328:                        throw new IllegalArgumentException(
0329:                                "Unexpected token (expected \"'\"): \"" + token
0330:                                        + "\"");
0331:                    }
0332:
0333:                    int fieldType = field.getType();
0334:                    if (fieldType == Field.TYPE_BINARY
0335:                            || fieldType == Field.TYPE_DOUBLE
0336:                            || fieldType == Field.TYPE_FLOAT
0337:                            || fieldType == Field.TYPE_INTEGER
0338:                            || fieldType == Field.TYPE_LONG
0339:                            || fieldType == Field.TYPE_NODE) {
0340:                        // String represents a numerical value.
0341:                        result = Double.valueOf((String) result);
0342:                    }
0343:                } else {
0344:                    result = Double.valueOf(token);
0345:                }
0346:                return result;
0347:            }
0348:
0349:            /**
0350:             * Parses SQL search condition string into separate tokens, discarding
0351:             * white spaces, concatenating strings between (single/double) quotes,
0352:             * and replacing escaped (single/double) quotes in strings by the
0353:             * original character.
0354:             *
0355:             * @param sqlConstraint The SQL constraint string.
0356:             * @return List of tokens.
0357:             */
0358:            // package visibility!
0359:            static List<String> tokenize(String sqlConstraint) {
0360:                // Parse into separate tokens.
0361:                List<String> tokens = new ArrayList<String>();
0362:                StringTokenizer st = new StringTokenizer(sqlConstraint,
0363:                        " ()'\"=<>!,", true);
0364:                tokenize: while (st.hasMoreTokens()) {
0365:                    String token = st.nextToken(" ()'\"=<>!,");
0366:
0367:                    // String, delimited by single or double quotes.
0368:                    if (token.equals("'") || token.equals("\"")) {
0369:                        tokens.add("'");
0370:                        StringBuilder sb = new StringBuilder();
0371:                        while (true) {
0372:                            String token2 = st.nextToken(token);
0373:                            if (token2.equals(token)) {
0374:                                if (!st.hasMoreTokens()) {
0375:                                    // Token 2 is end delimiter and last token.
0376:                                    tokens.add(sb.toString());
0377:                                    tokens.add("'");
0378:                                    break tokenize;
0379:                                } else {
0380:                                    String token3 = st.nextToken(" ()'\"=<>!,");
0381:                                    if (token3.equals(token)) {
0382:                                        // Token 2 and 3 are escaped delimiter.
0383:                                        sb.append(token);
0384:                                    } else {
0385:                                        // Token 2 is end delimiter, but not last token.
0386:                                        tokens.add(sb.toString());
0387:                                        tokens.add("'");
0388:                                        token = token3;
0389:                                        break;
0390:                                    }
0391:                                }
0392:                            } else {
0393:                                // Token 2 is string.
0394:                                sb.append(token2);
0395:                            }
0396:                        }
0397:                    }
0398:
0399:                    // Add token, but skip white spaces.
0400:                    if (!token.equals(" ")) {
0401:                        tokens.add(token);
0402:                    }
0403:                }
0404:                return tokens;
0405:            }
0406:
0407:            /**
0408:             * Creates <code>StepField</code> corresponding to field indicated by
0409:             * token, of one of the specified steps.
0410:             * <p>
0411:             * A <em>field</em> can be one of these forms:
0412:             * <ul>
0413:             * <li><em>stepalias</em><b>.</b><em>fieldname</em>
0414:             * <li>[<em>stepalias</em><b>.</b><em>fieldname</em>]
0415:             * <li><em>fieldname</em> (only when just one step is specified).
0416:             * <li>[<em>fieldname</em>] (only when just one step is specified).
0417:             * </ul>
0418:             *
0419:             * @param token The token.
0420:             * @param steps The steps.
0421:             * @return The field.
0422:             */
0423:
0424:            public static StepField getField(String token,
0425:                    List<? extends Step> steps) {
0426:                return getField(token, (List<BasicStep>) steps, null);
0427:            }
0428:
0429:            /**
0430:             * Creates <code>StepField</code> corresponding to field indicated by
0431:             * token, of one of the specified steps.
0432:             * <p>
0433:             * A <em>field</em> can be one of these forms:
0434:             * <ul>
0435:             * <li><em>stepalias</em><b>.</b><em>fieldname</em>
0436:             * <li>[<em>stepalias</em><b>.</b><em>fieldname</em>]
0437:             * <li><em>fieldname</em> (only when just one step is specified, or query is an instance of NodeQuery).
0438:             * <li>[<em>fieldname</em>] (only when just one step is specified, or query is an instance of NodeQuery).
0439:             * </ul>
0440:             *
0441:             * @param token The token.
0442:             * @param steps The steps.
0443:             * @param query The used query
0444:             * @return The field.
0445:             * @since MMBase-1.7.1
0446:             */
0447:
0448:            static StepField getField(String token, List<BasicStep> steps,
0449:                    SearchQuery query) {
0450:                BasicStep step = null;
0451:                int bracketOffset = (token.startsWith("[") && token
0452:                        .endsWith("]")) ? 1 : 0;
0453:                int idx = token.indexOf('.');
0454:                if (idx == -1) {
0455:                    if (steps.size() > 1) {
0456:                        if (query != null && query instanceof  NodeQuery) {
0457:                            step = (BasicStep) ((NodeQuery) query)
0458:                                    .getNodeStep();
0459:                            if (step == null) {
0460:                                throw new IllegalArgumentException(
0461:                                        "NodeQuery has no step; Fieldname not prefixed with table alias: \""
0462:                                                + token + "\"");
0463:                            }
0464:                        } else {
0465:                            throw new IllegalArgumentException(
0466:                                    "Fieldname not prefixed with table alias: \""
0467:                                            + token + "\"");
0468:                        }
0469:                    } else {
0470:                        step = steps.get(0);
0471:                    }
0472:                } else {
0473:                    step = getStep(token.substring(bracketOffset, idx), steps);
0474:                }
0475:                MMObjectBuilder builder = step.getBuilder();
0476:                String fieldName;
0477:                if (idx == -1) {
0478:                    fieldName = token.substring(bracketOffset, token.length()
0479:                            - bracketOffset);
0480:                } else {
0481:                    fieldName = token.substring(idx + 1, token.length()
0482:                            - bracketOffset);
0483:                }
0484:
0485:                CoreField coreField = builder.getField(fieldName);
0486:                // maybe the field was already escaped with getAllowedField
0487:                // otherwise it will definitely fail!
0488:                if (coreField == null) {
0489:                    String escapedFieldName = MMBase.getMMBase()
0490:                            .getStorageManagerFactory().getStorageIdentifier(
0491:                                    fieldName).toString();
0492:                    if (!escapedFieldName.equals(fieldName)) {
0493:                        coreField = builder.getField(fieldName);
0494:                        if (coreField == null) {
0495:                            throw new IllegalArgumentException(
0496:                                    "Unknown field (of builder "
0497:                                            + builder.getTableName() + "): \""
0498:                                            + escapedFieldName + "\"");
0499:                        }
0500:                    }
0501:                }
0502:                if (coreField == null) {
0503:                    throw new IllegalArgumentException(
0504:                            "Unknown field (of builder "
0505:                                    + builder.getTableName() + "): \""
0506:                                    + fieldName + "\"");
0507:                }
0508:                BasicStepField field = new BasicStepField(step, coreField);
0509:                return field;
0510:            }
0511:
0512:            /**
0513:             * Finds step by alias.
0514:             *
0515:             * @param alias The alias.
0516:             * @param steps The steps
0517:             * @return The step.
0518:             */
0519:            private static BasicStep getStep(String alias, List<BasicStep> steps) {
0520:                Iterator<BasicStep> iSteps = steps.iterator();
0521:                while (iSteps.hasNext()) {
0522:                    BasicStep step = iSteps.next();
0523:                    String alias2 = step.getAlias();
0524:                    if (alias2 == null) {
0525:                        alias2 = step.getTableName();
0526:                    }
0527:                    if (alias2.equals(alias)) {
0528:                        return step;
0529:                    }
0530:                }
0531:
0532:                // Not found.
0533:                throw new IllegalArgumentException("Unknown table alias: \""
0534:                        + alias + "\"");
0535:            }
0536:
0537:            /** Creates a new instance of ConstraintParser
0538:             * @param query
0539:             */
0540:            public ConstraintParser(SearchQuery query) {
0541:                this .query = query;
0542:                this .steps = query.getSteps();
0543:            }
0544:
0545:            /**
0546:             * Parses <em>SQL-search-condition</em>, and produces a corresponding
0547:             * {@link org.mmbase.storage.search.Constraint Constraint} object.
0548:             * <p>
0549:             * See {@link ConstraintParser above} for the format of a
0550:             * <em>SQL-search-condition</em>.
0551:             *
0552:             * @param sqlConstraint The non-null SQL constraint string.
0553:             * @return The constraint.
0554:             */
0555:            public Constraint toConstraint(String sqlConstraint) {
0556:                Constraint result = null;
0557:                try {
0558:                    ListIterator<String> iTokens = tokenize(sqlConstraint)
0559:                            .listIterator();
0560:                    result = parseCondition(iTokens);
0561:
0562:                    // If this doesn't work, fall back to legacy code.
0563:                } catch (Exception e) {
0564:                    // Log to fallback logger.
0565:                    if (fallbackLog.isServiceEnabled()) {
0566:                        fallbackLog
0567:                                .service(
0568:                                        "Failed to parse Constraint from search condition string: "
0569:                                                + "\n     sqlConstraint = "
0570:                                                + sqlConstraint
0571:                                                + "\n     exception: "
0572:                                                + e.getMessage()
0573:                                                + "\nFalling back to BasicLegacyConstraint...",
0574:                                        e);
0575:                    }
0576:                    String escapedSqlConstraint = convertClauseToDBS(sqlConstraint);
0577:                    if (!validConstraints(escapedSqlConstraint)) {
0578:                        throw new IllegalArgumentException(
0579:                                "Invalid constraints: " + sqlConstraint);
0580:                    }
0581:                    result = new BasicLegacyConstraint(escapedSqlConstraint);
0582:                }
0583:
0584:                if (log.isDebugEnabled()) {
0585:                    log.debug("Parsed constraint \"" + sqlConstraint
0586:                            + "\" to :\n" + result);
0587:                }
0588:                return result;
0589:            }
0590:
0591:            /**
0592:             * Parses a <em>field</em> string, and produces a corresponding
0593:             * <code>StepField</code> object.
0594:             * <p>
0595:             * See {@link ConstraintParser above} for the format of a
0596:             * <em>field</em>
0597:             *
0598:             * @param token The token.
0599:             * @return The field.
0600:             */
0601:            // package visibility!
0602:            StepField getField(String token) {
0603:                return getField(token, (List<BasicStep>) steps, query);
0604:            }
0605:
0606:            /**
0607:             * Parses <em>SQL-search-condition</em> string from list of tokens, and
0608:             * produces a corresponding <code>BasicConstraint</code> object.
0609:             * <p>
0610:             * See {@link ConstraintParser above} for the format of a
0611:             * <em>SQL-search-condition</em>
0612:             *
0613:             * @param iTokens Tokens iterator, must be positioned before the (first)
0614:             *        token representing the condition.
0615:             * @return The constraint.
0616:             */
0617:            // package visibility!
0618:            BasicConstraint parseCondition(ListIterator<String> iTokens) {
0619:                BasicCompositeConstraint composite = null;
0620:                BasicConstraint constraint = null;
0621:                while (iTokens.hasNext()) {
0622:                    boolean inverse = false;
0623:                    String token = iTokens.next();
0624:                    if (token.equalsIgnoreCase("NOT")) {
0625:                        // NOT.
0626:                        inverse = true;
0627:                        token = iTokens.next();
0628:                    }
0629:
0630:                    if (token.equals("(")) {
0631:                        // Start of (simple or composite) constraint
0632:                        // between parenthesis.
0633:                        constraint = parseCondition(iTokens);
0634:                    } else {
0635:                        // Simple condition.
0636:                        iTokens.previous();
0637:                        constraint = parseSimpleCondition(iTokens);
0638:                    }
0639:                    if (inverse) {
0640:                        constraint.setInverse(!constraint.isInverse());
0641:                    }
0642:                    if (composite != null) {
0643:                        composite.addChild(constraint);
0644:                    }
0645:
0646:                    if (iTokens.hasNext()) {
0647:                        token = iTokens.next();
0648:                        if (token.equals(")")) {
0649:                            // Start of (simple or composite) constraint
0650:                            // between parenthesis.
0651:                            break;
0652:                        }
0653:                        int logicalOperator = 0;
0654:                        if (token.equalsIgnoreCase("OR")) {
0655:                            logicalOperator = CompositeConstraint.LOGICAL_OR;
0656:                        } else if (token.equalsIgnoreCase("AND")) {
0657:                            logicalOperator = CompositeConstraint.LOGICAL_AND;
0658:                        } else {
0659:                            throw new IllegalArgumentException(
0660:                                    "Unexpected token (expected \"AND\" or \"OR\"): \""
0661:                                            + token + "\"");
0662:                        }
0663:                        if (composite == null) {
0664:                            composite = new BasicCompositeConstraint(
0665:                                    logicalOperator).addChild(constraint);
0666:                        }
0667:
0668:                        if (composite.getLogicalOperator() != logicalOperator) {
0669:                            composite = new BasicCompositeConstraint(
0670:                                    logicalOperator).addChild(composite);
0671:                        }
0672:
0673:                        if (!iTokens.hasNext()) {
0674:                            throw new IllegalArgumentException(
0675:                                    "Unexpected end of tokens after \"" + token
0676:                                            + "\"");
0677:                        }
0678:                    }
0679:                }
0680:                if (composite != null) {
0681:                    return composite;
0682:                } else {
0683:                    return constraint;
0684:                }
0685:            }
0686:
0687:            /**
0688:             * Parses a <em>simple-SQL-search-condition</em> string from list of tokens,
0689:             * and produces a corresponding <code>BasicConstraint</code> object.
0690:             * <p>
0691:             * See {@link ConstraintParser above} for the format of a
0692:             * <em>simple-SQL-search-condition</em>
0693:             *
0694:             * @param iTokens Tokens iterator, must be positioned before the (first)
0695:             *        token representing the condition.
0696:             * @return The constraint.
0697:             */
0698:            // package visibility!
0699:            BasicConstraint parseSimpleCondition(ListIterator<String> iTokens) {
0700:                BasicConstraint result = null;
0701:
0702:                String token = iTokens.next();
0703:                if (token.equalsIgnoreCase("StringSearch")) {
0704:                    // StringSearch constraint.
0705:                    return parseStringSearchCondition(iTokens);
0706:                }
0707:
0708:                String function = token.toUpperCase();
0709:                if (function.equals("LOWER") || function.equals("UPPER")) {
0710:                    if (iTokens.next().equals("(")) {
0711:                        // Function.
0712:                        token = iTokens.next();
0713:                    } else {
0714:                        // Not a function.
0715:                        iTokens.previous();
0716:                        function = null;
0717:                    }
0718:                } else {
0719:                    function = null;
0720:                }
0721:
0722:                StepField field = getField(token);
0723:
0724:                token = iTokens.next();
0725:                if (function != null) {
0726:                    if (!token.equals(")")) {
0727:                        throw new IllegalArgumentException(
0728:                                "Unexpected token (expected \")\"): \"" + token
0729:                                        + "\"");
0730:                    }
0731:                    token = iTokens.next();
0732:                }
0733:
0734:                boolean inverse = false;
0735:                if (token.equalsIgnoreCase("NOT")) {
0736:                    // NOT LIKE/NOT IN/NOT BETWEEN
0737:                    inverse = true;
0738:                    token = iTokens.next();
0739:                    if (!token.equalsIgnoreCase("LIKE")
0740:                            && !token.equalsIgnoreCase("IN")
0741:                            && !token.equalsIgnoreCase("BETWEEN")) {
0742:                        throw new IllegalArgumentException(
0743:                                "Unexpected token (expected "
0744:                                        + "\"LIKE\" OR \"IN\" OR \"BETWEEN\"): \""
0745:                                        + token + "\"");
0746:                    }
0747:                }
0748:
0749:                if (token.equalsIgnoreCase("LIKE")) {
0750:                    // LIKE 'value'
0751:                    String value = (String) parseValue(iTokens, field);
0752:                    boolean caseSensitive = true;
0753:                    if (function != null) {
0754:                        if ((function.equals("LOWER") && value.equals(value
0755:                                .toLowerCase()))
0756:                                || (function.equals("UPPER") && value
0757:                                        .equals(value.toUpperCase()))) {
0758:                            caseSensitive = false;
0759:                        }
0760:                    }
0761:                    result = new BasicFieldValueConstraint(field, value)
0762:                            .setOperator(FieldCompareConstraint.LIKE)
0763:                            .setCaseSensitive(caseSensitive);
0764:
0765:                } else if (token.equalsIgnoreCase("IS")) {
0766:                    // IS [NOT] NULL
0767:                    token = iTokens.next();
0768:                    if (token.equalsIgnoreCase("NOT")) {
0769:                        inverse = !inverse;
0770:                        token = iTokens.next();
0771:                    }
0772:                    if (token.equalsIgnoreCase("NULL")) {
0773:                        result = new BasicFieldNullConstraint(field);
0774:                    } else {
0775:                        throw new IllegalArgumentException(
0776:                                "Unexpected token (expected \"NULL\"): \""
0777:                                        + token + "\"");
0778:                    }
0779:                } else if (token.equalsIgnoreCase("IN")) {
0780:                    // IN (value1, value2, ...)
0781:                    String separator = iTokens.next();
0782:                    if (!separator.equals("(")) {
0783:                        throw new IllegalArgumentException(
0784:                                "Unexpected token (expected \"(\"): \""
0785:                                        + separator + "\"");
0786:                    }
0787:                    BasicFieldValueInConstraint fieldValueInConstraint = new BasicFieldValueInConstraint(
0788:                            field);
0789:                    if (!iTokens.next().equals(")")) {
0790:
0791:                        iTokens.previous();
0792:                        do {
0793:                            Object value = parseValue(iTokens, field);
0794:                            separator = iTokens.next();
0795:                            if (separator.equals(",") || separator.equals(")")) {
0796:                                fieldValueInConstraint.addValue(value);
0797:                            } else {
0798:                                throw new IllegalArgumentException(
0799:                                        "Unexpected token (expected \",\" or \")\"): \""
0800:                                                + separator + "\"");
0801:                            }
0802:                        } while (separator.equals(","));
0803:                    }
0804:                    result = fieldValueInConstraint;
0805:
0806:                } else if (token.equalsIgnoreCase("BETWEEN")) {
0807:                    // BETWEEN value1 AND value2
0808:                    Object value1 = parseValue(iTokens, field);
0809:                    String separator = iTokens.next();
0810:                    if (!separator.equals("AND")) {
0811:                        throw new IllegalArgumentException(
0812:                                "Unexpected token (expected \"AND\"): \""
0813:                                        + separator + "\"");
0814:                    }
0815:                    Object value2 = parseValue(iTokens, field);
0816:                    boolean caseSensitive = true;
0817:                    if (function != null && value1 instanceof  String
0818:                            && value2 instanceof  String) {
0819:                        String strValue1 = (String) value1;
0820:                        String strValue2 = (String) value2;
0821:                        if ((function.equals("LOWER")
0822:                                && strValue1.equals(strValue1.toLowerCase()) && strValue2
0823:                                .equals(strValue2.toLowerCase()))
0824:                                || (function.equals("UPPER")
0825:                                        && strValue1.equals(strValue1
0826:                                                .toUpperCase()) && strValue2
0827:                                        .equals(strValue2.toUpperCase()))) {
0828:                            caseSensitive = false;
0829:                        }
0830:                    }
0831:
0832:                    BasicFieldValueBetweenConstraint fieldValueBetweenConstraint = (BasicFieldValueBetweenConstraint) new BasicFieldValueBetweenConstraint(
0833:                            field, value1, value2)
0834:                            .setCaseSensitive(caseSensitive);
0835:                    result = fieldValueBetweenConstraint;
0836:
0837:                } else if (token.equals("=")) {
0838:                    token = iTokens.next();
0839:                    if (token.equals("=")) {
0840:                        try {
0841:                            // == value
0842:                            Object value = parseValue(iTokens, field);
0843:                            result = new BasicFieldValueConstraint(field, value)
0844:                                    .setOperator(FieldCompareConstraint.EQUAL);
0845:                        } catch (NumberFormatException e) {
0846:                            // == field2
0847:                            iTokens.previous();
0848:                            token = iTokens.next();
0849:                            StepField field2 = getField(token);
0850:                            result = new BasicCompareFieldsConstraint(field,
0851:                                    field2)
0852:                                    .setOperator(FieldCompareConstraint.EQUAL);
0853:                        }
0854:                    } else {
0855:                        iTokens.previous();
0856:                        try {
0857:                            // = value
0858:                            Object value = parseValue(iTokens, field);
0859:                            boolean caseSensitive = true;
0860:                            if (function != null && value instanceof  String) {
0861:                                String strValue = (String) value;
0862:                                if ((function.equals("LOWER") && strValue
0863:                                        .equals(strValue.toLowerCase()))
0864:                                        || (function.equals("UPPER") && strValue
0865:                                                .equals(strValue.toUpperCase()))) {
0866:                                    caseSensitive = false;
0867:                                }
0868:                            }
0869:                            result = new BasicFieldValueConstraint(field, value)
0870:                                    .setOperator(FieldCompareConstraint.EQUAL)
0871:                                    .setCaseSensitive(caseSensitive);
0872:                        } catch (NumberFormatException e) {
0873:                            // = field2
0874:                            iTokens.previous();
0875:                            token = iTokens.next();
0876:                            StepField field2 = getField(token);
0877:                            result = new BasicCompareFieldsConstraint(field,
0878:                                    field2)
0879:                                    .setOperator(FieldCompareConstraint.EQUAL);
0880:                        }
0881:                    }
0882:                } else if (token.equals("<")) {
0883:                    token = iTokens.next();
0884:                    if (token.equals("=")) {
0885:                        try {
0886:                            // <= value
0887:                            Object value = parseValue(iTokens, field);
0888:                            result = new BasicFieldValueConstraint(field, value)
0889:                                    .setOperator(FieldCompareConstraint.LESS_EQUAL);
0890:                        } catch (NumberFormatException e) {
0891:                            // <= field2
0892:                            iTokens.previous();
0893:                            token = iTokens.next();
0894:                            StepField field2 = getField(token);
0895:                            result = new BasicCompareFieldsConstraint(field,
0896:                                    field2)
0897:                                    .setOperator(FieldCompareConstraint.LESS_EQUAL);
0898:                        }
0899:                    } else if (token.equals(">")) {
0900:                        try {
0901:                            // <> value
0902:                            Object value = parseValue(iTokens, field);
0903:                            result = new BasicFieldValueConstraint(field, value)
0904:                                    .setOperator(FieldCompareConstraint.NOT_EQUAL);
0905:                        } catch (NumberFormatException e) {
0906:                            // <> field2
0907:                            iTokens.previous();
0908:                            token = iTokens.next();
0909:                            StepField field2 = getField(token);
0910:                            result = new BasicCompareFieldsConstraint(field,
0911:                                    field2)
0912:                                    .setOperator(FieldCompareConstraint.NOT_EQUAL);
0913:                        }
0914:                    } else {
0915:                        try {
0916:                            // < value
0917:                            iTokens.previous();
0918:                            Object value = parseValue(iTokens, field);
0919:                            result = new BasicFieldValueConstraint(field, value)
0920:                                    .setOperator(FieldCompareConstraint.LESS);
0921:                        } catch (NumberFormatException e) {
0922:                            // < field2
0923:                            iTokens.previous();
0924:                            token = iTokens.next();
0925:                            StepField field2 = getField(token);
0926:                            result = new BasicCompareFieldsConstraint(field,
0927:                                    field2)
0928:                                    .setOperator(FieldCompareConstraint.LESS);
0929:                        }
0930:                    }
0931:                } else if (token.equals(">")) {
0932:                    token = iTokens.next();
0933:                    if (token.equals("=")) {
0934:                        try {
0935:                            // >= value
0936:                            Object value = parseValue(iTokens, field);
0937:                            result = new BasicFieldValueConstraint(field, value)
0938:                                    .setOperator(FieldCompareConstraint.GREATER_EQUAL);
0939:                        } catch (NumberFormatException e) {
0940:                            // >= field2
0941:                            iTokens.previous();
0942:                            token = iTokens.next();
0943:                            StepField field2 = getField(token);
0944:                            result = new BasicCompareFieldsConstraint(field,
0945:                                    field2)
0946:                                    .setOperator(FieldCompareConstraint.GREATER_EQUAL);
0947:                        }
0948:                    } else {
0949:                        try {
0950:                            // > value
0951:                            iTokens.previous();
0952:                            Object value = parseValue(iTokens, field);
0953:                            result = new BasicFieldValueConstraint(field, value)
0954:                                    .setOperator(FieldCompareConstraint.GREATER);
0955:                        } catch (NumberFormatException e) {
0956:                            // > field2
0957:                            iTokens.previous();
0958:                            token = iTokens.next();
0959:                            StepField field2 = getField(token);
0960:                            result = new BasicCompareFieldsConstraint(field,
0961:                                    field2)
0962:                                    .setOperator(FieldCompareConstraint.GREATER);
0963:                        }
0964:                    }
0965:                } else if (token.equals("!")) {
0966:                    token = iTokens.next();
0967:                    if (token.equals("=")) {
0968:                        try {
0969:                            // != value
0970:                            Object value = parseValue(iTokens, field);
0971:                            result = new BasicFieldValueConstraint(field, value)
0972:                                    .setOperator(FieldCompareConstraint.NOT_EQUAL);
0973:                        } catch (NumberFormatException e) {
0974:                            // != field2
0975:                            iTokens.previous();
0976:                            token = iTokens.next();
0977:                            StepField field2 = getField(token);
0978:                            result = new BasicCompareFieldsConstraint(field,
0979:                                    field2)
0980:                                    .setOperator(FieldCompareConstraint.NOT_EQUAL);
0981:                        }
0982:                    } else {
0983:                        throw new IllegalArgumentException(
0984:                                "Unexpected token (expected \"=\"): \"" + token
0985:                                        + "\"");
0986:                    }
0987:                } else {
0988:                    throw new IllegalArgumentException("Unexpected token: \""
0989:                            + token + "\"");
0990:                }
0991:
0992:                if (inverse) {
0993:                    result.setInverse(!result.isInverse());
0994:                }
0995:
0996:                return result;
0997:            }
0998:
0999:            /**
1000:             * Parses a <em>stringsearch-condition</em> string from list of tokens,
1001:             * and produces a corresponding <code>BasicStringSearchConstraint</code> object.
1002:             * <p>
1003:             * See {@link ConstraintParser above} for the format of a
1004:             * <em>stringsearch-condition</em>
1005:             *
1006:             * @param iTokens Tokens iterator, must be positioned after the (first)
1007:             *        token representing the condition (e.g. after "StringSearch").
1008:             * @return The constraint.
1009:             */
1010:            private BasicStringSearchConstraint parseStringSearchCondition(
1011:                    ListIterator<String> iTokens) {
1012:
1013:                String token = iTokens.next();
1014:                if (!token.equals("(")) {
1015:                    throw new IllegalArgumentException(
1016:                            "Unexpected token (expected \"(\"): \"" + token
1017:                                    + "\"");
1018:                }
1019:
1020:                // Field
1021:                token = iTokens.next();
1022:                StepField field = getField(token);
1023:
1024:                token = iTokens.next();
1025:                if (!token.equals(",")) {
1026:                    throw new IllegalArgumentException(
1027:                            "Unexpected token (expected \",\"): \"" + token
1028:                                    + "\"");
1029:                }
1030:
1031:                // Searchtype
1032:                int searchType;
1033:                token = iTokens.next();
1034:                if (token.equalsIgnoreCase("PHRASE")) {
1035:                    searchType = StringSearchConstraint.SEARCH_TYPE_PHRASE_ORIENTED;
1036:                } else if (token.equalsIgnoreCase("PROXIMITY")) {
1037:                    searchType = StringSearchConstraint.SEARCH_TYPE_PROXIMITY_ORIENTED;
1038:                } else if (token.equalsIgnoreCase("WORD")) {
1039:                    searchType = StringSearchConstraint.SEARCH_TYPE_WORD_ORIENTED;
1040:                } else {
1041:                    throw new IllegalArgumentException(
1042:                            "Invalid searchtype (expected \"PHRASE\", \"PROXIMITY\" or \"WORD\": \""
1043:                                    + token + "\"");
1044:                }
1045:
1046:                token = iTokens.next();
1047:                if (!token.equals(",")) {
1048:                    throw new IllegalArgumentException(
1049:                            "Unexpected token (expected \",\"): \"" + token
1050:                                    + "\"");
1051:                }
1052:
1053:                // Matchtype
1054:                int matchType;
1055:                token = iTokens.next();
1056:                if (token.equalsIgnoreCase("FUZZY")) {
1057:                    matchType = StringSearchConstraint.MATCH_TYPE_FUZZY;
1058:                } else if (token.equalsIgnoreCase("LITERAL")) {
1059:                    matchType = StringSearchConstraint.MATCH_TYPE_LITERAL;
1060:                } else if (token.equalsIgnoreCase("SYNONYM")) {
1061:                    matchType = StringSearchConstraint.MATCH_TYPE_SYNONYM;
1062:                } else {
1063:                    throw new IllegalArgumentException(
1064:                            "Invalid matchtype (expected \"FUZZY\", \"LITERAL\" or \"SYNONYM\": \""
1065:                                    + token + "\"");
1066:                }
1067:
1068:                token = iTokens.next();
1069:                if (!token.equals(",")) {
1070:                    throw new IllegalArgumentException(
1071:                            "Unexpected token (expected \",\"): \"" + token
1072:                                    + "\"");
1073:                }
1074:
1075:                // SearchTerms
1076:                String searchTerms;
1077:                token = iTokens.next();
1078:                if (!token.equals("'")) {
1079:                    throw new IllegalArgumentException(
1080:                            "Unexpected token (expected \"'\" or \"\"\"): \""
1081:                                    + token + "\"");
1082:                }
1083:                searchTerms = iTokens.next();
1084:                token = iTokens.next();
1085:                if (!token.equals("'")) {
1086:                    throw new IllegalArgumentException(
1087:                            "Unexpected token (expected \"'\" or \"\"\"): \""
1088:                                    + token + "\"");
1089:                }
1090:
1091:                token = iTokens.next();
1092:                if (!token.equals(",")) {
1093:                    throw new IllegalArgumentException(
1094:                            "Unexpected token (expected \",\"): \"" + token
1095:                                    + "\"");
1096:                }
1097:
1098:                // CaseSensitive property
1099:                boolean caseSensitive;
1100:                token = iTokens.next();
1101:                if (token.equalsIgnoreCase("true")) {
1102:                    caseSensitive = true;
1103:                } else if (token.equalsIgnoreCase("false")) {
1104:                    caseSensitive = false;
1105:                } else {
1106:                    throw new IllegalArgumentException(
1107:                            "Invalid caseSensitive value (expected \"true\" "
1108:                                    + "or \"false\": \"" + token + "\"");
1109:                }
1110:
1111:                token = iTokens.next();
1112:                if (!token.equals(")")) {
1113:                    throw new IllegalArgumentException(
1114:                            "Unexpected token (expected \")\"): \"" + token
1115:                                    + "\"");
1116:                }
1117:
1118:                BasicStringSearchConstraint result = (BasicStringSearchConstraint) new BasicStringSearchConstraint(
1119:                        field, searchType, matchType, searchTerms)
1120:                        .setCaseSensitive(caseSensitive);
1121:
1122:                // .set(parametername, value)
1123:                while (iTokens.hasNext()) {
1124:                    token = iTokens.next();
1125:                    if (!token.equalsIgnoreCase(".set")) {
1126:                        iTokens.previous();
1127:                        break;
1128:                    }
1129:
1130:                    token = iTokens.next();
1131:                    if (!token.equals("(")) {
1132:                        throw new IllegalArgumentException(
1133:                                "Unexpected token (expected \"(\"): \"" + token
1134:                                        + "\"");
1135:                    }
1136:
1137:                    String parameterName = iTokens.next();
1138:
1139:                    token = iTokens.next();
1140:                    if (!token.equals(",")) {
1141:                        throw new IllegalArgumentException(
1142:                                "Unexpected token (expected \",\"): \"" + token
1143:                                        + "\"");
1144:                    }
1145:
1146:                    String parameterValue = iTokens.next();
1147:
1148:                    token = iTokens.next();
1149:                    if (!token.equals(")")) {
1150:                        throw new IllegalArgumentException(
1151:                                "Unexpected token (expected \")\"): \"" + token
1152:                                        + "\"");
1153:                    }
1154:
1155:                    if (parameterName.equalsIgnoreCase("FUZZINESS")) {
1156:                        result.setParameter(
1157:                                StringSearchConstraint.PARAM_FUZZINESS, Float
1158:                                        .valueOf(parameterValue));
1159:                    } else if (parameterName
1160:                            .equalsIgnoreCase("PROXIMITY_LIMIT")) {
1161:                        result.setParameter(
1162:                                StringSearchConstraint.PARAM_PROXIMITY_LIMIT,
1163:                                parameterValue);
1164:                    } else {
1165:                        throw new IllegalArgumentException(
1166:                                "Invalid parameter name (expected \"FUZZINESS\" or \"PROXIMITY\": \""
1167:                                        + parameterName + "\"");
1168:                    }
1169:                }
1170:
1171:                return result;
1172:            }
1173:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.