Source Code Cross Referenced for RecordParser.java in  » Web-Framework » makumba » org » makumba » providers » datadefinition » makumba » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Framework » makumba » org.makumba.providers.datadefinition.makumba 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // /////////////////////////////
0002:        //  Makumba, Makumba tag library
0003:        //  Copyright (C) 2000-2003 http://www.makumba.org
0004:        //
0005:        //  This library is free software; you can redistribute it and/or
0006:        //  modify it under the terms of the GNU Lesser General Public
0007:        //  License as published by the Free Software Foundation; either
0008:        //  version 2.1 of the License, or (at your option) any later version.
0009:        //
0010:        //  This library is distributed in the hope that it will be useful,
0011:        //  but WITHOUT ANY WARRANTY; without even the implied warranty of
0012:        //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0013:        //  Lesser General Public License for more details.
0014:        //
0015:        //  You should have received a copy of the GNU Lesser General Public
0016:        //  License along with this library; if not, write to the Free Software
0017:        //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0018:        //
0019:        //  -------------
0020:        //  $Id: RecordParser.java 2079 2007-11-20 22:43:24Z cristian_bogdan $
0021:        //  $Name$
0022:        /////////////////////////////////////
0023:
0024:        package org.makumba.providers.datadefinition.makumba;
0025:
0026:        import java.io.BufferedReader;
0027:        import java.io.File;
0028:        import java.io.IOException;
0029:        import java.io.InputStream;
0030:        import java.io.InputStreamReader;
0031:        import java.io.StringReader;
0032:        import java.util.ArrayList;
0033:        import java.util.Enumeration;
0034:        import java.util.HashMap;
0035:        import java.util.Properties;
0036:        import java.util.Vector;
0037:        import java.util.jar.JarEntry;
0038:        import java.util.regex.Matcher;
0039:        import java.util.regex.Pattern;
0040:
0041:        import org.makumba.DataDefinition;
0042:        import org.makumba.DataDefinitionParseError;
0043:        import org.makumba.FieldDefinition;
0044:        import org.makumba.MakumbaError;
0045:        import org.makumba.ValidationDefinitionParseError;
0046:        import org.makumba.ValidationRule;
0047:        import org.makumba.commons.OrderedProperties;
0048:        import org.makumba.commons.RegExpUtils;
0049:        import org.makumba.commons.ReservedKeywords;
0050:        import org.makumba.commons.StringUtils;
0051:        import org.makumba.providers.DataDefinitionProvider;
0052:        import org.makumba.providers.datadefinition.makumba.validation.BasicValidationRule;
0053:        import org.makumba.providers.datadefinition.makumba.validation.ComparisonValidationRule;
0054:        import org.makumba.providers.datadefinition.makumba.validation.NumberRangeValidationRule;
0055:        import org.makumba.providers.datadefinition.makumba.validation.RangeValidationRule;
0056:        import org.makumba.providers.datadefinition.makumba.validation.RegExpValidationRule;
0057:        import org.makumba.providers.datadefinition.makumba.validation.StringLengthValidationRule;
0058:
0059:        public class RecordParser {
0060:            public static final String VALIDATION_INDICATOR = "%";
0061:
0062:            // regular expressions for multi-field unique keys //
0063:            public static final String multiUniqueRegExpElement = RegExpUtils.LineWhitespaces
0064:                    + "("
0065:                    + RegExpUtils.fieldName
0066:                    + ")"
0067:                    + RegExpUtils.LineWhitespaces;
0068:
0069:            public static final String multiUniqueRegExpElementRepeatment = "(?:"
0070:                    + RegExpUtils.LineWhitespaces
0071:                    + ","
0072:                    + "(?:"
0073:                    + multiUniqueRegExpElement + "))*";
0074:
0075:            public static final String multiUniqueRegExp = RegExpUtils.LineWhitespaces
0076:                    + "(?:"
0077:                    + multiUniqueRegExpElement
0078:                    + ")"
0079:                    + multiUniqueRegExpElementRepeatment
0080:                    + RegExpUtils.LineWhitespaces;
0081:
0082:            public static final Pattern multiUniquePattern = Pattern
0083:                    .compile(multiUniqueRegExp);
0084:
0085:            // regular expressions for validation definitions //
0086:            public static final String validationDefinitionRegExp = RegExpUtils.LineWhitespaces
0087:                    + "("
0088:                    + RegExpUtils.fieldName
0089:                    + ")"
0090:                    + RegExpUtils.LineWhitespaces
0091:                    + VALIDATION_INDICATOR
0092:                    + "(matches|length|range|compare|unique)"
0093:                    + RegExpUtils.LineWhitespaces
0094:                    + "="
0095:                    + RegExpUtils.LineWhitespaces
0096:                    + "(.+)"
0097:                    + RegExpUtils.LineWhitespaces
0098:                    + ":"
0099:                    + RegExpUtils.LineWhitespaces + ".+";
0100:
0101:            public static final Pattern validationDefinitionPattern = Pattern
0102:                    .compile(validationDefinitionRegExp);
0103:
0104:            // regular expressions for function definitions //
0105:            /**
0106:             * defines all possible types. <br>
0107:             * FIXME: maybe this shall be move to {@link FieldDefinition}?
0108:             */
0109:            public static final String funcDefParamTypeRegExp = "(char|char\\[\\]|int|real|date|intEnum|charEnum|text|binary|ptr|set|setIntEnum|setCharEnum)";
0110:
0111:            /** defines "int a" or "int 5". */
0112:            public static final String funcDefParamRegExp = funcDefParamTypeRegExp
0113:                    + RegExpUtils.minOneLineWhitespace
0114:                    + "(\\d+|"
0115:                    + RegExpUtils.fieldName + ")";
0116:
0117:            /** treats (int a, char b, ...) */
0118:            public static final String funcDefParamRepeatRegExp = "\\((?:"
0119:                    + "(?:" + funcDefParamRegExp + ")" + "(?:"
0120:                    + RegExpUtils.LineWhitespaces + ","
0121:                    + RegExpUtils.LineWhitespaces + funcDefParamRegExp + ")*"
0122:                    + RegExpUtils.LineWhitespaces + ")?\\)";
0123:
0124:            /**
0125:             * treats function(params) = queryFragment : errorMessage.<br>
0126:             * FIXME: this regexp always produces at least 4 groups for the parameters, which get the value of null if there are
0127:             * no params --> would be good to remove this.
0128:             */
0129:            public static final String funcDefRegExp = "("
0130:                    + RegExpUtils.fieldName + ")" + funcDefParamRepeatRegExp
0131:                    + RegExpUtils.LineWhitespaces + "="
0132:                    + RegExpUtils.LineWhitespaces + "(.[^:]+)"
0133:                    + RegExpUtils.LineWhitespaces + "(?::"
0134:                    + RegExpUtils.LineWhitespaces + "(.*))?";
0135:
0136:            public static final Pattern funcDefPattern = Pattern
0137:                    .compile(funcDefRegExp);
0138:
0139:            OrderedProperties text;
0140:
0141:            OrderedProperties fields = new OrderedProperties();
0142:
0143:            OrderedProperties subfields = new OrderedProperties();
0144:
0145:            DataDefinitionParseError mpe;
0146:
0147:            Properties definedTypes;
0148:
0149:            DataDefinition dd;
0150:
0151:            // moved from ptrOneParser
0152:            HashMap<String, RecordParser> ptrOne_RecordParsers = new HashMap<String, RecordParser>();
0153:
0154:            // moved from setParser
0155:            HashMap<String, DataDefinition> setParser_settbls = new HashMap<String, DataDefinition>();
0156:
0157:            // moved from subtableParser
0158:            HashMap<String, DataDefinition> subtableParser_subtables = new HashMap<String, DataDefinition>();
0159:
0160:            HashMap<String, DataDefinition> subtableParser_here = new HashMap<String, DataDefinition>();
0161:
0162:            private ArrayList<String> unparsedValidationDefinitions = new ArrayList<String>();
0163:
0164:            public static boolean isValidationRule(String s) {
0165:                return validationDefinitionPattern.matcher(s).matches();
0166:            }
0167:
0168:            public static boolean isFunction(String s) {
0169:                return funcDefPattern.matcher(s).matches();
0170:            }
0171:
0172:            RecordParser() {
0173:                definedTypes = new Properties();
0174:            }
0175:
0176:            // for parsing of subtalbes
0177:            RecordParser(RecordInfo dd, RecordParser rp) {
0178:                this .dd = dd;
0179:                text = new OrderedProperties();
0180:                definedTypes = rp.definedTypes;
0181:                mpe = rp.mpe;
0182:            }
0183:
0184:            void parse(RecordInfo dd) {
0185:                this .dd = dd;
0186:                text = new OrderedProperties();
0187:                mpe = new DataDefinitionParseError();
0188:
0189:                try {
0190:                    read(text, dd.origin);
0191:                } catch (IOException e) {
0192:                    throw fail(e);
0193:                }
0194:                try {
0195:                    // make the default pointers resulted from the table name
0196:                    dd.addStandardFields(dd.name.substring(dd.name
0197:                            .lastIndexOf('.') + 1));
0198:                    parse();
0199:                } catch (RuntimeException e) {
0200:                    throw new MakumbaError(e,
0201:                            "Internal error in parser while parsing "
0202:                                    + dd.getName());
0203:                }
0204:                if (!mpe.isSingle() && !(dd.getParentField() != null))
0205:                    throw mpe;
0206:            }
0207:
0208:            DataDefinition parse(java.net.URL u, String path) {
0209:                dd = new RecordInfo(u, path);
0210:                parse((RecordInfo) dd);
0211:                return dd;
0212:            }
0213:
0214:            RecordInfo parse(String txt) {
0215:                dd = new RecordInfo();
0216:                text = new OrderedProperties();
0217:                mpe = new DataDefinitionParseError();
0218:
0219:                try {
0220:                    read(text, txt);
0221:                } catch (IOException e) {
0222:                    throw fail(e);
0223:                }
0224:                try {
0225:                    // make the default pointers resulted from the table name
0226:                    ((RecordInfo) dd).addStandardFields(dd.getName().substring(
0227:                            dd.getName().lastIndexOf('.') + 1));
0228:                    parse();
0229:                } catch (RuntimeException e) {
0230:                    throw new MakumbaError(e,
0231:                            "Internal error in parser while parsing "
0232:                                    + dd.getName());
0233:                }
0234:                if (!mpe.isSingle() && dd.getParentField() == null)
0235:                    throw mpe;
0236:
0237:                return (RecordInfo) dd;
0238:            }
0239:
0240:            void parse() {
0241:                // include all the files and add them to the text, delete the
0242:                // !include command
0243:                solveIncludes();
0244:
0245:                // put fields in the fields table, subfields in subfields
0246:                separateFields();
0247:
0248:                // determine the title field, delete !title
0249:                setTitle();
0250:
0251:                // read predefined types, delete all !type.*
0252:                readTypes();
0253:
0254:                // commands should be finished at this point
0255:                if (text.size() != 0)
0256:                    mpe.add(fail("unrecognized commands", text.toString()));
0257:
0258:                // make a FieldParser for each field, let it parse and substitute
0259:                // itself
0260:                treatMyFields();
0261:
0262:                // send info from the subfield table to the subfields
0263:                configSubfields();
0264:
0265:                // call solveAll() on all subfields
0266:                treatSubfields();
0267:
0268:                // parse validation definition
0269:                parseValidationDefinition();
0270:
0271:                // after all fields are processed, process the multi field indices & check for field existance
0272:                checkMultipleUniqueFields();
0273:
0274:            }
0275:
0276:            /** Check whether all fields used in multiple uniqueness checks are defined in the data definition. */
0277:            private void checkMultipleUniqueFields() {
0278:                for (int i = 0; i < dd.getMultiFieldUniqueKeys().length; i++) {
0279:                    DataDefinition.MultipleUniqueKeyDefinition multiUniqueKeyDefinition = (DataDefinition.MultipleUniqueKeyDefinition) dd
0280:                            .getMultiFieldUniqueKeys()[i];
0281:                    for (int j = 0; j < multiUniqueKeyDefinition.getFields().length; j++) {
0282:                        String fieldName = multiUniqueKeyDefinition.getFields()[j];
0283:
0284:                        // check for potential sub-fields
0285:                        DataDefinition checkedDataDef = dd;
0286:                        int indexOf = -1;
0287:                        while ((indexOf = fieldName.indexOf(".")) != -1) {
0288:                            // we have a sub-record-field
0289:                            String subFieldName = fieldName.substring(0,
0290:                                    indexOf);
0291:                            fieldName = fieldName.substring(indexOf + 1);
0292:                            checkedDataDef = checkedDataDef.getFieldDefinition(
0293:                                    subFieldName).getPointedType();
0294:                        }
0295:                        if (checkedDataDef.getFieldDefinition(fieldName) == null) {
0296:                            mpe.add(new DataDefinitionParseError(dd.getName(),
0297:                                    "Unique index contains an unknown field: "
0298:                                            + fieldName,
0299:                                    multiUniqueKeyDefinition.getLine()));
0300:                        } else if (checkedDataDef != dd) {
0301:                            multiUniqueKeyDefinition.setKeyOverSubfield(true);
0302:                        }
0303:                    }
0304:                }
0305:            }
0306:
0307:            void separateFields() {
0308:                for (Enumeration e = text.keys(); e.hasMoreElements();) {
0309:                    String k = (String) e.nextElement();
0310:                    if (k.indexOf('!') == 0)
0311:                        continue;
0312:
0313:                    if (k.indexOf("->") == -1)
0314:                        fields.putLast(k, text.getOriginal(k), text.remove(k));
0315:                    else
0316:                        subfields.putLast(k, text.getOriginal(k), text
0317:                                .remove(k));
0318:                }
0319:            }
0320:
0321:            void setTitle() {
0322:                String origCmd = (String) text.getOriginal("!title");
0323:                String ttl = (String) text.remove("!title");
0324:                String ttlt = null;
0325:                if (ttl != null) {
0326:                    if (fields.get(ttlt = ttl.trim()) == null) {
0327:                        mpe.add(fail("no such field for title", makeLine(
0328:                                origCmd, ttl)));
0329:                        return;
0330:                    }
0331:                } else if (fields.get("name") != null)
0332:                    ttlt = "name";
0333:                else
0334:                // if there are any relations, we skip their fields as
0335:                // titles...
0336:                if (fields.size() > 0)
0337:                    ttlt = fields.keyAt(0);
0338:                ((RecordInfo) dd).title = ttlt;
0339:            }
0340:
0341:            static java.net.URL getResource(String s) {
0342:                return org.makumba.commons.ClassResource.get(s);
0343:            }
0344:
0345:            static public java.net.URL findDataDefinition(String s, String ext) {
0346:                // must specify a filename, not a directory (or package), see bug 173
0347:                java.net.URL u = findDataDefinitionOrDirectory(s, ext);
0348:                if (u != null
0349:                        && (s.endsWith("/") || getResource(s + '/') != null))
0350:                    return null;
0351:                return u;
0352:            }
0353:
0354:            static public java.net.URL findDataDefinitionOrDirectory(String s,
0355:                    String ext) {
0356:                java.net.URL u = null;
0357:                if (s.startsWith("/"))
0358:                    s = s.substring(1);
0359:                if (s.endsWith(".") || s.endsWith("//"))
0360:                    return null;
0361:                u = getResource(s.replace('.', '/') + "." + ext);
0362:                if (u == null) {
0363:                    u = getResource("dataDefinitions/" + s.replace('.', '/')
0364:                            + "." + ext);
0365:                    if (u == null) {
0366:                        u = getResource("dataDefinitions/"
0367:                                + s.replace('.', '/'));
0368:                        if (u == null) {
0369:                            u = getResource(s.replace('.', '/'));
0370:                        }
0371:                    }
0372:                }
0373:                return u;
0374:            }
0375:
0376:            void solveIncludes() {
0377:                int line = 0;
0378:                OrderedProperties inclText;
0379:                Vector<String> overridenFields = new Vector<String>();
0380:
0381:                for (Enumeration e = text.keys(); e.hasMoreElements(); line++) {
0382:                    String st = (String) e.nextElement();
0383:
0384:                    if (st.startsWith("!include")) {
0385:                        String ok = text.getOriginal(st);
0386:                        String incl = (String) text.remove(st);
0387:                        line--;
0388:                        String s = incl.trim();
0389:                        java.net.URL u = findDataDefinition(s, "idd");
0390:                        // String n = "." + dd.getName();
0391:                        // if(u==null && s.indexOf('.')==-1)
0392:                        // u=findTable(n.substring(1, n.lastIndexOf('.')+1));
0393:
0394:                        if (u == null) {
0395:                            mpe.add(fail("could not find include file " + s, ok
0396:                                    + "=" + incl));
0397:                            return;
0398:                        }
0399:                        try {
0400:                            inclText = new OrderedProperties();
0401:                            read(inclText, u);
0402:                        } catch (IOException ioe) {
0403:                            mpe.add(fail("could not find include file " + s
0404:                                    + " " + ioe, ok + "=" + incl));
0405:                            ;
0406:                            return;
0407:                        }
0408:
0409:                        for (Enumeration k = inclText.keys(); k
0410:                                .hasMoreElements();) {
0411:                            String key = (String) k.nextElement();
0412:                            String val = text.getProperty(key);
0413:                            if (val == null) // new field, not overriden in main mdd
0414:                                text.putAt(++line, key, inclText
0415:                                        .getOriginal(key), inclText
0416:                                        .getProperty(key));
0417:                            else
0418:                                // field is overriden in main mdd, ignore it
0419:                                overridenFields.add(key);
0420:                        }
0421:                    }
0422:                }
0423:
0424:                // now we remove all overriden empty fields
0425:                // keep the non-overriden ones with empty definiton to report a mdd
0426:                // error
0427:                for (Enumeration k = overridenFields.elements(); k
0428:                        .hasMoreElements();) {
0429:                    String key = (String) k.nextElement();
0430:                    if (((String) text.get(key)).trim().length() == 0)
0431:                        text.remove(key);
0432:                }
0433:            }
0434:
0435:            void readTypes() {
0436:                for (Enumeration e = text.keys(); e.hasMoreElements();) {
0437:                    String s = (String) e.nextElement();
0438:                    if (s.startsWith("!type.")) {
0439:                        String nm = s.substring(6);
0440:                        definedTypes.put(nm, text.remove(s));
0441:                    }
0442:                }
0443:            }
0444:
0445:            FieldCursor currentRowCursor;
0446:
0447:            FieldInfo getFieldInfo(String fieldName) {
0448:                return (FieldInfo) dd.getFieldDefinition(fieldName);
0449:            }
0450:
0451:            void treatMyFields() {
0452:                FieldInfo fi;
0453:                String nm;
0454:
0455:                int line = 0;
0456:                for (Enumeration e = fields.keys(); e.hasMoreElements(); line++) {
0457:                    nm = (String) e.nextElement();
0458:                    // check name for validity:
0459:                    for (int i = 0; i < nm.length(); i++) {
0460:                        if (i == 0
0461:                                && !Character.isJavaIdentifierStart(nm
0462:                                        .charAt(i))
0463:                                || i > 0
0464:                                && !Character
0465:                                        .isJavaIdentifierPart(nm.charAt(i)))
0466:                            mpe.add(fail("Invalid character \"" + nm.charAt(i)
0467:                                    + "\" in field name \"" + nm + "\"", nm));
0468:                    }
0469:
0470:                    if (ReservedKeywords.isReservedKeyword(nm)) {
0471:                        mpe.add(fail(
0472:                                "Error: field name cannot be one of the reserved keywords "
0473:                                        + ReservedKeywords
0474:                                                .getKeywordsAsString(), nm));
0475:                    }
0476:
0477:                    fi = new FieldInfo((RecordInfo) dd, nm);
0478:                    ((RecordInfo) dd).addField1(fi);
0479:                    try {
0480:                        parse(nm, new FieldCursor(this , makeLine(fields, nm)));
0481:                    } catch (DataDefinitionParseError pe) {
0482:                        ((RecordInfo) dd).fields.remove(nm);
0483:                        ((RecordInfo) dd).fieldOrder.remove(nm);
0484:                        mpe.add(pe);
0485:                        continue;
0486:                    }
0487:                }
0488:            }
0489:
0490:            void configSubfields() {
0491:                String nm;
0492:                int p;
0493:                for (Enumeration e = subfields.keys(); e.hasMoreElements();) {
0494:                    nm = (String) e.nextElement();
0495:
0496:                    p = nm.indexOf("->");
0497:                    FieldInfo fieldInfo = getFieldInfo(nm.substring(0, p));
0498:                    if (fieldInfo == null) { // we did not find the field info, i.e. accessed unknownField->field.
0499:                        mpe.add(fail("Could not find subfield '"
0500:                                + nm.substring(0, p) + "'", makeLine(subfields,
0501:                                nm)));
0502:                        continue;
0503:                    }
0504:                    String type = (String) fieldInfo.type;
0505:                    if (type == null) {
0506:                        mpe.add(fail("no such field in subfield definition",
0507:                                makeLine(subfields, nm)));
0508:                        continue;
0509:                    }
0510:
0511:                    String s;
0512:                    if ((s = addText(nm.substring(0, p), nm.substring(p + 2),
0513:                            subfields.getOriginal(nm), subfields
0514:                                    .getProperty(nm))) != null)
0515:                        mpe.add(fail(s, makeLine(subfields, nm)));
0516:                }
0517:            }
0518:
0519:            void treatSubfields() {
0520:                for (Enumeration e = dd.getFieldNames().elements(); e
0521:                        .hasMoreElements();) {
0522:                    String fieldName = (String) e.nextElement();
0523:                    parseSubfields(fieldName);
0524:                }
0525:            }
0526:
0527:            static String makeLine(String origKey, String value) {
0528:                return origKey + "=" + value;
0529:            }
0530:
0531:            static String makeLine(OrderedProperties p, String k) {
0532:                return p.getOriginal(k) + "=" + p.getProperty(k);
0533:            }
0534:
0535:            DataDefinitionParseError fail(String why, String where) {
0536:                return new DataDefinitionParseError(dd.getName(), why, where,
0537:                        where.length());
0538:            }
0539:
0540:            DataDefinitionParseError fail(IOException ioe) {
0541:                return new DataDefinitionParseError(dd.getName(), ioe);
0542:            }
0543:
0544:            void read(OrderedProperties op, String txt) throws IOException {
0545:                read(op, new BufferedReader(new StringReader(txt)));
0546:            }
0547:
0548:            void read(OrderedProperties op, java.net.URL u) throws IOException {
0549:                read(op, new BufferedReader(new InputStreamReader(
0550:                        (InputStream) u.getContent())));
0551:            }
0552:
0553:            void read(OrderedProperties op, BufferedReader rd)
0554:                    throws IOException {
0555:                while (true) {
0556:                    String s = null;
0557:                    s = rd.readLine();
0558:                    if (s == null)
0559:                        break;
0560:
0561:                    String st = s.trim();
0562:                    if (st.length() == 0 || st.charAt(0) == '#')
0563:                        continue;
0564:
0565:                    String lineWithoutComment = null;
0566:                    if (st.indexOf(";") == -1) {
0567:                        lineWithoutComment = st;
0568:                    } else {
0569:                        lineWithoutComment = st.substring(0, st.indexOf(";"));
0570:                    }
0571:
0572:                    // check if the line is a validation definition
0573:                    Matcher matcher = validationDefinitionPattern
0574:                            .matcher(lineWithoutComment);
0575:                    if (matcher.matches()) {
0576:                        // we parse them later
0577:                        unparsedValidationDefinitions.add(lineWithoutComment);
0578:                        continue;
0579:                    }
0580:
0581:                    // check if the line is a function definition
0582:                    matcher = funcDefPattern.matcher(lineWithoutComment);
0583:                    if (matcher.matches()) {
0584:                        String name = matcher.group(1);
0585:                        if (dd.getFunction(name) != null) {
0586:                            mpe.add(new DataDefinitionParseError(dd.getName(),
0587:                                    "Duplicate function name: " + name, st));
0588:                        }
0589:                        String queryFragment = matcher.group(matcher
0590:                                .groupCount() - 1);
0591:                        String errorMessage = matcher.group(matcher
0592:                                .groupCount());
0593:                        DataDefinition params = new RecordInfo(dd.getName()
0594:                                + "." + matcher.group(0));
0595:                        for (int i = 2; i < matcher.groupCount() - 2; i += 2) {
0596:                            String type = matcher.group(i);
0597:                            // if we provide < 2 params, we still get 2 * 2 empty groups matched ==> need to check tht here
0598:                            // see the comment in the field init.
0599:                            if (type != null) {
0600:                                if (type.equals("char[]")) { // we substitute char[] with the max char length
0601:                                    type = ("char[255]");
0602:                                }
0603:                                params.addField(new FieldInfo(matcher
0604:                                        .group(i + 1), type));
0605:                            }
0606:                        }
0607:                        DataDefinition.QueryFragmentFunction function = new DataDefinition.QueryFragmentFunction(
0608:                                name, queryFragment, params, errorMessage);
0609:                        dd.addFunction(name, function);
0610:                        continue;
0611:                    }
0612:
0613:                    int l = s.indexOf('=');
0614:                    if (l == -1) {
0615:                        mpe
0616:                                .add(fail(
0617:                                        "non-empty, non-comment line without =",
0618:                                        s));
0619:                        continue;
0620:                    }
0621:                    String k = s.substring(0, l);
0622:                    String kt = k.trim();
0623:                    if (kt.length() == 0) {
0624:                        mpe.add(fail("zero length key", s));
0625:                        continue;
0626:                    }
0627:                    if (kt.charAt(0) == '!' && kt.length() == 1) {
0628:                        mpe.add(fail("zero length command", s));
0629:                        continue;
0630:                    }
0631:
0632:                    if (kt.startsWith("!include")) {
0633:                        if (kt.length() > 8) {
0634:                            mpe.add(fail("unknown command: " + kt, s));
0635:                            continue;
0636:                        }
0637:                        while (op.get(kt) != null)
0638:                            kt = kt + "_";
0639:                    }
0640:                    String val = s.substring(l + 1);
0641:                    if (op.putLast(kt, k, val) != null)
0642:                        mpe.add(fail("ambiguous key " + kt, s));
0643:                }
0644:                rd.close();
0645:            }
0646:
0647:            // moved from FieldParser
0648:            public void parseSubfields(String fieldName) {
0649:                switch (getFieldInfo(fieldName).getIntegerType()) {
0650:                case FieldDefinition._setComplex:
0651:                case FieldDefinition._ptrOne:
0652:                    parse_ptrOne_Subfields(fieldName);
0653:                    break;
0654:                case FieldDefinition._set:
0655:                    parse_set_Subfields(fieldName);
0656:                    break;
0657:                default:
0658:                    ;
0659:                }
0660:            }
0661:
0662:            // moved from ptrOneParser
0663:            public void parse_ptrOne_Subfields(String fieldName) {
0664:                ptrOne_RecordParsers.get(fieldName).parse();
0665:                getFieldInfo(fieldName).extra2 = ((RecordParser) ptrOne_RecordParsers
0666:                        .get(fieldName)).dd.getTitleFieldName();
0667:            }
0668:
0669:            // moved from setParser
0670:            public void parse_set_Subfields(String fieldName) {
0671:                if (getFieldInfo(fieldName).extra2 == null) {
0672:                    getFieldInfo(fieldName).extra2 = ((RecordInfo) subtableParser_subtables
0673:                            .get(fieldName)).title = ((DataDefinition) setParser_settbls
0674:                            .get(fieldName)).getTitleFieldName();
0675:                }
0676:            }
0677:
0678:            // moved from FieldParser
0679:            String acceptTitle(String fieldName, String nm, String origNm,
0680:                    String val, Object o) {
0681:                val = val.trim();
0682:                if (nm.equals("!title")) {
0683:                    DataDefinition ri = (DataDefinition) o;
0684:                    if (ri.getFieldDefinition(val) == null)
0685:                        return ri.getName() + " has no field called " + val;
0686:                    getFieldInfo(fieldName).extra2 = val;
0687:                    return null;
0688:                }
0689:                return addText(fieldName, nm, origNm, val);
0690:            }
0691:
0692:            // moved from FieldParser
0693:            String addText(String fieldName, String nm, String origNm,
0694:                    String val) {
0695:                switch (getFieldInfo(fieldName).getIntegerType()) {
0696:                case FieldDefinition._ptr:
0697:                case FieldDefinition._ptrRel:
0698:                    return add_ptr_Text(fieldName, nm, origNm, val);
0699:                case FieldDefinition._ptrOne:
0700:                case FieldDefinition._setComplex:
0701:                    return add_ptrOne_Text(fieldName, nm, origNm, val);
0702:                case FieldDefinition._set:
0703:                    return add_set_Text(fieldName, nm, origNm, val);
0704:                default:
0705:                    return base_addText(fieldName, nm, origNm, val);
0706:                }
0707:            }
0708:
0709:            // original from FieldParser
0710:            String base_addText(String fieldName, String nm, String origNm,
0711:                    String val) {
0712:                return "subfield not allowed";
0713:            }
0714:
0715:            // moved from ptrParser
0716:            String add_ptr_Text(String fieldName, String nm, String origNm,
0717:                    String val) {
0718:                return acceptTitle(fieldName, nm, origNm, val,
0719:                        getFieldInfo(fieldName).extra1);
0720:            }
0721:
0722:            // moved from ptrOneParser
0723:            String add_ptrOne_Text(String fieldName, String nm, String origNm,
0724:                    String val) {
0725:                if (ptrOne_RecordParsers.get(fieldName).text.putLast(nm,
0726:                        origNm, val) != null)
0727:                    return "field already exists";
0728:                return null;
0729:            }
0730:
0731:            // moved from setParser
0732:            String add_set_Text(String fieldName, String nm, String origNm,
0733:                    String val) {
0734:                String s = acceptTitle(fieldName, nm, origNm, val,
0735:                        (DataDefinition) setParser_settbls.get(fieldName));
0736:                if (s == null)
0737:                    ((RecordInfo) subtableParser_subtables.get(fieldName)).title = val
0738:                            .trim();
0739:                return s;
0740:            }
0741:
0742:            // moved from FieldParser
0743:            void parse(String fieldName, FieldCursor fc)
0744:                    throws org.makumba.DataDefinitionParseError {
0745:                while (true) {
0746:                    if (fc.lookup("not")) {
0747:                        if (getFieldInfo(fieldName).notNull)
0748:                            throw fc.fail("too many not null");
0749:                        fc.expect("null");
0750:                        fc.expectWhitespace();
0751:                        getFieldInfo(fieldName).notNull = true;
0752:                        continue;
0753:                    }
0754:
0755:                    if (fc.lookup("fixed")) {
0756:                        fc.expectWhitespace();
0757:                        if (getFieldInfo(fieldName).fixed)
0758:                            throw fc.fail("too many fixed");
0759:                        getFieldInfo(fieldName).fixed = true;
0760:                        continue;
0761:                    }
0762:
0763:                    if (fc.lookup("unique")) {
0764:                        fc.expectWhitespace();
0765:                        if (getFieldInfo(fieldName).unique)
0766:                            throw fc.fail("already unique");
0767:                        getFieldInfo(fieldName).unique = true;
0768:                        continue;
0769:                    }
0770:
0771:                    break;
0772:                }
0773:
0774:                if (setType(fieldName, fc.expectTypeLiteral(), fc) == null) {
0775:                    String s = definedTypes
0776:                            .getProperty(getFieldInfo(fieldName).type);
0777:                    if (s == null)
0778:                        throw fc.fail("unknown type: "
0779:                                + getFieldInfo(fieldName).type);
0780:
0781:                    fc.substitute(getFieldInfo(fieldName).type.length(), s);
0782:
0783:                    if (setType(fieldName, fc.expectTypeLiteral(), fc) == null)
0784:                        throw fc.fail("unknown type: "
0785:                                + getFieldInfo(fieldName).type);
0786:                }
0787:                getFieldInfo(fieldName).description = getFieldInfo(fieldName).description == null ? getFieldInfo(fieldName).name
0788:                        : getFieldInfo(fieldName).description;
0789:
0790:            }
0791:
0792:            // moved from FieldParser
0793:            String setType(String fieldName, String type, FieldCursor fc)
0794:                    throws org.makumba.DataDefinitionParseError {
0795:                String initialType = type;
0796:                getFieldInfo(fieldName).type = type;
0797:                while (true) {
0798:                    if (FieldInfo.integerTypeMap
0799:                            .get(getFieldInfo(fieldName).type) == null) {
0800:                        // getFieldInfo(fieldName).type = null;
0801:                        return null;
0802:                    }
0803:                    parse1(fieldName, fc);
0804:                    if (getFieldInfo(fieldName).type.equals(initialType))
0805:                        return initialType;
0806:                    initialType = getFieldInfo(fieldName).type;
0807:                }
0808:            }
0809:
0810:            /**
0811:             * switch for the existing parse methods. set the field type to another value if we want to change it
0812:             */
0813:            void parse1(String fieldName, FieldCursor fc) {
0814:                switch (getFieldInfo(fieldName).getIntegerType()) {
0815:                case FieldDefinition._charEnum:
0816:                    charEnum_parse1(fieldName, fc);
0817:                    return;
0818:                case FieldDefinition._char:
0819:                    char_parse1(fieldName, fc);
0820:                    return;
0821:                case FieldDefinition._intEnum:
0822:                    intEnum_parse1(fieldName, fc);
0823:                    return;
0824:                case FieldDefinition._int:
0825:                    int_parse1(fieldName, fc);
0826:                    return;
0827:                case FieldDefinition._ptrOne:
0828:                    ptrOne_parse1(fieldName, fc);
0829:                    return;
0830:                case FieldDefinition._ptrRel:
0831:                case FieldDefinition._ptr:
0832:                    ptr_parse1(fieldName, fc);
0833:                    return;
0834:                case FieldDefinition._setCharEnum:
0835:                    setCharEnum_parse1(fieldName, fc);
0836:                    return;
0837:                case FieldDefinition._setComplex:
0838:                    setComplex_parse1(fieldName, fc);
0839:                    return;
0840:                case FieldDefinition._setIntEnum:
0841:                    setIntEnum_parse1(fieldName, fc);
0842:                    return;
0843:                case FieldDefinition._set:
0844:                    set_parse1(fieldName, fc);
0845:                    return;
0846:                case FieldDefinition._text:
0847:                    text_parse1(fieldName, fc);
0848:                    return;
0849:                case FieldDefinition._date:
0850:                case FieldDefinition._real:
0851:                case FieldDefinition._ptrIndex:
0852:                case FieldDefinition._dateCreate:
0853:                case FieldDefinition._dateModify:
0854:                    simple_parse1(fieldName, fc);
0855:                    return;
0856:                default:
0857:                    ;
0858:                }
0859:            }
0860:
0861:            // moved from intParser
0862:            public void int_parse1(String fieldName, FieldCursor fc) {
0863:                if (!fc.lookup("{")) {
0864:                    getFieldInfo(fieldName).description = fc
0865:                            .lookupDescription();
0866:                    return;
0867:                }
0868:                getFieldInfo(fieldName).type = "intEnum";
0869:            }
0870:
0871:            // moved from intEnumParser
0872:            public void intEnum_parse1(String fieldName, FieldCursor fc) {
0873:                fc.expectIntEnum(getFieldInfo(fieldName));
0874:                getFieldInfo(fieldName).description = fc.lookupDescription();
0875:                return;
0876:            }
0877:
0878:            // moved from charParser
0879:            public void char_parse1(String fieldName, FieldCursor fc) {
0880:                if (!fc.lookup("{")) {
0881:                    fc.expect("[");
0882:                    Integer size = fc.expectInteger();
0883:                    if (size.intValue() > 255 || size.intValue() < 0)
0884:                        throw fc
0885:                                .fail("char size must be between 0 and 255, not "
0886:                                        + size.toString());
0887:                    getFieldInfo(fieldName).extra2 = size;
0888:                    fc.expect("]");
0889:                    getFieldInfo(fieldName).description = fc
0890:                            .lookupDescription();
0891:                    return;
0892:                }
0893:
0894:                getFieldInfo(fieldName).type = "charEnum";
0895:            }
0896:
0897:            // moved from charEnumParser
0898:            public void charEnum_parse1(String fieldName, FieldCursor fc) {
0899:                fc.expectCharEnum(getFieldInfo(fieldName));
0900:                getFieldInfo(fieldName).description = fc.lookupDescription();
0901:                return;
0902:            }
0903:
0904:            // moved from simpleParser
0905:            public void simple_parse1(String fieldName, FieldCursor fc) {
0906:                getFieldInfo(fieldName).description = fc.lookupDescription();
0907:                return;
0908:            }
0909:
0910:            // moved from textParser
0911:            public void text_parse1(String fieldName, FieldCursor fc)
0912:                    throws org.makumba.DataDefinitionParseError {
0913:                if (getFieldInfo(fieldName).isUnique())
0914:                    throw fc.fail("text fields can't be declared unique");
0915:                return;
0916:            }
0917:
0918:            // moved from setComplexParser
0919:            public void setComplex_parse1(String fieldName, FieldCursor fc) {
0920:                ptrOne_parse1(fieldName, fc);
0921:                ((RecordInfo) subtableParser_subtables.get(fieldName)).mainPtr = addPtrHere(fieldName);
0922:                return;
0923:            }
0924:
0925:            // moved from ptrOneParser
0926:            public void ptrOne_parse1(String fieldName, FieldCursor fc) {
0927:                makeSubtable(fieldName, fc);
0928:                ptrOne_RecordParsers.put(fieldName, new RecordParser(
0929:                        ((RecordInfo) subtableParser_subtables.get(fieldName)),
0930:                        this ));
0931:                return;
0932:            }
0933:
0934:            // moved from setEnumParser, setChatEnumParser
0935:            public void setCharEnum_parse1(String fieldName, FieldCursor fc) {
0936:                FieldInfo _enum = new FieldInfo(
0937:                        ((RecordInfo) subtableParser_subtables.get(fieldName)),
0938:                        "enum");
0939:                makeSubtable(fieldName, fc);
0940:                ((RecordInfo) subtableParser_subtables.get(fieldName)).mainPtr = addPtrHere(fieldName);
0941:                ((RecordInfo) subtableParser_subtables.get(fieldName))
0942:                        .addField1(_enum);
0943:                ((RecordInfo) subtableParser_subtables.get(fieldName)).title = _enum.name;
0944:                ((RecordInfo) subtableParser_subtables.get(fieldName)).setField = _enum.name;
0945:                _enum.type = "charEnum";
0946:                fc.expectCharEnum(_enum);
0947:                getFieldInfo(fieldName).description = fc.lookupDescription();
0948:                _enum.description = getFieldInfo(fieldName).getDescription() == null ? _enum.name
0949:                        : getFieldInfo(fieldName).getDescription();
0950:                return;
0951:            }
0952:
0953:            // moved from setEnumParser, setIntEnumParser
0954:            public void setIntEnum_parse1(String fieldName, FieldCursor fc) {
0955:                FieldInfo _enum = new FieldInfo(
0956:                        ((RecordInfo) subtableParser_subtables.get(fieldName)),
0957:                        "enum");
0958:                makeSubtable(fieldName, fc);
0959:                ((RecordInfo) subtableParser_subtables.get(fieldName)).mainPtr = addPtrHere(fieldName);
0960:                ((RecordInfo) subtableParser_subtables.get(fieldName))
0961:                        .addField1(_enum);
0962:                ((RecordInfo) subtableParser_subtables.get(fieldName)).title = _enum.name;
0963:                ((RecordInfo) subtableParser_subtables.get(fieldName)).setField = _enum.name;
0964:                _enum.type = "intEnum";
0965:                fc.expectIntEnum(_enum);
0966:                getFieldInfo(fieldName).description = fc.lookupDescription();
0967:                _enum.description = getFieldInfo(fieldName).getDescription() == null ? _enum.name
0968:                        : getFieldInfo(fieldName).getDescription();
0969:                return;
0970:            }
0971:
0972:            // moved from ptrParser
0973:            public void ptr_parse1(String fieldName, FieldCursor fc) {
0974:                Object o = fc.lookupTableSpecifier();
0975:
0976:                if (o != null)
0977:                    getFieldInfo(fieldName).extra1 = o;
0978:                try {
0979:                    getFieldInfo(fieldName).description = fc
0980:                            .lookupDescription();
0981:                } catch (org.makumba.DataDefinitionParseError e) {
0982:                    throw fc.fail("table specifier or nothing expected");
0983:                }
0984:
0985:                if (o != null)
0986:                    return;
0987:
0988:                // getFieldInfo(fieldName).unique = true;
0989:                getFieldInfo(fieldName).type = "ptrOne";
0990:            }
0991:
0992:            // moved from setParser
0993:            public void set_parse1(String fieldName, FieldCursor fc) {
0994:                if (getFieldInfo(fieldName).isUnique())
0995:                    throw fc.fail("sets can't be declared unique");
0996:
0997:                DataDefinition ori = fc.lookupTableSpecifier();
0998:                if (ori == null) {
0999:                    String word = fc.lookupTypeLiteral();
1000:                    if (word == null) {
1001:                        try {
1002:                            getFieldInfo(fieldName).description = fc
1003:                                    .lookupDescription();
1004:                        } catch (org.makumba.DataDefinitionParseError pe) {
1005:                            throw fc
1006:                                    .fail("table specifier, enumeration type, or nothing expected");
1007:                        }
1008:                        getFieldInfo(fieldName).type = "setComplex";
1009:                        return;
1010:                    }
1011:                    String newName = enumSet(fieldName, fc, word);
1012:                    if (newName != null) {
1013:                        getFieldInfo(fieldName).type = newName;
1014:                        return;
1015:                    }
1016:                    String s = fc.rp.definedTypes.getProperty(word);
1017:                    if (s == null)
1018:                        throw fc
1019:                                .fail("table, char{}, int{} or macro type expected after set");
1020:
1021:                    fc.substitute(word.length(), s);
1022:
1023:                    newName = enumSet(fieldName, fc, fc.expectTypeLiteral());
1024:
1025:                    if (newName != null) {
1026:                        getFieldInfo(fieldName).type = newName;
1027:                        return;
1028:                    }
1029:
1030:                    throw fc.fail("int{} or char{} macro expected after set");
1031:                }
1032:
1033:                makeSubtable(fieldName, fc);
1034:                ((RecordInfo) subtableParser_subtables.get(fieldName)).mainPtr = addPtrHere(fieldName);
1035:
1036:                setParser_settbls.put(fieldName, ori);
1037:                ((RecordInfo) subtableParser_subtables.get(fieldName)).setField = addPtr(
1038:                        fieldName, ((RecordInfo) setParser_settbls
1039:                                .get(fieldName)).getBaseName(), ori);
1040:                return;
1041:            }
1042:
1043:            // moved from setParser
1044:            String enumSet(String fieldName, FieldCursor fc, String word) {
1045:                String newName;
1046:                if (fc.lookup("{")) {
1047:                    newName = "set" + word + "Enum";
1048:                    getFieldInfo(fieldName).type = newName;
1049:                    if (newName != null)
1050:                        return newName;
1051:                    fc.fail("int{} or char{} expected after set");
1052:                }
1053:                return null;
1054:            }
1055:
1056:            // moved from subtableParser
1057:            void makeSubtable(String fieldName, FieldCursor fc) {
1058:                subtableParser_here.put(fieldName, dd);
1059:
1060:                subtableParser_subtables.put(fieldName,
1061:                        ((RecordInfo) subtableParser_here.get(fieldName))
1062:                                .makeSubtable(getFieldInfo(fieldName).name));
1063:                ((RecordInfo) subtableParser_subtables.get(fieldName))
1064:                        .addStandardFields(((RecordInfo) subtableParser_subtables
1065:                                .get(fieldName)).subfield);
1066:                getFieldInfo(fieldName).extra1 = ((RecordInfo) subtableParser_subtables
1067:                        .get(fieldName));
1068:            }
1069:
1070:            // moved from subtableParser
1071:            String addPtr(String fieldName, String name, DataDefinition o) {
1072:                int n = name.lastIndexOf('.');
1073:                if (n != -1)
1074:                    name = name.substring(n + 1);
1075:                while (((RecordInfo) subtableParser_subtables.get(fieldName)).fields
1076:                        .get(name) != null)
1077:                    name = name + "_";
1078:
1079:                FieldInfo ptr = new FieldInfo(
1080:                        ((RecordInfo) subtableParser_subtables.get(fieldName)),
1081:                        name);
1082:                ((RecordInfo) subtableParser_subtables.get(fieldName))
1083:                        .addField1(ptr);
1084:                ptr.fixed = true;
1085:                ptr.notNull = true;
1086:                ptr.type = "ptrRel";
1087:                ptr.extra1 = o;
1088:                ptr.description = "relational pointer";
1089:                return name;
1090:            }
1091:
1092:            // moved from subtableParser
1093:            String addPtrHere(String fieldName) {
1094:                // System.err.println(here.canonicalName()+"
1095:                // "+subtable.canonicalName());
1096:                ((RecordInfo) subtableParser_subtables.get(fieldName)).relations = 1;
1097:                if (((RecordInfo) subtableParser_here.get(fieldName))
1098:                        .getParentField() != null)
1099:                    return addPtr(fieldName, ((RecordInfo) subtableParser_here
1100:                            .get(fieldName)).subfield,
1101:                            ((RecordInfo) subtableParser_here.get(fieldName)));
1102:                else
1103:                    return addPtr(fieldName, ((RecordInfo) subtableParser_here
1104:                            .get(fieldName)).name,
1105:                            ((RecordInfo) subtableParser_here.get(fieldName)));
1106:            }
1107:
1108:            public void parseValidationDefinition()
1109:                    throws ValidationDefinitionParseError {
1110:                ValidationDefinitionParseError mpe = new ValidationDefinitionParseError();
1111:                for (int i = 0; i < unparsedValidationDefinitions.size(); i++) {
1112:                    String line = unparsedValidationDefinitions.get(i);
1113:                    try {
1114:                        line = line.trim();
1115:                        if (line.indexOf(";") != -1) { // cut off end-of-line comments
1116:                            line = line.substring(0, line.indexOf(";")).trim();
1117:                        }
1118:
1119:                        // check if the line is a validation definition
1120:                        Matcher singleValidationMatcher = validationDefinitionPattern
1121:                                .matcher(line);
1122:                        if (!singleValidationMatcher.matches()) {
1123:                            throw new ValidationDefinitionParseError(dd
1124:                                    .getName(), "Illegal rule definition!",
1125:                                    line);
1126:                        }
1127:                        String[] definitionParts = line.split(":");
1128:                        if (definitionParts.length < 2) {
1129:                            throw new ValidationDefinitionParseError(
1130:                                    dd.getName(),
1131:                                    "Rule does not consist of the two parts <rule>:<message>!",
1132:                                    line);
1133:                        }
1134:                        String fieldName = singleValidationMatcher.group(1)
1135:                                .trim();
1136:                        String operation = singleValidationMatcher.group(2)
1137:                                .trim();
1138:                        String ruleDef = singleValidationMatcher.group(3)
1139:                                .trim();
1140:                        String errorMessage = definitionParts[1].trim();
1141:                        String ruleName = line;
1142:                        ValidationRule rule = null;
1143:                        Matcher matcher;
1144:
1145:                        // check all possible validation types
1146:                        if (StringUtils.equals(operation, RegExpValidationRule
1147:                                .getOperator())) {
1148:                            // regexp validation
1149:                            FieldDefinition fd = DataDefinitionProvider
1150:                                    .getFieldDefinition(dd, fieldName, line);
1151:                            rule = new RegExpValidationRule(fd, fieldName,
1152:                                    ruleName, errorMessage, ruleDef);
1153:
1154:                        } else if (StringUtils.equals(operation,
1155:                                NumberRangeValidationRule.getOperator())) {
1156:                            // number (int or real) validation
1157:                            FieldDefinition fd = DataDefinitionProvider
1158:                                    .getFieldDefinition(dd, fieldName, line);
1159:                            matcher = RangeValidationRule.getMatcher(ruleDef);
1160:                            if (!matcher.matches()) {
1161:                                throw new ValidationDefinitionParseError("",
1162:                                        "Illegal range definition", line);
1163:                            }
1164:                            rule = new NumberRangeValidationRule(fd, fieldName,
1165:                                    ruleName, errorMessage, matcher.group(1)
1166:                                            .trim(), matcher.group(2).trim());
1167:
1168:                        } else if (StringUtils.equals(operation,
1169:                                StringLengthValidationRule.getOperator())) {
1170:                            // string lenght (char or text) validation
1171:                            FieldDefinition fd = DataDefinitionProvider
1172:                                    .getFieldDefinition(dd, fieldName, line);
1173:                            matcher = RangeValidationRule.getMatcher(ruleDef);
1174:                            if (!matcher.matches()) {
1175:                                throw new ValidationDefinitionParseError("",
1176:                                        "Illegal range definition", line);
1177:                            }
1178:                            rule = new StringLengthValidationRule(fd,
1179:                                    fieldName, ruleName, errorMessage, matcher
1180:                                            .group(1).trim(), matcher.group(2)
1181:                                            .trim());
1182:
1183:                        } else if (StringUtils.equals(operation,
1184:                                ComparisonValidationRule.getOperator())) {
1185:                            // comparison validation, compares two fields or a field with a constant
1186:                            // fieldName = matcher.group(1);
1187:                            matcher = ComparisonValidationRule
1188:                                    .getMatcher(ruleDef);
1189:                            if (!matcher.matches()) {
1190:                                throw new ValidationDefinitionParseError("",
1191:                                        "Illegal comparison definition", line);
1192:                            }
1193:                            if (dd.getFieldDefinition(fieldName) == null) { // let's see if the first part is a field name
1194:                                fieldName = matcher.group(1);
1195:                            }
1196:                            String functionName = null;
1197:                            if (BasicValidationRule
1198:                                    .isValidFunctionCall(fieldName)) {
1199:                                functionName = BasicValidationRule
1200:                                        .extractFunctionNameFromStatement(fieldName);
1201:                                fieldName = BasicValidationRule
1202:                                        .extractFunctionArgument(fieldName);
1203:                            }
1204:                            FieldDefinition fd = DataDefinitionProvider
1205:                                    .getFieldDefinition(dd, fieldName, line);
1206:                            String operator = matcher.group(2).trim();
1207:                            String compareTo = matcher.group(3).trim();
1208:                            if (fd.getIntegerType() == FieldDefinition._date
1209:                                    && ComparisonValidationRule
1210:                                            .matchesDateExpression(compareTo)) {
1211:                                // we have a comparison to a date constant / expression
1212:                                rule = new ComparisonValidationRule(fd,
1213:                                        fieldName, compareTo, ruleName,
1214:                                        errorMessage, operator);
1215:                            } else {
1216:                                FieldDefinition otherFd = DataDefinitionProvider
1217:                                        .getFieldDefinition(dd, compareTo, line);
1218:                                rule = new ComparisonValidationRule(fd,
1219:                                        fieldName, functionName, otherFd,
1220:                                        compareTo, ruleName, errorMessage,
1221:                                        operator);
1222:                            }
1223:                        } else if (StringUtils.equals(operation, "unique")) {
1224:                            // check if the line defines a multi-field unique key
1225:                            matcher = multiUniquePattern.matcher(ruleDef);
1226:                            if (!matcher.matches()) {
1227:                                throw new ValidationDefinitionParseError(
1228:                                        "",
1229:                                        "Illegal multi-field unique definition",
1230:                                        line);
1231:                            }
1232:                            ArrayList<String> groupList = new ArrayList<String>();
1233:                            for (int j = 1; j <= matcher.groupCount(); j++) {
1234:                                if (matcher.group(j) != null) {
1235:                                    // checking if the fields exist will be done later
1236:                                    groupList.add(matcher.group(j).trim());
1237:                                }
1238:                            }
1239:                            String[] groups = (String[]) groupList
1240:                                    .toArray(new String[groupList.size()]);
1241:                            dd
1242:                                    .addMultiUniqueKey(new DataDefinition.MultipleUniqueKeyDefinition(
1243:                                            groups, line));
1244:                            java.util.logging.Logger
1245:                                    .getLogger(
1246:                                            "org.makumba."
1247:                                                    + "datadefinition.makumba")
1248:                                    .finer(
1249:                                            "added multi-field unique key: "
1250:                                                    + new DataDefinition.MultipleUniqueKeyDefinition(
1251:                                                            groups, line));
1252:                            continue;
1253:                        } else {
1254:                            // no recognised rule
1255:                            throw new ValidationDefinitionParseError("",
1256:                                    "Rule type not recognised!", line);
1257:                        }
1258:                        rule.getFieldDefinition().addValidationRule(rule);
1259:                        // validationRules.put(fieldName, rule);
1260:                        ((RecordInfo) dd).addValidationRule(rule);
1261:                        java.util.logging.Logger.getLogger(
1262:                                "org.makumba." + "datadefinition.makumba")
1263:                                .finer("added rule: " + rule);
1264:                    } catch (ValidationDefinitionParseError e) {
1265:                        mpe.add(e);
1266:                    }
1267:
1268:                    if (!mpe.isSingle()) {
1269:                        throw mpe;
1270:                    }
1271:                }
1272:
1273:                if (!mpe.isSingle()) {
1274:                    throw mpe;
1275:                }
1276:                // System.out.println("Finished parsing validation definition '" + name + "'.");
1277:            }
1278:
1279:            public static void main(String[] args) {
1280:                // test some function definition
1281:                RegExpUtils
1282:                        .evaluate(
1283:                                RecordParser.funcDefPattern,
1284:                                new String[] {
1285:                                        " someFunc() = abc : errorMessage",
1286:                                        " someFunc(char[] a, int 5) =abc:errorMessages",
1287:                                        "someFunction(int a, char[] b) = yeah:errorMessage3",
1288:                                        "someOtherFunction(int age, char[] b) = this.age > age : You are too young!" });
1289:
1290:                // test some mdd reading
1291:                RecordInfo.getRecordInfo("test.Person");
1292:            }
1293:
1294:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.