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: }
|