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 * Checks whether a document id is valid. A document id is a
23 * non-null ASCII visible printable string of
24 * {@literal #MAXIMUM_DOCUMENT_ID_LENGTH} characters which does not start
25 * with '!' which is reserved for system documents.
27 * @param documentId the document id to check
28 * @return the checked document id
29 * @throws IllegalArgumentException if the document id is invalid
31 public static String
checkDocumentId(String documentId
) {
32 Preconditions
.checkArgument(!Strings
.isNullOrEmpty(documentId
), "Document id is null or empty");
33 Preconditions
.checkArgument(
34 documentId
.length() <= SearchApiLimits
.MAXIMUM_DOCUMENT_ID_LENGTH
,
35 "Document id is longer than %d: %s",
36 SearchApiLimits
.MAXIMUM_DOCUMENT_ID_LENGTH
, documentId
);
37 Preconditions
.checkArgument(IndexChecker
.isAsciiVisiblePrintable(documentId
),
38 "Document id must be ASCII visible printable: %s", documentId
);
39 Preconditions
.checkArgument(!IndexChecker
.isReserved(documentId
),
40 "Document id must not start with !: %s", documentId
);
45 * Checks whether a document's field set is valid.
46 * A field set is valid if it does not contain any number or date fields with the same name.
48 * @param document the document to check
49 * @throws IllegalArgumentException if the document contains an invalid set of fields.
51 public static void checkFieldSet(DocumentPb
.Document document
) {
52 Set
<String
> noRepeatNames
= Sets
.newHashSet();
53 for (DocumentPb
.Field field
: document
.getFieldList()) {
54 if (field
.getValue().getType() == DocumentPb
.FieldValue
.ContentType
.NUMBER
||
55 field
.getValue().getType() == DocumentPb
.FieldValue
.ContentType
.DATE
) {
56 if (noRepeatNames
.contains(field
.getName())) {
57 throw new IllegalArgumentException(
58 "Invalid document " + document
.getId() + ": field " + field
.getName() +
59 "with type date or number may not be repeated.");
61 noRepeatNames
.add(field
.getName());
67 * Checks whether a {@link DocumentPb.Document} has a valid set
70 * @param pb the {@link DocumentPb.Document} protocol buffer to check
71 * @return the checked document
72 * @throws IllegalArgumentException if some field is invalid such as
73 * document id or fields
75 public static DocumentPb
.Document
checkValid(DocumentPb
.Document pb
) {
76 Preconditions
.checkArgument(pb
.getSerializedSize() <= SearchApiLimits
.MAXIMUM_DOCUMENT_LENGTH
,
77 "Document length %d is greater than the maximum %d bytes",
78 pb
.getSerializedSize(), SearchApiLimits
.MAXIMUM_DOCUMENT_LENGTH
);
80 checkDocumentId(pb
.getId());
82 mandatoryCheckValid(pb
);
87 * Does only the {@link DocumentPb.Document} validity checks that must be satisfied for all
88 * customer types that use the search API.
90 * @param pb the {@link DocumentPb.Document} protocol buffer to check
91 * @throws IllegalArgumentException if the document is invalid.
93 static void mandatoryCheckValid(DocumentPb
.Document pb
) {
94 Preconditions
.checkArgument(!pb
.getFieldList().isEmpty(),
95 "Empty list of fields in document for indexing");
100 * @return the number of seconds since 2011/1/1
102 public static int getNumberOfSecondsSince() {
103 long millisSince
= Math
.max(0L,
104 (System
.currentTimeMillis() - MILLIS_UP_TO_1ST_JAN_2011
) / 1000L);
105 Preconditions
.checkArgument(millisSince
<= Integer
.MAX_VALUE
,
106 "API failure due to date conversion overflow");
107 return (int) millisSince
;