/**
   * Retrieves the last modified date of a document from a connector instance.
   *
   * @param metadata the Document metadata
   * @return a long integer specifying the time the document was last modified, in milliseconds
   *     since midnight, January 1, 1970 GMT, or -1L if the time is not known
   */
  @VisibleForTesting
  static long handleGetLastModified(Document metadata) {
    if (metadata == null) {
      return -1L;
    }

    try {
      // TODO: Value and DateValue Calendar methods are too weak to try to get
      // last modified from non-DateValues.
      ValueImpl value =
          (ValueImpl) Value.getSingleValue(metadata, SpiConstants.PROPNAME_LASTMODIFIED);
      if (value == null) {
        LOGGER.log(
            Level.FINEST, "Document does not contain {0}", SpiConstants.PROPNAME_LASTMODIFIED);
      } else if (value instanceof DateValue) {
        // DateValues don't give direct access to their Calendar object, but
        // I can get the Calendar back out by parsing the stringized version.
        // This method also applies the FeedTimeZone, if needed.
        // TODO: Add a DateValue.getTimeMillis() or getCalendar() method to
        // directly access the wrapped value.
        String lastModified = ((DateValue) value).toIso8601();
        LOGGER.log(Level.FINEST, "Document last modified {0}", lastModified);
        return Value.iso8601ToCalendar(lastModified).getTimeInMillis();
      }
    } catch (RepositoryException e) {
      LOGGER.log(Level.WARNING, "Failed to retrieve last-modified date", e);
    } catch (ParseException e) {
      LOGGER.log(Level.WARNING, "Failed to parse last-modified date", e);
    }
    return -1L;
  }
  @VisibleForTesting
  static int handleMarkingDocumentSecurity(
      HttpServletRequest req, HttpServletResponse res, Document metadata) throws IOException {
    if (req.getHeader("Authorization") != null) {
      // GSA logged in; it is aware of the access restrictions on the document.
      return HttpServletResponse.SC_OK;
    }

    if (metadata == null) {
      return HttpServletResponse.SC_SERVICE_UNAVAILABLE;
    }

    ValueImpl isPublicVal;
    try {
      isPublicVal = (ValueImpl) Value.getSingleValue(metadata, SpiConstants.PROPNAME_ISPUBLIC);
    } catch (RepositoryException ex) {
      LOGGER.log(Level.WARNING, "Failed retrieving isPublic property", ex);
      return HttpServletResponse.SC_SERVICE_UNAVAILABLE;
    }
    boolean isPublic = isPublicVal == null || isPublicVal.toBoolean();

    if (isSecurityHeaderSupported()) {
      res.setHeader("X-Gsa-Serve-Security", isPublic ? "public" : "secure");
      return HttpServletResponse.SC_OK;
    } else {
      if (isPublic) {
        return HttpServletResponse.SC_OK;
      } else {
        res.setHeader("WWW-Authenticate", "Basic realm=\"Retriever\"");
        return HttpServletResponse.SC_UNAUTHORIZED;
      }
    }
  }
 private int countDocuments(DocumentList documentList) throws RepositoryException {
   int counter = 0;
   if (documentList != null) {
     Document document = null;
     while ((document = documentList.nextDocument()) != null) {
       logger.info(Value.getSingleValueString(document, SpiConstants.PROPNAME_DOCID));
       counter++;
     }
   }
   return counter;
 }
  /**
   * Test generating checkpoints.
   *
   * @throws RepositoryException
   * @throws JSONException
   */
  public void testCheckpoint() throws RepositoryException, JSONException {
    // We're comparing date strings here, so we need a fixed time zone.
    Value.setFeedTimeZone("GMT");

    MockRepositoryEventList mrel = new MockRepositoryEventList("MockRepositoryEventLog1.txt");
    MockRepository r = new MockRepository(mrel);
    MockRepositoryDocument mockDoc = r.getStore().getDocByID("doc1");
    Document doc = new JcrDocument(new MockJcrNode(mockDoc));
    String checkpointString = JcrDocumentList.checkpoint(doc);
    logger.info(checkpointString);

    JSONObject jo = new JSONObject(checkpointString);

    String lastModified = jo.getString("lastModified");
    Assert.assertEquals("1970-01-01T00:00:10.000Z", lastModified);
    String uuid = jo.getString("uuid");
    Assert.assertEquals("doc1", uuid);
  }
 /**
  * Retrieves the content length of a document from a connector instance.
  *
  * @param metadata the Document metadata
  * @return the content-length of the document, as an Integer, or {@code null} if the content
  *     length is not known, less than or equal to zero, or the value does not fit in an Integer.
  *     Note that if the content-length returned by the connector is zero, this returns null, since
  *     the GSA does not support empty documents, so the empty content will be replaced by
  *     ProductionManager with alternate non-empty content.
  */
 @VisibleForTesting
 static Integer handleGetContentLength(Document metadata) {
   if (metadata != null) {
     try {
       String lengthStr =
           Value.getSingleValueString(metadata, SpiConstants.PROPNAME_CONTENT_LENGTH);
       if (!Strings.isNullOrEmpty(lengthStr)) {
         Integer length = Integer.valueOf(lengthStr);
         return (length > 0) ? length : null;
       }
     } catch (NumberFormatException e) {
       LOGGER.log(Level.WARNING, "Failed to retrieve content-length", e);
     } catch (RepositoryException e) {
       LOGGER.log(Level.WARNING, "Failed to retrieve content-length", e);
     }
   }
   return null;
 }
 /**
  * Retrieves the content type of a document from a connector instance.
  *
  * @param metadata the Document metadata
  * @return the content-type of the document, as a string, or {@link SpiConstants.DEFAULT_MIMETYPE}
  *     if the content type is not supplied.
  */
 @VisibleForTesting
 static String handleGetContentType(Document metadata) {
   // NOTE: To maintain consistency with the XmlFeed, this code returns
   // SpiConstants.DEFAULT_MIMETYPE ("text/html") if the Document supplies
   // no mime type property. However, the GSA would really rather receive
   // MimeTypeDetector.UKNOWN_MIMETYPE ("application/octet-stream").
   if (metadata != null) {
     try {
       String mimeType = Value.getSingleValueString(metadata, SpiConstants.PROPNAME_MIMETYPE);
       if (!Strings.isNullOrEmpty(mimeType)) {
         return mimeType;
       }
     } catch (RepositoryException e) {
       LOGGER.log(Level.WARNING, "Failed to retrieve content-type", e);
     }
   }
   return SpiConstants.DEFAULT_MIMETYPE;
 }
 @Override
 public void tearDown() {
   // Reset the default time zone.
   Value.setFeedTimeZone("");
 }