@Test
  public void testReadAclAfterSetACP() {
    DocumentModel folder = new DocumentModelImpl("/", "folder", "Folder");
    folder = session.createDocument(folder);
    DocumentModel doc = new DocumentModelImpl("/folder", "doc", "File");
    doc = session.createDocument(doc);
    session.save();

    // nothing can be seen by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(0, list.size());
      list = joeSession.query("SELECT * FROM File");
      assertEquals(0, list.size());
    }

    // set ACL on folder
    ACL acl = new ACLImpl();
    acl.add(new ACE("Everyone", "Read", true));
    ACP acp = new ACPImpl();
    acp.addACL(acl);
    folder.setACP(acp, true);
    session.save();

    // now joe sees things
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
      assertEquals(folder.getId(), list.get(0).getId());
      list = joeSession.query("SELECT * FROM File");
      assertEquals(1, list.size());
      assertEquals(doc.getId(), list.get(0).getId());
    }
  }
  @Test
  public void testReadAclAfterCopy() {
    DocumentModel folder1 = new DocumentModelImpl("/", "folder1", "Folder");
    folder1 = session.createDocument(folder1);
    DocumentModel folder2 = new DocumentModelImpl("/", "folder2", "Folder");
    folder2 = session.createDocument(folder2);
    DocumentModel doc = new DocumentModelImpl("/folder1", "doc", "File");
    doc = session.createDocument(doc);

    // set ACL on folder2
    ACL acl = new ACLImpl();
    acl.add(new ACE("Everyone", "Read", true));
    ACP acp = new ACPImpl();
    acp.addACL(acl);
    folder2.setACP(acp, true);
    session.save();

    // doc under folder1 cannot be read by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM File");
      assertEquals(0, list.size());
    }

    // copy doc under folder2
    session.copy(doc.getRef(), folder2.getRef(), "doccopy");
    session.save();

    // check doc copy now readable by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM File");
      assertEquals(1, list.size());
      assertEquals("doccopy", list.get(0).getName());
    }
  }
  @Test
  public void testReadAclSecurityUpdate() {
    // check that aclOptimization update the user aclr cache
    // NXP-13109
    DocumentModel root = session.getRootDocument();
    // Create a doc and set a new ACLR on it
    DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "foo", "Folder");
    doc = session.createDocument(doc);
    ACP acp = doc.getACP();
    assertNotNull(acp);
    acp = new ACPImpl();
    ACL acl = new ACLImpl();
    acl.add(new ACE("Everyone", "Read", true));
    acp.addACL(acl);
    doc.setACP(acp, true);
    session.save();

    CoreSession joeSession = openSessionAs("joe");
    try {
      DocumentModelList list;
      list = joeSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
      // Remove the document, so the ACLR created is not anymore assigned
      session.removeDocument(doc.getRef());
      session.save();
      list = joeSession.query("SELECT * FROM Folder");
      assertEquals(0, list.size());
    } finally {
      closeSession(joeSession);
    }

    CoreSession bobSession = openSessionAs("bob");
    try {
      DocumentModelList list;
      // Perform a query to init the ACLR cache
      list = bobSession.query("SELECT * FROM Folder");
      assertEquals(0, list.size());
      // Create a new doc with the same ACLR
      doc = new DocumentModelImpl(root.getPathAsString(), "bar", "Folder");
      doc = session.createDocument(doc);
      doc.setACP(acp, true);
      session.save();
      // Check that the ACLR has been added to the user cache
      list = bobSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
    } finally {
      closeSession(bobSession);
    }
  }
  @Test
  public void testReadAclAfterCreate() {
    DocumentModel folder = new DocumentModelImpl("/", "folder", "Folder");
    folder = session.createDocument(folder);
    session.save();

    // folder can be seen by a member
    UserPrincipal joeMember =
        new UserPrincipal("joe", Arrays.asList("Everyone", "members"), false, false);
    try (CoreSession joeSession = openSessionAs(joeMember)) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
      assertEquals(folder.getId(), list.get(0).getId());
    }

    // but not as a non-member
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(0, list.size());
    }

    // set ACL on folder
    ACL acl = new ACLImpl();
    acl.add(new ACE("Everyone", "Read", true));
    ACP acp = new ACPImpl();
    acp.addACL(acl);
    folder.setACP(acp, true);
    session.save();

    // the folder can be seen by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
      assertEquals(folder.getId(), list.get(0).getId());
    }

    // create a doc under the folder
    DocumentModel doc = new DocumentModelImpl("/folder", "doc", "File");
    doc = session.createDocument(doc);
    session.save();

    // the doc can be seen by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM File");
      assertEquals(1, list.size());
      assertEquals(doc.getId(), list.get(0).getId());
    }
  }
 public static final List<LabsSite> getTemplateSites() throws ClientException {
   SiteManager sm;
   List<LabsSite> adaptersList = new ArrayList<LabsSite>();
   try {
     sm = Framework.getService(SiteManager.class);
   } catch (Exception e) {
     return adaptersList;
   }
   StringBuilder query = new StringBuilder();
   CoreSession session = getCoreSession();
   query
       .append("SELECT * FROM ")
       .append(Docs.SITE.type())
       .append(" WHERE ")
       .append(NXQL.ECM_LIFECYCLESTATE)
       .append(" = '")
       .append(State.PUBLISH.getState())
       .append("'")
       .append(" AND ")
       .append(NXQL.ECM_PATH)
       .append(" STARTSWITH '")
       .append(sm.getSiteRoot(session).getPathAsString().replace("'", "\\'"))
       .append("'")
       .append(" AND ")
       .append(NXQL.ECM_MIXINTYPE)
       .append("='")
       .append(LabsSiteConstants.FacetNames.LABS_ELEMENT_TEMPLATE)
       .append("'");
   DocumentModelList list = session.query(query.toString());
   for (DocumentModel site : list) {
     adaptersList.add(Tools.getAdapter(LabsSite.class, site, session));
   }
   return adaptersList;
 }
 public static void updatePageTemplate(CoreSession session) {
   try {
     DocumentModelList docs = session.query("SELECT * FROM Page");
     LabsTemplate template = null;
     String templateName = null;
     for (DocumentModel doc : docs) {
       template = Tools.getAdapter(LabsTemplate.class, doc, session);
       templateName = template.getDocumentTemplateName();
       if (!StringUtils.isEmpty(templateName)) {
         if (templateName.equals("homeSimple")) {
           template.setTemplateName("left");
         } else if (templateName.equals("homeLeftComplex")) {
           template.setTemplateName("left");
         } else if (templateName.equals("homeRightComplex")) {
           template.setTemplateName("right");
         } else if (templateName.equals("homeRightSimple")) {
           template.setTemplateName("right");
         }
         session.saveDocument(doc);
       }
     }
     session.save();
   } catch (ClientException e) {
     LOG.error("updatePageTemplate : ", e);
   }
 }
 /**
  * update isTop to default value : false
  *
  * @param session
  */
 public static void updateIsTopOnLabsnews(CoreSession session) {
   try {
     DocumentModelList children = session.query("SELECT * FROM LabsNews");
     for (DocumentModel labsnews : children) {
       labsnews.getAdapter(LabsNews.class).setTop(false);
       session.saveDocument(labsnews);
     }
     session.save();
   } catch (ClientException e) {
     LOG.error("updateIsTopOnLabsnews : ", e);
   }
 }
  /**
   * Returns the CSIDs of CollectionObject records that are related to a Movement record.
   *
   * @param movementCsid the CSID of a Movement record.
   * @param coreSession a repository session.
   * @throws ClientException
   * @return the CSIDs of the CollectionObject records, if any, which are related to the Movement
   *     record.
   */
  private Set<String> getCollectionObjectCsidsRelatedToMovement(
      String movementCsid, CoreSession coreSession) throws ClientException {

    Set<String> csids = new HashSet<>();

    // Via an NXQL query, get a list of active relation records where:
    // * This movement record's CSID is the subject CSID of the relation,
    //   and its object document type is a CollectionObject doctype;
    // or
    // * This movement record's CSID is the object CSID of the relation,
    //   and its subject document type is a CollectionObject doctype.
    //
    // Some values below are hard-coded for readability, rather than
    // being obtained from constants.
    String query =
        String.format(
            "SELECT * FROM %1$s WHERE " // collectionspace_core:tenantId = 1 "
                + "("
                + "  (%2$s:subjectCsid = '%3$s' "
                + "  AND %2$s:objectDocumentType = '%4$s') "
                + " OR "
                + "  (%2$s:objectCsid = '%3$s' "
                + "  AND %2$s:subjectDocumentType = '%4$s') "
                + ")"
                + ACTIVE_DOCUMENT_WHERE_CLAUSE_FRAGMENT,
            RELATION_DOCTYPE,
            RELATIONS_COMMON_SCHEMA,
            movementCsid,
            COLLECTIONOBJECT_DOCTYPE);
    DocumentModelList relationDocModels = coreSession.query(query);
    if (relationDocModels == null || relationDocModels.isEmpty()) {
      // Encountering a Movement record that is not related to any
      // CollectionObject is potentially a normal occurrence, so no
      // error messages are logged here when we stop handling this event.
      return csids;
    }
    // Iterate through the list of Relation records found and build
    // a list of CollectionObject CSIDs, by extracting the relevant CSIDs
    // from those Relation records.
    String csid;
    for (DocumentModel relationDocModel : relationDocModels) {
      csid =
          getCsidForDesiredDocTypeFromRelation(
              relationDocModel, COLLECTIONOBJECT_DOCTYPE, MOVEMENT_DOCTYPE);
      if (Tools.notBlank(csid)) {
        csids.add(csid);
      }
    }
    return csids;
  }
 /**
  * update the setter of comments'size on th line of pageList
  *
  * @param session
  */
 public static void updateAllCommentsOnLinesOfPageList(CoreSession session) {
   try {
     DocumentModelList children = session.query("SELECT * FROM PageListLine");
     for (DocumentModel lineDoc : children) {
       lineDoc
           .getAdapter(PageListLine.class)
           .setNbComments(
               Tools.getAdapter(CommentableDocument.class, lineDoc, null).getComments().size());
       session.saveDocument(lineDoc);
     }
     session.save();
   } catch (ClientException e) {
     LOG.error("updateNbCommentsListLine : ", e);
   }
 }
 /**
  * update updateEmptySidebar
  *
  * @param session
  */
 public static void updateEmptySidebar(CoreSession session) {
   try {
     DocumentModelList children = session.query("SELECT * FROM " + Docs.SITE.type());
     for (DocumentModel docLabsSite : children) {
       LabsSite labsSite = Tools.getAdapter(LabsSite.class, docLabsSite, session);
       HtmlPage sidebar = labsSite.getSidebar();
       if (sidebar.getSections().size() < 2) {
         session.removeDocument(sidebar.getDocument().getRef());
         session.save();
         LabsSiteUtils.createDefaultSidebarPage(labsSite.getDocument(), session);
         session.save();
       }
     }
   } catch (ClientException e) {
     LOG.error("updateEmptySidebar : ", e);
   }
 }
  public String searchDocuments() throws ClientException {
    if (log.isDebugEnabled())
      log.debug("Making call to get documents list for keywords: " + searchKeywords);

    // reset existing search results
    resultDocuments = null;
    List<String> constraints = new ArrayList<String>();
    if (searchKeywords != null) {
      searchKeywords = searchKeywords.trim();
      if (searchKeywords.length() > 0) {
        if (!searchKeywords.equals("*")) {
          // full text search
          constraints.add(String.format("ecm:fulltext LIKE '%s'", searchKeywords));
        }
      }
    }
    // no folderish doc nor hidden doc
    constraints.add("ecm:mixinType != 'Folderish'");
    constraints.add("ecm:mixinType != 'HiddenInNavigation'");
    // no archived revisions
    constraints.add("ecm:isCheckedInVersion = 0");
    // filter current document
    DocumentModel currentDocument = getCurrentDocument();
    if (currentDocument != null) {
      constraints.add(String.format("ecm:uuid != '%s'", currentDocument.getId()));
    }
    // search keywords
    String query =
        String.format(
            "SELECT * FROM Document WHERE %s", StringUtils.join(constraints.toArray(), " AND "));

    if (log.isDebugEnabled()) log.debug("query: " + query);

    resultDocuments = documentManager.query(query, 100);
    hasSearchResults = !resultDocuments.isEmpty();

    if (log.isDebugEnabled())
      log.debug("query result contains: " + resultDocuments.size() + " docs.");

    return "create_relation_search_document";
  }
 /** Looks if an existing Document has the same value for a given property. */
 public static DocumentModel getExistingDocByPropertyName(
     CoreSession documentManager, String path, String value, String propertyName)
     throws ClientException {
   DocumentModel existing = null;
   String parentId = documentManager.getDocument(new PathRef(path)).getId();
   String query =
       "SELECT * FROM Document WHERE ecm:parentId = '"
           + parentId
           + "' AND "
           + propertyName
           + " = '"
           + value.replace("'", "\\\'")
           + "' AND ecm:currentLifeCycleState != '"
           + LifeCycleConstants.DELETED_STATE
           + "'";
   DocumentModelList docs = documentManager.query(query, 1);
   if (docs.size() > 0) {
     existing = docs.get(0);
   }
   return existing;
 }
 /** @param session */
 public static void updateSiteTemplateAndSidebar(CoreSession session) {
   try {
     DocumentModelList children = session.query("SELECT * FROM " + Docs.SITE.type());
     for (DocumentModel docLabsSite : children) {
       LabsSite labsSite = Tools.getAdapter(LabsSite.class, docLabsSite, session);
       String templateName = labsSite.getTemplate().getTemplateName();
       if (templateName.equals("homeSimple")) {
         labsSite.setTopPageNavigation(false);
         labsSite.getTemplate().setTemplateName("left");
         LabsSiteUtils.createSimpleSidebarPage(labsSite.getDocument(), session);
       } else if (templateName.equals("homeLeftComplex")) {
         labsSite.setTopPageNavigation(true);
         labsSite.getTemplate().setTemplateName("left");
         LabsSiteUtils.createComplexSidebarPage(labsSite.getDocument(), session);
       } else if (templateName.equals("centerFullScreen")) {
         labsSite.setTopPageNavigation(true);
         LabsSiteUtils.createDefaultSidebarPage(labsSite.getDocument(), session);
       } else if (templateName.equals("homeRightComplex")) {
         labsSite.getTemplate().setTemplateName("right");
         labsSite.setTopPageNavigation(true);
         LabsSiteUtils.createComplexSidebarPage(labsSite.getDocument(), session);
       } else if (templateName.equals("homeRightSimple")) {
         labsSite.getTemplate().setTemplateName("right");
         labsSite.setTopPageNavigation(false);
         LabsSiteUtils.createSimpleSidebarPage(labsSite.getDocument(), session);
       } else if (templateName.equals("domi")) {
         labsSite.setTopPageNavigation(true);
         LabsSiteUtils.createDefaultSidebarPage(labsSite.getDocument(), session);
       } else if (templateName.equals("supplyChain")) {
         labsSite.setTopPageNavigation(true);
         LabsSiteUtils.createDefaultSidebarPage(labsSite.getDocument(), session);
       }
       session.saveDocument(docLabsSite);
     }
     session.save();
   } catch (ClientException e) {
     LOG.error("updateSiteTemplateAndSidebar : ", e);
   }
 }
 /**
  * Returns a document model for a record identified by a CSID.
  *
  * @param session a repository session.
  * @param collectionObjectCsid a CollectionObject identifier (CSID)
  * @return a document model for the record identified by the supplied CSID.
  */
 protected static DocumentModel getDocModelFromCsid(
     CoreSession session, String collectionObjectCsid) {
   DocumentModelList collectionObjectDocModels = null;
   try {
     final String query =
         "SELECT * FROM "
             + NuxeoUtils.BASE_DOCUMENT_TYPE
             + " WHERE "
             + NuxeoUtils.getByNameWhereClause(collectionObjectCsid);
     collectionObjectDocModels = session.query(query);
   } catch (Exception e) {
     logger.warn("Exception in query to get document model for CollectionObject: ", e);
   }
   if (collectionObjectDocModels == null || collectionObjectDocModels.isEmpty()) {
     logger.warn("Could not get document models for CollectionObject(s).");
     return null;
   } else if (collectionObjectDocModels.size() != 1) {
     logger.debug("Found more than 1 document with CSID=" + collectionObjectCsid);
     return null;
   }
   return collectionObjectDocModels.get(0);
 }
  @Test
  public void testReadAclSecurity() {
    // Check that all permissions that contain Browse enable to list a
    // document using aclOptimization
    SecurityService securityService = NXCore.getSecurityService();
    String[] browsePermissions = securityService.getPermissionsToCheck(BROWSE);
    // Check for test permission contribution
    assertTrue(Arrays.asList(browsePermissions).contains("ViewTest"));
    List<String> docNames = new ArrayList<String>(browsePermissions.length);
    DocumentModel root = session.getRootDocument();
    for (String permission : browsePermissions) {
      // Create a folder with only the browse permission
      String name = "joe-has-" + permission + "-permission";
      docNames.add(name);
      DocumentModel folder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
      folder = session.createDocument(folder);
      ACP acp = folder.getACP();
      assertNotNull(acp); // the acp inherited from root is returned
      acp = new ACPImpl();
      ACL acl = new ACLImpl();
      acl.add(new ACE("joe", permission, true));
      acp.addACL(acl);
      folder.setACP(acp, true);
    }
    session.save();
    CoreSession joeSession = openSessionAs("joe");
    try {
      DocumentModelList list;
      list = joeSession.query("SELECT * FROM Folder");
      List<String> names = new ArrayList<String>();
      for (DocumentModel doc : list) {
        names.add(doc.getName());
      }
      assertEquals(
          "Expecting " + docNames + " got " + names, browsePermissions.length, list.size());

      list = joeSession.query("SELECT * FROM Folder WHERE ecm:isProxy = 0");
      names.clear();
      for (DocumentModel doc : list) {
        names.add(doc.getName());
      }
      assertEquals(
          "Expecting " + docNames + " got " + names, browsePermissions.length, list.size());

      // Add a new folder to update the read acls
      DocumentModel folder = new DocumentModelImpl(root.getPathAsString(), "new-folder", "Folder");
      folder = session.createDocument(folder);
      ACP acp = folder.getACP();
      assertNotNull(acp); // the acp inherited from root is returned
      acp = new ACPImpl();
      ACL acl = new ACLImpl();
      acl.add(new ACE("joe", browsePermissions[0], true));
      acl.add(new ACE("bob", browsePermissions[0], true));
      acp.addACL(acl);
      folder.setACP(acp, true);
      session.save();

      list = joeSession.query("SELECT * FROM Folder");
      assertEquals(browsePermissions.length + 1, list.size());

    } finally {
      closeSession(joeSession);
    }
  }
  @Test
  public void testWriteOperations() throws Exception {

    // ------------------------------------------------------
    // Check #createFolder
    // ------------------------------------------------------
    // Not allowed to create a folder in a non FolderItem
    try {
      fileSystemItemManagerService.createFolder(
          DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId(), "A new folder", principal);
      fail("Folder creation in a non folder item should fail.");
    } catch (NuxeoException e) {
      assertEquals(
          String.format(
              "Cannot create a folder in file system item with id %s because it is not a folder but is: "
                  + "DocumentBackedFileItem(id=\"%s\", name=\"Joe.odt\")",
              DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId(),
              DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId()),
          e.getMessage());
    }

    // Folder creation
    FolderItem newFolderItem =
        fileSystemItemManagerService.createFolder(
            DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId(), "A new folder", principal);
    assertNotNull(newFolderItem);
    assertEquals(DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId(), newFolderItem.getParentId());
    assertEquals("A new folder", newFolderItem.getName());
    DocumentModelList folderChildren =
        session.query(
            String.format(
                "select * from Document where ecm:parentId = '%s' and ecm:primaryType = 'Folder' order by dc:title asc",
                folder.getId()));
    DocumentModel newFolder = folderChildren.get(0);
    assertTrue(newFolder.isFolder());
    assertEquals("A new folder", newFolder.getTitle());

    // Parent folder children check
    assertEquals(
        6,
        fileSystemItemManagerService
            .getChildren(DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId(), principal)
            .size());

    // ------------------------------------------------------
    // Check #createFile
    // ------------------------------------------------------
    // File creation
    Blob blob = new StringBlob("Content of a new file.");
    blob.setFilename("New file.odt");
    blob.setMimeType("application/vnd.oasis.opendocument.text");
    FileItem fileItem =
        fileSystemItemManagerService.createFile(newFolderItem.getId(), blob, principal);
    assertNotNull(fileItem);
    assertEquals(newFolderItem.getId(), fileItem.getParentId());
    assertEquals("New file.odt", fileItem.getName());
    folderChildren =
        session.query(
            String.format("select * from Document where ecm:parentId = '%s'", newFolder.getId()));
    assertEquals(1, folderChildren.size());
    DocumentModel newFile = folderChildren.get(0);
    assertEquals("File", newFile.getType());
    assertEquals("New file.odt", newFile.getTitle());
    assertEquals("/syncRoot1/aFolder/A new folder/New file.odt", newFile.getPathAsString());
    Blob newFileBlob = (Blob) newFile.getPropertyValue("file:content");
    assertEquals("New file.odt", newFileBlob.getFilename());
    assertEquals("Content of a new file.", newFileBlob.getString());
    assertEquals(
        "nxfile/test/" + newFile.getId() + "/blobholder:0/New%20file.odt",
        fileItem.getDownloadURL());
    assertEquals("MD5", fileItem.getDigestAlgorithm());
    assertEquals(newFileBlob.getDigest(), fileItem.getDigest());

    // Parent folder children check
    assertEquals(
        1, fileSystemItemManagerService.getChildren(newFolderItem.getId(), principal).size());

    // ------------------------------------------------------
    // Check #updateFile
    // ------------------------------------------------------
    String fileItemId = fileItem.getId();
    String fileItemParentId = fileItem.getParentId();
    blob = new StringBlob("Modified content of an existing file.");
    fileItem = fileSystemItemManagerService.updateFile(fileItemId, blob, principal);
    assertNotNull(fileItem);
    assertEquals(fileItemId, fileItem.getId());
    assertEquals(fileItemParentId, fileItem.getParentId());
    assertEquals("New file.odt", fileItem.getName());
    folderChildren =
        session.query(
            String.format("select * from Document where ecm:parentId = '%s'", newFolder.getId()));
    assertEquals(1, folderChildren.size());
    DocumentModel updatedFile = folderChildren.get(0);
    assertEquals("File", updatedFile.getType());
    assertEquals("New file.odt", updatedFile.getTitle());
    assertEquals("/syncRoot1/aFolder/A new folder/New file.odt", updatedFile.getPathAsString());
    Blob updatedFileBlob = (Blob) updatedFile.getPropertyValue("file:content");
    assertEquals("New file.odt", updatedFileBlob.getFilename());
    assertEquals("Modified content of an existing file.", updatedFileBlob.getString());
    assertEquals(
        "nxfile/test/" + updatedFile.getId() + "/blobholder:0/New%20file.odt",
        fileItem.getDownloadURL());
    assertEquals("MD5", fileItem.getDigestAlgorithm());
    assertEquals(updatedFileBlob.getDigest(), fileItem.getDigest());

    // ------------------------------------------------------
    // Check #delete
    // ------------------------------------------------------
    // File deletion
    fileSystemItemManagerService.delete(
        DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + updatedFile.getId(), principal);
    updatedFile = session.getDocument(new IdRef(updatedFile.getId()));
    assertEquals("deleted", updatedFile.getCurrentLifeCycleState());

    // Parent folder children check
    assertTrue(
        fileSystemItemManagerService.getChildren(newFolderItem.getId(), principal).isEmpty());

    // ------------------------------------------------------
    // Check #rename
    // ------------------------------------------------------
    // Folder rename
    String fsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId();
    FileSystemItem fsItem =
        fileSystemItemManagerService.rename(fsItemId, "Jack's folder has a new name", principal);
    assertEquals(fsItemId, fsItem.getId());
    String expectedSyncRoot1Id = DEFAULT_SYNC_ROOT_ITEM_ID_PREFIX + syncRoot1.getId();
    assertEquals(expectedSyncRoot1Id, fsItem.getParentId());
    assertEquals("Jack's folder has a new name", fsItem.getName());
    folder = session.getDocument(folder.getRef());
    assertEquals("Jack's folder has a new name", folder.getTitle());

    // File rename with title != filename
    // => should rename filename but not title
    assertEquals("aFile", file.getTitle());
    assertEquals("Joe.odt", ((Blob) file.getPropertyValue("file:content")).getFilename());
    fsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId();
    fsItem = fileSystemItemManagerService.rename(fsItemId, "File new name.odt", principal);
    assertEquals(fsItemId, fsItem.getId());
    assertEquals(DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId(), fsItem.getParentId());
    assertEquals("File new name.odt", fsItem.getName());
    file = session.getDocument(file.getRef());
    assertEquals("aFile", file.getTitle());
    Blob fileBlob = (Blob) file.getPropertyValue("file:content");
    assertEquals("File new name.odt", fileBlob.getFilename());
    fileItem = (FileItem) fsItem;
    assertEquals(
        "nxfile/test/" + file.getId() + "/blobholder:0/File%20new%20name.odt",
        fileItem.getDownloadURL());
    assertEquals("MD5", fileItem.getDigestAlgorithm());
    assertEquals(fileBlob.getDigest(), fileItem.getDigest());

    // File rename with title == filename
    // => should rename filename and title
    blob = new StringBlob("File for a doc with title == filename.");
    blob.setFilename("Title-filename equality.odt");
    blob.setMimeType("application/vnd.oasis.opendocument.text");
    fileItem = fileSystemItemManagerService.createFile(newFolderItem.getId(), blob, principal);
    // Note that the PathSegmentService truncates doc title at 24 characters
    newFile =
        session.getDocument(
            new PathRef("/syncRoot1/aFolder/A new folder/Title-filename equality."));
    assertEquals("Title-filename equality.odt", newFile.getTitle());
    assertEquals(
        "Title-filename equality.odt",
        ((Blob) newFile.getPropertyValue("file:content")).getFilename());
    fileItem =
        (FileItem)
            fileSystemItemManagerService.rename(
                DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + newFile.getId(),
                "Renamed title-filename equality.odt",
                principal);
    assertEquals("Renamed title-filename equality.odt", fileItem.getName());
    newFile = session.getDocument(newFile.getRef());
    assertEquals("Renamed title-filename equality.odt", newFile.getTitle());
    newFileBlob = (Blob) newFile.getPropertyValue("file:content");
    assertEquals("Renamed title-filename equality.odt", newFileBlob.getFilename());
    assertEquals(
        "nxfile/test/" + newFile.getId() + "/blobholder:0/Renamed%20title-filename%20equality.odt",
        fileItem.getDownloadURL());
    assertEquals("MD5", fileItem.getDigestAlgorithm());
    assertEquals(newFileBlob.getDigest(), fileItem.getDigest());

    // ------------------------------------------------------
    // Check #move
    // ------------------------------------------------------
    // Not allowed to move a file system item to a non FolderItem
    String srcFsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + note.getId();
    String destFsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId();
    try {
      fileSystemItemManagerService.move(srcFsItemId, destFsItemId, principal);
      fail("Move to a non folder item should fail.");
    } catch (NuxeoException e) {
      assertEquals(
          String.format(
              "Cannot move a file system item to file system item with id %s because it is not a folder.",
              DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId()),
          e.getMessage());
    }

    // Move to a FolderItem
    destFsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + subFolder.getId();
    FileSystemItem movedFsItem =
        fileSystemItemManagerService.move(srcFsItemId, destFsItemId, principal);
    assertEquals(srcFsItemId, movedFsItem.getId());
    assertEquals(destFsItemId, movedFsItem.getParentId());
    assertEquals("aNote.txt", movedFsItem.getName());
    note = session.getDocument(note.getRef());
    assertEquals("/syncRoot1/aFolder/aSubFolder/aNote", note.getPathAsString());
    assertEquals("aNote", note.getTitle());
  }
  /**
   * Returns the most recent Movement record related to a CollectionObject.
   *
   * <p>This method currently returns the related Movement record with the latest (i.e. most recent
   * in time) Location Date field value.
   *
   * @param session a repository session.
   * @param collectionObjectCsid a CollectionObject identifier (CSID)
   * @throws ClientException
   * @return the most recent Movement record related to the CollectionObject identified by the
   *     supplied CSID.
   */
  protected static DocumentModel getMostRecentMovement(
      CoreSession session, String collectionObjectCsid) throws ClientException {
    DocumentModel mostRecentMovementDocModel = null;
    // Get Relation records for Movements related to this CollectionObject.
    //
    // Some values below are hard-coded for readability, rather than
    // being obtained from constants.
    String query =
        String.format(
            "SELECT * FROM %1$s WHERE " // collectionspace_core:tenantId = 1 "
                + "("
                + "  (%2$s:subjectCsid = '%3$s' "
                + "  AND %2$s:objectDocumentType = '%4$s') "
                + " OR "
                + "  (%2$s:objectCsid = '%3$s' "
                + "  AND %2$s:subjectDocumentType = '%4$s') "
                + ")"
                + ACTIVE_DOCUMENT_WHERE_CLAUSE_FRAGMENT,
            RELATION_DOCTYPE,
            RELATIONS_COMMON_SCHEMA,
            collectionObjectCsid,
            MOVEMENT_DOCTYPE);
    if (logger.isTraceEnabled()) {
      logger.trace("query=" + query);
    }
    DocumentModelList relationDocModels = session.query(query);
    if (relationDocModels == null || relationDocModels.isEmpty()) {
      logger.warn(
          "Unexpectedly found no relations to Movement records to/from to this CollectionObject record.");
      return mostRecentMovementDocModel;
    } else {
      if (logger.isTraceEnabled()) {
        logger.trace(
            "Found "
                + relationDocModels.size()
                + " relations to Movement records to/from this CollectionObject record.");
      }
    }
    // Iterate through related movement records, to find the related
    // Movement record with the most recent location date.
    GregorianCalendar mostRecentLocationDate = EARLIEST_COMPARISON_DATE;
    // Note: the following value is used to compare any two records, rather
    // than to identify the most recent value so far encountered. Thus, it may
    // occasionally be set backward or forward in time, within the loop below.
    GregorianCalendar comparisonCreationDate = EARLIEST_COMPARISON_DATE;
    DocumentModel movementDocModel;
    Set<String> alreadyProcessedMovementCsids = new HashSet<>();
    String relatedMovementCsid;
    for (DocumentModel relationDocModel : relationDocModels) {
      // Due to the 'OR' operator in the query above, related Movement
      // record CSIDs may reside in either the subject or object CSID fields
      // of the relation record. Whichever CSID value doesn't match the
      // CollectionObject's CSID is inferred to be the related Movement record's CSID.
      relatedMovementCsid =
          (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, SUBJECT_CSID_PROPERTY);
      if (relatedMovementCsid.equals(collectionObjectCsid)) {
        relatedMovementCsid =
            (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, OBJECT_CSID_PROPERTY);
      }
      if (Tools.isBlank(relatedMovementCsid)) {
        continue;
      }
      // Because of the OR clause used in the query above, there may be
      // two or more Relation records returned in the query results that
      // reference the same Movement record, as either the subject
      // or object of a relation to the same CollectionObject record;
      // we need to filter out those duplicates.
      if (alreadyProcessedMovementCsids.contains(relatedMovementCsid)) {
        continue;
      } else {
        alreadyProcessedMovementCsids.add(relatedMovementCsid);
      }
      if (logger.isTraceEnabled()) {
        logger.trace("Related movement CSID=" + relatedMovementCsid);
      }
      movementDocModel = getDocModelFromCsid(session, relatedMovementCsid);
      if (movementDocModel == null) {
        continue;
      }

      // Verify that the Movement record is active. This will also exclude
      // versioned Movement records from the computation of the current
      // location, for tenants that are versioning such records.
      if (!isActiveDocument(movementDocModel)) {
        if (logger.isTraceEnabled()) {
          logger.trace("Skipping this inactive Movement record ...");
        }
        continue;
      }
      GregorianCalendar locationDate =
          (GregorianCalendar)
              movementDocModel.getProperty(MOVEMENTS_COMMON_SCHEMA, LOCATION_DATE_PROPERTY);
      // If the current Movement record lacks a location date, it cannot
      // be established as the most recent Movement record; skip over it.
      if (locationDate == null) {
        continue;
      }
      GregorianCalendar creationDate =
          (GregorianCalendar)
              movementDocModel.getProperty(COLLECTIONSPACE_CORE_SCHEMA, CREATED_AT_PROPERTY);
      if (locationDate.after(mostRecentLocationDate)) {
        mostRecentLocationDate = locationDate;
        if (creationDate != null) {
          comparisonCreationDate = creationDate;
        }
        mostRecentMovementDocModel = movementDocModel;
        // If the current Movement record's location date is identical
        // to that of the (at this time) most recent Movement record, then
        // instead compare the two records using their creation date values
      } else if (locationDate.compareTo(mostRecentLocationDate) == 0) {
        if (creationDate != null && creationDate.after(comparisonCreationDate)) {
          // The most recent location date value doesn't need to be
          // updated here, as the two records' values are identical
          comparisonCreationDate = creationDate;
          mostRecentMovementDocModel = movementDocModel;
        }
      }
    }
    return mostRecentMovementDocModel;
  }
  @Test
  public void documentManagementInTestCasesExample() throws ClientException {
    SchemaManager typeService = Framework.getLocalService(SchemaManager.class);

    DocumentType[] types = typeService.getDocumentTypes();
    for (DocumentType type : types) {
      System.out.println(type.getName());
    }

    DocumentModel mydoc = session.createDocumentModel("File");
    // DocumentModel mydoc = session.createDocumentModel("/", "toto",
    // "File");

    mydoc.setPathInfo("/", "toto");
    mydoc.setPropertyValue("dc:title", "Toto");
    mydoc = session.createDocument(mydoc);
    session.save();

    DocumentModelList docs = session.query("SELECT * FROM Document WHERE dc:title = 'Toto'");
    assertEquals(1, docs.size());
    mydoc = docs.get(0);
    assertEquals("toto", mydoc.getName());
    assertEquals("project", mydoc.getCurrentLifeCycleState());

    for (String state : mydoc.getAllowedStateTransitions()) {
      System.out.println("Transition : " + state);
    }

    // session.followTransition(mydoc.getRef(), "approve");
    mydoc.followTransition("approve");

    mydoc.setPropertyValue("dc:description", "My Description");
    mydoc = session.saveDocument(mydoc);
    session.save();

    assertEquals("approved", mydoc.getCurrentLifeCycleState());
    assertEquals("0.0", mydoc.getVersionLabel());
    assertEquals(0, session.getVersions(mydoc.getRef()).size());

    session.checkIn(mydoc.getRef(), VersioningOption.MINOR, "");
    mydoc = session.getDocument(mydoc.getRef());
    assertEquals("0.1", mydoc.getVersionLabel());
    assertEquals(1, session.getVersions(mydoc.getRef()).size());

    DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
    folder.setPropertyValue("dc:title", "Folder");
    folder = session.createDocument(folder);
    session.save();

    assertEquals(0, session.getChildren(folder.getRef()).size());
    session.publishDocument(mydoc, folder);
    assertEquals(1, session.getChildren(folder.getRef()).size());

    DocumentModel folder2 = session.createDocumentModel("/", "folder2", "Folder");
    folder2.setPropertyValue("dc:title", "Folder2");
    folder2 = session.createDocument(folder2);
    session.save();

    DocumentModel proxy = session.createProxy(mydoc.getRef(), folder2.getRef());

    assertEquals("Toto", proxy.getPropertyValue("dc:title"));
    mydoc.setPropertyValue("dc:title", "Tutu");
    session.saveDocument(mydoc);
    session.save();

    proxy = session.getDocument(proxy.getRef());
    assertEquals("Tutu", proxy.getPropertyValue("dc:title"));

    proxy.setPropertyValue("dc:title", "Tata");
    session.saveDocument(proxy);
    session.save();

    mydoc = session.getDocument(mydoc.getRef());
    assertEquals("Tata", mydoc.getPropertyValue("dc:title"));
  }