1 // Copyright 2010 Google Inc. All Rights Reserved.
3 package com
.google
.appengine
.api
.search
.checkers
;
5 import com
.google
.apphosting
.api
.AppEngineInternal
;
6 import com
.google
.apphosting
.api
.search
.DocumentPb
;
7 import com
.google
.common
.base
.Strings
;
8 import com
.google
.common
.collect
.Sets
;
13 * Checks values of a {@link com.google.appengine.api.search.Document}.
17 public final class DocumentChecker
{
19 private static final long MILLIS_UP_TO_1ST_JAN_2011
= 1293840000000L;
22 * The maximum length of a document id.
23 * @deprecated From 1.7.4, use {@link SearchApiLimits#MAXIMUM_DOCUMENT_ID_LENGTH}
25 @Deprecated public static final int MAXIMUM_DOCUMENT_ID_LENGTH
= 500;
28 * The maximum length of a document.
29 * @deprecated From 1.7.4, use {@link SearchApiLimits#MAXIMUM_DOCUMENT_LENGTH}
31 @Deprecated public static final int MAXIMUM_DOCUMENT_LENGTH
= 1 << 20;
34 * Checks whether a document id is valid. A document id is a
35 * non-null ASCII visible printable string of
36 * {@literal #MAXIMUM_DOCUMENT_ID_LENGTH} characters which does not start
37 * with '!' which is reserved for system documents.
39 * @param documentId the document id to check
40 * @return the checked document id
41 * @throws IllegalArgumentException if the document id is invalid
43 public static String
checkDocumentId(String documentId
) {
44 Preconditions
.checkArgument(!Strings
.isNullOrEmpty(documentId
), "Document id is null or empty");
45 Preconditions
.checkArgument(
46 documentId
.length() <= SearchApiLimits
.MAXIMUM_DOCUMENT_ID_LENGTH
,
47 "Document id is longer than %d: %s",
48 SearchApiLimits
.MAXIMUM_DOCUMENT_ID_LENGTH
, documentId
);
49 Preconditions
.checkArgument(IndexChecker
.isAsciiVisiblePrintable(documentId
),
50 "Document id must be ASCII visible printable: %s", documentId
);
51 Preconditions
.checkArgument(!IndexChecker
.isReserved(documentId
),
52 "Document id must not start with !: %s", documentId
);
57 * Checks whether a document's field set is valid.
58 * A field set is valid if it does not contain any number or date fields with the same name.
60 * @param document the document to check
61 * @throws IllegalArgumentException if the document contains an invalid set of fields.
63 public static void checkFieldSet(DocumentPb
.Document document
) {
64 Set
<String
> noRepeatNames
= Sets
.newHashSet();
65 for (DocumentPb
.Field field
: document
.getFieldList()) {
66 if (field
.getValue().getType() == DocumentPb
.FieldValue
.ContentType
.NUMBER
||
67 field
.getValue().getType() == DocumentPb
.FieldValue
.ContentType
.DATE
) {
68 if (noRepeatNames
.contains(field
.getName())) {
69 throw new IllegalArgumentException(
70 "Invalid document " + document
.getId() + ": field " + field
.getName() +
71 "with type date or number may not be repeated.");
73 noRepeatNames
.add(field
.getName());
79 * Checks whether a {@link DocumentPb.Document} has a valid set
82 * @param pb the {@link DocumentPb.Document} protocol buffer to check
83 * @return the checked document
84 * @throws IllegalArgumentException if some field is invalid such as
85 * document id or fields
87 public static DocumentPb
.Document
checkValid(DocumentPb
.Document pb
) {
88 Preconditions
.checkArgument(pb
.getSerializedSize() <= SearchApiLimits
.MAXIMUM_DOCUMENT_LENGTH
,
89 "Document length %d is greater than the maximum %d bytes",
90 pb
.getSerializedSize(), SearchApiLimits
.MAXIMUM_DOCUMENT_LENGTH
);
92 checkDocumentId(pb
.getId());
94 mandatoryCheckValid(pb
);
99 * Does only the {@link DocumentPb.Document} validity checks that must be satisfied for all
100 * customer types that use the search API.
102 * @param pb the {@link DocumentPb.Document} protocol buffer to check
103 * @throws IllegalArgumentException if the document is invalid.
105 static void mandatoryCheckValid(DocumentPb
.Document pb
) {
106 Preconditions
.checkArgument(pb
.getFieldList() != null,
107 "Null list of fields in document for indexing");
112 * @return the number of seconds since 2011/1/1
114 public static int getNumberOfSecondsSince() {
115 long millisSince
= Math
.max(0L,
116 (System
.currentTimeMillis() - MILLIS_UP_TO_1ST_JAN_2011
) / 1000L);
117 Preconditions
.checkArgument(millisSince
<= Integer
.MAX_VALUE
,
118 "API failure due to date conversion overflow");
119 return (int) millisSince
;