Source Code Cross Referenced for Identifier.java in  » Content-Management-System » daisy » org » outerj » daisy » query » model » 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 » Content Management System » daisy » org.outerj.daisy.query.model 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2004 Outerthought bvba and Schaubroeck nv
0003:         *
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         *
0008:         *     http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:        package org.outerj.daisy.query.model;
0017:
0018:        import java.io.ByteArrayInputStream;
0019:        import java.lang.reflect.Constructor;
0020:        import java.sql.PreparedStatement;
0021:        import java.sql.SQLException;
0022:        import java.util.*;
0023:        import java.util.regex.Pattern;
0024:        import java.util.regex.Matcher;
0025:
0026:        import org.apache.xmlbeans.XmlCursor;
0027:        import org.apache.xmlbeans.XmlObject;
0028:        import org.apache.xmlbeans.XmlOptions;
0029:        import org.outerj.daisy.query.EvaluationInfo;
0030:        import org.outerj.daisy.query.QueryContext;
0031:        import org.outerj.daisy.repository.*;
0032:        import org.outerj.daisy.repository.namespace.Namespace;
0033:        import org.outerj.daisy.repository.namespace.NamespaceNotFoundException;
0034:        import org.outerj.daisy.repository.query.QueryException;
0035:        import org.outerj.daisy.repository.schema.DocumentType;
0036:        import org.outerj.daisy.repository.schema.DocumentTypeNotFoundException;
0037:        import org.outerj.daisy.repository.schema.FieldType;
0038:        import org.outerj.daisy.repository.schema.PartType;
0039:        import org.outerj.daisy.repository.variant.Branch;
0040:        import org.outerj.daisy.repository.variant.Language;
0041:        import org.outerj.daisy.repository.variant.BranchNotFoundException;
0042:        import org.outerj.daisy.repository.variant.LanguageNotFoundException;
0043:        import org.outerj.daisy.xmlutil.LocalSAXParserFactory;
0044:
0045:        public final class Identifier extends AbstractExpression implements 
0046:                ValueExpr, Cloneable {
0047:            private final String id;
0048:            private final String subId;
0049:            private final ValueExpr multiValueIndexExpr;
0050:            private final ValueExpr hierarchyIndexExpr;
0051:            private DelegateIdentifier delegate;
0052:            private QueryContext prepareOnlyQueryContext;
0053:            private static final Map<String, Constructor> delegateClasses = new HashMap<String, Constructor>();
0054:            static {
0055:                try {
0056:                    delegateClasses.put(DocumentTypeIdentifier.NAME,
0057:                            DocumentTypeIdentifier.class
0058:                                    .getConstructor(Identifier.class));
0059:                    delegateClasses.put(DocumentNameIdentifier.NAME,
0060:                            DocumentNameIdentifier.class
0061:                                    .getConstructor(Identifier.class));
0062:                    delegateClasses.put(CreationTimeIdentifier.NAME,
0063:                            CreationTimeIdentifier.class
0064:                                    .getConstructor(Identifier.class));
0065:                    delegateClasses.put(DocumentIdIdentifier.NAME,
0066:                            DocumentIdIdentifier.class
0067:                                    .getConstructor(Identifier.class));
0068:                    delegateClasses.put(DocumentNamespaceIdentifier.NAME,
0069:                            DocumentNamespaceIdentifier.class
0070:                                    .getConstructor(Identifier.class));
0071:                    delegateClasses.put(DocumentLinkIdentifier.NAME,
0072:                            DocumentLinkIdentifier.class
0073:                                    .getConstructor(Identifier.class));
0074:                    delegateClasses.put(SummaryIdentifier.NAME,
0075:                            SummaryIdentifier.class
0076:                                    .getConstructor(Identifier.class));
0077:                    delegateClasses.put(VersionCreationTimeIdentifier.NAME,
0078:                            VersionCreationTimeIdentifier.class
0079:                                    .getConstructor(Identifier.class));
0080:                    delegateClasses.put(VersionCreatorIdIdentifier.NAME,
0081:                            VersionCreatorIdIdentifier.class
0082:                                    .getConstructor(Identifier.class));
0083:                    delegateClasses.put(VersionCreatorNameIdentifier.NAME,
0084:                            VersionCreatorNameIdentifier.class
0085:                                    .getConstructor(Identifier.class));
0086:                    delegateClasses.put(VersionCreatorLoginIdentifier.NAME,
0087:                            VersionCreatorLoginIdentifier.class
0088:                                    .getConstructor(Identifier.class));
0089:                    delegateClasses.put(VersionStateIdentifier.NAME,
0090:                            VersionStateIdentifier.class
0091:                                    .getConstructor(Identifier.class));
0092:                    delegateClasses.put(TotalSizeOfPartsIdentifier.NAME,
0093:                            TotalSizeOfPartsIdentifier.class
0094:                                    .getConstructor(Identifier.class));
0095:                    // note: the old (pre 2.2 name) of this property is deprecated and will be removed in the future
0096:                    delegateClasses.put(
0097:                            VersionLastModifiedIdentifier.PRE_2_2_NAME,
0098:                            VersionLastModifiedIdentifier.class
0099:                                    .getConstructor(Identifier.class));
0100:                    delegateClasses.put(VersionLastModifiedIdentifier.NAME,
0101:                            VersionLastModifiedIdentifier.class
0102:                                    .getConstructor(Identifier.class));
0103:                    delegateClasses.put(RetiredIdentifier.NAME,
0104:                            RetiredIdentifier.class
0105:                                    .getConstructor(Identifier.class));
0106:                    delegateClasses.put(PrivateIdentifier.NAME,
0107:                            PrivateIdentifier.class
0108:                                    .getConstructor(Identifier.class));
0109:                    delegateClasses.put(LockTypeIdentifier.NAME,
0110:                            LockTypeIdentifier.class
0111:                                    .getConstructor(Identifier.class));
0112:                    delegateClasses.put(LockOwnerIdIdentifier.NAME,
0113:                            LockOwnerIdIdentifier.class
0114:                                    .getConstructor(Identifier.class));
0115:                    delegateClasses.put(LockOwnerLoginIdentifier.NAME,
0116:                            LockOwnerLoginIdentifier.class
0117:                                    .getConstructor(Identifier.class));
0118:                    delegateClasses.put(LockOwnerNameIdentifier.NAME,
0119:                            LockOwnerNameIdentifier.class
0120:                                    .getConstructor(Identifier.class));
0121:                    delegateClasses.put(LockDurationIdentifier.NAME,
0122:                            LockDurationIdentifier.class
0123:                                    .getConstructor(Identifier.class));
0124:                    delegateClasses.put(LockTimeAcquiredIdentifier.NAME,
0125:                            LockTimeAcquiredIdentifier.class
0126:                                    .getConstructor(Identifier.class));
0127:                    delegateClasses.put(OwnerIdIdentifier.NAME,
0128:                            OwnerIdIdentifier.class
0129:                                    .getConstructor(Identifier.class));
0130:                    delegateClasses.put(OwnerLoginIdentifier.NAME,
0131:                            OwnerLoginIdentifier.class
0132:                                    .getConstructor(Identifier.class));
0133:                    delegateClasses.put(OwnerNameIdentifier.NAME,
0134:                            OwnerNameIdentifier.class
0135:                                    .getConstructor(Identifier.class));
0136:                    delegateClasses.put(LastModifierIdIdentifier.NAME,
0137:                            LastModifierIdIdentifier.class
0138:                                    .getConstructor(Identifier.class));
0139:                    delegateClasses.put(LastModifierLoginIdentifier.NAME,
0140:                            LastModifierLoginIdentifier.class
0141:                                    .getConstructor(Identifier.class));
0142:                    delegateClasses.put(LastModifierNameIdentifier.NAME,
0143:                            LastModifierNameIdentifier.class
0144:                                    .getConstructor(Identifier.class));
0145:                    delegateClasses.put(LastModifiedIdentifier.NAME,
0146:                            LastModifiedIdentifier.class
0147:                                    .getConstructor(Identifier.class));
0148:                    delegateClasses.put(BranchIdIdentifier.NAME,
0149:                            BranchIdIdentifier.class
0150:                                    .getConstructor(Identifier.class));
0151:                    delegateClasses.put(BranchNameIdentifier.NAME,
0152:                            BranchNameIdentifier.class
0153:                                    .getConstructor(Identifier.class));
0154:                    delegateClasses.put(LanguageIdIdentifier.NAME,
0155:                            LanguageIdIdentifier.class
0156:                                    .getConstructor(Identifier.class));
0157:                    delegateClasses.put(LanguageNameIdentifier.NAME,
0158:                            LanguageNameIdentifier.class
0159:                                    .getConstructor(Identifier.class));
0160:                    delegateClasses.put(VariantLastModifiedIdentifier.NAME,
0161:                            VariantLastModifiedIdentifier.class
0162:                                    .getConstructor(Identifier.class));
0163:                    delegateClasses.put(VariantLastModifierIdIdentifier.NAME,
0164:                            VariantLastModifierIdIdentifier.class
0165:                                    .getConstructor(Identifier.class));
0166:                    delegateClasses.put(
0167:                            VariantLastModifierLoginIdentifier.NAME,
0168:                            VariantLastModifierLoginIdentifier.class
0169:                                    .getConstructor(Identifier.class));
0170:                    delegateClasses.put(VariantLastModifierNameIdentifier.NAME,
0171:                            VariantLastModifierNameIdentifier.class
0172:                                    .getConstructor(Identifier.class));
0173:                    delegateClasses.put(CollectionsIdentifier.NAME,
0174:                            CollectionsIdentifier.class
0175:                                    .getConstructor(Identifier.class));
0176:                    delegateClasses.put(CollectionsValueCountIdentifier.NAME,
0177:                            CollectionsValueCountIdentifier.class
0178:                                    .getConstructor(Identifier.class));
0179:                    delegateClasses.put(VariantsIdentifier.NAME,
0180:                            VariantsIdentifier.class
0181:                                    .getConstructor(Identifier.class));
0182:                    delegateClasses.put(VariantsValueCountIdentifier.NAME,
0183:                            VariantsValueCountIdentifier.class
0184:                                    .getConstructor(Identifier.class));
0185:                    delegateClasses.put(VersionIdIdentifier.NAME,
0186:                            VersionIdIdentifier.class
0187:                                    .getConstructor(Identifier.class));
0188:                    delegateClasses.put(ScoreIdentifier.NAME,
0189:                            ScoreIdentifier.class
0190:                                    .getConstructor(Identifier.class));
0191:                    delegateClasses.put(ReferenceLanguageIdIdentifier.NAME,
0192:                            ReferenceLanguageIdIdentifier.class
0193:                                    .getConstructor(Identifier.class));
0194:                    delegateClasses.put(ReferenceLanguageNameIdentifier.NAME,
0195:                            ReferenceLanguageNameIdentifier.class
0196:                                    .getConstructor(Identifier.class));
0197:                    delegateClasses.put(VersionChangeTypeIdentifier.NAME,
0198:                            VersionChangeTypeIdentifier.class
0199:                                    .getConstructor(Identifier.class));
0200:                    delegateClasses.put(VersionCommentIdentifier.NAME,
0201:                            VersionCommentIdentifier.class
0202:                                    .getConstructor(Identifier.class));
0203:                    delegateClasses.put(
0204:                            LastMajorChangeVersionIdIdentifier.NAME,
0205:                            LastMajorChangeVersionIdIdentifier.class
0206:                                    .getConstructor(Identifier.class));
0207:                    delegateClasses.put(
0208:                            LiveMajorChangeVersionIdIdentifier.NAME,
0209:                            LiveMajorChangeVersionIdIdentifier.class
0210:                                    .getConstructor(Identifier.class));
0211:                    delegateClasses.put(SyncedWithIdentifier.NAME,
0212:                            SyncedWithIdentifier.class
0213:                                    .getConstructor(Identifier.class));
0214:                    delegateClasses.put(SyncedWithVersionIdIdentifier.NAME,
0215:                            SyncedWithVersionIdIdentifier.class
0216:                                    .getConstructor(Identifier.class));
0217:                    delegateClasses.put(SyncedWithLanguageIdIdentifier.NAME,
0218:                            SyncedWithLanguageIdIdentifier.class
0219:                                    .getConstructor(Identifier.class));
0220:                    delegateClasses.put(SyncedWithLanguageNameIdentifier.NAME,
0221:                            SyncedWithLanguageNameIdentifier.class
0222:                                    .getConstructor(Identifier.class));
0223:                } catch (Exception e) {
0224:                    throw new RuntimeException(
0225:                            "Error initializing delegate identifier map.", e);
0226:                }
0227:            }
0228:            private static final QValueType[] valueTypeToOutputValueType;
0229:            static {
0230:                valueTypeToOutputValueType = new QValueType[9];
0231:                valueTypeToOutputValueType[ValueType.STRING.getCode()] = QValueType.STRING;
0232:                valueTypeToOutputValueType[ValueType.DATE.getCode()] = QValueType.DATE;
0233:                valueTypeToOutputValueType[ValueType.DATETIME.getCode()] = QValueType.DATETIME;
0234:                valueTypeToOutputValueType[ValueType.LONG.getCode()] = QValueType.LONG;
0235:                valueTypeToOutputValueType[ValueType.DOUBLE.getCode()] = QValueType.DOUBLE;
0236:                valueTypeToOutputValueType[ValueType.DECIMAL.getCode()] = QValueType.DECIMAL;
0237:                valueTypeToOutputValueType[ValueType.BOOLEAN.getCode()] = QValueType.BOOLEAN;
0238:                valueTypeToOutputValueType[ValueType.LINK.getCode()] = QValueType.LINK;
0239:            }
0240:            private static final long CONTENT_INCLUDE_LIMIT = 200000; // about 200k
0241:
0242:            public Identifier(String id, String subId,
0243:                    ValueExpr multiValueIndexExpr, ValueExpr hierarchyIndexExpr) {
0244:                this .id = id;
0245:                this .subId = subId;
0246:                this .multiValueIndexExpr = multiValueIndexExpr;
0247:                this .hierarchyIndexExpr = hierarchyIndexExpr;
0248:            }
0249:
0250:            protected Identifier(String id, String subId, QueryContext context,
0251:                    DelegateIdentifier delegate) {
0252:                this .id = id;
0253:                this .subId = subId;
0254:                this .multiValueIndexExpr = null;
0255:                this .hierarchyIndexExpr = null;
0256:                this .prepareOnlyQueryContext = context;
0257:                this .delegate = delegate;
0258:            }
0259:
0260:            public ValueExpr clone() {
0261:                Identifier clone = new Identifier(this .id, this .subId,
0262:                        this .multiValueIndexExpr, this .hierarchyIndexExpr);
0263:                if (this .prepareOnlyQueryContext == null)
0264:                    throw new RuntimeException(
0265:                            "Cannot clone non-prepared identifier");
0266:                try {
0267:                    // easier to re-prepare then to implement cloning of the delegates too
0268:                    clone.prepare(this .prepareOnlyQueryContext);
0269:                } catch (QueryException e) {
0270:                    throw new RuntimeException(
0271:                            "Unexpected exception while cloning identifier", e);
0272:                }
0273:                return clone;
0274:            }
0275:
0276:            public void prepare(QueryContext context) throws QueryException {
0277:                this .prepareOnlyQueryContext = context;
0278:
0279:                if ((multiValueIndexExpr != null || hierarchyIndexExpr != null)
0280:                        && id.charAt(0) != '$')
0281:                    throw new QueryException(
0282:                            "Index-expressions ([..]) can only be used with field identifiers, at "
0283:                                    + getLocation());
0284:
0285:                if (id.charAt(0) == '$') { // id's starting with $ represent fields
0286:                    String fieldName = id.substring(1);
0287:
0288:                    FieldType fieldType;
0289:                    try {
0290:                        fieldType = context.getFieldTypeByName(fieldName);
0291:                    } catch (RepositoryException e) {
0292:                        throw new QueryException("Error with identifier \""
0293:                                + id + "\".", e);
0294:                    }
0295:
0296:                    if (multiValueIndexExpr != null) {
0297:                        if (!fieldType.isMultiValue())
0298:                            throw new QueryException(
0299:                                    "A multivalue index ([..]) is specified for a non-multivalue field, at "
0300:                                            + multiValueIndexExpr.getLocation());
0301:                        multiValueIndexExpr.prepare(context);
0302:                        if (!ValueExprUtil.isCompatPrimitiveValue(
0303:                                QValueType.LONG, multiValueIndexExpr)) {
0304:                            throw new QueryException(
0305:                                    "Multivalue index should evaluate to a long value, at "
0306:                                            + multiValueIndexExpr.getLocation());
0307:                        }
0308:                    }
0309:
0310:                    if (hierarchyIndexExpr != null) {
0311:                        if (!fieldType.isHierarchical())
0312:                            throw new QueryException(
0313:                                    "A hierarchy path index ([..][..]) is specified for a non-hierarchical field, at "
0314:                                            + hierarchyIndexExpr.getLocation());
0315:                        hierarchyIndexExpr.prepare(context);
0316:                        if (!ValueExprUtil.isCompatPrimitiveValue(
0317:                                QValueType.LONG, hierarchyIndexExpr)) {
0318:                            throw new QueryException(
0319:                                    "Hierarchy path index should evaluate to a long value, at "
0320:                                            + hierarchyIndexExpr.getLocation());
0321:                        }
0322:                    }
0323:
0324:                    if (subId == null) {
0325:                        this .delegate = new FieldIdentifier(fieldType);
0326:                    } else if (subId.equals(FieldValueCountIdentifier.NAME)) {
0327:                        this .delegate = new FieldValueCountIdentifier(fieldType);
0328:                    } else if (subId.equals(LinkFieldDocumentIdIdentifier.NAME)) {
0329:                        if (fieldType.getValueType() != ValueType.LINK)
0330:                            throw new QueryException(
0331:                                    "Sub-field identifier "
0332:                                            + LinkFieldDocumentIdIdentifier.NAME
0333:                                            + " can only be used with link-type fields.");
0334:                        this .delegate = new LinkFieldDocumentIdIdentifier(
0335:                                fieldType);
0336:                    } else if (subId.equals(LinkFieldBranchIdIdentifier.NAME)) {
0337:                        if (fieldType.getValueType() != ValueType.LINK)
0338:                            throw new QueryException(
0339:                                    "Sub-field identifier "
0340:                                            + LinkFieldBranchIdIdentifier.NAME
0341:                                            + " can only be used with link-type fields.");
0342:                        this .delegate = new LinkFieldBranchIdIdentifier(
0343:                                fieldType);
0344:                    } else if (subId.equals(LinkFieldLanguageIdIdentifier.NAME)) {
0345:                        if (fieldType.getValueType() != ValueType.LINK)
0346:                            throw new QueryException(
0347:                                    "Sub-field identifier "
0348:                                            + LinkFieldLanguageIdIdentifier.NAME
0349:                                            + " can only be used with link-type fields.");
0350:                        this .delegate = new LinkFieldLanguageIdIdentifier(
0351:                                fieldType);
0352:                    } else if (subId.equals(LinkFieldBranchIdentifier.NAME)) {
0353:                        if (fieldType.getValueType() != ValueType.LINK)
0354:                            throw new QueryException(
0355:                                    "Sub-field identifier "
0356:                                            + LinkFieldBranchIdentifier.NAME
0357:                                            + " can only be used with link-type fields.");
0358:                        this .delegate = new LinkFieldBranchIdentifier(fieldType);
0359:                    } else if (subId.equals(LinkFieldLanguageIdentifier.NAME)) {
0360:                        if (fieldType.getValueType() != ValueType.LINK)
0361:                            throw new QueryException(
0362:                                    "Sub-field identifier "
0363:                                            + LinkFieldLanguageIdentifier.NAME
0364:                                            + " can only be used with link-type fields.");
0365:                        this .delegate = new LinkFieldLanguageIdentifier(
0366:                                fieldType);
0367:                    } else if (subId.equals(LinkFieldNamespaceIdentifier.NAME)) {
0368:                        if (fieldType.getValueType() != ValueType.LINK)
0369:                            throw new QueryException(
0370:                                    "Sub-field identifier "
0371:                                            + LinkFieldNamespaceIdentifier.NAME
0372:                                            + " can only be used with link-type fields.");
0373:                        this .delegate = new LinkFieldNamespaceIdentifier(
0374:                                fieldType);
0375:                    } else {
0376:                        throw new QueryException(
0377:                                "Invalid sub-field identifier: " + subId);
0378:                    }
0379:                } else if (id.charAt(0) == '%') { // id's starting with % represent parts
0380:                    String partId = id.substring(1);
0381:                    if (subId == null)
0382:                        throw new QueryException(
0383:                                "Identifier \""
0384:                                        + id
0385:                                        + "\": missing sub-part identifier (ie a dot followed by what information of the part to use).");
0386:
0387:                    PartType partType;
0388:                    try {
0389:                        partType = context.getPartTypeByName(partId);
0390:                    } catch (RepositoryException e) {
0391:                        throw new QueryException("Error with identifier \""
0392:                                + id + "\".", e);
0393:                    }
0394:
0395:                    if (subId.equals("content")) {
0396:                        this .delegate = new PartContentIdentifier(id, partType);
0397:                    } else if (subId.equals("mimeType")) {
0398:                        this .delegate = new PartMimeTypeIdentifier(id, partType);
0399:                    } else if (subId.equals("size")) {
0400:                        this .delegate = new PartSizeIdentifier(id, partType);
0401:                    } else {
0402:                        throw new QueryException("Identifier \"" + id
0403:                                + "\": invalid subpart id \"" + subId + "\".");
0404:                    }
0405:                } else if (id.charAt(0) == '#') {
0406:                    String customFieldName = id.substring(1);
0407:                    this .delegate = new CustomFieldIdentifier(customFieldName);
0408:                } else {
0409:                    String fullId = subId == null ? id : id + "." + subId;
0410:                    Constructor constructor = delegateClasses.get(fullId);
0411:                    if (constructor == null) {
0412:                        throw new QueryException("Unknown identifier: \""
0413:                                + fullId + "\".");
0414:                    } else {
0415:                        try {
0416:                            this .delegate = (DelegateIdentifier) constructor
0417:                                    .newInstance(this );
0418:                        } catch (Exception e) {
0419:                            throw new QueryException(
0420:                                    "Error instantiating identifier class.", e);
0421:                        }
0422:                    }
0423:                }
0424:            }
0425:
0426:            public Object evaluate(QValueType valueType, ExprDocData data,
0427:                    EvaluationInfo evaluationInfo) throws QueryException {
0428:                if (data == null)
0429:                    throw new ExprDocDataMissingException(getExpression(),
0430:                            getLocation());
0431:                return delegate.evaluate(data, evaluationInfo);
0432:            }
0433:
0434:            public String getSqlPreConditions(SqlGenerationContext context)
0435:                    throws QueryException {
0436:                return delegate.getSqlPreConditions(context);
0437:            }
0438:
0439:            public void generateSqlValueExpr(StringBuilder sql,
0440:                    SqlGenerationContext context) throws QueryException {
0441:                delegate.generateSqlValueExpr(sql, context);
0442:            }
0443:
0444:            public int bindPreConditions(PreparedStatement stmt, int bindPos,
0445:                    EvaluationInfo evaluationInfo) throws SQLException,
0446:                    QueryException {
0447:                return delegate
0448:                        .bindPreConditions(stmt, bindPos, evaluationInfo);
0449:            }
0450:
0451:            public int bindValueExpr(PreparedStatement stmt, int bindPos,
0452:                    QValueType valueType, EvaluationInfo evaluationInfo)
0453:                    throws SQLException, QueryException {
0454:                return delegate.bindValueExpr(stmt, bindPos, valueType);
0455:            }
0456:
0457:            public QValueType getValueType() {
0458:                return delegate.getValueType();
0459:            }
0460:
0461:            public boolean isMultiValue() {
0462:                return delegate.isMultiValue();
0463:            }
0464:
0465:            public boolean isHierarchical() {
0466:                return delegate.isHierarchical();
0467:            }
0468:
0469:            public QValueType getOutputValueType() {
0470:                return delegate.getOutputValueType();
0471:            }
0472:
0473:            public final Object getOutputValue(ExprDocData data,
0474:                    EvaluationInfo evaluationInfo) throws QueryException {
0475:                if (data == null)
0476:                    throw new ExprDocDataMissingException(getExpression(),
0477:                            getLocation());
0478:                return delegate.getOutputValue(data, evaluationInfo);
0479:            }
0480:
0481:            public String getTitle(Locale locale) {
0482:                return delegate.getTitle(locale);
0483:            }
0484:
0485:            public String getExpression() {
0486:                StringBuilder expr = new StringBuilder();
0487:                expr.append(id);
0488:                if (multiValueIndexExpr != null) {
0489:                    expr.append("[")
0490:                            .append(multiValueIndexExpr.getExpression())
0491:                            .append("]");
0492:                }
0493:                if (hierarchyIndexExpr != null) {
0494:                    if (multiValueIndexExpr != null)
0495:                        expr.append("[*]");
0496:                    expr.append("[").append(hierarchyIndexExpr.getExpression())
0497:                            .append("]");
0498:                }
0499:                if (subId != null)
0500:                    expr.append(".").append(subId);
0501:                return expr.toString();
0502:            }
0503:
0504:            /**
0505:             * May this identifier be used in ACL evaluation expressions?
0506:             */
0507:            public AclConditionViolation isAclAllowed() {
0508:                return delegate.isAclAllowed();
0509:            }
0510:
0511:            /**
0512:             * Must only be implemented by classes for which
0513:             * isAclAllowed returns null.
0514:             */
0515:            public boolean canTestAppliesTo() {
0516:                return delegate.canTestappliesTo();
0517:            }
0518:
0519:            public boolean isSymbolicIdentifier() {
0520:                return delegate.isSymbolic();
0521:            }
0522:
0523:            public Object translateSymbolic(ValueExpr valueExpr,
0524:                    EvaluationInfo evaluationInfo) throws QueryException {
0525:                return delegate.translateSymbolic(valueExpr, evaluationInfo);
0526:            }
0527:
0528:            /**
0529:             * If true, then this identifier does not present a field on which can be searched,
0530:             * and only the method getOutputValue should be called on it.
0531:             */
0532:            public boolean isOutputOnly() {
0533:                return delegate.isOutputOnly();
0534:            }
0535:
0536:            public void collectAccessRestrictions(
0537:                    AccessRestrictions restrictions) {
0538:                delegate.collectAccessRestrictions(restrictions);
0539:            }
0540:
0541:            public void doInContext(SqlGenerationContext context,
0542:                    ContextualizedRunnable runnable) throws QueryException {
0543:                runnable.run(context);
0544:            }
0545:
0546:            public DelegateIdentifier getDelegate() {
0547:                return delegate;
0548:            }
0549:
0550:            /**
0551:             * If isMultiValue() returns true, this method returns the corresponding value count
0552:             * identifier.
0553:             */
0554:            Identifier getValueCountIdentifier() {
0555:                return delegate.getValueCountIdentifier();
0556:            }
0557:
0558:            interface DelegateIdentifier {
0559:                void prepare(QueryContext context);
0560:
0561:                QValueType getValueType();
0562:
0563:                boolean isMultiValue();
0564:
0565:                boolean isHierarchical();
0566:
0567:                Identifier getValueCountIdentifier();
0568:
0569:                Object evaluate(ExprDocData data, EvaluationInfo evaluationInfo)
0570:                        throws QueryException;
0571:
0572:                AclConditionViolation isAclAllowed();
0573:
0574:                String getSqlPreConditions(SqlGenerationContext context)
0575:                        throws QueryException;
0576:
0577:                void generateSqlValueExpr(StringBuilder sql,
0578:                        SqlGenerationContext context) throws QueryException;
0579:
0580:                int bindPreConditions(PreparedStatement stmt, int bindPos,
0581:                        EvaluationInfo evaluationInfo) throws SQLException,
0582:                        QueryException;
0583:
0584:                public int bindValueExpr(PreparedStatement stmt, int bindPos,
0585:                        QValueType valueType) throws SQLException,
0586:                        QueryException;
0587:
0588:                boolean isSymbolic();
0589:
0590:                Object translateSymbolic(ValueExpr valueExpr,
0591:                        EvaluationInfo evaluationInfo) throws QueryException;
0592:
0593:                QValueType getOutputValueType();
0594:
0595:                Object getOutputValue(ExprDocData data,
0596:                        EvaluationInfo evaluationInfo) throws QueryException;
0597:
0598:                boolean canTestappliesTo();
0599:
0600:                boolean isOutputOnly();
0601:
0602:                String getName();
0603:
0604:                String getTitle(Locale locale);
0605:
0606:                void collectAccessRestrictions(AccessRestrictions restrictions);
0607:            }
0608:
0609:            public abstract class AbstractIdentifier implements 
0610:                    DelegateIdentifier {
0611:                public void prepare(QueryContext context) {
0612:                }
0613:
0614:                public boolean isMultiValue() {
0615:                    return false;
0616:                }
0617:
0618:                public boolean isHierarchical() {
0619:                    return false;
0620:                }
0621:
0622:                public Identifier getValueCountIdentifier() {
0623:                    return null;
0624:                }
0625:
0626:                public AclConditionViolation isAclAllowed() {
0627:                    return null;
0628:                }
0629:
0630:                public String getTitle(Locale locale) {
0631:                    return getLocalizedString(getName(), locale);
0632:                }
0633:
0634:                public boolean isSymbolic() {
0635:                    return false;
0636:                }
0637:
0638:                public Object translateSymbolic(ValueExpr valueExpr,
0639:                        EvaluationInfo evaluationInfo) throws QueryException {
0640:                    throw new QueryException(
0641:                            "translateSymbolic should not be called if isSymbolic returns false");
0642:                }
0643:
0644:                public boolean canTestappliesTo() {
0645:                    return false;
0646:                }
0647:
0648:                public String getSqlPreConditions(SqlGenerationContext context)
0649:                        throws QueryException {
0650:                    return null;
0651:                }
0652:
0653:                public int bindPreConditions(PreparedStatement stmt,
0654:                        int bindPos, EvaluationInfo evaluationInfo)
0655:                        throws SQLException, QueryException {
0656:                    return bindPos;
0657:                }
0658:
0659:                public int bindValueExpr(PreparedStatement stmt, int bindPos,
0660:                        QValueType valueType) throws SQLException,
0661:                        QueryException {
0662:                    return bindPos;
0663:                }
0664:
0665:                public boolean isOutputOnly() {
0666:                    return false;
0667:                }
0668:
0669:                public void collectAccessRestrictions(
0670:                        AccessRestrictions restrictions) {
0671:                    // do nothing
0672:                }
0673:            }
0674:
0675:            public abstract class AbstractNonAclIdentifier extends
0676:                    AbstractIdentifier {
0677:                public AclConditionViolation isAclAllowed() {
0678:                    return new AclConditionViolation("Identifier '" + getName()
0679:                            + "' is not allowed in ACL conditions.");
0680:                }
0681:            }
0682:
0683:            public abstract class AbstractFieldIdentifier extends
0684:                    AbstractIdentifier {
0685:                protected FieldType fieldType;
0686:
0687:                protected AbstractFieldIdentifier(FieldType fieldType) {
0688:                    this .fieldType = fieldType;
0689:                }
0690:
0691:                public boolean isMultiValue() {
0692:                    return fieldType.isMultiValue()
0693:                            && multiValueIndexExpr == null;
0694:                }
0695:
0696:                public boolean isHierarchical() {
0697:                    return fieldType.isHierarchical()
0698:                            && hierarchyIndexExpr == null;
0699:                }
0700:
0701:                public String getSqlPreConditions(SqlGenerationContext context)
0702:                        throws QueryException {
0703:                    if (multiValueIndexExpr == null
0704:                            && hierarchyIndexExpr == null)
0705:                        return null;
0706:
0707:                    StringBuilder builder = new StringBuilder();
0708:
0709:                    builder.append(" (");
0710:                    if (multiValueIndexExpr != null) {
0711:                        String mvPreCond = multiValueIndexExpr
0712:                                .getSqlPreConditions(context);
0713:                        if (mvPreCond != null)
0714:                            builder.append(mvPreCond);
0715:
0716:                        builder.append(getTableAlias()).append(".value_seq")
0717:                                .append(" = ");
0718:                        multiValueIndexExpr.generateSqlValueExpr(builder,
0719:                                context);
0720:
0721:                        // support negative index counting from the end
0722:                        builder.append(" or ");
0723:                        builder.append(getTableAlias()).append(".value_seq")
0724:                                .append(" = ");
0725:                        builder.append(getTableAlias()).append(".value_count")
0726:                                .append(" + 1 + ");
0727:                        multiValueIndexExpr.generateSqlValueExpr(builder,
0728:                                context);
0729:                    }
0730:
0731:                    if (hierarchyIndexExpr != null) {
0732:                        if (multiValueIndexExpr != null)
0733:                            builder.append(" and ");
0734:                        String hierPreCond = hierarchyIndexExpr
0735:                                .getSqlPreConditions(context);
0736:                        if (hierPreCond != null)
0737:                            builder.append(hierPreCond);
0738:
0739:                        builder.append(getTableAlias()).append(".hier_seq")
0740:                                .append(" = ");
0741:                        hierarchyIndexExpr.generateSqlValueExpr(builder,
0742:                                context);
0743:
0744:                        // support negative index counting from the end
0745:                        builder.append("or ");
0746:                        builder.append(getTableAlias()).append(".hier_seq")
0747:                                .append(" = ");
0748:                        builder.append(getTableAlias()).append(".hier_count")
0749:                                .append(" + 1 + ");
0750:                        hierarchyIndexExpr.generateSqlValueExpr(builder,
0751:                                context);
0752:                    }
0753:                    builder.append(") ");
0754:
0755:                    return builder.toString();
0756:                }
0757:
0758:                public int bindPreConditions(PreparedStatement stmt,
0759:                        int bindPos, EvaluationInfo evaluationInfo)
0760:                        throws SQLException, QueryException {
0761:                    if (multiValueIndexExpr != null) {
0762:                        bindPos = multiValueIndexExpr.bindPreConditions(stmt,
0763:                                bindPos, evaluationInfo);
0764:                        bindPos = multiValueIndexExpr.bindValueExpr(stmt,
0765:                                bindPos, QValueType.LONG, evaluationInfo);
0766:                        bindPos = multiValueIndexExpr.bindValueExpr(stmt,
0767:                                bindPos, QValueType.LONG, evaluationInfo);
0768:                    }
0769:
0770:                    if (hierarchyIndexExpr != null) {
0771:                        bindPos = hierarchyIndexExpr.bindPreConditions(stmt,
0772:                                bindPos, evaluationInfo);
0773:                        bindPos = hierarchyIndexExpr.bindValueExpr(stmt,
0774:                                bindPos, QValueType.LONG, evaluationInfo);
0775:                        bindPos = hierarchyIndexExpr.bindValueExpr(stmt,
0776:                                bindPos, QValueType.LONG, evaluationInfo);
0777:                    }
0778:
0779:                    return bindPos;
0780:                }
0781:
0782:                public abstract String getTableAlias();
0783:
0784:                public Object processValue(Object object, ExprDocData data,
0785:                        EvaluationInfo evaluationInfo,
0786:                        ValueExtractor valueExtractor) throws QueryException {
0787:                    if (object instanceof  Object[]) {
0788:                        return processMultiValue((Object[]) object, data,
0789:                                evaluationInfo, valueExtractor);
0790:                    } else if (object instanceof  HierarchyPath) {
0791:                        return processHierarchyPath((HierarchyPath) object,
0792:                                data, evaluationInfo, valueExtractor);
0793:                    } else {
0794:                        return valueExtractor.extract(object);
0795:                    }
0796:                }
0797:
0798:                private Object processMultiValue(Object[] values,
0799:                        ExprDocData data, EvaluationInfo evaluationInfo,
0800:                        ValueExtractor valueExtractor) throws QueryException {
0801:                    if (multiValueIndexExpr != null) {
0802:                        Number number = (Number) multiValueIndexExpr.evaluate(
0803:                                QValueType.LONG, data, evaluationInfo);
0804:                        if (number == null)
0805:                            return null;
0806:                        int index = number.intValue();
0807:                        index = index < 0 ? values.length + index : index - 1;
0808:                        if (index >= 0 && index < values.length)
0809:                            return processValue(values[index], data,
0810:                                    evaluationInfo, valueExtractor);
0811:                        return null;
0812:                    } else {
0813:                        List<Object> result = new ArrayList<Object>(
0814:                                values.length);
0815:                        for (Object value : values) {
0816:                            value = processValue(value, data, evaluationInfo,
0817:                                    valueExtractor);
0818:                            if (value != null)
0819:                                result.add(value);
0820:                        }
0821:                        return result.isEmpty() ? null : result.toArray();
0822:                    }
0823:                }
0824:
0825:                private Object processHierarchyPath(HierarchyPath path,
0826:                        ExprDocData data, EvaluationInfo evaluationInfo,
0827:                        ValueExtractor valueExtractor) throws QueryException {
0828:                    Object[] elements = path.getElements();
0829:                    if (hierarchyIndexExpr != null) {
0830:                        Number number = (Number) hierarchyIndexExpr.evaluate(
0831:                                QValueType.LONG, data, evaluationInfo);
0832:                        if (number == null)
0833:                            return null;
0834:                        int index = number.intValue();
0835:                        index = index < 0 ? elements.length + index : index - 1;
0836:                        if (index >= 0 && index < elements.length)
0837:                            return valueExtractor.extract(elements[index]);
0838:                        return null;
0839:                    } else {
0840:                        Object[] newElements = new Object[elements.length];
0841:                        for (int i = 0; i < elements.length; i++) {
0842:                            newElements[i] = valueExtractor
0843:                                    .extract(elements[i]);
0844:                        }
0845:                        return new HierarchyPath(newElements);
0846:                    }
0847:                }
0848:
0849:                public void collectAccessRestrictions(
0850:                        AccessRestrictions resrestrictions) {
0851:                    resrestrictions.addFieldReference(fieldType.getName());
0852:                }
0853:            }
0854:
0855:            private static interface ValueExtractor {
0856:                public Object extract(Object object);
0857:            }
0858:
0859:            public final class FieldIdentifier extends AbstractFieldIdentifier {
0860:                private String alias;
0861:                private QValueType valueType;
0862:
0863:                public FieldIdentifier(FieldType fieldType) {
0864:                    super (fieldType);
0865:                }
0866:
0867:                public String getName() {
0868:                    return "$" + fieldType.getName();
0869:                }
0870:
0871:                public long getfieldTypeId() {
0872:                    return fieldType.getId();
0873:                }
0874:
0875:                public QValueType getValueType() {
0876:                    if (valueType == null) {
0877:                        ValueType fieldValueType = fieldType.getValueType();
0878:                        if (fieldValueType == ValueType.STRING)
0879:                            valueType = QValueType.STRING;
0880:                        else if (fieldValueType == ValueType.DATE)
0881:                            valueType = QValueType.DATE;
0882:                        else if (fieldValueType == ValueType.DATETIME)
0883:                            valueType = QValueType.DATETIME;
0884:                        else if (fieldValueType == ValueType.LONG)
0885:                            valueType = QValueType.LONG;
0886:                        else if (fieldValueType == ValueType.DOUBLE)
0887:                            valueType = QValueType.DOUBLE;
0888:                        else if (fieldValueType == ValueType.DECIMAL)
0889:                            valueType = QValueType.DECIMAL;
0890:                        else if (fieldValueType == ValueType.BOOLEAN)
0891:                            valueType = QValueType.BOOLEAN;
0892:                        else if (fieldValueType == ValueType.LINK)
0893:                            valueType = QValueType.LINK;
0894:                        else
0895:                            throw new RuntimeException(
0896:                                    "Unrecognized field value type: "
0897:                                            + fieldValueType);
0898:                    }
0899:                    return valueType;
0900:                }
0901:
0902:                public Identifier getValueCountIdentifier() {
0903:                    return new Identifier(getName(), "valueCount",
0904:                            prepareOnlyQueryContext,
0905:                            new FieldValueCountIdentifier(fieldType));
0906:                }
0907:
0908:                public Object evaluate(final ExprDocData data,
0909:                        EvaluationInfo evaluationInfo) throws QueryException {
0910:                    if (data.versionedData.hasField(fieldType.getId())) {
0911:                        Object value = data.versionedData.getField(
0912:                                fieldType.getId()).getValue();
0913:                        return super .processValue(value, data, evaluationInfo,
0914:                                new ValueExtractor() {
0915:                                    public Object extract(Object object) {
0916:                                        if (fieldType.getValueType() == ValueType.LINK) {
0917:                                            return absolutizeVariantKey(
0918:                                                    (VariantKey) object,
0919:                                                    data.document);
0920:                                        } else {
0921:                                            return object;
0922:                                        }
0923:                                    }
0924:                                });
0925:                    } else {
0926:                        return null;
0927:                    }
0928:                }
0929:
0930:                private VariantKey absolutizeVariantKey(VariantKey key,
0931:                        Document document) {
0932:                    if (key.getBranchId() == -1 || key.getLanguageId() == -1)
0933:                        return new VariantKey(key.getDocumentId(), key
0934:                                .getBranchId() == -1 ? document.getBranchId()
0935:                                : key.getBranchId(),
0936:                                key.getLanguageId() == -1 ? document
0937:                                        .getLanguageId() : key.getLanguageId());
0938:                    else
0939:                        return key;
0940:                }
0941:
0942:                public QValueType getOutputValueType() {
0943:                    return valueTypeToOutputValueType[fieldType.getValueType()
0944:                            .getCode()];
0945:                }
0946:
0947:                public Object getOutputValue(ExprDocData data,
0948:                        EvaluationInfo evaluationInfo) throws QueryException {
0949:                    return evaluate(data, evaluationInfo);
0950:                }
0951:
0952:                public AclConditionViolation isAclAllowed() {
0953:                    if (!fieldType.isAclAllowed()) {
0954:                        return new AclConditionViolation(
0955:                                "Field \""
0956:                                        + fieldType.getName()
0957:                                        + "\" (ID: "
0958:                                        + fieldType.getId()
0959:                                        + ") may not be used in ACL object expressions.");
0960:                    } else {
0961:                        return null;
0962:                    }
0963:                }
0964:
0965:                public boolean canTestappliesTo() {
0966:                    return false;
0967:                }
0968:
0969:                public String getSqlPreConditions(SqlGenerationContext context)
0970:                        throws QueryException {
0971:                    // the alias/join is [also] created here for some special conditions (like IsNull) that never make use of the value expr
0972:                    alias = context.getNewFieldsTable(fieldType.getId())
0973:                            .getName();
0974:                    return super .getSqlPreConditions(context);
0975:                }
0976:
0977:                public void generateSqlValueExpr(StringBuilder sql,
0978:                        SqlGenerationContext context) {
0979:                    String valueColumn = SqlGenerationContext.FieldsTable
0980:                            .getValueColumn(getValueType());
0981:                    sql.append(alias).append(".").append(valueColumn);
0982:                }
0983:
0984:                /**
0985:                 * For exceptional uses only.
0986:                 */
0987:                public String getTableAlias() {
0988:                    return alias;
0989:                }
0990:
0991:                public String getTitle(Locale locale) {
0992:                    return fieldType.getLabel(locale);
0993:                }
0994:            }
0995:
0996:            public final class FieldValueCountIdentifier extends
0997:                    AbstractNonAclIdentifier {
0998:                static final String NAME = "valueCount";
0999:                private final FieldType fieldType;
1000:                private String alias;
1001:
1002:                public FieldValueCountIdentifier(FieldType fieldType) {
1003:                    this .fieldType = fieldType;
1004:                }
1005:
1006:                public String getTitle(Locale locale) {
1007:                    String fieldLabel = fieldType.getLabel(locale);
1008:                    String valueCount = getLocalizedString("fieldValueCount",
1009:                            locale);
1010:                    return fieldLabel + ": " + valueCount;
1011:                }
1012:
1013:                public QValueType getValueType() {
1014:                    return QValueType.LONG;
1015:                }
1016:
1017:                public Object evaluate(ExprDocData data,
1018:                        EvaluationInfo evaluationInfo) {
1019:                    if (data.versionedData.hasField(fieldType.getId())) {
1020:                        if (fieldType.isMultiValue()) {
1021:                            return new Long(
1022:                                    ((Object[]) data.versionedData.getField(
1023:                                            fieldType.getId()).getValue()).length);
1024:                        } else {
1025:                            return new Long(1);
1026:                        }
1027:                    } else {
1028:                        return new Long(0);
1029:                    }
1030:                }
1031:
1032:                public String getSqlPreConditions(SqlGenerationContext context) {
1033:                    // the alias/join is created here for some special conditions (like IsNull) that never make use of the value expr
1034:                    alias = context.getNewFieldsTable(fieldType.getId())
1035:                            .getName();
1036:                    return null;
1037:                }
1038:
1039:                public void generateSqlValueExpr(StringBuilder sql,
1040:                        SqlGenerationContext context) {
1041:                    sql.append(alias).append('.').append("value_count");
1042:                }
1043:
1044:                public QValueType getOutputValueType() {
1045:                    return QValueType.LONG;
1046:                }
1047:
1048:                public Object getOutputValue(ExprDocData data,
1049:                        EvaluationInfo evaluationInfo) {
1050:                    return evaluate(data, null);
1051:                }
1052:
1053:                public String getName() {
1054:                    return "$" + fieldType.getName() + "." + NAME;
1055:                }
1056:
1057:                public int bindPreConditions(PreparedStatement stmt,
1058:                        int bindPos, EvaluationInfo evaluationInfo) {
1059:                    return bindPos;
1060:                }
1061:            }
1062:
1063:            public final class LinkFieldDocumentIdIdentifier extends
1064:                    AbstractFieldIdentifier {
1065:                public static final String NAME = "documentId";
1066:                private String alias;
1067:
1068:                public LinkFieldDocumentIdIdentifier(FieldType fieldType) {
1069:                    super (fieldType);
1070:                }
1071:
1072:                public String getName() {
1073:                    return "$" + fieldType.getName() + "." + NAME;
1074:                }
1075:
1076:                public QValueType getValueType() {
1077:                    return QValueType.DOCID;
1078:                }
1079:
1080:                public Object evaluate(ExprDocData data,
1081:                        EvaluationInfo evaluationInfo) throws QueryException {
1082:                    return evaluate(data, false, evaluationInfo);
1083:                }
1084:
1085:                public boolean isSymbolic() {
1086:                    return true;
1087:                }
1088:
1089:                public Object translateSymbolic(ValueExpr valueExpr,
1090:                        EvaluationInfo evaluationInfo) throws QueryException {
1091:                    String documentId = (String) valueExpr.evaluate(
1092:                            QValueType.STRING, null, evaluationInfo);
1093:                    return SqlUtils.parseDocId(documentId, evaluationInfo
1094:                            .getQueryContext());
1095:                }
1096:
1097:                public Object evaluate(ExprDocData data,
1098:                        final boolean returnStrings,
1099:                        final EvaluationInfo evaluationInfo)
1100:                        throws QueryException {
1101:                    if (data.versionedData.hasField(fieldType.getId())) {
1102:                        Object value = data.versionedData.getField(
1103:                                fieldType.getId()).getValue();
1104:                        return super .processValue(value, data, evaluationInfo,
1105:                                new ValueExtractor() {
1106:                                    public Object extract(Object object) {
1107:                                        if (returnStrings) {
1108:                                            return ((VariantKey) object)
1109:                                                    .getDocumentId();
1110:                                        } else {
1111:                                            return evaluationInfo
1112:                                                    .getQueryContext()
1113:                                                    .parseDocId(
1114:                                                            ((VariantKey) object)
1115:                                                                    .getDocumentId());
1116:                                        }
1117:                                    }
1118:                                });
1119:                    } else {
1120:                        return null;
1121:                    }
1122:                }
1123:
1124:                public String getSqlPreConditions(SqlGenerationContext context)
1125:                        throws QueryException {
1126:                    // the alias/join is [also] created here for some special conditions (like IsNull) that never make use of the value expr
1127:                    alias = context.getNewFieldsTable(fieldType.getId())
1128:                            .getName();
1129:                    return super .getSqlPreConditions(context);
1130:                }
1131:
1132:                public int bindPreConditions(PreparedStatement stmt,
1133:                        int bindPos, EvaluationInfo evaluationInfo)
1134:                        throws SQLException, QueryException {
1135:                    return super .bindPreConditions(stmt, bindPos,
1136:                            evaluationInfo);
1137:                }
1138:
1139:                public String getTableAlias() {
1140:                    return alias;
1141:                }
1142:
1143:                public void generateSqlValueExpr(StringBuilder sql,
1144:                        SqlGenerationContext context) {
1145:                    sql.append(alias).append('.').append(
1146:                            SqlGenerationContext.FieldsTable.LINK_SEARCHDOCID);
1147:                }
1148:
1149:                public QValueType getOutputValueType() {
1150:                    return QValueType.STRING;
1151:                }
1152:
1153:                public Object getOutputValue(ExprDocData data,
1154:                        EvaluationInfo evaluationInfo) throws QueryException {
1155:                    return evaluate(data, true, evaluationInfo);
1156:                }
1157:
1158:                public String getTitle(Locale locale) {
1159:                    String fieldLabel = fieldType.getLabel(locale);
1160:                    String branchId = getLocalizedString("id", locale);
1161:                    return fieldLabel + ": " + branchId;
1162:                }
1163:            }
1164:
1165:            public final class LinkFieldNamespaceIdentifier extends
1166:                    AbstractFieldIdentifier {
1167:                public static final String NAME = "namespace";
1168:                private String alias;
1169:
1170:                public LinkFieldNamespaceIdentifier(FieldType fieldType) {
1171:                    super (fieldType);
1172:                }
1173:
1174:                public String getName() {
1175:                    return "$" + fieldType.getName() + "." + NAME;
1176:                }
1177:
1178:                public QValueType getValueType() {
1179:                    return QValueType.LONG;
1180:                }
1181:
1182:                public QValueType getOutputValueType() {
1183:                    return QValueType.STRING;
1184:                }
1185:
1186:                public Object evaluate(ExprDocData data,
1187:                        EvaluationInfo evaluationInfo) throws QueryException {
1188:                    return evaluate(data, false, evaluationInfo);
1189:                }
1190:
1191:                public Object evaluate(ExprDocData data,
1192:                        final boolean returnStrings,
1193:                        final EvaluationInfo evaluationInfo)
1194:                        throws QueryException {
1195:                    if (data.versionedData.hasField(fieldType.getId())) {
1196:                        Object value = data.versionedData.getField(
1197:                                fieldType.getId()).getValue();
1198:                        return super .processValue(value, data, evaluationInfo,
1199:                                new ValueExtractor() {
1200:                                    public Object extract(Object object) {
1201:                                        if (returnStrings) {
1202:                                            return getNamespace(((VariantKey) object)
1203:                                                    .getDocumentId());
1204:                                        } else {
1205:                                            return new Long(getNamespaceId(
1206:                                                    ((VariantKey) object)
1207:                                                            .getDocumentId(),
1208:                                                    evaluationInfo
1209:                                                            .getQueryContext()));
1210:                                        }
1211:                                    }
1212:                                });
1213:                    } else {
1214:                        return null;
1215:                    }
1216:                }
1217:
1218:                private String getNamespace(String documentId) {
1219:                    int dashPos = documentId.indexOf('-');
1220:                    if (dashPos == -1)
1221:                        throw new RepositoryRuntimeException(
1222:                                "Unexpected error: no dash in document ID "
1223:                                        + documentId
1224:                                        + " in link field namespace identifier.");
1225:                    return documentId.substring(dashPos + 1);
1226:                }
1227:
1228:                private long getNamespaceId(String documentId,
1229:                        QueryContext queryContext) {
1230:                    int dashPos = documentId.indexOf('-');
1231:                    if (dashPos == -1)
1232:                        throw new RepositoryRuntimeException(
1233:                                "Unexpected error: no dash in document ID "
1234:                                        + documentId
1235:                                        + " in link field namespace identifier.");
1236:                    String ns = documentId.substring(dashPos + 1);
1237:                    try {
1238:                        return queryContext.getNamespace(ns).getId();
1239:                    } catch (NamespaceNotFoundException e) {
1240:                        throw new RepositoryRuntimeException(
1241:                                "Unexpected error: namespace in document ID "
1242:                                        + documentId
1243:                                        + " selected in link field namespace identifier for "
1244:                                        + fieldType.getName()
1245:                                        + " does not exist.");
1246:                    }
1247:                }
1248:
1249:                public Object getOutputValue(ExprDocData data,
1250:                        EvaluationInfo evaluationInfo) throws QueryException {
1251:                    return evaluate(data, true, evaluationInfo);
1252:                }
1253:
1254:                public boolean isSymbolic() {
1255:                    return true;
1256:                }
1257:
1258:                public Object translateSymbolic(ValueExpr valueExpr,
1259:                        EvaluationInfo evaluationInfo) throws QueryException {
1260:                    String namespaceName = (String) valueExpr.evaluate(
1261:                            QValueType.STRING, null, evaluationInfo);
1262:                    Namespace namespace;
1263:                    try {
1264:                        namespace = evaluationInfo.getQueryContext()
1265:                                .getNamespace(namespaceName);
1266:                    } catch (NamespaceNotFoundException e) {
1267:                        // it is inconvenient if searching on a non-registered namespace would fail
1268:                        // there return here an ID that does not exist in the database.
1269:                        return new Long(-1);
1270:                    } catch (RepositoryException e) {
1271:                        throw new QueryException(
1272:                                "Error consulting repository namespace information.",
1273:                                e);
1274:                    }
1275:                    return new Long(namespace.getId());
1276:                }
1277:
1278:                public String getSqlPreConditions(SqlGenerationContext context)
1279:                        throws QueryException {
1280:                    // the alias/join is created here for some special conditions (like IsNull) that never make use of the value expr
1281:                    alias = context.getNewFieldsTable(fieldType.getId())
1282:                            .getName();
1283:                    return super .getSqlPreConditions(context);
1284:                }
1285:
1286:                public int bindPreConditions(PreparedStatement stmt,
1287:                        int bindPos, EvaluationInfo evaluationInfo)
1288:                        throws SQLException, QueryException {
1289:                    return super .bindPreConditions(stmt, bindPos,
1290:                            evaluationInfo);
1291:                }
1292:
1293:                public String getTableAlias() {
1294:                    return alias;
1295:                }
1296:
1297:                public void generateSqlValueExpr(StringBuilder sql,
1298:                        SqlGenerationContext context) {
1299:                    sql.append(alias).append('.').append(
1300:                            SqlGenerationContext.FieldsTable.LINK_NSID);
1301:                }
1302:
1303:                public String getTitle(Locale locale) {
1304:                    String fieldLabel = fieldType.getLabel(locale);
1305:                    String namespace = getLocalizedString("namespace", locale);
1306:                    return fieldLabel + ": " + namespace;
1307:                }
1308:
1309:            }
1310:
1311:            public class LinkFieldBranchIdIdentifier extends
1312:                    AbstractFieldIdentifier {
1313:                public static final String NAME = "branchId";
1314:                private String alias;
1315:
1316:                public LinkFieldBranchIdIdentifier(FieldType fieldType) {
1317:                    super (fieldType);
1318:                }
1319:
1320:                public String getName() {
1321:                    return "$" + fieldType.getName() + "." + NAME;
1322:                }
1323:
1324:                public QValueType getValueType() {
1325:                    return QValueType.LONG;
1326:                }
1327:
1328:                public Object evaluate(ExprDocData data,
1329:                        EvaluationInfo evaluationInfo) throws QueryException {
1330:                    if (data.versionedData.hasField(fieldType.getId())) {
1331:                        final long documentBranchId = data.document
1332:                                .getBranchId();
1333:                        Object value = data.versionedData.getField(
1334:                                fieldType.getId()).getValue();
1335:                        return super .processValue(value, data, evaluationInfo,
1336:                                new ValueExtractor() {
1337:                                    public Object extract(Object object) {
1338:                                        VariantKey key = (VariantKey) object;
1339:                                        return new Long(
1340:                                                key.getBranchId() != -1 ? key
1341:                                                        .getBranchId()
1342:                                                        : documentBranchId);
1343:                                    }
1344:                                });
1345:                    } else {
1346:                        return null;
1347:                    }
1348:                }
1349:
1350:                public String getSqlPreConditions(SqlGenerationContext context)
1351:                        throws QueryException {
1352:                    alias = context.getNewFieldsTable(fieldType.getId())
1353:                            .getName();
1354:                    return super .getSqlPreConditions(context);
1355:                }
1356:
1357:                public int bindPreConditions(PreparedStatement stmt,
1358:                        int bindPos, EvaluationInfo evaluationInfo)
1359:                        throws SQLException, QueryException {
1360:                    return super .bindPreConditions(stmt, bindPos,
1361:                            evaluationInfo);
1362:                }
1363:
1364:                public String getTableAlias() {
1365:                    return alias;
1366:                }
1367:
1368:                public void generateSqlValueExpr(StringBuilder sql,
1369:                        SqlGenerationContext context) {
1370:                    sql
1371:                            .append(alias)
1372:                            .append('.')
1373:                            .append(
1374:                                    SqlGenerationContext.FieldsTable.LINK_SEARCHBRANCHID);
1375:                }
1376:
1377:                public QValueType getOutputValueType() {
1378:                    return QValueType.LONG;
1379:                }
1380:
1381:                public Object getOutputValue(ExprDocData data,
1382:                        EvaluationInfo evaluationInfo) throws QueryException {
1383:                    return evaluate(data, evaluationInfo);
1384:                }
1385:
1386:                public String getTitle(Locale locale) {
1387:                    String fieldLabel = fieldType.getLabel(locale);
1388:                    String branchId = getLocalizedString("branchId", locale);
1389:                    return fieldLabel + ": " + branchId;
1390:                }
1391:            }
1392:
1393:            public class LinkFieldLanguageIdIdentifier extends
1394:                    AbstractFieldIdentifier {
1395:                public static final String NAME = "languageId";
1396:                private String alias;
1397:
1398:                public LinkFieldLanguageIdIdentifier(FieldType fieldType) {
1399:                    super (fieldType);
1400:                }
1401:
1402:                public String getName() {
1403:                    return "$" + fieldType.getName() + "." + NAME;
1404:                }
1405:
1406:                public QValueType getValueType() {
1407:                    return QValueType.LONG;
1408:                }
1409:
1410:                public Object evaluate(ExprDocData data,
1411:                        EvaluationInfo evaluationInfo) throws QueryException {
1412:                    final long documentLanguageId = data.document
1413:                            .getLanguageId();
1414:                    if (data.versionedData.hasField(fieldType.getId())) {
1415:                        Object value = data.versionedData.getField(
1416:                                fieldType.getId()).getValue();
1417:                        return super .processValue(value, data, evaluationInfo,
1418:                                new ValueExtractor() {
1419:                                    public Object extract(Object object) {
1420:                                        VariantKey key = (VariantKey) object;
1421:                                        return new Long(
1422:                                                key.getLanguageId() != -1 ? key
1423:                                                        .getLanguageId()
1424:                                                        : documentLanguageId);
1425:                                    }
1426:                                });
1427:                    } else {
1428:                        return null;
1429:                    }
1430:                }
1431:
1432:                public String getSqlPreConditions(SqlGenerationContext context)
1433:                        throws QueryException {
1434:                    // the alias/join is created here for some special conditions (like IsNull) that never make use of the value expr
1435:                    alias = context.getNewFieldsTable(fieldType.getId())
1436:                            .getName();
1437:                    return super .getSqlPreConditions(context);
1438:                }
1439:
1440:                public int bindPreConditions(PreparedStatement stmt,
1441:                        int bindPos, EvaluationInfo evaluationInfo)
1442:                        throws SQLException, QueryException {
1443:                    return super .bindPreConditions(stmt, bindPos,
1444:                            evaluationInfo);
1445:                }
1446:
1447:                public String getTableAlias() {
1448:                    return alias;
1449:                }
1450:
1451:                public void generateSqlValueExpr(StringBuilder sql,
1452:                        SqlGenerationContext context) {
1453:                    sql.append(alias).append('.').append(
1454:                            SqlGenerationContext.FieldsTable.LINK_SEARCHLANGID);
1455:                }
1456:
1457:                public QValueType getOutputValueType() {
1458:                    return QValueType.LONG;
1459:                }
1460:
1461:                public Object getOutputValue(ExprDocData data,
1462:                        EvaluationInfo evaluationInfo) throws QueryException {
1463:                    return evaluate(data, evaluationInfo);
1464:                }
1465:
1466:                public String getTitle(Locale locale) {
1467:                    String fieldLabel = fieldType.getLabel(locale);
1468:                    String languageId = getLocalizedString("languageId", locale);
1469:                    return fieldLabel + ": " + languageId;
1470:                }
1471:            }
1472:
1473:            public final class LinkFieldBranchIdentifier extends
1474:                    LinkFieldBranchIdIdentifier {
1475:                public static final String NAME = "branch";
1476:
1477:                public LinkFieldBranchIdentifier(FieldType fieldType) {
1478:                    super (fieldType);
1479:                }
1480:
1481:                public String getName() {
1482:                    return "$" + fieldType.getName() + "." + NAME;
1483:                }
1484:
1485:                public QValueType getOutputValueType() {
1486:                    return QValueType.STRING;
1487:                }
1488:
1489:                public Object getOutputValue(ExprDocData data,
1490:                        final EvaluationInfo evaluationInfo)
1491:                        throws QueryException {
1492:                    if (data.versionedData.hasField(fieldType.getId())) {
1493:                        final long documentBranchId = data.document
1494:                                .getBranchId();
1495:                        Object value = data.versionedData.getField(
1496:                                fieldType.getId()).getValue();
1497:                        return super .processValue(value, data, evaluationInfo,
1498:                                new ValueExtractor() {
1499:                                    public Object extract(Object object) {
1500:                                        VariantKey key = (VariantKey) object;
1501:                                        long branchId = key.getBranchId() != -1 ? key
1502:                                                .getBranchId()
1503:                                                : documentBranchId;
1504:                                        try {
1505:                                            return evaluationInfo
1506:                                                    .getQueryContext()
1507:                                                    .getBranch(branchId)
1508:                                                    .getName();
1509:                                        } catch (RepositoryException e) {
1510:                                            throw new RuntimeException(e);
1511:                                        }
1512:                                    }
1513:                                });
1514:                    } else {
1515:                        return null;
1516:                    }
1517:                }
1518:
1519:                public boolean isSymbolic() {
1520:                    return true;
1521:                }
1522:
1523:                public Object translateSymbolic(ValueExpr valueExpr,
1524:                        EvaluationInfo evaluationInfo) throws QueryException {
1525:                    String branchName = (String) valueExpr.evaluate(
1526:                            QValueType.STRING, null, evaluationInfo);
1527:                    Branch branch;
1528:                    try {
1529:                        branch = evaluationInfo.getQueryContext()
1530:                                .getBranchByName(branchName);
1531:                    } catch (RepositoryException e) {
1532:                        throw new QueryException("Error with branch name \""
1533:                                + branchName + "\".", e);
1534:                    }
1535:                    return new Long(branch.getId());
1536:                }
1537:
1538:                public String getTitle(Locale locale) {
1539:                    String fieldLabel = fieldType.getLabel(locale);
1540:                    String branch = getLocalizedString("branch", locale);
1541:                    return fieldLabel + ": " + branch;
1542:                }
1543:            }
1544:
1545:            public final class LinkFieldLanguageIdentifier extends
1546:                    LinkFieldLanguageIdIdentifier {
1547:                public static final String NAME = "language";
1548:
1549:                public LinkFieldLanguageIdentifier(FieldType fieldType) {
1550:                    super (fieldType);
1551:                }
1552:
1553:                public String getName() {
1554:                    return "$" + fieldType.getName() + "." + NAME;
1555:                }
1556:
1557:                public QValueType getOutputValueType() {
1558:                    return QValueType.STRING;
1559:                }
1560:
1561:                public Object getOutputValue(ExprDocData data,
1562:                        final EvaluationInfo evaluationInfo)
1563:                        throws QueryException {
1564:                    final long documentLanguageId = data.document
1565:                            .getLanguageId();
1566:                    if (data.versionedData.hasField(fieldType.getId())) {
1567:                        Object value = data.versionedData.getField(
1568:                                fieldType.getId()).getValue();
1569:                        return super .processValue(value, data, evaluationInfo,
1570:                                new ValueExtractor() {
1571:                                    public Object extract(Object object) {
1572:                                        VariantKey key = (VariantKey) object;
1573:                                        long languageId = key.getLanguageId() != -1 ? key
1574:                                                .getLanguageId()
1575:                                                : documentLanguageId;
1576:                                        try {
1577:                                            return evaluationInfo
1578:                                                    .getQueryContext()
1579:                                                    .getLanguage(languageId)
1580:                                                    .getName();
1581:                                        } catch (RepositoryException e) {
1582:                                            throw new RuntimeException(e);
1583:                                        }
1584:                                    }
1585:                                });
1586:                    } else {
1587:                        return null;
1588:                    }
1589:                }
1590:
1591:                public boolean isSymbolic() {
1592:                    return true;
1593:                }
1594:
1595:                public Object translateSymbolic(ValueExpr valueExpr,
1596:                        EvaluationInfo evaluationInfo) throws QueryException {
1597:                    String languageName = (String) valueExpr.evaluate(
1598:                            QValueType.STRING, null, evaluationInfo);
1599:                    Language language;
1600:                    try {
1601:                        language = evaluationInfo.getQueryContext()
1602:                                .getLanguageByName(languageName);
1603:                    } catch (RepositoryException e) {
1604:                        throw new QueryException("Error with language name \""
1605:                                + languageName + "\".", e);
1606:                    }
1607:                    return new Long(language.getId());
1608:                }
1609:
1610:                public String getTitle(Locale locale) {
1611:                    String fieldLabel = fieldType.getLabel(locale);
1612:                    String language = getLocalizedString("language", locale);
1613:                    return fieldLabel + ": " + language;
1614:                }
1615:            }
1616:
1617:            /**
1618:             * Exposes the collections a document belongs to as a multi-value identifier.
1619:             */
1620:            public final class CollectionsIdentifier extends AbstractIdentifier {
1621:                public static final String NAME = "collections";
1622:
1623:                public CollectionsIdentifier() {
1624:                }
1625:
1626:                public String getName() {
1627:                    return NAME;
1628:                }
1629:
1630:                public QValueType getValueType() {
1631:                    return QValueType.LONG;
1632:                }
1633:
1634:                public boolean isMultiValue() {
1635:                    return true;
1636:                }
1637:
1638:                public Identifier getValueCountIdentifier() {
1639:                    return new Identifier(CollectionsValueCountIdentifier.NAME,
1640:                            null, prepareOnlyQueryContext,
1641:                            new CollectionsValueCountIdentifier());
1642:                }
1643:
1644:                public Object evaluate(ExprDocData data,
1645:                        EvaluationInfo evaluationInfo) {
1646:                    DocumentCollection[] collections = data.document
1647:                            .getCollections().getArray();
1648:                    if (collections.length == 0)
1649:                        return null;
1650:                    Long[] collectionIds = new Long[collections.length];
1651:                    for (int i = 0; i < collectionIds.length; i++)
1652:                        collectionIds[i] = new Long(collections[i].getId());
1653:                    return collectionIds;
1654:                }
1655:
1656:                public QValueType getOutputValueType() {
1657:                    return QValueType.STRING;
1658:                }
1659:
1660:                public Object getOutputValue(ExprDocData data,
1661:                        EvaluationInfo evaluationInfo) {
1662:                    DocumentCollection[] collections = data.document
1663:                            .getCollections().getArray();
1664:                    if (collections.length == 0)
1665:                        return null;
1666:                    String[] collectionNames = new String[collections.length];
1667:                    for (int i = 0; i < collectionNames.length; i++)
1668:                        collectionNames[i] = collections[i].getName();
1669:                    return collectionNames;
1670:                }
1671:
1672:                public boolean canTestappliesTo() {
1673:                    return true;
1674:                }
1675:
1676:                public void generateSqlValueExpr(StringBuilder sql,
1677:                        SqlGenerationContext context) {
1678:                    String alias = context.getNewCollectionsTable().getName();
1679:                    sql.append(alias).append(".collection_id");
1680:                }
1681:
1682:                public boolean isSymbolic() {
1683:                    return true;
1684:                }
1685:
1686:                public Object translateSymbolic(ValueExpr valueExpr,
1687:                        EvaluationInfo evaluationInfo) throws QueryException {
1688:                    String collectionName = (String) valueExpr.evaluate(
1689:                            QValueType.STRING, null, evaluationInfo);
1690:                    DocumentCollection collection;
1691:                    try {
1692:                        collection = evaluationInfo.getQueryContext()
1693:                                .getCollection(collectionName);
1694:                    } catch (CollectionNotFoundException e) {
1695:                        throw new QueryException("\"" + collectionName
1696:                                + "\" is not an existing collection.");
1697:                    } catch (RepositoryException e) {
1698:                        throw new QueryException(
1699:                                "Error consulting collection information.", e);
1700:                    }
1701:                    return new Long(collection.getId());
1702:                }
1703:            }
1704:
1705:            private static final ParamString COLL_VALUE_COUNT_EXPR = new ParamString(
1706:                    " (select count(*) from document_collections where document_id = {document_variants}.doc_id and branch_id = {document_variants}.branch_id and lang_id = {document_variants}.lang_id) ");
1707:
1708:            public final class CollectionsValueCountIdentifier extends
1709:                    AbstractNonAclIdentifier {
1710:                public static final String NAME = "collections.valueCount";
1711:
1712:                public String getName() {
1713:                    return NAME;
1714:                }
1715:
1716:                public QValueType getValueType() {
1717:                    return QValueType.LONG;
1718:                }
1719:
1720:                public Object evaluate(ExprDocData data,
1721:                        EvaluationInfo evaluationInfo) {
1722:                    return new Long(
1723:                            data.document.getCollections().getArray().length);
1724:                }
1725:
1726:                public QValueType getOutputValueType() {
1727:                    return QValueType.LONG;
1728:                }
1729:
1730:                public Object getOutputValue(ExprDocData data,
1731:                        EvaluationInfo evaluationInfo) {
1732:                    return evaluate(data, null);
1733:                }
1734:
1735:                public void generateSqlValueExpr(StringBuilder sql,
1736:                        SqlGenerationContext context) {
1737:                    Map<String, String> params = new HashMap<String, String>();
1738:                    params.put("document_variants", context
1739:                            .getDocumentVariantsTable().getName());
1740:                    sql.append(COLL_VALUE_COUNT_EXPR.toString(params));
1741:                }
1742:
1743:                public boolean isSymbolic() {
1744:                    return false;
1745:                }
1746:
1747:                public boolean isOutputOnly() {
1748:                    return false;
1749:                }
1750:
1751:                public String getTitle(Locale locale) {
1752:                    return getLocalizedString(getName(), locale);
1753:                }
1754:            }
1755:
1756:            private static final Pattern VARIANT_SEARCH_PATTERN = Pattern
1757:                    .compile("^([^:]*):([^:]*)$");
1758:            private static final ParamString VARIANT_SEARCH_JOIN_EXPR = new ParamString(
1759:                    " left join document_variants {docVariantsAlias} on ({document_variants}.doc_id = {docVariantsAlias}.doc_id and {document_variants}.ns_id = {docVariantsAlias}.ns_id) ");
1760:
1761:            /**
1762:             * Exposes the variants of a document as a multi-value identifier.
1763:             */
1764:            public final class VariantsIdentifier extends AbstractIdentifier {
1765:                public static final String NAME = "variants";
1766:
1767:                public VariantsIdentifier() {
1768:                }
1769:
1770:                public String getName() {
1771:                    return NAME;
1772:                }
1773:
1774:                public QValueType getValueType() {
1775:                    return QValueType.STRING;
1776:                }
1777:
1778:                public boolean isMultiValue() {
1779:                    return true;
1780:                }
1781:
1782:                public Identifier getValueCountIdentifier() {
1783:                    return new Identifier(VariantsValueCountIdentifier.NAME,
1784:                            null, prepareOnlyQueryContext,
1785:                            new VariantsValueCountIdentifier());
1786:                }
1787:
1788:                public Object evaluate(ExprDocData data,
1789:                        EvaluationInfo evaluationInfo) {
1790:                    AvailableVariant[] variants;
1791:                    try {
1792:                        variants = data.document.getAvailableVariants()
1793:                                .getArray();
1794:                    } catch (RepositoryException e) {
1795:                        return null;
1796:                    }
1797:
1798:                    if (variants.length == 0) // can't normally occur
1799:                        return null;
1800:
1801:                    String[] keys = new String[variants.length];
1802:                    for (int i = 0; i < variants.length; i++)
1803:                        keys[i] = variants[i].getBranchId() + ":"
1804:                                + variants[i].getLanguageId();
1805:                    return keys;
1806:                }
1807:
1808:                public QValueType getOutputValueType() {
1809:                    return QValueType.LINK;
1810:                }
1811:
1812:                public Object getOutputValue(ExprDocData data,
1813:                        EvaluationInfo evaluationInfo) {
1814:                    AvailableVariant[] variants;
1815:                    try {
1816:                        variants = data.document.getAvailableVariants()
1817:                                .getArray();
1818:                    } catch (RepositoryException e) {
1819:                        return null;
1820:                    }
1821:
1822:                    if (variants.length == 0) // can't normally occur
1823:                        return null;
1824:
1825:                    VariantKey[] keys = new VariantKey[variants.length];
1826:                    String documentId = data.document.getId();
1827:                    for (int i = 0; i < variants.length; i++)
1828:                        keys[i] = new VariantKey(documentId, variants[i]
1829:                                .getBranchId(), variants[i].getLanguageId());
1830:                    return keys;
1831:                }
1832:
1833:                public boolean canTestappliesTo() {
1834:                    return true;
1835:                }
1836:
1837:                public void generateSqlValueExpr(StringBuilder sql,
1838:                        SqlGenerationContext context) {
1839:                    final String alias = "variantsearch"
1840:                            + context.getNewAliasCounter();
1841:                    final String currentDocVariantsAlias = context
1842:                            .getDocumentVariantsTable().getName();
1843:                    context
1844:                            .needsJoinWithTable(new SqlGenerationContext.Table() {
1845:
1846:                                public String getName() {
1847:                                    return null;
1848:                                }
1849:
1850:                                public String getJoinExpression(
1851:                                        boolean searchLastVersion)
1852:                                        throws QueryException {
1853:                                    Map<String, String> params = new HashMap<String, String>();
1854:                                    params.put("docVariantsAlias", alias);
1855:                                    params.put("document_variants",
1856:                                            currentDocVariantsAlias);
1857:                                    return VARIANT_SEARCH_JOIN_EXPR
1858:                                            .toString(params);
1859:                                }
1860:
1861:                                public int bindJoin(PreparedStatement stmt,
1862:                                        int bindPos,
1863:                                        EvaluationInfo evaluationInfo)
1864:                                        throws SQLException, QueryException {
1865:                                    return bindPos;
1866:                                }
1867:                            });
1868:                    sql.append(alias).append(".variant_search");
1869:                }
1870:
1871:                public boolean isSymbolic() {
1872:                    return true;
1873:                }
1874:
1875:                public Object translateSymbolic(ValueExpr valueExpr,
1876:                        EvaluationInfo evaluationInfo) throws QueryException {
1877:                    String variant = (String) valueExpr.evaluate(
1878:                            QValueType.STRING, null, evaluationInfo);
1879:                    Matcher matcher = VARIANT_SEARCH_PATTERN.matcher(variant);
1880:                    if (matcher.matches()) {
1881:                        String branch = matcher.group(1);
1882:                        String language = matcher.group(2);
1883:                        long branchId;
1884:                        long languageId;
1885:                        try {
1886:                            branchId = evaluationInfo.getQueryContext()
1887:                                    .getBranch(branch).getId();
1888:                            languageId = evaluationInfo.getQueryContext()
1889:                                    .getLanguage(language).getId();
1890:                        } catch (BranchNotFoundException e) {
1891:                            throw new QueryException("Branch specified in \""
1892:                                    + variant + "\" does not exist.");
1893:                        } catch (LanguageNotFoundException e) {
1894:                            throw new QueryException("Language specified in \""
1895:                                    + variant + "\" does not exist.");
1896:                        } catch (RepositoryException e) {
1897:                            throw new QueryException(
1898:                                    "Problem parsing branch:language specification \""
1899:                                            + variant + "\".");
1900:                        }
1901:                        return branchId + ":" + languageId;
1902:                    } else {
1903:                        throw new QueryException(
1904:                                "Invalid branch:language specification: \""
1905:                                        + variant + "\".");
1906:                    }
1907:                }
1908:            }
1909:
1910:            private static final ParamString VARIANTS_VALUE_COUNT_EXPR = new ParamString(
1911:                    " (select count(*) from document_variants vvc where vvc.doc_id = {document_variants}.doc_id and vvc.ns_id = {document_variants}.ns_id) ");
1912:
1913:            public final class VariantsValueCountIdentifier extends
1914:                    AbstractNonAclIdentifier {
1915:                public static final String NAME = "variants.valueCount";
1916:
1917:                public String getName() {
1918:                    return NAME;
1919:                }
1920:
1921:                public QValueType getValueType() {
1922:                    return QValueType.LONG;
1923:                }
1924:
1925:                public Object evaluate(ExprDocData data,
1926:                        EvaluationInfo evaluationInfo) {
1927:                    try {
1928:                        return new Long(data.document.getAvailableVariants()
1929:                                .getArray().length);
1930:                    } catch (RepositoryException e) {
1931:                        // either this or throwing an exception
1932:                        return new Long(-1);
1933:                    }
1934:                }
1935:
1936:                public QValueType getOutputValueType() {
1937:                    return QValueType.LONG;
1938:                }
1939:
1940:                public Object getOutputValue(ExprDocData data,
1941:                        EvaluationInfo evaluationInfo) {
1942:                    return evaluate(data, null);
1943:                }
1944:
1945:                public void generateSqlValueExpr(StringBuilder sql,
1946:                        SqlGenerationContext context) {
1947:                    Map<String, String> params = new HashMap<String, String>();
1948:                    params.put("document_variants", context
1949:                            .getDocumentVariantsTable().getName());
1950:                    sql.append(VARIANTS_VALUE_COUNT_EXPR.toString(params));
1951:                }
1952:
1953:                public boolean isSymbolic() {
1954:                    return false;
1955:                }
1956:
1957:                public boolean isOutputOnly() {
1958:                    return false;
1959:                }
1960:
1961:                public String getTitle(Locale locale) {
1962:                    return getLocalizedString(getName(), locale);
1963:                }
1964:            }
1965:
1966:            private String getUserDisplayName(long userId,
1967:                    QueryContext queryContext) {
1968:                try {
1969:                    return queryContext.getUserDisplayName(userId);
1970:                } catch (RepositoryException e) {
1971:                    throw new RuntimeException(
1972:                            "Error getting display name for user " + userId, e);
1973:                }
1974:            }
1975:
1976:            private String getUserLogin(long userId, QueryContext queryContext) {
1977:                try {
1978:                    return queryContext.getUserLogin(userId);
1979:                } catch (RepositoryException e) {
1980:                    throw new RuntimeException("Error getting login for user "
1981:                            + userId, e);
1982:                }
1983:            }
1984:
1985:            private static String getLocalizedString(String name, Locale locale) {
1986:                ResourceBundle bundle = ResourceBundle.getBundle(
1987:                        "org/outerj/daisy/query/model/messages", locale);
1988:                return bundle.getString(name);
1989:            }
1990:
1991:            public final class DocumentTypeIdentifier extends
1992:                    AbstractIdentifier {
1993:                public static final String NAME = "documentType";
1994:
1995:                public String getName() {
1996:                    return NAME;
1997:                }
1998:
1999:                public QValueType getValueType() {
2000:                    return QValueType.LONG;
2001:                }
2002:
2003:                public Object evaluate(ExprDocData data,
2004:                        EvaluationInfo evaluationInfo) {
2005:                    return new Long(data.document.getDocumentTypeId());
2006:                }
2007:
2008:                public QValueType getOutputValueType() {
2009:                    return QValueType.STRING;
2010:                }
2011:
2012:                public Object getOutputValue(ExprDocData data,
2013:                        EvaluationInfo evaluationInfo) {
2014:                    try {
2015:                        return evaluationInfo.getQueryContext()
2016:                                .getDocumentTypeById(
2017:                                        data.document.getDocumentTypeId())
2018:                                .getName();
2019:                    } catch (RepositoryException e) {
2020:                        return "<ERROR>";
2021:                    }
2022:                }
2023:
2024:                public boolean canTestappliesTo() {
2025:                    return true;
2026:                }
2027:
2028:                public void generateSqlValueExpr(StringBuilder sql,
2029:                        SqlGenerationContext context) {
2030:                    sql.append(context.getDocumentVariantsTable().getName());
2031:                    sql.append('.');
2032:                    sql
2033:                            .append(SqlGenerationContext.DocumentVariantsTable.DOCTYPE_ID);
2034:                }
2035:
2036:                public boolean isSymbolic() {
2037:                    return true;
2038:                }
2039:
2040:                public Object translateSymbolic(ValueExpr valueExpr,
2041:                        EvaluationInfo evaluationInfo) throws QueryException {
2042:                    String documentTypeName = (String) valueExpr.evaluate(
2043:                            QValueType.STRING, null, evaluationInfo);
2044:                    DocumentType documentType;
2045:                    try {
2046:                        documentType = evaluationInfo.getQueryContext()
2047:                                .getDocumentTypeByName(documentTypeName);
2048:                    } catch (DocumentTypeNotFoundException e) {
2049:                        throw new QueryException("\"" + documentTypeName
2050:                                + "\" is not a valid document type name.");
2051:                    } catch (RepositoryException e) {
2052:                        throw new QueryException(
2053:                                "Error consulting repository schema information.",
2054:                                e);
2055:                    }
2056:                    return new Long(documentType.getId());
2057:                }
2058:            }
2059:
2060:            public final class DocumentNameIdentifier extends
2061:                    AbstractNonAclIdentifier {
2062:                public static final String NAME = "name";
2063:
2064:                public String getName() {
2065:                    return NAME;
2066:                }
2067:
2068:                public QValueType getValueType() {
2069:                    return QValueType.STRING;
2070:                }
2071:
2072:                public Object evaluate(ExprDocData data,
2073:                        EvaluationInfo evaluationInfo) {
2074:                    return data.versionedData.getDocumentName();
2075:                }
2076:
2077:                public void generateSqlValueExpr(StringBuilder sql,
2078:                        SqlGenerationContext context) {
2079:                    sql.append(context.getVersionsTable().getName());
2080:                    sql.append('.');
2081:                    sql.append(SqlGenerationContext.VersionsTable.NAME);
2082:                }
2083:
2084:                public QValueType getOutputValueType() {
2085:                    return QValueType.STRING;
2086:                }
2087:
2088:                public Object getOutputValue(ExprDocData data,
2089:                        EvaluationInfo evaluationInfo) {
2090:                    return evaluate(data, null);
2091:                }
2092:            }
2093:
2094:            public final class CreationTimeIdentifier extends
2095:                    AbstractNonAclIdentifier {
2096:                public static final String NAME = "creationTime";
2097:
2098:                public String getName() {
2099:                    return NAME;
2100:                }
2101:
2102:                public QValueType getValueType() {
2103:                    return QValueType.DATETIME;
2104:                }
2105:
2106:                public Object evaluate(ExprDocData data,
2107:                        EvaluationInfo evaluationInfo) {
2108:                    return data.document.getCreated();
2109:                }
2110:
2111:                public void generateSqlValueExpr(StringBuilder sql,
2112:                        SqlGenerationContext context) {
2113:                    sql.append(context.getDocumentsTable().getName());
2114:                    sql.append('.');
2115:                    sql.append(SqlGenerationContext.DocumentsTable.CREATED);
2116:                }
2117:
2118:                public QValueType getOutputValueType() {
2119:                    return QValueType.DATETIME;
2120:                }
2121:
2122:                public Object getOutputValue(ExprDocData data,
2123:                        EvaluationInfo evaluationInfo) {
2124:                    return evaluate(data, null);
2125:                }
2126:            }
2127:
2128:            public final class DocumentIdIdentifier extends AbstractIdentifier {
2129:                public static final String NAME = "id";
2130:
2131:                public String getName() {
2132:                    return NAME;
2133:                }
2134:
2135:                public QValueType getValueType() {
2136:                    return QValueType.DOCID;
2137:                }
2138:
2139:                public boolean isSymbolic() {
2140:                    return true;
2141:                }
2142:
2143:                public Object translateSymbolic(ValueExpr valueExpr,
2144:                        EvaluationInfo evaluationInfo) throws QueryException {
2145:                    String documentId = (String) valueExpr.evaluate(
2146:                            QValueType.STRING, null, evaluationInfo);
2147:                    return SqlUtils.parseDocId(documentId, evaluationInfo
2148:                            .getQueryContext());
2149:                }
2150:
2151:                public Object evaluate(ExprDocData data,
2152:                        EvaluationInfo evaluationInfo) {
2153:                    String id = data.document.getId();
2154:                    return id == null ? null : evaluationInfo.getQueryContext()
2155:                            .parseDocId(id);
2156:                }
2157:
2158:                public void generateSqlValueExpr(StringBuilder sql,
2159:                        SqlGenerationContext context) {
2160:                    // The document ID as known to the external world is internally stored
2161:                    // in two database columns: the numeric ID and the namespace ID. This mismatch
2162:                    // leads to some difficulties for searching, especially considering that this
2163:                    // not only needs to work for the '=' operator but also for others such as 'IN'.
2164:                    // Therefore a special id_search column is maintained that allows to treat
2165:                    // the document ID again as one atomic value.
2166:                    // (Note: this same technique is used for searching on link type fields where
2167:                    // the doc id, ns id, branch and lang are stored in multiple columns)
2168:                    // The format of the ID_SEARCH column is docSeqId + '-' + internal namespace ID (not name) 
2169:                    sql.append(context.getDocumentsTable().getName());
2170:                    sql.append('.');
2171:                    sql.append(SqlGenerationContext.DocumentsTable.ID_SEARCH);
2172:                }
2173:
2174:                public QValueType getOutputValueType() {
2175:                    return QValueType.STRING;
2176:                }
2177:
2178:                public Object getOutputValue(ExprDocData data,
2179:                        EvaluationInfo evaluationInfo) {
2180:                    return data.document.getId();
2181:                }
2182:            }
2183:
2184:            public final class DocumentNamespaceIdentifier extends
2185:                    AbstractIdentifier {
2186:                public static final String NAME = "namespace";
2187:
2188:                public String getName() {
2189:                    return NAME;
2190:                }
2191:
2192:                public QValueType getValueType() {
2193:                    return QValueType.LONG;
2194:                }
2195:
2196:                public boolean isSymbolic() {
2197:                    return true;
2198:                }
2199:
2200:                public Object translateSymbolic(ValueExpr valueExpr,
2201:                        EvaluationInfo evaluationInfo) throws QueryException {
2202:                    String namespaceName = (String) valueExpr.evaluate(
2203:                            QValueType.STRING, null, evaluationInfo);
2204:                    Namespace namespace;
2205:                    try {
2206:                        namespace = evaluationInfo.getQueryContext()
2207:                                .getNamespace(namespaceName);
2208:                    } catch (NamespaceNotFoundException e) {
2209:                        // it is inconvenient if searching on a non-registered namespace would fail
2210:                        // there return here an ID that does not exist in the database.
2211:                        return new Long(-1);
2212:                    } catch (RepositoryException e) {
2213:                        throw new QueryException(
2214:                                "Error consulting repository namespace information.",
2215:                                e);
2216:                    }
2217:                    return new Long(namespace.getId());
2218:                }
2219:
2220:                public Object evaluate(ExprDocData data,
2221:                        EvaluationInfo evaluationInfo) {
2222:                    String namespaceName = data.document.getNamespace();
2223:                    if (namespaceName == null) // namespace can be null on not-yet saved documents
2224:                        return null;
2225:
2226:                    try {
2227:                        Namespace namespace = evaluationInfo.getQueryContext()
2228:                                .getNamespace(namespaceName);
2229:                        return new Long(namespace.getId());
2230:                    } catch (RepositoryException e) {
2231:                        throw new RepositoryRuntimeException(
2232:                                "Error consulting repository namespace information.",
2233:                                e);
2234:                    }
2235:                }
2236:
2237:                public void generateSqlValueExpr(StringBuilder sql,
2238:                        SqlGenerationContext context) {
2239:                    sql.append(context.getDocumentVariantsTable().getName());
2240:                    sql.append('.');
2241:                    sql.append(SqlGenerationContext.DocumentsTable.NS_ID);
2242:                }
2243:
2244:                public QValueType getOutputValueType() {
2245:                    return QValueType.STRING;
2246:                }
2247:
2248:                public Object getOutputValue(ExprDocData data,
2249:                        EvaluationInfo evaluationInfo) {
2250:                    return data.document.getNamespace();
2251:                }
2252:            }
2253:
2254:            public final class DocumentLinkIdentifier extends
2255:                    AbstractIdentifier {
2256:                public static final String NAME = "link";
2257:
2258:                public String getName() {
2259:                    return NAME;
2260:                }
2261:
2262:                public QValueType getValueType() {
2263:                    return QValueType.LINK;
2264:                }
2265:
2266:                public Object evaluate(ExprDocData data,
2267:                        EvaluationInfo evaluationInfo) {
2268:                    return data.document.getVariantKey();
2269:                }
2270:
2271:                public void generateSqlValueExpr(StringBuilder sql,
2272:                        SqlGenerationContext context) {
2273:                    sql.append(context.getDocumentVariantsTable().getName());
2274:                    sql.append(".");
2275:                    sql
2276:                            .append(SqlGenerationContext.DocumentVariantsTable.LINK_SEARCH);
2277:                }
2278:
2279:                public QValueType getOutputValueType() {
2280:                    return QValueType.LINK;
2281:                }
2282:
2283:                public Object getOutputValue(ExprDocData data,
2284:                        EvaluationInfo evaluationInfo) {
2285:                    return evaluate(data, null);
2286:                }
2287:            }
2288:
2289:            public final class BranchIdIdentifier extends AbstractIdentifier {
2290:                public static final String NAME = "branchId";
2291:
2292:                public String getName() {
2293:                    return NAME;
2294:                }
2295:
2296:                public QValueType getValueType() {
2297:                    return QValueType.LONG;
2298:                }
2299:
2300:                public Object evaluate(ExprDocData data,
2301:                        EvaluationInfo evaluationInfo) {
2302:                    return new Long(data.document.getBranchId());
2303:                }
2304:
2305:                public void generateSqlValueExpr(StringBuilder sql,
2306:                        SqlGenerationContext context) {
2307:                    sql.append(context.getDocumentVariantsTable().getName());
2308:                    sql.append('.');
2309:                    sql
2310:                            .append(SqlGenerationContext.DocumentVariantsTable.BRANCH_ID);
2311:                }
2312:
2313:                public QValueType getOutputValueType() {
2314:                    return QValueType.LONG;
2315:                }
2316:
2317:                public Object getOutputValue(ExprDocData data,
2318:                        EvaluationInfo evaluationInfo) {
2319:                    return evaluate(data, null);
2320:                }
2321:            }
2322:
2323:            public final class BranchNameIdentifier extends AbstractIdentifier {
2324:                public static final String NAME = "branch";
2325:
2326:                public String getName() {
2327:                    return NAME;
2328:                }
2329:
2330:                public QValueType getValueType() {
2331:                    return QValueType.LONG;
2332:                }
2333:
2334:                public Object evaluate(ExprDocData data,
2335:                        EvaluationInfo evaluationInfo) {
2336:                    return new Long(data.document.getBranchId());
2337:                }
2338:
2339:                public void generateSqlValueExpr(StringBuilder sql,
2340:                        SqlGenerationContext context) {
2341:                    sql.append(context.getDocumentVariantsTable().getName());
2342:                    sql.append('.');
2343:                    sql
2344:                            .append(SqlGenerationContext.DocumentVariantsTable.BRANCH_ID);
2345:                }
2346:
2347:                public QValueType getOutputValueType() {
2348:                    return QValueType.STRING;
2349:                }
2350:
2351:                public Object getOutputValue(ExprDocData data,
2352:                        EvaluationInfo evaluationInfo) {
2353:                    try {
2354:                        return evaluationInfo.getQueryContext().getBranch(
2355:                                data.document.getBranchId()).getName();
2356:                    } catch (RepositoryException e) {
2357:                        throw new RuntimeException(e);
2358:                    }
2359:                }
2360:
2361:                public boolean isSymbolic() {
2362:                    return true;
2363:                }
2364:
2365:                public Object translateSymbolic(ValueExpr valueExpr,
2366:                        EvaluationInfo evaluationInfo) throws QueryException {
2367:                    String branchName = (String) valueExpr.evaluate(
2368:                            QValueType.STRING, null, evaluationInfo);
2369:                    Branch branch;
2370:                    try {
2371:                        branch = evaluationInfo.getQueryContext()
2372:                                .getBranchByName(branchName);
2373:                    } catch (RepositoryException e) {
2374:                        throw new QueryException("Error with branch name \""
2375:                                + branchName + "\".", e);
2376:                    }
2377:                    return new Long(branch.getId());
2378:                }
2379:            }
2380:
2381:            public final class LanguageIdIdentifier extends AbstractIdentifier {
2382:                public static final String NAME = "languageId";
2383:
2384:                public String getName() {
2385:                    return NAME;
2386:                }
2387:
2388:                public QValueType getValueType() {
2389:                    return QValueType.LONG;
2390:                }
2391:
2392:                public Object evaluate(ExprDocData data,
2393:                        EvaluationInfo evaluationInfo) {
2394:                    return new Long(data.document.getLanguageId());
2395:                }
2396:
2397:                public void generateSqlValueExpr(StringBuilder sql,
2398:                        SqlGenerationContext context) {
2399:                    sql.append(context.getDocumentVariantsTable().getName());
2400:                    sql.append('.');
2401:                    sql
2402:                            .append(SqlGenerationContext.DocumentVariantsTable.LANG_ID);
2403:                }
2404:
2405:                public QValueType getOutputValueType() {
2406:                    return QValueType.LONG;
2407:                }
2408:
2409:                public Object getOutputValue(ExprDocData data,
2410:                        EvaluationInfo evaluationInfo) {
2411:                    return new Long(data.document.getLanguageId());
2412:                }
2413:            }
2414:
2415:            public final class LanguageNameIdentifier extends
2416:                    AbstractIdentifier {
2417:                public static final String NAME = "language";
2418:
2419:                public String getName() {
2420:                    return NAME;
2421:                }
2422:
2423:                public QValueType getValueType() {
2424:                    return QValueType.LONG;
2425:                }
2426:
2427:                public Object evaluate(ExprDocData data,
2428:                        EvaluationInfo evaluationInfo) {
2429:                    return new Long(data.document.getLanguageId());
2430:                }
2431:
2432:                public void generateSqlValueExpr(StringBuilder sql,
2433:                        SqlGenerationContext context) {
2434:                    sql.append(context.getDocumentVariantsTable().getName());
2435:                    sql.append('.');
2436:                    sql
2437:                            .append(SqlGenerationContext.DocumentVariantsTable.LANG_ID);
2438:                }
2439:
2440:                public QValueType getOutputValueType() {
2441:                    return QValueType.STRING;
2442:                }
2443:
2444:                public Object getOutputValue(ExprDocData data,
2445:                        EvaluationInfo evaluationInfo) {
2446:                    try {
2447:                        return evaluationInfo.getQueryContext().getLanguage(
2448:                                data.document.getLanguageId()).getName();
2449:                    } catch (RepositoryException e) {
2450:                        throw new RuntimeException(e);
2451:                    }
2452:                }
2453:
2454:                public boolean isSymbolic() {
2455:                    return true;
2456:                }
2457:
2458:                public Object translateSymbolic(ValueExpr valueExpr,
2459:                        EvaluationInfo evaluationInfo) throws QueryException {
2460:                    String languageName = (String) valueExpr.evaluate(
2461:                            QValueType.STRING, null, evaluationInfo);
2462:                    Language language;
2463:                    try {
2464:                        language = evaluationInfo.getQueryContext()
2465:                                .getLanguageByName(languageName);
2466:                    } catch (RepositoryException e) {
2467:                        throw new QueryException("Error with language name \""
2468:                                + languageName + "\".", e);
2469:                    }
2470:                    return new Long(language.getId());
2471:                }
2472:            }
2473:
2474:            public final class VersionCreationTimeIdentifier extends
2475:                    AbstractNonAclIdentifier {
2476:                public static final String NAME = "versionCreationTime";
2477:
2478:                public String getName() {
2479:                    return NAME;
2480:                }
2481:
2482:                public QValueType getValueType() {
2483:                    return QValueType.DATETIME;
2484:                }
2485:
2486:                public Object evaluate(ExprDocData data,
2487:                        EvaluationInfo evaluationInfo) {
2488:                    if (data.version != null) {
2489:                        return data.version.getCreated();
2490:                    } else {
2491:                        return null;
2492:                    }
2493:                }
2494:
2495:                public void generateSqlValueExpr(StringBuilder sql,
2496:                        SqlGenerationContext context) {
2497:                    sql.append(context.getVersionsTable().getName());
2498:                    sql.append('.');
2499:                    sql.append(SqlGenerationContext.VersionsTable.CREATED_ON);
2500:                }
2501:
2502:                public QValueType getOutputValueType() {
2503:                    return QValueType.DATETIME;
2504:                }
2505:
2506:                public Object getOutputValue(ExprDocData data,
2507:                        EvaluationInfo evaluationInfo) {
2508:                    return evaluate(data, null);
2509:                }
2510:            }
2511:
2512:            public final class TotalSizeOfPartsIdentifier extends
2513:                    AbstractNonAclIdentifier {
2514:                public static final String NAME = "totalSizeOfParts";
2515:
2516:                public String getName() {
2517:                    return NAME;
2518:                }
2519:
2520:                public QValueType getValueType() {
2521:                    return QValueType.LONG;
2522:                }
2523:
2524:                public Object evaluate(ExprDocData data,
2525:                        EvaluationInfo evaluationInfo) {
2526:                    if (data.version != null) {
2527:                        return new Long(data.version.getTotalSizeOfParts());
2528:                    } else {
2529:                        return null;
2530:                    }
2531:                }
2532:
2533:                public void generateSqlValueExpr(StringBuilder sql,
2534:                        SqlGenerationContext context) {
2535:                    sql.append(context.getVersionsTable().getName());
2536:                    sql.append('.');
2537:                    sql
2538:                            .append(SqlGenerationContext.VersionsTable.TOTAL_SIZE_OF_PARTS);
2539:                }
2540:
2541:                public QValueType getOutputValueType() {
2542:                    return QValueType.LONG;
2543:                }
2544:
2545:                public Object getOutputValue(ExprDocData data,
2546:                        EvaluationInfo evaluationInfo) {
2547:                    return evaluate(data, null);
2548:                }
2549:            }
2550:
2551:            public final class VersionLastModifiedIdentifier extends
2552:                    AbstractNonAclIdentifier {
2553:                public static final String NAME = "versionLastModified";
2554:                public static final String PRE_2_2_NAME = "versionStateLastModified";
2555:
2556:                public String getName() {
2557:                    return NAME;
2558:                }
2559:
2560:                public QValueType getValueType() {
2561:                    return QValueType.DATETIME;
2562:                }
2563:
2564:                public Object evaluate(ExprDocData data,
2565:                        EvaluationInfo evaluationInfo) {
2566:                    if (data.version != null) {
2567:                        return data.version.getLastModified();
2568:                    } else {
2569:                        return null;
2570:                    }
2571:                }
2572:
2573:                public void generateSqlValueExpr(StringBuilder sql,
2574:                        SqlGenerationContext context) {
2575:                    sql.append(context.getVersionsTable().getName());
2576:                    sql.append('.');
2577:                    sql
2578:                            .append(SqlGenerationContext.VersionsTable.LAST_MODIFIED);
2579:                }
2580:
2581:                public QValueType getOutputValueType() {
2582:                    return QValueType.DATETIME;
2583:                }
2584:
2585:                public Object getOutputValue(ExprDocData data,
2586:                        EvaluationInfo evaluationInfo) {
2587:                    return evaluate(data, null);
2588:                }
2589:            }
2590:
2591:            public final class VersionCreatorIdIdentifier extends
2592:                    AbstractNonAclIdentifier {
2593:                public static final String NAME = "versionCreatorId";
2594:
2595:                public String getName() {
2596:                    return NAME;
2597:                }
2598:
2599:                public QValueType getValueType() {
2600:                    return QValueType.LONG;
2601:                }
2602:
2603:                public Object evaluate(ExprDocData data,
2604:                        EvaluationInfo evaluationInfo) {
2605:                    if (data.version != null) {
2606:                        return new Long(data.version.getCreator());
2607:                    } else {
2608:                        return null;
2609:                    }
2610:                }
2611:
2612:                public void generateSqlValueExpr(StringBuilder sql,
2613:                        SqlGenerationContext context) {
2614:                    sql.append(context.getVersionsTable().getName());
2615:                    sql.append('.');
2616:                    sql.append(SqlGenerationContext.VersionsTable.CREATED_BY);
2617:                }
2618:
2619:                public QValueType getOutputValueType() {
2620:                    return QValueType.LONG;
2621:                }
2622:
2623:                public Object getOutputValue(ExprDocData data,
2624:                        EvaluationInfo evaluationInfo) {
2625:                    return evaluate(data, null);
2626:                }
2627:            }
2628:
2629:            public abstract class AbstractLoginIdentifier extends
2630:                    AbstractNonAclIdentifier {
2631:                public QValueType getValueType() {
2632:                    return QValueType.LONG;
2633:                }
2634:
2635:                public QValueType getOutputValueType() {
2636:                    return QValueType.STRING;
2637:                }
2638:
2639:                public boolean isSymbolic() {
2640:                    return true;
2641:                }
2642:
2643:                public Object translateSymbolic(ValueExpr valueExpr,
2644:                        EvaluationInfo evaluationInfo) throws QueryException {
2645:                    String login = (String) valueExpr.evaluate(
2646:                            QValueType.STRING, null, evaluationInfo);
2647:                    long userId;
2648:                    try {
2649:                        userId = evaluationInfo.getQueryContext().getUserId(
2650:                                login);
2651:                    } catch (RepositoryException e) {
2652:                        throw new QueryException(
2653:                                "Error getting user information for user with login \""
2654:                                        + login + "\".", e);
2655:                    }
2656:                    return new Long(userId);
2657:                }
2658:            }
2659:
2660:            public final class VersionCreatorLoginIdentifier extends
2661:                    AbstractLoginIdentifier {
2662:                public static final String NAME = "versionCreatorLogin";
2663:
2664:                public String getName() {
2665:                    return NAME;
2666:                }
2667:
2668:                public Object evaluate(ExprDocData data,
2669:                        EvaluationInfo evaluationInfo) {
2670:                    if (data.version != null) {
2671:                        return new Long(data.version.getCreator());
2672:                    } else {
2673:                        return null;
2674:                    }
2675:                }
2676:
2677:                public void generateSqlValueExpr(StringBuilder sql,
2678:                        SqlGenerationContext context) {
2679:                    sql.append(context.getVersionsTable().getName());
2680:                    sql.append('.');
2681:                    sql.append(SqlGenerationContext.VersionsTable.CREATED_BY);
2682:                }
2683:
2684:                public Object getOutputValue(ExprDocData data,
2685:                        EvaluationInfo evaluationInfo) {
2686:                    Long creatorId = (Long) evaluate(data, null);
2687:                    return creatorId != null ? getUserLogin(creatorId
2688:                            .longValue(), evaluationInfo.getQueryContext())
2689:                            : null;
2690:                }
2691:            }
2692:
2693:            public final class PrivateIdentifier extends
2694:                    AbstractNonAclIdentifier {
2695:                public static final String NAME = "private";
2696:
2697:                public String getName() {
2698:                    return NAME;
2699:                }
2700:
2701:                public QValueType getValueType() {
2702:                    return QValueType.BOOLEAN;
2703:                }
2704:
2705:                public Object evaluate(ExprDocData data,
2706:                        EvaluationInfo evaluationInfo) {
2707:                    return data.document.isPrivate() ? Boolean.TRUE
2708:                            : Boolean.FALSE;
2709:                }
2710:
2711:                public void generateSqlValueExpr(StringBuilder sql,
2712:                        SqlGenerationContext context) {
2713:                    sql.append(context.getDocumentsTable().getName());
2714:                    sql.append('.');
2715:                    sql.append(SqlGenerationContext.DocumentsTable.PRIVATE);
2716:                }
2717:
2718:                public QValueType getOutputValueType() {
2719:                    return QValueType.BOOLEAN;
2720:                }
2721:
2722:                public Object getOutputValue(ExprDocData data,
2723:                        EvaluationInfo evaluationInfo) {
2724:                    return evaluate(data, null);
2725:                }
2726:            }
2727:
2728:            public final class RetiredIdentifier extends
2729:                    AbstractNonAclIdentifier {
2730:                public static final String NAME = "retired";
2731:
2732:                public String getName() {
2733:                    return NAME;
2734:                }
2735:
2736:                public QValueType getValueType() {
2737:                    return QValueType.BOOLEAN;
2738:                }
2739:
2740:                public Object evaluate(ExprDocData data,
2741:                        EvaluationInfo evaluationInfo) {
2742:                    return data.document.isRetired() ? Boolean.TRUE
2743:                            : Boolean.FALSE;
2744:                }
2745:
2746:                public void generateSqlValueExpr(StringBuilder sql,
2747:                        SqlGenerationContext context) {
2748:                    sql.append(context.getDocumentVariantsTable().getName());
2749:                    sql.append('.');
2750:                    sql
2751:                            .append(SqlGenerationContext.DocumentVariantsTable.RETIRED);
2752:                }
2753:
2754:                public QValueType getOutputValueType() {
2755:                    return QValueType.BOOLEAN;
2756:                }
2757:
2758:                public Object getOutputValue(ExprDocData data,
2759:                        EvaluationInfo evaluationInfo) {
2760:                    return evaluate(data, null);
2761:                }
2762:            }
2763:
2764:            public final class VersionCreatorNameIdentifier extends
2765:                    AbstractOutputIdentifier {
2766:                public static final String NAME = "versionCreatorName";
2767:
2768:                public QValueType getValueType() {
2769:                    return QValueType.STRING;
2770:                }
2771:
2772:                public String getName() {
2773:                    return NAME;
2774:                }
2775:
2776:                public QValueType getOutputValueType() {
2777:                    return QValueType.STRING;
2778:                }
2779:
2780:                public Object getOutputValue(ExprDocData data,
2781:                        EvaluationInfo evaluationInfo) {
2782:                    return data.version != null ? getUserDisplayName(
2783:                            data.version.getCreator(), evaluationInfo
2784:                                    .getQueryContext()) : null;
2785:                }
2786:            }
2787:
2788:            public abstract class AbstractOutputIdentifier extends
2789:                    AbstractIdentifier {
2790:                public boolean isOutputOnly() {
2791:                    return true;
2792:                }
2793:
2794:                public QValueType getValueType() {
2795:                    return getOutputValueType();
2796:                }
2797:
2798:                public Object evaluate(ExprDocData data,
2799:                        EvaluationInfo evaluationInfo) throws QueryException {
2800:                    return getOutputValue(data, evaluationInfo);
2801:                }
2802:
2803:                public AclConditionViolation isAclAllowed() {
2804:                    return new AclConditionViolation("Identifier \""
2805:                            + getName()
2806:                            + "\" is not allowed in ACL conditions.");
2807:                }
2808:
2809:                public boolean canTestappliesTo() {
2810:                    return false;
2811:                }
2812:
2813:                public String getSqlPreConditions(SqlGenerationContext context)
2814:                        throws QueryException {
2815:                    throw new QueryException(
2816:                            "It is not possible to search on identifier "
2817:                                    + getName());
2818:                }
2819:
2820:                public void generateSqlValueExpr(StringBuilder sql,
2821:                        SqlGenerationContext context) throws QueryException {
2822:                    throw new QueryException(
2823:                            "It is not possible to search on identifier "
2824:                                    + getName());
2825:                }
2826:
2827:                public int bindPreConditions(PreparedStatement stmt,
2828:                        int bindPos, EvaluationInfo evaluationInfo)
2829:                        throws SQLException, QueryException {
2830:                    // This will never be reached, as the SQL generation methods throw exceptions
2831:                    throw new IllegalStateException();
2832:                }
2833:
2834:                public int bindValueExpr(PreparedStatement stmt, int bindPos,
2835:                        QValueType valueType) throws SQLException,
2836:                        QueryException {
2837:                    // This will never be reached, as the SQL generation methods throw exceptions
2838:                    throw new IllegalStateException();
2839:                }
2840:            }
2841:
2842:            public final class SummaryIdentifier extends
2843:                    AbstractOutputIdentifier {
2844:                public static final String NAME = "summary";
2845:
2846:                public String getName() {
2847:                    return NAME;
2848:                }
2849:
2850:                public QValueType getOutputValueType() {
2851:                    return QValueType.STRING;
2852:                }
2853:
2854:                public Object getOutputValue(ExprDocData data,
2855:                        EvaluationInfo evaluationInfo) {
2856:                    return data.document.getSummary();
2857:                }
2858:            }
2859:
2860:            public final class VersionStateIdentifier extends
2861:                    AbstractNonAclIdentifier {
2862:                public static final String NAME = "versionState";
2863:
2864:                public String getName() {
2865:                    return NAME;
2866:                }
2867:
2868:                public QValueType getOutputValueType() {
2869:                    return QValueType.VERSION_STATE;
2870:                }
2871:
2872:                public Object getOutputValue(ExprDocData data,
2873:                        EvaluationInfo evaluationInfo) {
2874:                    if (data.version != null) {
2875:                        return data.version.getState();
2876:                    } else {
2877:                        return null;
2878:                    }
2879:                }
2880:
2881:                public QValueType getValueType() {
2882:                    return QValueType.STRING;
2883:                }
2884:
2885:                public Object evaluate(ExprDocData data,
2886:                        EvaluationInfo evaluationInfo) {
2887:                    if (data.version != null) {
2888:                        return data.version.getState().getCode();
2889:                    } else {
2890:                        return null;
2891:                    }
2892:                }
2893:
2894:                public void generateSqlValueExpr(StringBuilder sql,
2895:                        SqlGenerationContext context) {
2896:                    sql.append(context.getVersionsTable().getName());
2897:                    sql.append('.');
2898:                    sql.append(SqlGenerationContext.VersionsTable.STATE);
2899:                }
2900:
2901:                public boolean isSymbolic() {
2902:                    return true;
2903:                }
2904:
2905:                public Object translateSymbolic(ValueExpr valueExpr,
2906:                        EvaluationInfo evaluationInfo) throws QueryException {
2907:                    String versionStateName = (String) valueExpr.evaluate(
2908:                            QValueType.STRING, null, evaluationInfo);
2909:                    VersionState versionState = VersionState
2910:                            .fromString(versionStateName);
2911:                    return versionState.getCode();
2912:                }
2913:            }
2914:
2915:            public final class PartContentIdentifier extends
2916:                    AbstractOutputIdentifier {
2917:                private final String name;
2918:                private final PartType partType;
2919:
2920:                public PartContentIdentifier(String name, PartType partType) {
2921:                    this .name = name;
2922:                    this .partType = partType;
2923:                }
2924:
2925:                public QValueType getOutputValueType() {
2926:                    return QValueType.XML;
2927:                }
2928:
2929:                public Object getOutputValue(ExprDocData data,
2930:                        EvaluationInfo evaluationInfo) {
2931:                    if (data.versionedData.hasPart(partType.getId())) {
2932:                        try {
2933:                            Part part = data.versionedData.getPart(partType
2934:                                    .getId());
2935:                            if (part.getMimeType().equals("text/xml")
2936:                                    && part.getSize() < CONTENT_INCLUDE_LIMIT) {
2937:                                XmlOptions xmlOptions = new XmlOptions()
2938:                                        .setLoadUseXMLReader(LocalSAXParserFactory
2939:                                                .newXmlReader());
2940:                                return XmlObject.Factory
2941:                                        .parse(new ByteArrayInputStream(part
2942:                                                .getData()), xmlOptions);
2943:                            }
2944:                        } catch (Exception e) {
2945:                            XmlObject error = XmlObject.Factory.newInstance();
2946:                            XmlCursor cursor = error.newCursor();
2947:                            cursor.toNextToken();
2948:                            cursor.beginElement("p");
2949:                            cursor.insertAttributeWithValue("class",
2950:                                    "daisy-error");
2951:                            cursor
2952:                                    .insertChars("Error getting part data for part "
2953:                                            + partType.getId()
2954:                                            + " of document "
2955:                                            + data.document.getVariantKey()
2956:                                            + ", error message: "
2957:                                            + e.getMessage());
2958:                            cursor.dispose();
2959:                            return error;
2960:                        }
2961:                    }
2962:                    return null;
2963:                }
2964:
2965:                public String getName() {
2966:                    return name;
2967:                }
2968:
2969:                public String getTitle(Locale locale) {
2970:                    return partType.getLabel(locale);
2971:                }
2972:
2973:                public void collectAccessRestrictions(
2974:                        AccessRestrictions restrictions) {
2975:                    restrictions.addPartReference(partType.getName());
2976:                }
2977:            }
2978:
2979:            public final class PartMimeTypeIdentifier extends
2980:                    AbstractNonAclIdentifier {
2981:                private final String name;
2982:                private final PartType partType;
2983:                private String alias;
2984:
2985:                public PartMimeTypeIdentifier(String name, PartType partType) {
2986:                    this .name = name;
2987:                    this .partType = partType;
2988:                }
2989:
2990:                public QValueType getValueType() {
2991:                    return QValueType.STRING;
2992:                }
2993:
2994:                public Object evaluate(ExprDocData data,
2995:                        EvaluationInfo evaluationInfo) {
2996:                    if (data.versionedData.hasPart(partType.getId())) {
2997:                        return data.versionedData.getPart(partType.getId())
2998:                                .getMimeType();
2999:                    } else {
3000:                        return null;
3001:                    }
3002:                }
3003:
3004:                public String getSqlPreConditions(SqlGenerationContext context) {
3005:                    alias = context.getNewPartsTable().getName();
3006:                    return alias + '.'
3007:                            + SqlGenerationContext.PartsTable.PARTTYPE_ID
3008:                            + " = ? ";
3009:                }
3010:
3011:                public void generateSqlValueExpr(StringBuilder sql,
3012:                        SqlGenerationContext context) {
3013:                    sql.append(alias).append('.').append(
3014:                            SqlGenerationContext.PartsTable.MIMETYPE);
3015:                }
3016:
3017:                public int bindPreConditions(PreparedStatement stmt,
3018:                        int bindPos, EvaluationInfo evaluationInfo)
3019:                        throws SQLException {
3020:                    stmt.setLong(bindPos, partType.getId());
3021:                    return ++bindPos;
3022:                }
3023:
3024:                public QValueType getOutputValueType() {
3025:                    return QValueType.STRING;
3026:                }
3027:
3028:                public Object getOutputValue(ExprDocData data,
3029:                        EvaluationInfo evaluationInfo) {
3030:                    return evaluate(data, null);
3031:                }
3032:
3033:                public String getName() {
3034:                    return name;
3035:                }
3036:
3037:                public String getTitle(Locale locale) {
3038:                    return partType.getLabel(locale) + " ("
3039:                            + getLocalizedString("part.mimetype", locale) + ")";
3040:                }
3041:
3042:                public void collectAccessRestrictions(
3043:                        AccessRestrictions restrictions) {
3044:                    restrictions.addPartReference(partType.getName());
3045:                }
3046:            }
3047:
3048:            public final class PartSizeIdentifier extends
3049:                    AbstractNonAclIdentifier {
3050:                private final String name;
3051:                private final PartType partType;
3052:                private String alias;
3053:
3054:                public PartSizeIdentifier(String name, PartType partType) {
3055:                    this .name = name;
3056:                    this .partType = partType;
3057:                }
3058:
3059:                public QValueType getValueType() {
3060:                    return QValueType.LONG;
3061:                }
3062:
3063:                public Object evaluate(ExprDocData data,
3064:                        EvaluationInfo evaluationInfo) {
3065:                    if (data.versionedData.hasPart(partType.getId())) {
3066:                        return new Long(data.versionedData.getPart(
3067:                                partType.getId()).getSize());
3068:                    } else {
3069:                        return null;
3070:                    }
3071:                }
3072:
3073:                public String getSqlPreConditions(SqlGenerationContext context) {
3074:                    alias = context.getNewPartsTable().getName();
3075:                    return alias + '.'
3076:                            + SqlGenerationContext.PartsTable.PARTTYPE_ID
3077:                            + " = ? ";
3078:                }
3079:
3080:                public void generateSqlValueExpr(StringBuilder sql,
3081:                        SqlGenerationContext context) {
3082:                    sql.append(alias).append('.').append(
3083:                            SqlGenerationContext.PartsTable.SIZE);
3084:                }
3085:
3086:                public int bindPreConditions(PreparedStatement stmt,
3087:                        int bindPos, EvaluationInfo evaluationInfo)
3088:                        throws SQLException {
3089:                    stmt.setLong(bindPos, partType.getId());
3090:                    return ++bindPos;
3091:                }
3092:
3093:                public QValueType getOutputValueType() {
3094:                    return QValueType.LONG;
3095:                }
3096:
3097:                public Object getOutputValue(ExprDocData data,
3098:                        EvaluationInfo evaluationInfo) {
3099:                    return evaluate(data, null);
3100:                }
3101:
3102:                public String getName() {
3103:                    return name;
3104:                }
3105:
3106:                public String getTitle(Locale locale) {
3107:                    return partType.getLabel(locale) + " ("
3108:                            + getLocalizedString("part.size", locale) + ")";
3109:                }
3110:
3111:                public void collectAccessRestrictions(
3112:                        AccessRestrictions restrictions) {
3113:                    restrictions.addPartReference(partType.getName());
3114:                }
3115:            }
3116:
3117:            public final class LockTypeIdentifier extends
3118:                    AbstractNonAclIdentifier {
3119:                public static final String NAME = "lockType";
3120:
3121:                public QValueType getValueType() {
3122:                    return QValueType.STRING;
3123:                }
3124:
3125:                public Object evaluate(ExprDocData data,
3126:                        EvaluationInfo evaluationInfo) {
3127:                    LockInfo lockInfo;
3128:                    try {
3129:                        lockInfo = data.document.getLockInfo(false);
3130:                    } catch (RepositoryException e) {
3131:                        throw new RuntimeException(e);
3132:                    }
3133:                    if (lockInfo.hasLock()) {
3134:                        return lockInfo.getType().getCode();
3135:                    } else {
3136:                        return null;
3137:                    }
3138:                }
3139:
3140:                public void generateSqlValueExpr(StringBuilder sql,
3141:                        SqlGenerationContext context) {
3142:                    sql.append(context.getLocksTable().getName());
3143:                    sql.append('.');
3144:                    sql.append(SqlGenerationContext.LocksTable.LOCKTYPE);
3145:                }
3146:
3147:                public boolean isSymbolic() {
3148:                    return true;
3149:                }
3150:
3151:                public Object translateSymbolic(ValueExpr valueExpr,
3152:                        EvaluationInfo evaluationInfo) throws QueryException {
3153:                    String lockTypeName = (String) valueExpr.evaluate(
3154:                            QValueType.STRING, null, evaluationInfo);
3155:                    LockType lockType = LockType.fromString(lockTypeName);
3156:                    return lockType.getCode();
3157:                }
3158:
3159:                public QValueType getOutputValueType() {
3160:                    return QValueType.STRING;
3161:                }
3162:
3163:                public Object getOutputValue(ExprDocData data,
3164:                        EvaluationInfo evaluationInfo) {
3165:                    LockInfo lockInfo;
3166:                    try {
3167:                        lockInfo = data.document.getLockInfo(false);
3168:                    } catch (RepositoryException e) {
3169:                        throw new RuntimeException(e);
3170:                    }
3171:                    if (lockInfo.hasLock()) {
3172:                        return lockInfo.getType().toString();
3173:                    } else {
3174:                        return null;
3175:                    }
3176:                }
3177:
3178:                public String getName() {
3179:                    return NAME;
3180:                }
3181:            }
3182:
3183:            public final class LockOwnerIdIdentifier extends
3184:                    AbstractNonAclIdentifier {
3185:                public static final String NAME = "lockOwnerId";
3186:
3187:                public QValueType getValueType() {
3188:                    return QValueType.LONG;
3189:                }
3190:
3191:                public Object evaluate(ExprDocData data,
3192:                        EvaluationInfo evaluationInfo) {
3193:                    LockInfo lockInfo;
3194:                    try {
3195:                        lockInfo = data.document.getLockInfo(false);
3196:                    } catch (RepositoryException e) {
3197:                        throw new RuntimeException(e);
3198:                    }
3199:                    if (lockInfo.hasLock()) {
3200:                        return new Long(lockInfo.getUserId());
3201:                    } else {
3202:                        return null;
3203:                    }
3204:                }
3205:
3206:                public void generateSqlValueExpr(StringBuilder sql,
3207:                        SqlGenerationContext context) {
3208:                    sql.append(context.getLocksTable().getName());
3209:                    sql.append('.');
3210:                    sql.append(SqlGenerationContext.LocksTable.OWNER_ID);
3211:                }
3212:
3213:                public QValueType getOutputValueType() {
3214:                    return QValueType.LONG;
3215:                }
3216:
3217:                public Object getOutputValue(ExprDocData data,
3218:                        EvaluationInfo evaluationInfo) {
3219:                    return evaluate(data, null);
3220:                }
3221:
3222:                public String getName() {
3223:                    return NAME;
3224:                }
3225:            }
3226:
3227:            public final class LockOwnerLoginIdentifier extends
3228:                    AbstractLoginIdentifier {
3229:                public static final String NAME = "lockOwnerLogin";
3230:
3231:                public Object evaluate(ExprDocData data,
3232:                        EvaluationInfo evaluationInfo) {
3233:                    LockInfo lockInfo;
3234:                    try {
3235:                        lockInfo = data.document.getLockInfo(false);
3236:                    } catch (RepositoryException e) {
3237:                        throw new RuntimeException(e);
3238:                    }
3239:                    if (lockInfo.hasLock()) {
3240:                        return new Long(lockInfo.getUserId());
3241:                    } else {
3242:                        return null;
3243:                    }
3244:                }
3245:
3246:                public void generateSqlValueExpr(StringBuilder sql,
3247:                        SqlGenerationContext context) {
3248:                    sql.append(context.getLocksTable().getName());
3249:                    sql.append('.');
3250:                    sql.append(SqlGenerationContext.LocksTable.OWNER_ID);
3251:                }
3252:
3253:                public Object getOutputValue(ExprDocData data,
3254:                        EvaluationInfo evaluationInfo) {
3255:                    LockInfo lockInfo;
3256:                    try {
3257:                        lockInfo = data.document.getLockInfo(false);
3258:                    } catch (RepositoryException e) {
3259:                        throw new RuntimeException(e);
3260:                    }
3261:                    if (lockInfo.hasLock()) {
3262:                        return getUserLogin(lockInfo.getUserId(),
3263:                                evaluationInfo.getQueryContext());
3264:                    } else {
3265:                        return null;
3266:                    }
3267:                }
3268:
3269:                public String getName() {
3270:                    return NAME;
3271:                }
3272:            }
3273:
3274:            public final class LockOwnerNameIdentifier extends
3275:                    AbstractOutputIdentifier {
3276:                public static final String NAME = "lockOwnerName";
3277:
3278:                public QValueType getOutputValueType() {
3279:                    return QValueType.STRING;
3280:                }
3281:
3282:                public Object getOutputValue(ExprDocData data,
3283:                        EvaluationInfo evaluationInfo) {
3284:                    LockInfo lockInfo;
3285:                    try {
3286:                        lockInfo = data.document.getLockInfo(false);
3287:                    } catch (RepositoryException e) {
3288:                        throw new RuntimeException(e);
3289:                    }
3290:                    if (lockInfo.hasLock()) {
3291:                        return getUserDisplayName(lockInfo.getUserId(),
3292:                                evaluationInfo.getQueryContext());
3293:                    } else {
3294:                        return null;
3295:                    }
3296:                }
3297:
3298:                public String getName() {
3299:                    return NAME;
3300:                }
3301:            }
3302:
3303:            public final class LockTimeAcquiredIdentifier extends
3304:                    AbstractNonAclIdentifier {
3305:                public static final String NAME = "lockTimeAcquired";
3306:
3307:                public QValueType getValueType() {
3308:                    return QValueType.DATETIME;
3309:                }
3310:
3311:                public Object evaluate(ExprDocData data,
3312:                        EvaluationInfo evaluationInfo) {
3313:                    LockInfo lockInfo;
3314:                    try {
3315:                        lockInfo = data.document.getLockInfo(false);
3316:                    } catch (RepositoryException e) {
3317:                        throw new RuntimeException(e);
3318:                    }
3319:                    if (lockInfo.hasLock()) {
3320:                        return lockInfo.getTimeAcquired();
3321:                    } else {
3322:                        return null;
3323:                    }
3324:                }
3325:
3326:                public void generateSqlValueExpr(StringBuilder sql,
3327:                        SqlGenerationContext context) {
3328:                    sql.append(context.getLocksTable().getName());
3329:                    sql.append('.');
3330:                    sql.append(SqlGenerationContext.LocksTable.TIME_ACQUIRED);
3331:                }
3332:
3333:                public QValueType getOutputValueType() {
3334:                    return QValueType.DATETIME;
3335:                }
3336:
3337:                public Object getOutputValue(ExprDocData data,
3338:                        EvaluationInfo evaluationInfo) {
3339:                    return evaluate(data, null);
3340:                }
3341:
3342:                public String getName() {
3343:                    return NAME;
3344:                }
3345:            }
3346:
3347:            public final class LockDurationIdentifier extends
3348:                    AbstractNonAclIdentifier {
3349:                public static final String NAME = "lockDuration";
3350:
3351:                public QValueType getValueType() {
3352:                    return QValueType.LONG;
3353:                }
3354:
3355:                public Object evaluate(ExprDocData data,
3356:                        EvaluationInfo evaluationInfo) {
3357:                    LockInfo lockInfo;
3358:                    try {
3359:                        lockInfo = data.document.getLockInfo(false);
3360:                    } catch (RepositoryException e) {
3361:                        throw new RuntimeException(e);
3362:                    }
3363:                    if (lockInfo.hasLock()) {
3364:                        return new Long(lockInfo.getDuration());
3365:                    } else {
3366:                        return null;
3367:                    }
3368:                }
3369:
3370:                public void generateSqlValueExpr(StringBuilder sql,
3371:                        SqlGenerationContext context) {
3372:                    sql.append(context.getLocksTable().getName());
3373:                    sql.append('.');
3374:                    sql.append(SqlGenerationContext.LocksTable.DURATION);
3375:                }
3376:
3377:                public QValueType getOutputValueType() {
3378:                    return QValueType.LONG;
3379:                }
3380:
3381:                public Object getOutputValue(ExprDocData data,
3382:                        EvaluationInfo evaluationInfo) {
3383:                    return evaluate(data, null);
3384:                }
3385:
3386:                public String getName() {
3387:                    return NAME;
3388:                }
3389:            }
3390:
3391:            public final class OwnerIdIdentifier extends
3392:                    AbstractNonAclIdentifier {
3393:                public static final String NAME = "ownerId";
3394:
3395:                public QValueType getValueType() {
3396:                    return QValueType.LONG;
3397:                }
3398:
3399:                public Object evaluate(ExprDocData data,
3400:                        EvaluationInfo evaluationInfo) {
3401:                    return new Long(data.document.getOwner());
3402:                }
3403:
3404:                public void generateSqlValueExpr(StringBuilder sql,
3405:                        SqlGenerationContext context) {
3406:                    sql.append(context.getDocumentsTable().getName());
3407:                    sql.append('.');
3408:                    sql.append(SqlGenerationContext.DocumentsTable.OWNER);
3409:                }
3410:
3411:                public QValueType getOutputValueType() {
3412:                    return QValueType.LONG;
3413:                }
3414:
3415:                public Object getOutputValue(ExprDocData data,
3416:                        EvaluationInfo evaluationInfo) {
3417:                    return evaluate(data, null);
3418:                }
3419:
3420:                public String getName() {
3421:                    return NAME;
3422:                }
3423:            }
3424:
3425:            public final class OwnerLoginIdentifier extends
3426:                    AbstractLoginIdentifier {
3427:                public static final String NAME = "ownerLogin";
3428:
3429:                public Object evaluate(ExprDocData data,
3430:                        EvaluationInfo evaluationInfo) {
3431:                    return new Long(data.document.getOwner());
3432:                }
3433:
3434:                public void generateSqlValueExpr(StringBuilder sql,
3435:                        SqlGenerationContext context) {
3436:                    sql.append(context.getDocumentsTable().getName());
3437:                    sql.append('.');
3438:                    sql.append(SqlGenerationContext.DocumentsTable.OWNER);
3439:                }
3440:
3441:                public Object getOutputValue(ExprDocData data,
3442:                        EvaluationInfo evaluationInfo) {
3443:                    return getUserLogin(data.document.getOwner(),
3444:                            evaluationInfo.getQueryContext());
3445:                }
3446:
3447:                public String getName() {
3448:                    return NAME;
3449:                }
3450:            }
3451:
3452:            public final class OwnerNameIdentifier extends
3453:                    AbstractOutputIdentifier {
3454:                public static final String NAME = "ownerName";
3455:
3456:                public QValueType getOutputValueType() {
3457:                    return QValueType.STRING;
3458:                }
3459:
3460:                public Object getOutputValue(ExprDocData data,
3461:                        EvaluationInfo evaluationInfo) {
3462:                    return getUserDisplayName(data.document.getOwner(),
3463:                            evaluationInfo.getQueryContext());
3464:                }
3465:
3466:                public String getName() {
3467:                    return NAME;
3468:                }
3469:            }
3470:
3471:            public final class LastModifierIdIdentifier extends
3472:                    AbstractNonAclIdentifier {
3473:                public static final String NAME = "lastModifierId";
3474:
3475:                public QValueType getValueType() {
3476:                    return QValueType.LONG;
3477:                }
3478:
3479:                public Object evaluate(ExprDocData data,
3480:                        EvaluationInfo evaluationInfo) {
3481:                    return new Long(data.document.getLastModifier());
3482:                }
3483:
3484:                public void generateSqlValueExpr(StringBuilder sql,
3485:                        SqlGenerationContext context) {
3486:                    sql.append(context.getDocumentsTable().getName());
3487:                    sql.append('.');
3488:                    sql
3489:                            .append(SqlGenerationContext.DocumentsTable.LAST_MODIFIER);
3490:                }
3491:
3492:                public QValueType getOutputValueType() {
3493:                    return QValueType.LONG;
3494:                }
3495:
3496:                public Object getOutputValue(ExprDocData data,
3497:                        EvaluationInfo evaluationInfo) {
3498:                    return evaluate(data, null);
3499:                }
3500:
3501:                public String getName() {
3502:                    return NAME;
3503:                }
3504:            }
3505:
3506:            public final class LastModifierLoginIdentifier extends
3507:                    AbstractLoginIdentifier {
3508:                public static final String NAME = "lastModifierLogin";
3509:
3510:                public Object evaluate(ExprDocData data,
3511:                        EvaluationInfo evaluationInfo) {
3512:                    return new Long(data.document.getLastModifier());
3513:                }
3514:
3515:                public void generateSqlValueExpr(StringBuilder sql,
3516:                        SqlGenerationContext context) {
3517:                    sql.append(context.getDocumentsTable().getName());
3518:                    sql.append('.');
3519:                    sql
3520:                            .append(SqlGenerationContext.DocumentsTable.LAST_MODIFIER);
3521:                }
3522:
3523:                public Object getOutputValue(ExprDocData data,
3524:                        EvaluationInfo evaluationInfo) {
3525:                    long lastModifier = data.document.getLastModifier();
3526:                    return lastModifier != -1 ? getUserLogin(lastModifier,
3527:                            evaluationInfo.getQueryContext()) : null;
3528:                }
3529:
3530:                public String getName() {
3531:                    return NAME;
3532:                }
3533:            }
3534:
3535:            public final class LastModifierNameIdentifier extends
3536:                    AbstractOutputIdentifier {
3537:                public static final String NAME = "lastModifierName";
3538:
3539:                public QValueType getOutputValueType() {
3540:                    return QValueType.STRING;
3541:                }
3542:
3543:                public Object getOutputValue(ExprDocData data,
3544:                        EvaluationInfo evaluationInfo) {
3545:                    long lastModifier = data.document.getLastModifier();
3546:                    return lastModifier != -1 ? getUserDisplayName(
3547:                            lastModifier, evaluationInfo.getQueryContext())
3548:                            : null;
3549:                }
3550:
3551:                public String getName() {
3552:                    return NAME;
3553:                }
3554:            }
3555:
3556:            public final class VariantLastModifierIdIdentifier extends
3557:                    AbstractNonAclIdentifier {
3558:                public static final String NAME = "variantLastModifierId";
3559:
3560:                public QValueType getValueType() {
3561:                    return QValueType.LONG;
3562:                }
3563:
3564:                public Object evaluate(ExprDocData data,
3565:                        EvaluationInfo evaluationInfo) {
3566:                    return new Long(data.document.getVariantLastModifier());
3567:                }
3568:
3569:                public void generateSqlValueExpr(StringBuilder sql,
3570:                        SqlGenerationContext context) {
3571:                    sql.append(context.getDocumentVariantsTable().getName());
3572:                    sql.append('.');
3573:                    sql
3574:                            .append(SqlGenerationContext.DocumentVariantsTable.LAST_MODIFIER);
3575:                }
3576:
3577:                public QValueType getOutputValueType() {
3578:                    return QValueType.LONG;
3579:                }
3580:
3581:                public Object getOutputValue(ExprDocData data,
3582:                        EvaluationInfo evaluationInfo) {
3583:                    return evaluate(data, null);
3584:                }
3585:
3586:                public String getName() {
3587:                    return NAME;
3588:                }
3589:            }
3590:
3591:            public final class VariantLastModifierLoginIdentifier extends
3592:                    AbstractLoginIdentifier {
3593:                public static final String NAME = "variantLastModifierLogin";
3594:
3595:                public Object evaluate(ExprDocData data,
3596:                        EvaluationInfo evaluationInfo) {
3597:                    return new Long(data.document.getLastModifier());
3598:                }
3599:
3600:                public void generateSqlValueExpr(StringBuilder sql,
3601:                        SqlGenerationContext context) {
3602:                    sql.append(context.getDocumentVariantsTable().getName());
3603:                    sql.append('.');
3604:                    sql
3605:                            .append(SqlGenerationContext.DocumentVariantsTable.LAST_MODIFIER);
3606:                }
3607:
3608:                public Object getOutputValue(ExprDocData data,
3609:                        EvaluationInfo evaluationInfo) {
3610:                    long lastModifier = data.document.getVariantLastModifier();
3611:                    return lastModifier != -1 ? getUserLogin(lastModifier,
3612:                            evaluationInfo.getQueryContext()) : null;
3613:                }
3614:
3615:                public String getName() {
3616:                    return NAME;
3617:                }
3618:            }
3619:
3620:            public final class VariantLastModifierNameIdentifier extends
3621:                    AbstractOutputIdentifier {
3622:                public static final String NAME = "variantLastModifierName";
3623:
3624:                public QValueType getOutputValueType() {
3625:                    return QValueType.STRING;
3626:                }
3627:
3628:                public Object getOutputValue(ExprDocData data,
3629:                        EvaluationInfo evaluationInfo) {
3630:                    long lastModifier = data.document.getVariantLastModifier();
3631:                    return lastModifier != -1 ? getUserDisplayName(
3632:                            lastModifier, evaluationInfo.getQueryContext())
3633:                            : null;
3634:                }
3635:
3636:                public String getName() {
3637:                    return NAME;
3638:                }
3639:            }
3640:
3641:            public final class LastModifiedIdentifier extends
3642:                    AbstractNonAclIdentifier {
3643:                public static final String NAME = "lastModified";
3644:
3645:                public QValueType getValueType() {
3646:                    return QValueType.DATETIME;
3647:                }
3648:
3649:                public Object evaluate(ExprDocData data,
3650:                        EvaluationInfo evaluationInfo) {
3651:                    return data.document.getLastModified();
3652:                }
3653:
3654:                public void generateSqlValueExpr(StringBuilder sql,
3655:                        SqlGenerationContext context) {
3656:                    sql.append(context.getDocumentsTable().getName());
3657:                    sql.append('.');
3658:                    sql
3659:                            .append(SqlGenerationContext.DocumentsTable.LAST_MODIFIED);
3660:                }
3661:
3662:                public QValueType getOutputValueType() {
3663:                    return QValueType.DATETIME;
3664:                }
3665:
3666:                public Object getOutputValue(ExprDocData data,
3667:                        EvaluationInfo evaluationInfo) {
3668:                    return evaluate(data, null);
3669:                }
3670:
3671:                public String getName() {
3672:                    return NAME;
3673:                }
3674:            }
3675:
3676:            public final class VariantLastModifiedIdentifier extends
3677:                    AbstractNonAclIdentifier {
3678:                public static final String NAME = "variantLastModified";
3679:
3680:                public QValueType getValueType() {
3681:                    return QValueType.DATETIME;
3682:                }
3683:
3684:                public Object evaluate(ExprDocData data,
3685:                        EvaluationInfo evaluationInfo) {
3686:                    return data.document.getVariantLastModified();
3687:                }
3688:
3689:                public void generateSqlValueExpr(StringBuilder sql,
3690:                        SqlGenerationContext context) {
3691:                    sql.append(context.getDocumentVariantsTable().getName());
3692:                    sql.append('.');
3693:                    sql
3694:                            .append(SqlGenerationContext.DocumentVariantsTable.LAST_MODIFIED);
3695:                }
3696:
3697:                public QValueType getOutputValueType() {
3698:                    return QValueType.DATETIME;
3699:                }
3700:
3701:                public Object getOutputValue(ExprDocData data,
3702:                        EvaluationInfo evaluationInfo) {
3703:                    return evaluate(data, null);
3704:                }
3705:
3706:                public String getName() {
3707:                    return NAME;
3708:                }
3709:            }
3710:
3711:            public final class VersionIdIdentifier extends
3712:                    AbstractNonAclIdentifier {
3713:                public static final String NAME = "versionId";
3714:
3715:                public QValueType getValueType() {
3716:                    return QValueType.LONG;
3717:                }
3718:
3719:                public Object evaluate(ExprDocData data,
3720:                        EvaluationInfo evaluationInfo) {
3721:                    if (data.version != null) {
3722:                        return new Long(data.version.getId());
3723:                    } else {
3724:                        return null;
3725:                    }
3726:                }
3727:
3728:                public void generateSqlValueExpr(StringBuilder sql,
3729:                        SqlGenerationContext context) {
3730:                    sql.append(context.getVersionsTable().getName());
3731:                    sql.append('.');
3732:                    sql.append(SqlGenerationContext.VersionsTable.ID);
3733:                }
3734:
3735:                public QValueType getOutputValueType() {
3736:                    return QValueType.LONG;
3737:                }
3738:
3739:                public Object getOutputValue(ExprDocData data,
3740:                        EvaluationInfo evaluationInfo) {
3741:                    return evaluate(data, null);
3742:                }
3743:
3744:                public String getName() {
3745:                    return NAME;
3746:                }
3747:            }
3748:
3749:            public class CustomFieldIdentifier extends AbstractNonAclIdentifier {
3750:                private final String name;
3751:                private String alias;
3752:
3753:                public CustomFieldIdentifier(String name) {
3754:                    this .name = name;
3755:                }
3756:
3757:                public QValueType getValueType() {
3758:                    return QValueType.STRING;
3759:                }
3760:
3761:                public Object evaluate(ExprDocData data,
3762:                        EvaluationInfo evaluationInfo) {
3763:                    return data.document.getCustomField(name);
3764:                }
3765:
3766:                public String getSqlPreConditions(SqlGenerationContext context)
3767:                        throws QueryException {
3768:                    // the alias/join is created here for some special conditions (like IsNull) that never make use of the value expr
3769:                    alias = context.getNewCustomFieldsTable(name).getName();
3770:                    return null;
3771:                }
3772:
3773:                public void generateSqlValueExpr(StringBuilder sql,
3774:                        SqlGenerationContext context) {
3775:                    sql.append(alias);
3776:                    sql.append('.');
3777:                    sql.append(SqlGenerationContext.CustomFieldsTable.VALUE);
3778:                }
3779:
3780:                public int bindPreConditions(PreparedStatement stmt,
3781:                        int bindPos, EvaluationInfo evaluationInfo)
3782:                        throws SQLException, QueryException {
3783:                    return bindPos;
3784:                }
3785:
3786:                public String getTableAlias() {
3787:                    return alias;
3788:                }
3789:
3790:                public QValueType getOutputValueType() {
3791:                    return QValueType.STRING;
3792:                }
3793:
3794:                public Object getOutputValue(ExprDocData data,
3795:                        EvaluationInfo evaluationInfo) {
3796:                    return evaluate(data, null);
3797:                }
3798:
3799:                public String getName() {
3800:                    return '#' + name;
3801:                }
3802:
3803:                public String getTitle(Locale locale) {
3804:                    return name;
3805:                }
3806:            }
3807:
3808:            public final class ScoreIdentifier extends AbstractOutputIdentifier {
3809:                public static final String NAME = "score";
3810:
3811:                public String getName() {
3812:                    return NAME;
3813:                }
3814:
3815:                public Object getOutputValue(ExprDocData data,
3816:                        EvaluationInfo evaluationInfo) {
3817:                    Document document = data.document;
3818:                    VariantKey key = new VariantKey(document.getId(), document
3819:                            .getBranchId(), document.getLanguageId());
3820:                    float score = 0;
3821:
3822:                    if (evaluationInfo.getHits() != null)
3823:                        score = evaluationInfo.getHits().score(key);
3824:                    return new Double(score);
3825:                }
3826:
3827:                public QValueType getOutputValueType() {
3828:                    return QValueType.DOUBLE;
3829:                }
3830:            }
3831:
3832:            public final class ReferenceLanguageIdIdentifier extends
3833:                    AbstractIdentifier {
3834:                public static final String NAME = "referenceLanguageId";
3835:
3836:                public String getName() {
3837:                    return NAME;
3838:                }
3839:
3840:                public QValueType getValueType() {
3841:                    return QValueType.LONG;
3842:                }
3843:
3844:                public Object evaluate(ExprDocData data,
3845:                        EvaluationInfo evaluationInfo) {
3846:                    long refLangId = data.document.getReferenceLanguageId();
3847:                    return refLangId == -1 ? null : new Long(refLangId);
3848:                }
3849:
3850:                public void generateSqlValueExpr(StringBuilder sql,
3851:                        SqlGenerationContext context) {
3852:                    sql.append(context.getDocumentsTable().getName());
3853:                    sql.append('.');
3854:                    sql
3855:                            .append(SqlGenerationContext.DocumentsTable.REFERENCE_LANGUAGE);
3856:                }
3857:
3858:                public QValueType getOutputValueType() {
3859:                    return QValueType.LONG;
3860:                }
3861:
3862:                public Object getOutputValue(ExprDocData data,
3863:                        EvaluationInfo evaluationInfo) {
3864:                    return evaluate(data, evaluationInfo);
3865:                }
3866:            }
3867:
3868:            public final class ReferenceLanguageNameIdentifier extends
3869:                    AbstractIdentifier {
3870:                public static final String NAME = "referenceLanguage";
3871:
3872:                public String getName() {
3873:                    return NAME;
3874:                }
3875:
3876:                public QValueType getValueType() {
3877:                    return QValueType.LONG;
3878:                }
3879:
3880:                public Object evaluate(ExprDocData data,
3881:                        EvaluationInfo evaluationInfo) {
3882:                    long refLangId = data.document.getReferenceLanguageId();
3883:                    return refLangId == -1 ? null : new Long(refLangId);
3884:                }
3885:
3886:                public void generateSqlValueExpr(StringBuilder sql,
3887:                        SqlGenerationContext context) {
3888:                    sql.append(context.getDocumentsTable().getName());
3889:                    sql.append('.');
3890:                    sql
3891:                            .append(SqlGenerationContext.DocumentsTable.REFERENCE_LANGUAGE);
3892:                }
3893:
3894:                public QValueType getOutputValueType() {
3895:                    return QValueType.STRING;
3896:                }
3897:
3898:                public Object getOutputValue(ExprDocData data,
3899:                        EvaluationInfo evaluationInfo) {
3900:                    long refLangId = data.document.getReferenceLanguageId();
3901:                    if (refLangId == -1)
3902:                        return null;
3903:                    try {
3904:                        return evaluationInfo.getQueryContext().getLanguage(
3905:                                refLangId).getName();
3906:                    } catch (RepositoryException e) {
3907:                        throw new RuntimeException(e);
3908:                    }
3909:                }
3910:
3911:                public boolean isSymbolic() {
3912:                    return true;
3913:                }
3914:
3915:                public Object translateSymbolic(ValueExpr valueExpr,
3916:                        EvaluationInfo evaluationInfo) throws QueryException {
3917:                    String languageName = (String) valueExpr.evaluate(
3918:                            QValueType.STRING, null, evaluationInfo);
3919:                    Language language;
3920:                    try {
3921:                        language = evaluationInfo.getQueryContext()
3922:                                .getLanguageByName(languageName);
3923:                    } catch (RepositoryException e) {
3924:                        throw new QueryException("Error with language name \""
3925:                                + languageName + "\".", e);
3926:                    }
3927:                    return new Long(language.getId());
3928:                }
3929:            }
3930:
3931:            public final class VersionCommentIdentifier extends
3932:                    AbstractNonAclIdentifier {
3933:                public static final String NAME = "versionComment";
3934:
3935:                public String getName() {
3936:                    return NAME;
3937:                }
3938:
3939:                public QValueType getValueType() {
3940:                    return QValueType.STRING;
3941:                }
3942:
3943:                public Object evaluate(ExprDocData data,
3944:                        EvaluationInfo evaluationInfo) {
3945:                    return data.version != null ? data.version
3946:                            .getChangeComment() : null;
3947:                }
3948:
3949:                public void generateSqlValueExpr(StringBuilder sql,
3950:                        SqlGenerationContext context) {
3951:                    sql.append(context.getVersionsTable().getName());
3952:                    sql.append('.');
3953:                    sql
3954:                            .append(SqlGenerationContext.VersionsTable.CHANGE_COMMENT);
3955:                }
3956:
3957:                public QValueType getOutputValueType() {
3958:                    return QValueType.STRING;
3959:                }
3960:
3961:                public Object getOutputValue(ExprDocData data,
3962:                        EvaluationInfo evaluationInfo) {
3963:                    return evaluate(data, null);
3964:                }
3965:            }
3966:
3967:            public final class VersionChangeTypeIdentifier extends
3968:                    AbstractNonAclIdentifier {
3969:                public static final String NAME = "versionChangeType";
3970:
3971:                public String getName() {
3972:                    return NAME;
3973:                }
3974:
3975:                public QValueType getValueType() {
3976:                    return QValueType.STRING;
3977:                }
3978:
3979:                public Object evaluate(ExprDocData data,
3980:                        EvaluationInfo evaluationInfo) {
3981:                    return data.version != null ? data.version.getChangeType()
3982:                            .getCode() : null;
3983:                }
3984:
3985:                public QValueType getOutputValueType() {
3986:                    return QValueType.STRING;
3987:                }
3988:
3989:                public Object getOutputValue(ExprDocData data,
3990:                        EvaluationInfo evaluationInfo) {
3991:                    return data.version.getChangeType().toString();
3992:                }
3993:
3994:                public void generateSqlValueExpr(StringBuilder sql,
3995:                        SqlGenerationContext context) {
3996:                    sql.append(context.getVersionsTable().getName());
3997:                    sql.append('.');
3998:                    sql.append(SqlGenerationContext.VersionsTable.CHANGE_TYPE);
3999:                }
4000:
4001:                public boolean isSymbolic() {
4002:                    return true;
4003:                }
4004:
4005:                public Object translateSymbolic(ValueExpr valueExpr,
4006:                        EvaluationInfo evaluationInfo) throws QueryException {
4007:                    String changeTypeName = (String) valueExpr.evaluate(
4008:                            QValueType.STRING, null, evaluationInfo);
4009:                    return ChangeType.fromString(changeTypeName).getCode();
4010:                }
4011:            }
4012:
4013:            public final class LastMajorChangeVersionIdIdentifier extends
4014:                    AbstractNonAclIdentifier {
4015:                public static final String NAME = "lastMajorChangeVersionId";
4016:
4017:                public QValueType getValueType() {
4018:                    return QValueType.LONG;
4019:                }
4020:
4021:                public Object evaluate(ExprDocData data,
4022:                        EvaluationInfo evaluationInfo) {
4023:                    long id = data.document.getLastMajorChangeVersionId();
4024:                    return id == -1 ? null : new Long(id);
4025:                }
4026:
4027:                public void generateSqlValueExpr(StringBuilder sql,
4028:                        SqlGenerationContext context) {
4029:                    sql.append(context.getDocumentVariantsTable().getName());
4030:                    sql.append('.');
4031:                    sql
4032:                            .append(SqlGenerationContext.DocumentVariantsTable.LAST_MAJOR_CHANGE_VERSION);
4033:                }
4034:
4035:                public QValueType getOutputValueType() {
4036:                    return QValueType.LONG;
4037:                }
4038:
4039:                public Object getOutputValue(ExprDocData data,
4040:                        EvaluationInfo evaluationInfo) {
4041:                    return evaluate(data, null);
4042:                }
4043:
4044:                public String getName() {
4045:                    return NAME;
4046:                }
4047:            }
4048:
4049:            public final class LiveMajorChangeVersionIdIdentifier extends
4050:                    AbstractNonAclIdentifier {
4051:                public static final String NAME = "liveMajorChangeVersionId";
4052:
4053:                public QValueType getValueType() {
4054:                    return QValueType.LONG;
4055:                }
4056:
4057:                public Object evaluate(ExprDocData data,
4058:                        EvaluationInfo evaluationInfo) {
4059:                    long id = data.document.getLiveMajorChangeVersionId();
4060:                    return id == -1 ? null : new Long(id);
4061:                }
4062:
4063:                public void generateSqlValueExpr(StringBuilder sql,
4064:                        SqlGenerationContext context) {
4065:                    sql.append(context.getDocumentVariantsTable().getName());
4066:                    sql.append('.');
4067:                    sql
4068:                            .append(SqlGenerationContext.DocumentVariantsTable.LIVE_MAJOR_CHANGE_VERSION);
4069:                }
4070:
4071:                public QValueType getOutputValueType() {
4072:                    return QValueType.LONG;
4073:                }
4074:
4075:                public Object getOutputValue(ExprDocData data,
4076:                        EvaluationInfo evaluationInfo) {
4077:                    return evaluate(data, null);
4078:                }
4079:
4080:                public String getName() {
4081:                    return NAME;
4082:                }
4083:            }
4084:
4085:            public final class SyncedWithIdentifier extends
4086:                    AbstractNonAclIdentifier {
4087:                public static final String NAME = "syncedWith";
4088:
4089:                public String getName() {
4090:                    return NAME;
4091:                }
4092:
4093:                public QValueType getValueType() {
4094:                    return QValueType.LINK;
4095:                }
4096:
4097:                public Object evaluate(ExprDocData data,
4098:                        EvaluationInfo evaluationInfo) {
4099:                    if (data.version != null) {
4100:                        VersionKey versionKey = data.version.getSyncedWith();
4101:                        if (versionKey != null)
4102:                            return new VariantKey(versionKey.getDocumentId(),
4103:                                    versionKey.getBranchId(), versionKey
4104:                                            .getLanguageId());
4105:                    }
4106:                    return null;
4107:                }
4108:
4109:                public void generateSqlValueExpr(StringBuilder sql,
4110:                        SqlGenerationContext context) {
4111:                    sql.append(context.getVersionsTable().getName());
4112:                    sql.append(".");
4113:                    sql
4114:                            .append(SqlGenerationContext.VersionsTable.SYNCED_WITH_SEARCH);
4115:                }
4116:
4117:                public QValueType getOutputValueType() {
4118:                    return QValueType.LINK;
4119:                }
4120:
4121:                public Object getOutputValue(ExprDocData data,
4122:                        EvaluationInfo evaluationInfo) {
4123:                    return evaluate(data, null);
4124:                }
4125:            }
4126:
4127:            public final class SyncedWithVersionIdIdentifier extends
4128:                    AbstractNonAclIdentifier {
4129:                public static final String NAME = "syncedWith.versionId";
4130:
4131:                public String getName() {
4132:                    return NAME;
4133:                }
4134:
4135:                public QValueType getValueType() {
4136:                    return QValueType.LONG;
4137:                }
4138:
4139:                public Object evaluate(ExprDocData data,
4140:                        EvaluationInfo evaluationInfo) {
4141:                    if (data.version != null) {
4142:                        VersionKey versionKey = data.version.getSyncedWith();
4143:                        if (versionKey != null)
4144:                            return new Long(versionKey.getVersionId());
4145:                    }
4146:                    return null;
4147:                }
4148:
4149:                public void generateSqlValueExpr(StringBuilder sql,
4150:                        SqlGenerationContext context) {
4151:                    sql.append(context.getVersionsTable().getName());
4152:                    sql.append(".");
4153:                    sql
4154:                            .append(SqlGenerationContext.VersionsTable.SYNCED_WITH_VERSION_ID);
4155:                }
4156:
4157:                public QValueType getOutputValueType() {
4158:                    return QValueType.LONG;
4159:                }
4160:
4161:                public Object getOutputValue(ExprDocData data,
4162:                        EvaluationInfo evaluationInfo) {
4163:                    return evaluate(data, null);
4164:                }
4165:            }
4166:
4167:            public class SyncedWithLanguageIdIdentifier extends
4168:                    AbstractNonAclIdentifier {
4169:                public static final String NAME = "syncedWith.languageId";
4170:
4171:                public String getName() {
4172:                    return NAME;
4173:                }
4174:
4175:                public QValueType getValueType() {
4176:                    return QValueType.LONG;
4177:                }
4178:
4179:                public Object evaluate(ExprDocData data,
4180:                        EvaluationInfo evaluationInfo) {
4181:                    if (data.version != null) {
4182:                        VersionKey versionKey = data.version.getSyncedWith();
4183:                        if (versionKey != null)
4184:                            return new Long(versionKey.getLanguageId());
4185:                    }
4186:                    return null;
4187:                }
4188:
4189:                public void generateSqlValueExpr(StringBuilder sql,
4190:                        SqlGenerationContext context) {
4191:                    sql.append(context.getVersionsTable().getName());
4192:                    sql.append(".");
4193:                    sql
4194:                            .append(SqlGenerationContext.VersionsTable.SYNCED_WITH_LANG_ID);
4195:                }
4196:
4197:                public QValueType getOutputValueType() {
4198:                    return QValueType.LONG;
4199:                }
4200:
4201:                public Object getOutputValue(ExprDocData data,
4202:                        EvaluationInfo evaluationInfo) {
4203:                    return evaluate(data, null);
4204:                }
4205:            }
4206:
4207:            public final class SyncedWithLanguageNameIdentifier extends
4208:                    SyncedWithLanguageIdIdentifier {
4209:                public static final String NAME = "syncedWith.language";
4210:
4211:                public String getName() {
4212:                    return NAME;
4213:                }
4214:
4215:                public void generateSqlValueExpr(StringBuilder sql,
4216:                        SqlGenerationContext context) {
4217:                    sql.append(context.getVersionsTable().getName());
4218:                    sql.append(".");
4219:                    sql
4220:                            .append(SqlGenerationContext.VersionsTable.SYNCED_WITH_LANG_ID);
4221:                }
4222:
4223:                public QValueType getOutputValueType() {
4224:                    return QValueType.STRING;
4225:                }
4226:
4227:                public Object getOutputValue(ExprDocData data,
4228:                        EvaluationInfo evaluationInfo) {
4229:                    if (data.version == null)
4230:                        return null;
4231:
4232:                    VersionKey versionKey = data.version.getSyncedWith();
4233:                    if (versionKey == null)
4234:                        return null;
4235:
4236:                    try {
4237:                        return evaluationInfo.getQueryContext().getLanguage(
4238:                                versionKey.getLanguageId()).getName();
4239:                    } catch (RepositoryException e) {
4240:                        throw new RuntimeException(e);
4241:                    }
4242:                }
4243:
4244:                public boolean isSymbolic() {
4245:                    return true;
4246:                }
4247:
4248:                public Object translateSymbolic(ValueExpr valueExpr,
4249:                        EvaluationInfo evaluationInfo) throws QueryException {
4250:                    String languageName = (String) valueExpr.evaluate(
4251:                            QValueType.STRING, null, evaluationInfo);
4252:                    Language language;
4253:                    try {
4254:                        language = evaluationInfo.getQueryContext()
4255:                                .getLanguageByName(languageName);
4256:                    } catch (RepositoryException e) {
4257:                        throw new QueryException("Error with language name \""
4258:                                + languageName + "\".", e);
4259:                    }
4260:                    return new Long(language.getId());
4261:                }
4262:            }
4263:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.