Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / search / checkers / DocumentChecker.java
blob69dcccb347b1b06173bcf09f0a78af1f7c4c1373
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;
10 import java.util.Set;
12 /**
13 * Checks values of a {@link com.google.appengine.api.search.Document}.
16 @AppEngineInternal
17 public final class DocumentChecker {
19 private static final long MILLIS_UP_TO_1ST_JAN_2011 = 1293840000000L;
21 /**
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);
41 return documentId;
44 /**
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());
66 /**
67 * Checks whether a {@link DocumentPb.Document} has a valid set
68 * of fields.
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);
79 if (pb.hasId()) {
80 checkDocumentId(pb.getId());
82 mandatoryCheckValid(pb);
83 return pb;
86 /**
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");
96 checkFieldSet(pb);
99 /**
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;