/*
* (C) Copyright 2006-2015 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Florent Guillaume
*/
package org.nuxeo.ecm.core;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import java.io.IOException;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javax.inject.Inject;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.lang3.mutable.MutableObject;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.common.utils.Path;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.Blobs;
import org.nuxeo.ecm.core.api.ConcurrentUpdateException;
import org.nuxeo.ecm.core.api.CoreInstance;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DataModel;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelIterator;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.DocumentNotFoundException;
import org.nuxeo.ecm.core.api.DocumentRef;
import org.nuxeo.ecm.core.api.DocumentSecurityException;
import org.nuxeo.ecm.core.api.Filter;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.core.api.IterableQueryResult;
import org.nuxeo.ecm.core.api.ListDiff;
import org.nuxeo.ecm.core.api.Lock;
import org.nuxeo.ecm.core.api.LockException;
import org.nuxeo.ecm.core.api.NuxeoException;
import org.nuxeo.ecm.core.api.NuxeoPrincipal;
import org.nuxeo.ecm.core.api.PathRef;
import org.nuxeo.ecm.core.api.VersionModel;
import org.nuxeo.ecm.core.api.VersioningOption;
import org.nuxeo.ecm.core.api.event.DocumentEventTypes;
import org.nuxeo.ecm.core.api.impl.DocumentModelImpl;
import org.nuxeo.ecm.core.api.impl.FacetFilter;
import org.nuxeo.ecm.core.api.impl.UserPrincipal;
import org.nuxeo.ecm.core.api.impl.VersionModelImpl;
import org.nuxeo.ecm.core.api.impl.blob.URLBlob;
import org.nuxeo.ecm.core.api.model.DocumentPart;
import org.nuxeo.ecm.core.api.model.Property;
import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
import org.nuxeo.ecm.core.api.security.ACE;
import org.nuxeo.ecm.core.api.security.ACL;
import org.nuxeo.ecm.core.api.security.ACP;
import org.nuxeo.ecm.core.api.security.impl.ACLImpl;
import org.nuxeo.ecm.core.api.security.impl.ACPImpl;
import org.nuxeo.ecm.core.blob.BlobManager;
import org.nuxeo.ecm.core.blob.BlobProvider;
import org.nuxeo.ecm.core.blob.binary.BinaryGarbageCollector;
import org.nuxeo.ecm.core.blob.binary.BinaryManager;
import org.nuxeo.ecm.core.blob.binary.BinaryManagerStatus;
import org.nuxeo.ecm.core.event.Event;
import org.nuxeo.ecm.core.event.EventContext;
import org.nuxeo.ecm.core.event.EventService;
import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
import org.nuxeo.ecm.core.model.Repository;
import org.nuxeo.ecm.core.repository.RepositoryService;
import org.nuxeo.ecm.core.schema.DocumentTypeDescriptor;
import org.nuxeo.ecm.core.schema.FacetNames;
import org.nuxeo.ecm.core.schema.SchemaManager;
import org.nuxeo.ecm.core.schema.SchemaManagerImpl;
import org.nuxeo.ecm.core.schema.types.Schema;
import org.nuxeo.ecm.core.storage.sql.listeners.DummyBeforeModificationListener;
import org.nuxeo.ecm.core.storage.sql.listeners.DummyTestListener;
import org.nuxeo.ecm.core.test.CoreFeature;
import org.nuxeo.ecm.core.test.annotations.Granularity;
import org.nuxeo.ecm.core.test.annotations.RepositoryConfig;
import org.nuxeo.ecm.core.versioning.VersioningService;
import org.nuxeo.runtime.test.runner.ConditionalIgnoreRule;
import org.nuxeo.runtime.test.runner.ConditionalIgnoreRule.IgnoreWindows;
import org.nuxeo.runtime.test.runner.Deploy;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.nuxeo.runtime.test.runner.LocalDeploy;
import org.nuxeo.runtime.transaction.TransactionHelper;
@RunWith(FeaturesRunner.class)
@Features(CoreFeature.class)
@RepositoryConfig(cleanup = Granularity.METHOD)
@Deploy({ "org.nuxeo.ecm.core.convert", //
"org.nuxeo.ecm.core.convert.plugins", //
})
@LocalDeploy({ "org.nuxeo.ecm.core.test.tests:OSGI-INF/test-repo-core-types-contrib.xml",
"org.nuxeo.ecm.core.test.tests:OSGI-INF/disable-schedulers.xml" })
public class TestSQLRepositoryAPI {
@Inject
protected CoreFeature coreFeature;
@Inject
protected EventService eventService;
@Inject
protected CoreSession session;
@Inject
protected SchemaManager schemaManager;
@Inject
protected BlobManager blobManager;
@Inject
protected RepositoryService repositoryService;
@After
public void clearDummyTestListener() {
DummyTestListener.clear();
}
protected CoreSession openSessionAs(String username) {
return CoreInstance.openCoreSession(session.getRepositoryName(), username);
}
protected CoreSession openSessionAs(NuxeoPrincipal principal) {
return CoreInstance.openCoreSession(session.getRepositoryName(), principal);
}
protected void reopenSession() {
session = coreFeature.reopenCoreSession();
}
protected void waitForAsyncCompletion() {
nextTransaction();
eventService.waitForAsyncCompletion();
}
protected void nextTransaction() {
if (TransactionHelper.isTransactionActiveOrMarkedRollback()) {
TransactionHelper.commitOrRollbackTransaction();
TransactionHelper.startTransaction();
}
}
protected boolean isDBS() {
return coreFeature.getStorageConfiguration().isDBS();
}
protected boolean isChangeTokenEnabled() {
return coreFeature.getStorageConfiguration().isChangeTokenEnabled();
}
/**
* Simulate change token init when there is no database-level change token.
*/
protected void maybeCreateChangeToken(DocumentModel doc) {
if (!isChangeTokenEnabled()) {
doc.setPropertyValue("dc:modified", Calendar.getInstance());
}
}
/**
* Simulate change token update when there is no database-level change token.
* <p>
* Done through the dublincore listener in a real instance.
*/
protected void maybeUpdateChangeToken(DocumentModel doc) {
if (!isChangeTokenEnabled()) {
maybeSleepToNextSecond();
doc.setPropertyValue("dc:modified", Calendar.getInstance());
}
}
/**
* Sleep 1s, useful for stupid databases (like MySQL) that don't have subsecond resolution in TIMESTAMP fields.
*/
protected void maybeSleepToNextSecond() {
coreFeature.getStorageConfiguration().maybeSleepToNextSecond();
}
/**
* @since 8.4
*/
@Test
public void testIsVersionWritable() {
DocumentModel doc = new DocumentModelImpl("/", "foo", "File");
doc = session.createDocument(doc);
session.save();
assertTrue(doc.addFacet("Aged"));
assertTrue(doc.hasFacet("Aged"));
doc = session.saveDocument(doc);
DocumentRef refVersion = doc.checkIn(VersioningOption.MAJOR, "blbabla");
DocumentModel version = session.getDocument(refVersion);
version.setPropertyValue("age:age", "123");
session.saveDocument(version);
}
@Test
public void testBasics() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel child = new DocumentModelImpl("/", "domain", "MyDocType");
child = session.createDocument(child);
session.save();
child.setProperty("dublincore", "title", "The title");
// use local tz
Calendar cal = new GregorianCalendar(2008, Calendar.JULY, 14, 12, 34, 56);
child.setProperty("dublincore", "modified", cal);
session.saveDocument(child);
session.save();
// ----- new session -----
reopenSession();
// root = session.getRootDocument();
child = session.getChild(root.getRef(), "domain");
String title = (String) child.getProperty("dublincore", "title");
assertEquals("The title", title);
String description = (String) child.getProperty("dublincore", "description");
assertNull(description);
Calendar modified = (Calendar) child.getProperty("dublincore", "modified");
assertEquals(cal, modified);
}
@Test
public void testLists() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel child = new DocumentModelImpl("/", "domain", "MyDocType");
child = session.createDocument(child);
session.save();
// simple list as array
child.setProperty("dublincore", "subjects", new String[] { "a", "b" });
// simple list as List
child.setProperty("dublincore", "contributors", new ArrayList<>(Arrays.asList("c", "d")));
// simple list as non-serializable array
child.setProperty("testList", "strings", new Object[] { "e", "f" });
// complex list as List
child.setProperty("testList", "participants", new ArrayList<>(Arrays.asList("c", "d")));
session.saveDocument(child);
session.save();
child = session.getDocument(child.getRef());
Object s = child.getProperty("testList", "strings");
assertTrue(s.getClass().isArray());
// Objet[] has been normalized to String[] when re-fetched from mapper cache
assertEquals(String.class, s.getClass().getComponentType());
// ----- new session -----
reopenSession();
root = session.getRootDocument();
child = session.getChild(root.getRef(), "domain");
Object subjects = child.getProperty("dublincore", "subjects");
assertTrue(subjects instanceof String[]);
assertEquals(Arrays.asList("a", "b"), Arrays.asList((String[]) subjects));
Object contributors = child.getProperty("dublincore", "contributors");
assertTrue(contributors instanceof String[]);
assertEquals(Arrays.asList("c", "d"), Arrays.asList((String[]) contributors));
Object strings = child.getProperty("testList", "strings");
assertTrue(strings.getClass().isArray());
// Objet[] has been normalized to String[] when re-read from database
assertEquals(String.class, strings.getClass().getComponentType());
assertEquals(Arrays.asList("e", "f"), Arrays.asList((Serializable[]) strings));
Object participants = child.getProperty("testList", "participants");
assertTrue(participants.getClass().isArray());
// List<> has been normalized to String[] when re-read from database
assertEquals(String.class, participants.getClass().getComponentType());
assertEquals(Arrays.asList("c", "d"), Arrays.asList((Serializable[]) participants));
}
@Test
public void testPathWithExtraSlash() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "doc", "MyDocType");
doc = session.createDocument(doc);
session.save();
DocumentModelList children = session.getChildren(new PathRef("/"));
assertEquals(1, children.size());
children = session.getChildren(new PathRef("/doc"));
assertEquals(0, children.size());
children = session.getChildren(new PathRef("/doc/"));
assertEquals(0, children.size());
}
@Test
public void testComplexType() throws Exception {
// boiler plate to handle the asynchronous full-text indexing of blob
// content in a deterministic way
DocumentModel doc = new DocumentModelImpl("/", "complex-doc", "ComplexDoc");
doc = session.createDocument(doc);
DocumentRef docRef = doc.getRef();
session.save();
waitForAsyncCompletion();
// test setting and reading a map with an empty list
reopenSession();
doc = session.getDocument(docRef);
Map<String, Object> attachedFile = new HashMap<>();
List<Map<String, Object>> vignettes = new ArrayList<>();
attachedFile.put("name", "somename");
attachedFile.put("vignettes", vignettes);
doc.setPropertyValue("cmpf:attachedFile", (Serializable) attachedFile);
session.saveDocument(doc);
session.save();
doc = session.getDocument(docRef);
assertEquals(attachedFile, doc.getProperty("cmpf:attachedFile").getValue());
assertEquals(attachedFile.get("vignettes"), doc.getProperty("cmpf:attachedFile/vignettes").getValue());
// test setting and reading a list of maps without a complex type in the
// maps
Map<String, Object> vignette = new HashMap<>();
vignette.put("width", Long.valueOf(0));
vignette.put("height", Long.valueOf(0));
vignette.put("content", Blobs.createBlob("textblob content"));
vignette.put("label", "vignettelabel");
vignettes.add(vignette);
doc.setPropertyValue("cmpf:attachedFile", (Serializable) attachedFile);
session.saveDocument(doc);
session.save();
doc = session.getDocument(docRef);
assertEquals("text/plain",
doc.getProperty("cmpf:attachedFile/vignettes/vignette[0]/content/mime-type").getValue());
assertEquals(Long.valueOf(0), doc.getProperty("cmpf:attachedFile/vignettes/vignette[0]/height").getValue());
assertEquals("vignettelabel", doc.getProperty("cmpf:attachedFile/vignettes/vignette[0]/label").getValue());
// test setting and reading a list of maps with a blob inside the map
Blob blob = Blobs.createBlob("01AB", "application/octet-stream", null, "file.bin");
vignette.put("content", blob);
doc.setPropertyValue("cmpf:attachedFile", (Serializable) attachedFile);
session.saveDocument(doc);
session.save();
doc = session.getDocument(docRef);
assertEquals(Long.valueOf(0), doc.getProperty("cmpf:attachedFile/vignettes/vignette[0]/height").getValue());
assertEquals("vignettelabel", doc.getProperty("cmpf:attachedFile/vignettes/vignette[0]/label").getValue());
// this doesn't work due to core restrictions (BlobProperty):
// assertEquals(blob.getFilename(), doc.getProperty(
// "cmpf:attachedFile/vignettes/vignette[0]/content/name").getValue());
Blob b = (Blob) doc.getProperty("cmpf:attachedFile/vignettes/vignette[0]/content").getValue();
assertEquals("file.bin", b.getFilename());
}
@Test
public void testComplexTypeOrdering() throws Exception {
// Oracle has problems opening and closing many connections in a short time span (Listener refused the
// connection with the following error: ORA-12519, TNS:no appropriate service handler found).
// It seems to have something to do with how closed sessions are not immediately accounted for by Oracle's PMON
// (process monitor).
// So don't run this test with Oracle.
assumeTrue("Test does too many open/close for Oracle", !coreFeature.getStorageConfiguration().isVCSOracle());
// test case to reproduce an ordering content related Heisenbug on
// postgresql: NXP-2810: Preserve creation order of children of a
// complex type property in SQL storage with PostgreSQL
// create documents with a list of ordered vignettes
createComplexDocs(0, 5);
// check that the created docs hold their complex content in the
// creation order
checkComplexDocs(0, 5);
// add some more docs
createComplexDocs(5, 10);
// check that both the old and new document still hold their complex
// content in the same creation order
checkComplexDocs(0, 10);
}
protected void createComplexDocs(int iMin, int iMax) {
for (int i = iMin; i < iMax; i++) {
DocumentModel doc = session.createDocumentModel("/", "doc" + i, "ComplexDoc");
Map<String, Object> attachedFile = new HashMap<>();
List<Map<String, Object>> vignettes = new ArrayList<>();
attachedFile.put("name", "some name");
attachedFile.put("vignettes", vignettes);
for (int j = 0; j < 3; j++) {
Map<String, Object> vignette = new HashMap<>();
vignette.put("width", Long.valueOf(j));
vignette.put("height", Long.valueOf(j));
vignette.put("content", Blobs.createBlob(String.format("document %d, vignette %d", i, j)));
vignettes.add(vignette);
}
doc.setPropertyValue("cmpf:attachedFile", (Serializable) attachedFile);
doc = session.createDocument(doc);
session.save();
}
}
protected void checkComplexDocs(int iMin, int iMax) throws IOException {
for (int i = iMin; i < iMax; i++) {
DocumentModel doc = session.getDocument(new PathRef("/doc" + i));
for (int j = 0; j < 3; j++) {
String propertyPath = String.format("cmpf:attachedFile/vignettes/%d/", j);
assertEquals(Long.valueOf(j), doc.getProperty(propertyPath + "height").getValue());
assertEquals(Long.valueOf(j), doc.getProperty(propertyPath + "width").getValue());
assertEquals(String.format("document %d, vignette %d", i, j),
doc.getProperty(propertyPath + "content").getValue(Blob.class).getString());
}
}
}
@Test
public void testMarkDirty() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "doc", "MyDocType");
doc = session.createDocument(doc);
session.save();
doc.setProperty("dublincore", "title", "title1");
doc.setProperty("testList", "participants", new ArrayList<>(Arrays.asList("a", "b")));
session.saveDocument(doc);
session.save();
doc.setProperty("dublincore", "title", "title2");
doc.setProperty("testList", "participants", new ArrayList<>(Arrays.asList("c", "d")));
session.saveDocument(doc);
session.save();
// ----- new session -----
reopenSession();
// root = session.getRootDocument();
doc = session.getDocument(new PathRef("/doc"));
String title = (String) doc.getProperty("dublincore", "title");
assertEquals("title2", title);
Object participants = doc.getProperty("testList", "participants");
assertEquals(Arrays.asList("c", "d"), Arrays.asList((Serializable[]) participants));
}
@Test
public void testMarkDirtyForList() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "doc", "ComplexDoc");
Map<String, Object> attachedFile = new HashMap<>();
List<Map<String, Object>> vignettes = new ArrayList<>();
attachedFile.put("vignettes", vignettes);
Map<String, Object> vignette = new HashMap<>();
vignette.put("width", 111L);
vignettes.add(vignette);
doc.setPropertyValue("cmpf:attachedFile", (Serializable) attachedFile);
doc = session.createDocument(doc);
session.save();
doc.getProperty("cmpf:attachedFile/vignettes/vignette[0]/width").setValue(222L);
session.saveDocument(doc);
session.save();
doc.getProperty("cmpf:attachedFile/vignettes/vignette[0]/width").setValue(333L);
session.saveDocument(doc);
session.save();
// ----- new session -----
reopenSession();
doc = session.getDocument(new PathRef("/doc"));
assertEquals(333L, doc.getProperty("cmpf:attachedFile/vignettes/vignette[0]/width").getValue());
}
//
//
// ----------------------------------------------------
// ----- copied from TestAPI in nuxeo-core-facade -----
// ----------------------------------------------------
//
//
protected final Random random = new Random(new Date().getTime());
protected String generateUnique() {
return String.valueOf(random.nextLong());
}
protected DocumentModel createChildDocument(DocumentModel childFolder) {
DocumentModel ret = session.createDocument(childFolder);
assertNotNull(ret);
assertNotNull(ret.getName());
assertNotNull(ret.getId());
assertNotNull(ret.getRef());
assertNotNull(ret.getPathAsString());
return ret;
}
protected List<DocumentModel> createChildDocuments(List<DocumentModel> childFolders) {
List<DocumentModel> rets = new ArrayList<>();
Collections.addAll(rets, session.createDocument(childFolders.toArray(new DocumentModel[0])));
assertNotNull(rets);
assertEquals(childFolders.size(), rets.size());
for (DocumentModel createdChild : rets) {
assertNotNull(createdChild);
assertNotNull(createdChild.getName());
assertNotNull(createdChild.getRef());
assertNotNull(createdChild.getPathAsString());
assertNotNull(createdChild.getId());
}
return rets;
}
@Test
public void testGetRootDocument() {
DocumentModel root = session.getRootDocument();
assertNotNull(root);
assertNotNull(root.getId());
assertNotNull(root.getRef());
assertNotNull(root.getPathAsString());
}
@SuppressWarnings({ "SimplifiableJUnitAssertion" })
@Test
public void testDocumentReferenceEqualitySameInstance() {
DocumentModel root = session.getRootDocument();
assertTrue(root.getRef().equals(root.getRef()));
}
@Test
public void testCancel() {
DocumentModel root = session.getRootDocument();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), "folder#" + generateUnique(),
"Folder");
childFolder = createChildDocument(childFolder);
session.cancel();
// TODO NXP-2514, cancel unimplemented
// assertFalse(session.exists(childFolder.getRef()));
}
@Test
public void testCreateDomainDocumentRefDocumentModel() {
DocumentModel root = session.getRootDocument();
String name = "domain#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Domain");
childFolder = createChildDocument(childFolder);
assertEquals("Domain", childFolder.getType());
assertEquals(name, childFolder.getName());
}
@Test
public void testCreateFolderDocumentRefDocumentModel() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
childFolder = createChildDocument(childFolder);
assertEquals("Folder", childFolder.getType());
assertEquals(name, childFolder.getName());
}
@Test
public void testCreateFileDocumentRefDocumentModel() {
DocumentModel root = session.getRootDocument();
String name = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name, "File");
childFile = createChildDocument(childFile);
assertEquals("File", childFile.getType());
assertEquals(name, childFile.getName());
}
@Test
public void testCreateFolderDocumentRefDocumentModelArray() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "folder#" + generateUnique();
DocumentModel childFolder2 = new DocumentModelImpl(root.getPathAsString(), name2, "Folder");
List<DocumentModel> childFolders = new ArrayList<>();
childFolders.add(childFolder);
childFolders.add(childFolder2);
List<DocumentModel> returnedChildFolders = createChildDocuments(childFolders);
assertEquals(name, returnedChildFolders.get(0).getName());
assertEquals(name2, returnedChildFolders.get(1).getName());
}
@Test
public void testCreateFileDocumentRefDocumentModelArray() {
DocumentModel root = session.getRootDocument();
String name = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name, "File");
String name2 = "file#" + generateUnique();
DocumentModel childFile2 = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childFiles = new ArrayList<>();
childFiles.add(childFile);
childFiles.add(childFile2);
List<DocumentModel> returnedChildFiles = createChildDocuments(childFiles);
assertEquals(name, returnedChildFiles.get(0).getName());
assertEquals(name2, returnedChildFiles.get(1).getName());
}
@Test
public void testExists() {
DocumentModel root = session.getRootDocument();
assertTrue(session.exists(root.getRef()));
}
@Test
public void testGetChild() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
assertFalse(session.hasChild(root.getRef(), name));
assertFalse(session.hasChild(root.getRef(), name2));
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
assertTrue(session.hasChild(root.getRef(), name));
assertTrue(session.hasChild(root.getRef(), name2));
DocumentModel retrievedChild = session.getChild(root.getRef(), name);
assertNotNull(retrievedChild);
assertNotNull(retrievedChild.getId());
assertNotNull(retrievedChild.getPathAsString());
assertNotNull(retrievedChild.getName());
assertNotNull(retrievedChild.getRef());
assertEquals(name, retrievedChild.getName());
retrievedChild = session.getChild(root.getRef(), name2);
assertNotNull(retrievedChild);
assertNotNull(retrievedChild.getId());
assertNotNull(retrievedChild.getPathAsString());
assertNotNull(retrievedChild.getName());
assertNotNull(retrievedChild.getRef());
assertEquals(name2, retrievedChild.getName());
try {
session.getChild(root.getRef(), "nosuchchild");
fail("Should fail with DocumentNotFoundException");
} catch (DocumentNotFoundException e) {
assertEquals("nosuchchild", e.getMessage());
}
}
@Test
public void testGetChildrenDocumentRef() {
DocumentModel root = session.getRootDocument();
List<DocumentModel> docs = session.getChildren(root.getRef());
assertEquals(0, docs.size());
}
@Test
public void testGetChildrenIteratorRoot() {
DocumentModel root = session.getRootDocument();
DocumentModelIterator docs = session.getChildrenIterator(root.getRef());
assertFalse(docs.hasNext());
}
@Test
public void testGetFileChildrenDocumentRefString() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
// get file children
List<DocumentModel> retrievedChilds = session.getChildren(root.getRef(), "File");
assertNotNull(retrievedChilds);
assertEquals(1, retrievedChilds.size());
assertNotNull(retrievedChilds.get(0));
assertNotNull(retrievedChilds.get(0).getId());
assertNotNull(retrievedChilds.get(0).getName());
assertNotNull(retrievedChilds.get(0).getPathAsString());
assertNotNull(retrievedChilds.get(0).getRef());
assertEquals(name2, retrievedChilds.get(0).getName());
assertEquals("File", retrievedChilds.get(0).getType());
}
@Test
public void testGetChildrenIteratorFile() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
// get file children
DocumentModelIterator retrievedChilds = session.getChildrenIterator(root.getRef(), "File", null, null);
assertNotNull(retrievedChilds);
assertTrue(retrievedChilds.hasNext());
DocumentModel doc = retrievedChilds.next();
assertFalse(retrievedChilds.hasNext());
assertNotNull(doc);
assertNotNull(doc.getId());
assertNotNull(doc.getName());
assertNotNull(doc.getPathAsString());
assertNotNull(doc.getRef());
assertEquals(name2, doc.getName());
assertEquals("File", doc.getType());
}
@Test
public void testGetChildrenIterator() {
int n = 200;
Set<String> names = new HashSet<>();
for (int i = 0; i < n; i++) {
String name = "doc" + i;
names.add(name);
DocumentModel doc = session.createDocumentModel("/", name, "File");
doc = session.createDocument(doc);
}
session.save();
DocumentModelIterator it = session.getChildrenIterator(new PathRef("/"), "File", null, null);
for (DocumentModel doc : it) {
String name = doc.getName();
if (!names.remove(name)) {
fail("Unknown or duplicate name" + name);
}
}
if (!names.isEmpty()) {
fail("Remaining names " + names);
}
}
@Test
public void testGetChildrenIteratorFilter() {
int n = 200;
Set<String> names = new HashSet<>();
for (int i = 0; i < n; i++) {
String name = "doc" + i;
names.add(name);
DocumentModel doc = session.createDocumentModel("/", name, "File");
doc = session.createDocument(doc);
// create spurious docs in the middle
DocumentModel doc2 = session.createDocumentModel("/", "foo" + i, "File");
doc2 = session.createDocument(doc2);
DocumentModel doc3 = session.createDocumentModel("/", "docNote" + i, "Note");
doc3 = session.createDocument(doc3);
}
session.save();
Filter filter = new Filter() {
private static final long serialVersionUID = 1L;
@Override
public boolean accept(DocumentModel docModel) {
return docModel.getName().startsWith("doc");
}
};
DocumentModelIterator it = session.getChildrenIterator(new PathRef("/"), "File", null, filter);
for (DocumentModel doc : it) {
String name = doc.getName();
if (!names.remove(name)) {
fail("Unknown or duplicate name " + name);
}
}
if (!names.isEmpty()) {
fail("Remaining names " + names);
}
}
@Test
public void testGetFolderChildrenDocumentRefString() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
// get folder children
List<DocumentModel> retrievedChilds = session.getChildren(root.getRef(), "Folder");
assertNotNull(retrievedChilds);
assertEquals(1, retrievedChilds.size());
assertNotNull(retrievedChilds.get(0));
assertNotNull(retrievedChilds.get(0).getId());
assertNotNull(retrievedChilds.get(0).getName());
assertNotNull(retrievedChilds.get(0).getPathAsString());
assertNotNull(retrievedChilds.get(0).getRef());
assertEquals(name, retrievedChilds.get(0).getName());
assertEquals("Folder", retrievedChilds.get(0).getType());
}
@Test
public void testGetChildrenIteratorFolder() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
// get folder children
DocumentModelIterator retrievedChilds = session.getChildrenIterator(root.getRef(), "Folder", null, null);
assertNotNull(retrievedChilds);
assertTrue(retrievedChilds.hasNext());
DocumentModel doc = retrievedChilds.next();
assertFalse(retrievedChilds.hasNext());
assertNotNull(doc);
assertNotNull(doc.getId());
assertNotNull(doc.getName());
assertNotNull(doc.getPathAsString());
assertNotNull(doc.getRef());
assertEquals(name, doc.getName());
assertEquals("Folder", doc.getType());
}
@Test
public void testGetChildrenIteratorRestrictedAccess() {
DocumentModel doc1 = session.createDocumentModel("/", "doc1", "File");
doc1 = session.createDocument(doc1);
DocumentModel doc2 = session.createDocumentModel("/", "doc2", "File");
doc2 = session.createDocument(doc2);
DocumentModel doc3 = session.createDocumentModel("/", "doc3", "File");
doc3 = session.createDocument(doc3);
// set ACP on root
ACP acp;
ACL acl;
acp = new ACPImpl();
acl = new ACLImpl();
acl.add(new ACE("Administrator", "Everything", true));
acl.add(new ACE("bob", "Everything", true));
acp.addACL(acl);
session.getRootDocument().setACP(acp, true);
// set ACP on doc2 to block bob
acp = new ACPImpl();
acl = new ACLImpl();
acl.add(new ACE("Administrator", "Everything", true));
acl.add(ACE.BLOCK);
acp.addACL(acl);
doc2.setACP(acp, true);
session.save();
// system sees all
Set<String> names = new HashSet<>();
for (DocumentModel doc : session.getChildrenIterator(new PathRef("/"))) {
names.add(doc.getName());
}
assertEquals(new HashSet<>(Arrays.asList("doc1", "doc2", "doc3")), names);
// bob doesn't see doc2
try (CoreSession bobSession = openSessionAs("bob")) {
names.clear();
for (DocumentModel doc : bobSession.getChildrenIterator(new PathRef("/"))) {
names.add(doc.getName());
}
// doc2 is not in the returned set
assertEquals(new HashSet<>(Arrays.asList("doc1", "doc3")), names);
}
}
@Test
public void testGetChildrenDocumentRefStringFilter() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "folder#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "Folder");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
/*
* Filter filter = new NameFilter(name2); // get folder children List<DocumentModel> retrievedChilds =
* session.getChildren(root.getRef(), null, null, filter, null); assertNotNull(retrievedChilds); assertEquals(1,
* retrievedChilds.size()); assertNotNull(retrievedChilds.get(0));
* assertNotNull(retrievedChilds.get(0).getId()); assertNotNull(retrievedChilds.get(0).getName());
* assertNotNull(retrievedChilds.get(0).getPathAsString()); assertNotNull(retrievedChilds.get(0).getRef());
* assertEquals(name2, retrievedChilds.get(0).getName());
*/
}
/**
* Test for NXP-741: Search based getChildren.
*/
@Test
public void testGetChildrenInFolderWithSearch() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel folder = new DocumentModelImpl(root.getPathAsString(), name, "FolderWithSearch");
folder = createChildDocument(folder);
// create more children
List<DocumentModel> childDocs = new ArrayList<>();
for (int i = 0; i < 5; i++) {
name = "File_" + i;
DocumentModel childFile = new DocumentModelImpl(folder.getPathAsString(), name, "File");
childDocs.add(childFile);
}
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
int i = 0;
for (DocumentModel retChild : returnedChildDocs) {
name = "File_" + i;
assertEquals(name, retChild.getName());
i++;
}
}
@Test
public void testGetDocumentDocumentRef() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
DocumentModel doc = session.getDocument(returnedChildDocs.get(0).getRef());
assertNotNull(doc);
assertNotNull(doc.getRef());
assertNotNull(doc.getName());
assertNotNull(doc.getId());
assertNotNull(doc.getPathAsString());
assertEquals(name, doc.getName());
assertEquals("Folder", doc.getType());
}
// TODO NXP-2514: fix this test.
@Test
@Ignore
public void testGetDocumentDocumentRefStringArray() {
DocumentModel root = session.getRootDocument();
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
childFile = createChildDocument(childFile);
session.save();
childFile.setProperty("dublincore", "title", "f1");
childFile.setProperty("dublincore", "description", "desc 1");
session.saveDocument(childFile);
session.save();
DocumentModel returnedDocument = session.getDocument(childFile.getRef());
assertNotNull(returnedDocument);
assertNotNull(returnedDocument.getRef());
assertNotNull(returnedDocument.getId());
assertNotNull(returnedDocument.getName());
assertNotNull(returnedDocument.getPathAsString());
assertNotNull(returnedDocument.getType());
assertNotNull(returnedDocument.getSchemas());
// TODO NXP-2514: should it contain 3 or 1 schemas? not sure about that.
List<String> schemas = Arrays.asList(returnedDocument.getSchemas());
assertEquals(3, schemas.size());
assertTrue(schemas.contains("common"));
assertTrue(schemas.contains("file"));
assertTrue(schemas.contains("dublincore"));
assertEquals("f1", returnedDocument.getProperty("dublincore", "title"));
assertEquals("desc 1", returnedDocument.getProperty("dublincore", "description"));
returnedDocument = session.getDocument(childFile.getRef());
assertNotNull(returnedDocument);
assertNotNull(returnedDocument.getRef());
assertNotNull(returnedDocument.getId());
assertNotNull(returnedDocument.getName());
assertNotNull(returnedDocument.getPathAsString());
assertNotNull(returnedDocument.getType());
assertNotNull(returnedDocument.getSchemas());
schemas = Arrays.asList(returnedDocument.getSchemas());
assertEquals(3, schemas.size());
assertTrue(schemas.contains("common"));
assertTrue(schemas.contains("file"));
assertTrue(schemas.contains("dublincore"));
assertEquals("f1", returnedDocument.getProperty("dublincore", "title"));
assertEquals("desc 1", returnedDocument.getProperty("dublincore", "description"));
}
@Test
public void testGetFilesDocumentRef() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
// get file children
List<DocumentModel> retrievedChilds = session.getFiles(root.getRef());
assertNotNull(retrievedChilds);
assertEquals(1, retrievedChilds.size());
assertNotNull(retrievedChilds.get(0));
assertNotNull(retrievedChilds.get(0).getId());
assertNotNull(retrievedChilds.get(0).getPathAsString());
assertNotNull(retrievedChilds.get(0).getName());
assertNotNull(retrievedChilds.get(0).getRef());
assertEquals(name2, retrievedChilds.get(0).getName());
assertEquals("File", retrievedChilds.get(0).getType());
}
@Test
@Ignore
public void testGetFilesDocumentRefFilterSorter() {
// not used at the moment
}
@Test
public void testGetFoldersDocumentRef() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
// get folder children
List<DocumentModel> retrievedChilds = session.getFolders(root.getRef());
assertNotNull(retrievedChilds);
assertEquals(1, retrievedChilds.size());
assertNotNull(retrievedChilds.get(0));
assertNotNull(retrievedChilds.get(0).getId());
assertNotNull(retrievedChilds.get(0).getPathAsString());
assertNotNull(retrievedChilds.get(0).getName());
assertNotNull(retrievedChilds.get(0).getRef());
assertEquals(name, retrievedChilds.get(0).getName());
assertEquals("Folder", retrievedChilds.get(0).getType());
}
@Test
public void testGetFoldersDocumentRefFilterSorter() {
DocumentModel root = session.getRootDocument();
// init children
DocumentModel childFolder1 = new DocumentModelImpl(root.getPathAsString(), "folder1#" + generateUnique(),
"Folder");
DocumentModel childFolder2 = new DocumentModelImpl(root.getPathAsString(), "folder2#" + generateUnique(),
"Folder");
DocumentModel childFolder3 = new DocumentModelImpl(root.getPathAsString(), "folder3#" + generateUnique(),
"OrderedFolder");
// persist
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder1);
childDocs.add(childFolder2);
childDocs.add(childFolder3);
createChildDocuments(childDocs);
// test no filter, no sorter
List<DocumentModel> folders = session.getFolders(root.getRef(), null, null);
assertNotNull(folders);
assertEquals(childDocs.size(), folders.size());
// test with filter, no sorter
Filter filter = new FacetFilter(FacetNames.ORDERABLE, true);
folders = session.getFolders(root.getRef(), filter, null);
assertNotNull(folders);
assertEquals(1, folders.size());
assertEquals(childDocs.get(childDocs.indexOf(childFolder3)).getName(), folders.get(0).getName());
}
@Test
public void testGetParentDocument() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
DocumentModel shouldBeRoot = session.getParentDocument(returnedChildDocs.get(0).getRef());
assertEquals(root.getPathAsString(), shouldBeRoot.getPathAsString());
}
@Test
public void testGetParentDocuments() {
List<DocumentModel> docs;
DocumentModel folder1 = new DocumentModelImpl("/", "folder1", "Folder");
folder1 = session.createDocument(folder1);
DocumentModel folder2 = new DocumentModelImpl("/folder1", "folder2", "Folder");
folder2 = session.createDocument(folder2);
DocumentModel file1 = new DocumentModelImpl("/folder1/folder2", "file1", "File");
file1 = session.createDocument(file1);
session.save();
docs = session.getParentDocuments(file1.getRef());
assertEquals(3, docs.size());
assertEquals("folder1", docs.get(0).getName());
assertEquals("folder2", docs.get(1).getName());
assertEquals("file1", docs.get(2).getName());
// root
docs = session.getParentDocuments(session.getRootDocument().getRef());
assertEquals(0, docs.size());
// relation, check as admin
try (CoreSession admSession = openSessionAs(new UserPrincipal("adm", null, false, true))) {
DocumentModel rel = admSession.createDocumentModel(null, "myrel", "Relation");
rel = admSession.createDocument(rel);
admSession.save();
docs = admSession.getParentDocuments(rel.getRef());
assertEquals(1, docs.size());
assertEquals("myrel", docs.get(0).getName());
}
}
@Test
public void testHasChildren() {
DocumentModel root = session.getRootDocument();
// the root document at the moment has no children
assertFalse(session.hasChildren(root.getRef()));
}
@Test
public void testRemoveChildren() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
session.removeChildren(root.getRef());
assertFalse(session.exists(returnedChildDocs.get(0).getRef()));
assertFalse(session.exists(returnedChildDocs.get(1).getRef()));
}
@Test
public void testRemoveChildren2() {
DocumentModel folder1 = session.createDocumentModel("/", "folder1", "Folder");
folder1 = session.createDocument(folder1);
DocumentModel folder2 = session.createDocumentModel("/folder1", "folder2", "Folder");
folder2 = session.createDocument(folder2);
DocumentModel doc1 = session.createDocumentModel("/folder1/folder2", "doc1", "File");
doc1 = session.createDocument(doc1);
session.save();
// now remove
session.removeDocument(folder2.getRef());
// don't save
// check that we don't get phantom docs when getting children
// for instance when updating ACLs recursively
session.setACP(folder1.getRef(), new ACPImpl(), true);
session.save();
}
protected void dumpAllDocuments(CoreSession session) {
DocumentModelList docs = session.query("select * from Document");
System.out.println("List all documents");
for (DocumentModel doc : docs) {
System.out.println(String.format("- type: %s, proxy: %s, version: %s %s", doc.getType(), doc.isProxy(),
doc.isVersion(), doc));
}
}
@Test
@Ignore("NXP-14686")
public void testRemoveChildrenWithVersion() {
DocumentModel root = session.getRootDocument();
DocumentModel doc = session.createDocumentModel(root.getPathAsString(), "somefile", "File");
session.createDocument(doc);
DocumentModel folder = session.createDocumentModel(root.getPathAsString(), "somefolder", "Folder");
folder = session.createDocument(folder);
DocumentModel file = session.getDocument(doc.getRef());
session.publishDocument(file, folder);
session.save();
// TransactionHelper.commitOrRollbackTransaction();
// TransactionHelper.startTransaction();
dumpAllDocuments(session);
session.removeChildren(root.getRef());
session.save();
// TransactionHelper.commitOrRollbackTransaction();
// TransactionHelper.startTransaction();
dumpAllDocuments(session);
assertTrue("NXP-14686 removeChildren fails to delete orphan version",
session.query("SELECT * FROM Document").isEmpty());
}
@Test
public void testRemoveDocument() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
session.removeDocument(returnedChildDocs.get(0).getRef());
assertFalse(session.exists(returnedChildDocs.get(0).getRef()));
}
@Test
public void testRemoveVersion() {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
doc = session.createDocument(doc);
// create version
DocumentRef version = doc.checkIn(VersioningOption.MAJOR, null);
// create proxy
DocumentModel proxy = session.createProxy(version, new PathRef("/"));
// cannot remove version due to existing proxy
try {
session.removeDocument(version);
fail();
} catch (DocumentSecurityException e) {
assertTrue(e.getMessage(), e.getMessage().contains("targets version"));
}
// remove proxy
session.removeDocument(proxy.getRef());
// create version 2
doc.checkOut();
doc.checkIn(VersioningOption.MAJOR, null);
// restore doc to version 1
session.restoreToVersion(doc.getRef(), version);
// cannot remove version due to live doc having it as base version
try {
session.removeDocument(version);
fail();
} catch (DocumentSecurityException e) {
assertTrue(e.getMessage(), e.getMessage().contains("is checked in with base version"));
}
// checkout live doc
doc.checkOut();
// now we can remove the version
session.removeDocument(version);
}
public void TODOtestQuery() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String fname1 = "file1#" + generateUnique();
DocumentModel childFile1 = new DocumentModelImpl(root.getPathAsString(), fname1, "File");
childFile1.setProperty("dublincore", "title", "abc");
String fname2 = "file2#" + generateUnique();
DocumentModel childFile2 = new DocumentModelImpl(root.getPathAsString(), fname2, "HiddenFile");
childFile2.setProperty("dublincore", "title", "def");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile1);
childDocs.add(childFile2);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
returnedChildDocs.get(1).setProperty("file", "content", Blobs.createBlob("blob1", "text/plain", "UTF-8", "f1"));
returnedChildDocs.get(2).setProperty("file", "content", Blobs.createBlob("blob1", "text/plain", "UTF-8", "f2"));
session.saveDocuments(returnedChildDocs.toArray(new DocumentModel[0]));
session.save();
DocumentModelList list = session.query("SELECT name FROM File");
assertEquals(1, list.size());
DocumentModel docModel = list.get(0);
List<String> schemas = Arrays.asList(docModel.getSchemas());
// TODO NXP-2514: is it 3 or 4? (should "uid" be in the list or not?)
// assertEquals(3, schemas.size());
assertTrue(schemas.contains("common"));
assertTrue(schemas.contains("file"));
assertTrue(schemas.contains("dublincore"));
// if we select filename, the returned docModel
// should have both schemas "file" and "common"
list = session.query("SELECT content/filename FROM File");
assertEquals(1, list.size());
docModel = list.get(0);
schemas = Arrays.asList(docModel.getSchemas());
// assertEquals(3, schemas.size());
assertTrue(schemas.contains("common"));
assertTrue(schemas.contains("file"));
assertTrue(schemas.contains("dublincore"));
// if we select all properties, the returned docModel
// should have at least the schemas "file" and "common"
// (it seems to also have "dublincore")
list = session.query("SELECT * FROM File");
assertEquals(1, list.size());
docModel = list.get(0);
schemas = Arrays.asList(docModel.getSchemas());
// assertEquals(3, schemas.size());
assertTrue(schemas.contains("common"));
assertTrue(schemas.contains("file"));
assertTrue(schemas.contains("dublincore"));
// if we select all files using the filter, we should get only one
Filter facetFilter = new FacetFilter("HiddenInNavigation", true);
list = session.query("SELECT * FROM HiddenFile", facetFilter);
assertEquals(1, list.size());
docModel = list.get(0);
schemas = Arrays.asList(docModel.getSchemas());
assertTrue(schemas.contains("common"));
assertTrue(schemas.contains("dublincore"));
// if we select all documents, we get the folder and the two files
list = session.query("SELECT * FROM Document");
assertEquals(3, list.size());
docModel = list.get(0);
schemas = Arrays.asList(docModel.getSchemas());
// assertEquals(3, schemas.size());
assertTrue(schemas.contains("common"));
assertTrue(schemas.contains("dublincore"));
list = session.query("SELECT * FROM Document WHERE dc:title = 'abc'");
assertEquals(1, list.size());
list = session.query("SELECT * FROM Document WHERE dc:title = 'abc' OR dc:title = 'def'");
assertEquals(2, list.size());
session.removeDocument(returnedChildDocs.get(0).getRef());
session.removeDocument(returnedChildDocs.get(1).getRef());
}
public void TODOtestQueryAfterEdit() {
DocumentModel root = session.getRootDocument();
String fname1 = "file1#" + generateUnique();
DocumentModel childFile1 = new DocumentModelImpl(root.getPathAsString(), fname1, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFile1);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(1, returnedChildDocs.size());
childFile1 = returnedChildDocs.get(0);
// add a blob
Blob blob = Blobs.createBlob("<html><head/><body>La la la!</body></html>", "text/html", "UTF-8", "f1");
childFile1.setProperty("file", "content", blob);
session.saveDocument(childFile1);
session.save();
DocumentModelList list;
DocumentModel docModel;
list = session.query("SELECT * FROM Document");
assertEquals(1, list.size());
docModel = list.get(0);
// read the properties
docModel.getProperty("dublincore", "title");
// edit the title without touching the blob
docModel.setProperty("dublincore", "title", "edited title");
docModel.setProperty("dublincore", "description", "edited description");
session.saveDocument(docModel);
session.save();
list = session.query("SELECT * FROM Document");
assertEquals(1, list.size());
docModel = list.get(0);
session.removeDocument(docModel.getRef());
}
@Test
public void testRemoveDocuments() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
DocumentRef[] refs = { returnedChildDocs.get(0).getRef(), returnedChildDocs.get(1).getRef() };
session.removeDocuments(refs);
assertFalse(session.exists(returnedChildDocs.get(0).getRef()));
assertFalse(session.exists(returnedChildDocs.get(1).getRef()));
}
/*
* case where some documents are actually children of other ones from the list
*/
@Test
public void testRemoveDocumentsWithDeps() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
// careless removing this one after the folder would fail
String name2 = "file#" + generateUnique();
DocumentModel folderChildFile = new DocumentModelImpl(childFolder.getPathAsString(), name2, "File");
// one more File object, whose path is greater than the folder's
String name3 = "file#" + generateUnique();
DocumentModel folderChildFile2 = new DocumentModelImpl(childFolder.getPathAsString(), name3, "File");
// one more File object at the root,
// whose path is greater than the folder's
String name4 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name4, "File");
// one more File object at the root, whose path is greater than the
// folder's and with name conflict resolved by core directly, see
// NXP-3240
DocumentModel childFile2 = new DocumentModelImpl(root.getPathAsString(), name4, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(folderChildFile);
childDocs.add(folderChildFile2);
childDocs.add(childFile);
childDocs.add(childFile2);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
assertEquals(name3, returnedChildDocs.get(2).getName());
assertEquals(name4, returnedChildDocs.get(3).getName());
// not the same here: conflict resolved by core session
String name5 = returnedChildDocs.get(4).getName();
assertNotSame(name4, name5);
assertTrue(name5.startsWith(name4));
DocumentRef[] refs = { returnedChildDocs.get(0).getRef(), returnedChildDocs.get(1).getRef(),
returnedChildDocs.get(2).getRef(), returnedChildDocs.get(3).getRef(), returnedChildDocs.get(4).getRef() };
session.removeDocuments(refs);
assertFalse(session.exists(returnedChildDocs.get(0).getRef()));
assertFalse(session.exists(returnedChildDocs.get(1).getRef()));
assertFalse(session.exists(returnedChildDocs.get(2).getRef()));
assertFalse(session.exists(returnedChildDocs.get(3).getRef()));
assertFalse(session.exists(returnedChildDocs.get(4).getRef()));
}
/*
* Same as testRemoveDocumentWithDeps with a different given ordering of documents to delete
*/
@Test
public void testRemoveDocumentsWithDeps2() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
// careless removing this one after the folder would fail
String name2 = "file#" + generateUnique();
DocumentModel folderChildFile = new DocumentModelImpl(childFolder.getPathAsString(), name2, "File");
// one more File object, whose path is greater than the folder's
String name3 = "file#" + generateUnique();
DocumentModel folderChildFile2 = new DocumentModelImpl(childFolder.getPathAsString(), name3, "File");
// one more File object at the root,
// whose path is greater than the folder's
String name4 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name4, "File");
// one more File object at the root, whose path is greater than the
// folder's and with name conflict resolved by core directly, see
// NXP-3240
DocumentModel childFile2 = new DocumentModelImpl(root.getPathAsString(), name4, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(folderChildFile);
childDocs.add(folderChildFile2);
childDocs.add(childFile);
childDocs.add(childFile2);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
assertEquals(name3, returnedChildDocs.get(2).getName());
assertEquals(name4, returnedChildDocs.get(3).getName());
// not the same here: conflict resolved by core session
String name5 = returnedChildDocs.get(4).getName();
assertNotSame(name4, name5);
assertTrue(name5.startsWith(name4));
// here's the different ordering
DocumentRef[] refs = { returnedChildDocs.get(1).getRef(), returnedChildDocs.get(0).getRef(),
returnedChildDocs.get(4).getRef(), returnedChildDocs.get(3).getRef(), returnedChildDocs.get(2).getRef() };
session.removeDocuments(refs);
assertFalse(session.exists(returnedChildDocs.get(0).getRef()));
assertFalse(session.exists(returnedChildDocs.get(1).getRef()));
assertFalse(session.exists(returnedChildDocs.get(2).getRef()));
assertFalse(session.exists(returnedChildDocs.get(3).getRef()));
assertFalse(session.exists(returnedChildDocs.get(4).getRef()));
}
@Test
public void testRemoveDocumentTreeWithSecurity() throws Exception {
ACP acp;
ACL acl;
DocumentModelList dml;
DocumentModel root = session.getRootDocument();
DocumentModel f1 = session.createDocumentModel("/", "f1", "Folder");
f1 = session.createDocument(f1);
DocumentModel doc1 = session.createDocumentModel("/f1", "doc1", "File");
doc1 = session.createDocument(doc1);
DocumentModel doc2 = session.createDocumentModel("/f1", "doc2", "File");
doc2 = session.createDocument(doc2);
// set ACP on root
acp = new ACPImpl();
acl = new ACLImpl();
acl.add(new ACE("Administrator", "Everything", true));
acl.add(new ACE("bob", "Everything", true));
acp.addACL(acl);
root.setACP(acp, true);
// set ACP on doc1 to block bob
acp = new ACPImpl();
acl = new ACLImpl();
acl.add(new ACE("Administrator", "Everything", true));
acl.add(ACE.BLOCK);
acp.addACL(acl);
doc1.setACP(acp, true);
session.save();
// check admin sees doc1 and doc2
dml = session.query("SELECT * FROM Document WHERE ecm:path STARTSWITH '/f1'");
assertEquals(2, dml.size());
// as bob
try (CoreSession bobSession = openSessionAs("bob")) {
// check bob doesn't see doc1
dml = bobSession.query("SELECT * FROM Document WHERE ecm:path STARTSWITH '/f1'");
assertEquals(1, dml.size());
// do copy
bobSession.copy(f1.getRef(), root.getRef(), "f2");
// save is mandatory to propagate read acls after a copy
bobSession.save();
// check bob doesn't see doc1's copy
dml = bobSession.query("SELECT * FROM Document WHERE ecm:path STARTSWITH '/f2'");
assertEquals(1, dml.size());
}
}
@Test
public void testSave() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
childFolder = createChildDocument(childFolder);
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
childFile = createChildDocument(childFile);
session.save();
// TODO NXP-2514: this should be tested across sessions - when it can be done
assertTrue(session.exists(childFolder.getRef()));
assertTrue(session.exists(childFile.getRef()));
}
@Test
public void testSaveFolder() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
childFolder = createChildDocument(childFolder);
childFolder.setProperty("dublincore", "title", "f1");
childFolder.setProperty("dublincore", "description", "desc 1");
session.saveDocument(childFolder);
// TODO NXP-2514: this should be tested across sessions - when it can be done
assertTrue(session.exists(childFolder.getRef()));
assertEquals("f1", childFolder.getProperty("dublincore", "title"));
assertEquals("desc 1", childFolder.getProperty("dublincore", "description"));
}
@Test
public void testSaveFile() {
DocumentModel root = session.getRootDocument();
String name = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name, "File");
childFile.setProperty("dublincore", "title", "f1");
childFile.setProperty("dublincore", "description", "desc 1");
childFile = createChildDocument(childFile);
Property p = childFile.getProperty("/dublincore:/description");
// System.out.println(p.getPath());
// TODO NXP-2514: this should be tested across sessions - when it can be done
assertTrue(session.exists(childFile.getRef()));
DocumentModel retrievedFile = session.getDocument(childFile.getRef());
assertEquals("f1", retrievedFile.getProperty("dublincore", "title"));
assertEquals("desc 1", retrievedFile.getProperty("dublincore", "description"));
}
@Test
public void testSaveDocuments() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
childFolder = createChildDocument(childFolder);
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
childFile = createChildDocument(childFile);
DocumentModel[] docs = { childFolder, childFile };
session.saveDocuments(docs);
// TODO NXP-2514: this should be tested across sessions - when it can be done
assertTrue(session.exists(childFolder.getRef()));
assertTrue(session.exists(childFile.getRef()));
}
@Test
public void testGetDataModel() {
DocumentModel root = session.getRootDocument();
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
childFile = createChildDocument(childFile);
session.save();
childFile.setProperty("dublincore", "title", "f1");
childFile.setProperty("dublincore", "description", "desc 1");
childFile.setProperty("file", "content", Blobs.createBlob("b1", "text/plain", "UTF-8", "second name"));
session.saveDocument(childFile);
Schema dublincore = childFile.getDocumentType().getSchema("dublincore");
DataModel dm = session.getDataModel(childFile.getRef(), dublincore);
assertNotNull(dm);
assertNotNull(dm.getMap());
assertNotNull(dm.getSchema());
assertEquals("dublincore", dm.getSchema());
assertEquals("f1", dm.getData("title"));
assertEquals("desc 1", dm.getData("description"));
Schema file = childFile.getDocumentType().getSchema("file");
dm = session.getDataModel(childFile.getRef(), file);
assertNotNull(dm);
assertNotNull(dm.getMap());
assertNotNull(dm.getSchema());
assertEquals("file", dm.getSchema());
assertEquals("second name", ((Blob) dm.getData("content")).getFilename());
}
@Test
public void testDocumentReferenceEqualityDifferentInstances() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
DocumentModel retrievedChild = session.getChild(root.getRef(), name);
assertNotNull(retrievedChild);
assertNotNull(retrievedChild.getId());
assertNotNull(retrievedChild.getPathAsString());
assertNotNull(retrievedChild.getName());
assertNotNull(retrievedChild.getRef());
assertEquals(name, retrievedChild.getName());
assertEquals(root.getRef(), retrievedChild.getParentRef());
retrievedChild = session.getChild(root.getRef(), name2);
assertNotNull(retrievedChild);
assertNotNull(retrievedChild.getId());
assertNotNull(retrievedChild.getPathAsString());
assertNotNull(retrievedChild.getName());
assertNotNull(retrievedChild.getRef());
assertEquals(name2, retrievedChild.getName());
assertEquals(root.getRef(), retrievedChild.getParentRef());
}
@Test
public void testDocumentReferenceNonEqualityDifferentInstances() {
DocumentModel root = session.getRootDocument();
String name = "folder#" + generateUnique();
DocumentModel childFolder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
List<DocumentModel> childDocs = new ArrayList<>();
childDocs.add(childFolder);
childDocs.add(childFile);
List<DocumentModel> returnedChildDocs = createChildDocuments(childDocs);
assertEquals(name, returnedChildDocs.get(0).getName());
assertEquals(name2, returnedChildDocs.get(1).getName());
DocumentModel retrievedChild = session.getChild(root.getRef(), name);
assertNotNull(retrievedChild);
assertNotNull(retrievedChild.getId());
assertNotNull(retrievedChild.getPathAsString());
assertNotNull(retrievedChild.getName());
assertNotNull(retrievedChild.getRef());
assertEquals(name, retrievedChild.getName());
assertFalse(retrievedChild.getRef().equals(root.getRef()));
assertFalse(retrievedChild.getRef().equals(retrievedChild.getParentRef()));
}
@Test
public void testFolderFacet() throws Exception {
DocumentModel child1 = new DocumentModelImpl("/", "file1", "File");
DocumentModel child2 = new DocumentModelImpl("/", "fold1", "Folder");
DocumentModel child3 = new DocumentModelImpl("/", "ws1", "Workspace");
List<DocumentModel> returnedChildFiles = createChildDocuments(Arrays.asList(child1, child2, child3));
assertFalse(returnedChildFiles.get(0).isFolder());
assertTrue(returnedChildFiles.get(1).isFolder());
assertTrue(returnedChildFiles.get(2).isFolder());
}
@Test
public void testFacetAPI() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "foo", "File");
doc = session.createDocument(doc);
session.save();
DocumentModelList dml;
// facet not yet present
assertFalse(doc.hasFacet("Aged"));
assertFalse(doc.hasFacet(FacetNames.HIDDEN_IN_NAVIGATION));
Set<String> baseFacets = new HashSet<>(Arrays.asList(FacetNames.DOWNLOADABLE, FacetNames.VERSIONABLE,
FacetNames.PUBLISHABLE, FacetNames.COMMENTABLE, FacetNames.HAS_RELATED_TEXT));
assertEquals(baseFacets, doc.getFacets());
try {
doc.setPropertyValue("age:age", "123");
fail();
} catch (PropertyNotFoundException e) {
// ok
}
dml = session.query("SELECT * FROM File WHERE ecm:mixinType = 'Aged'");
assertEquals(0, dml.size());
dml = session.query("SELECT * FROM Document WHERE ecm:mixinType <> 'Aged'");
assertEquals(1, dml.size());
// cannot add nonexistent facet
try {
doc.addFacet("nosuchfacet");
fail();
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage(), e.getMessage().contains("No such facet"));
}
assertEquals(baseFacets, doc.getFacets());
assertFalse(doc.removeFacet("nosuchfacet"));
assertEquals(baseFacets, doc.getFacets());
// add facet
assertTrue(doc.addFacet("Aged"));
assertTrue(doc.hasFacet("Aged"));
assertEquals(baseFacets.size() + 1, doc.getFacets().size());
doc.setPropertyValue("age:age", "123");
doc = session.saveDocument(doc);
assertTrue(doc.hasFacet("Aged"));
assertEquals(baseFacets.size() + 1, doc.getFacets().size());
assertEquals("123", doc.getPropertyValue("age:age"));
session.save();
reopenSession();
doc = session.getDocument(doc.getRef());
assertTrue(doc.hasFacet("Aged"));
assertEquals(baseFacets.size() + 1, doc.getFacets().size());
assertEquals("123", doc.getPropertyValue("age:age"));
dml = session.query("SELECT * FROM File WHERE ecm:mixinType = 'Aged'");
assertEquals(1, dml.size());
dml = session.query("SELECT * FROM Document WHERE ecm:mixinType <> 'Aged'");
assertEquals(0, dml.size());
// add twice
assertFalse(doc.addFacet("Aged"));
assertEquals(baseFacets.size() + 1, doc.getFacets().size());
// add other facet with no schema
assertTrue(doc.addFacet(FacetNames.HIDDEN_IN_NAVIGATION));
assertTrue(doc.hasFacet("Aged"));
assertTrue(doc.hasFacet(FacetNames.HIDDEN_IN_NAVIGATION));
assertEquals(baseFacets.size() + 2, doc.getFacets().size());
// remove first facet
assertTrue(doc.removeFacet("Aged"));
assertFalse(doc.hasFacet("Aged"));
assertTrue(doc.hasFacet(FacetNames.HIDDEN_IN_NAVIGATION));
assertEquals(baseFacets.size() + 1, doc.getFacets().size());
try {
doc.getPropertyValue("age:age");
fail();
} catch (PropertyNotFoundException e) {
// ok
}
doc = session.saveDocument(doc);
assertFalse(doc.hasFacet("Aged"));
assertTrue(doc.hasFacet(FacetNames.HIDDEN_IN_NAVIGATION));
assertEquals(baseFacets.size() + 1, doc.getFacets().size());
try {
doc.getPropertyValue("age:age");
fail();
} catch (PropertyNotFoundException e) {
// ok
}
session.save();
reopenSession();
doc = session.getDocument(doc.getRef());
assertFalse(doc.hasFacet("Aged"));
assertTrue(doc.hasFacet(FacetNames.HIDDEN_IN_NAVIGATION));
assertEquals(baseFacets.size() + 1, doc.getFacets().size());
try {
doc.getPropertyValue("age:age");
fail();
} catch (PropertyNotFoundException e) {
// ok
}
dml = session.query("SELECT * FROM File WHERE ecm:mixinType = 'Aged'");
assertEquals(0, dml.size());
dml = session.query("SELECT * FROM Document WHERE ecm:mixinType <> 'Aged'");
assertEquals(1, dml.size());
// remove twice
assertFalse(doc.removeFacet("Aged"));
assertEquals(baseFacets.size() + 1, doc.getFacets().size());
// remove other facet
assertTrue(doc.removeFacet(FacetNames.HIDDEN_IN_NAVIGATION));
assertFalse(doc.hasFacet("Aged"));
assertFalse(doc.hasFacet(FacetNames.HIDDEN_IN_NAVIGATION));
assertEquals(baseFacets, doc.getFacets());
}
@Test
public void testFacetIncludedInPrimaryType() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "foo", "DocWithAge");
doc.setPropertyValue("age:age", "123");
doc = session.createDocument(doc);
session.save();
// new session
reopenSession();
doc = session.getDocument(doc.getRef());
assertEquals("123", doc.getPropertyValue("age:age"));
// API on doc whose type has a facet
assertEquals(Collections.singleton("Aged"), doc.getFacets());
assertTrue(doc.hasFacet("Aged"));
assertFalse(doc.addFacet("Aged"));
assertFalse(doc.removeFacet("Aged"));
}
@Test
public void testFacetAddRemove() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "foo", "File");
doc = session.createDocument(doc);
session.save();
// mixin not there
try {
doc.getPropertyValue("age:age");
fail();
} catch (PropertyNotFoundException e) {
// ok
}
// add
assertTrue(doc.addFacet("Aged"));
doc.setPropertyValue("age:age", "123");
session.save();
// remove
assertTrue(doc.removeFacet("Aged"));
session.save();
// mixin not there anymore
try {
doc.getPropertyValue("age:age");
fail();
} catch (PropertyNotFoundException e) {
// ok
}
}
// mixin on doc with same schema in primary type does no harm
@Test
public void testFacetAddRemove2() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "foo", "DocWithAge");
doc.setPropertyValue("age:age", "123");
doc = session.createDocument(doc);
session.save();
assertFalse(doc.addFacet("Aged"));
assertEquals("123", doc.getPropertyValue("age:age"));
assertFalse(doc.removeFacet("Aged"));
assertEquals("123", doc.getPropertyValue("age:age"));
}
@Test
public void testFacetAddRemoveWhenSchemaAlreadyPresent() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "foo", "File");
doc.setPropertyValue("file:content", (Serializable) Blobs.createBlob("hello"));
doc = session.createDocument(doc);
session.save();
doc = session.getDocument(doc.getRef());
Blob blob = (Blob) doc.getPropertyValue("file:content");
assertEquals("hello", blob.getString());
// add WithFile facet, where file schema is already present in doc
assertTrue(doc.addFacet("WithFile"));
doc = session.saveDocument(doc);
session.save();
reopenSession();
// check getting the blob works (complex child "file:content" not re-added)
doc = session.getDocument(doc.getRef());
blob = (Blob) doc.getPropertyValue("file:content");
assertNotNull(blob);
assertEquals("hello", blob.getString());
// now remove facet
doc.removeFacet("WithFile");
doc = session.saveDocument(doc);
session.save();
reopenSession();
// schema still present because of primary type
doc = session.getDocument(doc.getRef());
blob = (Blob) doc.getPropertyValue("file:content");
assertNotNull(blob);
assertEquals("hello", blob.getString());
/*
* two facets with the same schema
*/
doc = new DocumentModelImpl("/", "bar", "Folder");
doc.addFacet("WithFile2");
doc.setPropertyValue("file:content", (Serializable) Blobs.createBlob("hello"));
doc = session.createDocument(doc);
session.save();
doc = session.getDocument(doc.getRef());
blob = (Blob) doc.getPropertyValue("file:content");
assertEquals("hello", blob.getString());
// add WithFile facet, where file schema is already present in doc
assertTrue(doc.addFacet("WithFile"));
doc = session.saveDocument(doc);
session.save();
reopenSession();
// check getting the blob works (complex child "file:content" not re-added)
doc = session.getDocument(doc.getRef());
blob = (Blob) doc.getPropertyValue("file:content");
assertNotNull(blob);
assertEquals("hello", blob.getString());
// now remove facet, but other facet WithFile2 is still present
doc.removeFacet("WithFile");
doc = session.saveDocument(doc);
session.save();
reopenSession();
// schema still present because of other facet
doc = session.getDocument(doc.getRef());
blob = (Blob) doc.getPropertyValue("file:content");
assertNotNull(blob);
assertEquals("hello", blob.getString());
}
@Test
public void testFacetWithSamePropertyName() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "foo", "File");
doc.setPropertyValue("dc:title", "bar");
doc = session.createDocument(doc);
session.save();
doc.addFacet("Aged");
doc.setPropertyValue("age:title", "gee");
doc = session.saveDocument(doc);
session.save();
assertEquals("bar", doc.getPropertyValue("dc:title"));
assertEquals("gee", doc.getPropertyValue("age:title"));
// refetch
doc = session.getDocument(doc.getRef());
assertEquals("bar", doc.getPropertyValue("dc:title"));
assertEquals("gee", doc.getPropertyValue("age:title"));
}
@Test
public void testFacetCopy() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "foo", "File");
doc.addFacet("Aged");
doc.setPropertyValue("age:age", "123");
doc = session.createDocument(doc);
session.save();
// copy the doc
DocumentModel copy = session.copy(doc.getRef(), session.getRootDocument().getRef(), "bar");
assertTrue(copy.hasFacet("Aged"));
assertEquals("123", copy.getPropertyValue("age:age"));
}
@Test
public void testFacetQueryContent() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "foo", "File");
doc.addFacet("Aged");
doc.setPropertyValue("age:age", "barbar");
doc = session.createDocument(doc);
session.save();
DocumentModelList list = session.query("SELECT * FROM File WHERE age:age = 'barbar'");
assertEquals(1, list.size());
}
@Test
public void testFacetRefresh() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "foo", "File");
doc = session.createDocument(doc);
assertFalse(doc.hasFacet("Aged"));
// fetch another DocumentModel instance of the same doc
DocumentModel doc2 = session.getDocument(doc.getRef());
// facet not yet present
assertFalse(doc2.hasFacet("Aged"));
// cannot write property
try {
doc2.setPropertyValue("age:age", "123");
fail();
} catch (PropertyNotFoundException e) {
// ok
}
// add facet in first doc
assertTrue(doc.addFacet("Aged"));
assertTrue(doc.hasFacet("Aged"));
doc.setPropertyValue("age:age", "123");
doc = session.saveDocument(doc);
// after refresh should be also visible in second doc
doc2.refresh();
assertTrue(doc2.hasFacet("Aged"));
assertEquals("123", doc2.getPropertyValue("age:age"));
// change value in first doc
doc.setPropertyValue("age:age", "456");
doc = session.saveDocument(doc);
// after refresh should be also visible in second doc
doc2.refresh();
assertTrue(doc2.hasFacet("Aged"));
assertEquals("456", doc2.getPropertyValue("age:age"));
// remove facet in first doc
assertTrue(doc.removeFacet("Aged"));
doc = session.saveDocument(doc);
// after refresh should be removed in second doc
doc2.refresh();
assertFalse(doc2.hasFacet("Aged"));
try {
doc2.setPropertyValue("age:age", "123");
fail();
} catch (PropertyNotFoundException e) {
// ok
}
// check immutable facet
DocumentRef verRef = doc.checkIn(VersioningOption.MINOR, null);
DocumentModel version = session.getDocument(verRef);
assertTrue(version.hasFacet(FacetNames.IMMUTABLE));
version.refresh();
assertTrue(version.hasFacet(FacetNames.IMMUTABLE));
// check that REFRESH_STATE does not overwrite facets
// this is called by doc.isCheckedOut() for instance
doc = session.getDocument(doc.getRef());
doc.addFacet("Aged");
assertTrue(doc.hasFacet("Aged"));
assertTrue(doc.hasSchema("age"));
doc.refresh(DocumentModel.REFRESH_STATE, null);
assertTrue(doc.hasFacet("Aged"));
assertTrue(doc.hasSchema("age"));
doc = session.saveDocument(doc);
doc.refresh(DocumentModel.REFRESH_ALL, null);
}
@Test
public void testLifeCycleAPI() {
DocumentModel root = session.getRootDocument();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), "file#" + generateUnique(), "File");
childFile = createChildDocument(childFile);
assertEquals("default", session.getLifeCyclePolicy(childFile.getRef()));
assertEquals("project", session.getCurrentLifeCycleState(childFile.getRef()));
Collection<String> allowedStateTransitions = session.getAllowedStateTransitions(childFile.getRef());
assertEquals(3, allowedStateTransitions.size());
assertTrue(allowedStateTransitions.contains("approve"));
assertTrue(allowedStateTransitions.contains("obsolete"));
assertTrue(allowedStateTransitions.contains("delete"));
assertTrue(session.followTransition(childFile.getRef(), "approve"));
assertEquals("approved", session.getCurrentLifeCycleState(childFile.getRef()));
allowedStateTransitions = session.getAllowedStateTransitions(childFile.getRef());
assertEquals(2, allowedStateTransitions.size());
assertTrue(allowedStateTransitions.contains("delete"));
assertTrue(allowedStateTransitions.contains("backToProject"));
session.reinitLifeCycleState(childFile.getRef());
assertEquals("project", session.getCurrentLifeCycleState(childFile.getRef()));
}
@Test
public void testLifeCycleVersioning() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), "file#" + generateUnique(), "File");
childFile = createChildDocument(childFile);
assertEquals("default", session.getLifeCyclePolicy(childFile.getRef()));
assertEquals("project", session.getCurrentLifeCycleState(childFile.getRef()));
assertTrue("Document should be checkout after creation", childFile.isCheckedOut());
session.checkIn(childFile.getRef(), VersioningOption.MAJOR, "Increment major version");
childFile = session.getDocument(childFile.getRef());
assertEquals("1.0", childFile.getVersionLabel());
assertFalse("Document should be checkin after version ", childFile.isCheckedOut());
boolean success = session.followTransition(childFile.getRef(), "approve");
assertTrue(success);
childFile = session.getDocument(childFile.getRef());
assertEquals("1.0+", childFile.getVersionLabel());
assertTrue("Document should be checkout after following a transition", childFile.isCheckedOut());
}
@Test
public void testDataModelLifeCycleAPI() {
DocumentModel root = session.getRootDocument();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), "file#" + generateUnique(), "File");
childFile = createChildDocument(childFile);
assertEquals("default", childFile.getLifeCyclePolicy());
assertEquals("project", childFile.getCurrentLifeCycleState());
Collection<String> allowedStateTransitions = childFile.getAllowedStateTransitions();
assertEquals(3, allowedStateTransitions.size());
assertTrue(allowedStateTransitions.contains("approve"));
assertTrue(allowedStateTransitions.contains("obsolete"));
assertTrue(allowedStateTransitions.contains("delete"));
assertTrue(childFile.followTransition("obsolete"));
assertEquals("obsolete", childFile.getCurrentLifeCycleState());
allowedStateTransitions = childFile.getAllowedStateTransitions();
assertEquals(2, allowedStateTransitions.size());
assertTrue(allowedStateTransitions.contains("delete"));
assertTrue(allowedStateTransitions.contains("backToProject"));
}
@Test
public void testCopy() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel folder1 = new DocumentModelImpl(root.getPathAsString(), "folder1", "Folder");
DocumentModel folder2 = new DocumentModelImpl(root.getPathAsString(), "folder2", "Folder");
DocumentModel file = new DocumentModelImpl(folder1.getPathAsString(), "file", "File");
folder1 = createChildDocument(folder1);
folder2 = createChildDocument(folder2);
file = createChildDocument(file);
session.save();
assertTrue(session.exists(new PathRef("/folder1/file")));
assertFalse(session.exists(new PathRef("/folder2/file")));
// copy using orig name
DocumentModel copy1 = session.copy(file.getRef(), folder2.getRef(), null);
assertTrue(session.exists(new PathRef("/folder1/file")));
assertTrue(session.exists(new PathRef("/folder2/file")));
assertFalse(session.exists(new PathRef("/folder2/fileCopy")));
assertTrue(session.getChildren(folder2.getRef()).contains(copy1));
// copy using another name
DocumentModel copy2 = session.copy(file.getRef(), folder2.getRef(), "fileCopy");
assertTrue(session.exists(new PathRef("/folder1/file")));
assertTrue(session.exists(new PathRef("/folder2/file")));
assertTrue(session.exists(new PathRef("/folder2/fileCopy")));
assertTrue(session.getChildren(folder2.getRef()).contains(copy2));
// copy again to same space
DocumentModel copy3 = session.copy(file.getRef(), folder2.getRef(), null);
assertTrue(session.exists(new PathRef("/folder1/file")));
assertTrue(session.exists(new PathRef("/folder2/file")));
assertTrue(session.getChildren(folder2.getRef()).contains(copy3));
assertNotSame(copy1.getName(), copy3.getName());
// copy again again to same space
if (SystemUtils.IS_OS_WINDOWS) {
// windows has too coarse time granularity for SQLSession.findFreeName
Thread.sleep(1000);
}
DocumentModel copy4 = session.copy(file.getRef(), folder2.getRef(), null);
assertTrue(session.exists(new PathRef("/folder1/file")));
assertTrue(session.exists(new PathRef("/folder2/file")));
assertTrue(session.getChildren(folder2.getRef()).contains(copy4));
assertNotSame(copy1.getName(), copy4.getName());
assertNotSame(copy3.getName(), copy4.getName());
// copy inplace
DocumentModel copy5 = session.copy(file.getRef(), folder1.getRef(), null);
assertTrue(session.exists(new PathRef("/folder1/file")));
assertTrue(session.exists(new PathRef("/folder2/file")));
assertTrue(session.getChildren(folder1.getRef()).contains(copy5));
assertNotSame(copy1.getName(), copy5.getName());
session.cancel();
}
@Test
public void testCopyProxyAsDocument() throws Exception {
// create a folder tree
DocumentModel root = session.getRootDocument();
DocumentModel folder1 = new DocumentModelImpl(root.getPathAsString(), "folder1", "Folder");
DocumentModel folder2 = new DocumentModelImpl(root.getPathAsString(), "folder2", "Folder");
DocumentModel folder3 = new DocumentModelImpl(root.getPathAsString(), "folder3", "Folder");
DocumentModel file = new DocumentModelImpl(folder1.getPathAsString(), "copyProxyAsDocument_test", "File");
folder1 = createChildDocument(folder1);
folder2 = createChildDocument(folder2);
folder3 = createChildDocument(folder3);
file = createChildDocument(file);
session.save();
// create a file in folder 1
file.setProperty("dublincore", "title", "the title");
file = session.saveDocument(file);
// create a proxy in folder2
DocumentModel proxy = session.publishDocument(file, folder2);
assertTrue(proxy.isProxy());
// copy proxy into folder3
DocumentModel copy1 = session.copyProxyAsDocument(proxy.getRef(), folder3.getRef(), null);
assertFalse(copy1.isProxy());
assertEquals(proxy.getName(), copy1.getName());
assertEquals(proxy.getProperty("dublincore", "title"), copy1.getProperty("dublincore", "title"));
// copy proxy using another name
DocumentModel copy2 = session.copyProxyAsDocument(proxy.getRef(), folder3.getRef(), "foo");
assertFalse(copy2.isProxy());
assertEquals("foo", copy2.getName());
assertEquals(file.getProperty("dublincore", "title"), copy2.getProperty("dublincore", "title"));
session.cancel();
}
@Test
public void testCopyVersionable() throws Exception {
DocumentModel note = new DocumentModelImpl("/", "note", "Note");
DocumentModel folder = new DocumentModelImpl("/", "folder", "Folder");
note = session.createDocument(note);
folder = session.createDocument(folder);
session.save();
assertTrue(session.exists(new PathRef("/note")));
assertTrue(session.exists(new PathRef("/folder")));
// only one version at first
List<DocumentRef> versions = session.getVersionsRefs(note.getRef());
assertEquals(1, versions.size());
// version the note
note.setProperty("dublincore", "title", "blah");
note.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MINOR);
session.saveDocument(note);
session.save();
// check versions
versions = session.getVersionsRefs(note.getRef());
assertEquals(2, versions.size());
// copy
DocumentModel copy = session.copy(note.getRef(), folder.getRef(), null);
// check no versions on copy
versions = session.getVersionsRefs(copy.getRef());
assertEquals(0, versions.size());
session.cancel();
}
@Test
public void testCopyFolderOfVersionable() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel folder = new DocumentModelImpl("/", "folder", "Folder");
DocumentModel note = new DocumentModelImpl("/folder", "note", "Note");
folder = session.createDocument(folder);
note = session.createDocument(note);
session.save();
assertTrue(session.exists(new PathRef("/folder")));
assertTrue(session.exists(new PathRef("/folder/note")));
// only one version at first
List<DocumentRef> versions = session.getVersionsRefs(note.getRef());
assertEquals(1, versions.size());
// version the note
note.setProperty("dublincore", "title", "blah");
note.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MINOR);
session.saveDocument(note);
session.save();
// check versions
versions = session.getVersionsRefs(note.getRef());
assertEquals(2, versions.size());
// copy folder, use an all-digit name to test for xpath escaping
DocumentModel copy = session.copy(folder.getRef(), root.getRef(), "123");
// check no versions on copied note
DocumentModel note2 = session.getChild(copy.getRef(), "note");
versions = session.getVersionsRefs(note2.getRef());
assertEquals(0, versions.size());
session.cancel();
}
@Test
public void testMove() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel folder1 = new DocumentModelImpl(root.getPathAsString(), "folder1", "Folder");
DocumentModel folder2 = new DocumentModelImpl(root.getPathAsString(), "folder2", "Folder");
DocumentModel file = new DocumentModelImpl(folder1.getPathAsString(), "file", "File");
folder1 = createChildDocument(folder1);
folder2 = createChildDocument(folder2);
file = createChildDocument(file);
assertTrue(session.exists(new PathRef("/folder1/file")));
assertFalse(session.exists(new PathRef("/folder2/file")));
assertFalse(session.exists(new PathRef("/folder1/fileMove")));
// move using orig name
session.move(file.getRef(), folder2.getRef(), null);
assertFalse(session.exists(new PathRef("/folder1/file")));
assertTrue(session.exists(new PathRef("/folder2/file")));
file = session.getChild(folder2.getRef(), "file");
session.move(file.getRef(), folder1.getRef(), "fileMove");
assertTrue(session.exists(new PathRef("/folder1/fileMove")));
DocumentModel file2 = new DocumentModelImpl(folder2.getPathAsString(), "file2", "File");
file2 = createChildDocument(file2);
assertTrue(session.exists(new PathRef("/folder2/file2")));
DocumentModel newFile2 = session.move(file.getRef(), folder2.getRef(), "file2"); // collision
String newName = newFile2.getName();
assertFalse("file2".equals(newName));
assertTrue(session.exists(new PathRef("/folder2/file2")));
assertTrue(session.exists(new PathRef("/folder2/" + newName)));
// move with null dest (rename)
DocumentModel newFile3 = session.move(file.getRef(), null, "file3");
assertEquals("file3", newFile3.getName());
}
@Test
public void testMoveConcurrentWithGetChild() throws Exception {
assumeTrue("VCS read-committed semantics cannot enforce this", isDBS());
prepareDocsForMoveConcurrentWithGetChildren();
try {
session.getChild(new PathRef("/folder"), "doc");
fail("should not find child moved under /folder in another transaction");
} catch (DocumentNotFoundException e) {
assertEquals("doc", e.getMessage());
}
}
@Test
public void testMoveConcurrentWithGetChildren() throws Exception {
assumeTrue("VCS read-committed semantics cannot enforce this", isDBS());
prepareDocsForMoveConcurrentWithGetChildren();
// should not find child moved under /folder in another transaction
DocumentModelList children = session.getChildren(new PathRef("/folder"));
assertEquals(0, children.size());
}
@Test
public void testMoveConcurrentWithGetChildrenRefs() throws Exception {
assumeTrue("VCS read-committed semantics cannot enforce this", isDBS());
prepareDocsForMoveConcurrentWithGetChildren();
// should not find child moved under /folder in another transaction
List<DocumentRef> children = session.getChildrenRefs(new PathRef("/folder"), null);
assertEquals(0, children.size());
}
protected void prepareDocsForMoveConcurrentWithGetChildren() throws Exception {
// create folder
DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
folder = session.createDocument(folder);
// create doc outside of folder
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
doc = session.createDocument(doc);
session.save();
nextTransaction();
// load doc as DBS transient
session.getDocument(doc.getRef());
// in other thread, move doc into folder
MutableObject<RuntimeException> me = new MutableObject<>();
Thread thread = new Thread(() -> {
TransactionHelper.runInTransaction(() -> {
try (CoreSession session2 = CoreInstance.openCoreSession(coreFeature.getRepositoryName())) {
session2.move(new PathRef("/doc"), new PathRef("/folder"), null);
session2.save();
} catch (RuntimeException e) {
me.setValue(e);
}
});
});
thread.start();
thread.join();
if (me.getValue() != null) {
throw new RuntimeException(me.getValue());
}
}
// TODO NXP-2514: fix this test
@Test
@Ignore
public void testScalarList() throws Exception {
DocumentModel root = session.getRootDocument();
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
childFile = createChildDocument(childFile);
String[] str = { "a", "b", "c" };
childFile.setProperty("dublincore", "participants", str);
session.saveDocument(childFile);
childFile = session.getChild(root.getRef(), childFile.getName());
str = (String[]) childFile.getProperty("dublincore", "participants");
assertNotNull(str);
List<String> list = Arrays.asList(str);
assertTrue(list.contains("a"));
assertTrue(list.contains("b"));
assertTrue(list.contains("c"));
// modify the array
str = new String[] { "a", "b" };
childFile.setProperty("dublincore", "participants", str);
session.saveDocument(childFile);
str = (String[]) childFile.getProperty("dublincore", "participants");
childFile = session.getChild(root.getRef(), childFile.getName());
str = (String[]) childFile.getProperty("dublincore", "participants");
assertNotNull(str);
list = Arrays.asList(str);
assertTrue(list.contains("a"));
assertTrue(list.contains("b"));
}
@Test
public void testBlob() throws Exception {
DocumentModel root = session.getRootDocument();
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
childFile = createChildDocument(childFile);
session.save();
byte[] bytes = IOUtils.toByteArray(Blob.class.getResourceAsStream("Blob.class"));
Blob blob = Blobs.createBlob(bytes, "java/class", "UTF8");
blob.setFilename("blob.txt");
blob.setDigest("XXX");
long length = blob.getLength();
byte[] content = blob.getByteArray();
childFile.setProperty("dublincore", "title", "Blob test");
childFile.setProperty("dublincore", "description", "this is a test");
childFile.setProperty("file", "content", blob);
session.saveDocument(childFile);
childFile = session.getDocument(childFile.getRef());
blob = (Blob) childFile.getProperty("file", "content");
// digest algorithm is null for any type of blob other than BinaryBlob
assertNull(blob.getDigestAlgorithm());
assertEquals("XXX", blob.getDigest());
assertEquals("blob.txt", blob.getFilename());
assertEquals(length, blob.getLength());
assertEquals("UTF8", blob.getEncoding());
assertEquals("java/class", blob.getMimeType());
assertTrue(Arrays.equals(content, blob.getByteArray()));
// blob from a stream, with no known length
URL url = getClass().getClassLoader().getResource("META-INF/MANIFEST.MF");
blob = new URLBlob(url, "java/manifest", null);
blob.setFilename("manifest.mf");
blob.setDigest("YYY");
childFile.setPropertyValue("content", (Serializable) blob);
session.saveDocument(childFile);
childFile = session.getDocument(childFile.getRef());
blob = (Blob) childFile.getPropertyValue("content");
assertEquals("YYY", blob.getDigest());
assertEquals("manifest.mf", blob.getFilename());
assertEquals(null, blob.getEncoding());
assertEquals("java/manifest", blob.getMimeType());
assertEquals(IOUtils.toByteArray(url).length, blob.getLength());
}
@Test
public void testRetrieveSamePropertyInAncestors() {
DocumentModel root = session.getRootDocument();
DocumentModel folder1 = new DocumentModelImpl(root.getPathAsString(), "folder1", "Folder");
folder1 = createChildDocument(folder1);
folder1.setProperty("dublincore", "title", "folder #1");
assertEquals("folder #1", folder1.getProperty("dublincore", "title"));
DocumentModel folder2 = new DocumentModelImpl(folder1.getPathAsString(), "folder2", "Folder");
folder2 = createChildDocument(folder2);
folder2.setProperty("dublincore", "title", "folder #2");
assertEquals("folder #2", folder2.getProperty("dublincore", "title"));
DocumentModel file = new DocumentModelImpl(folder2.getPathAsString(), "file", "File");
file = createChildDocument(file);
file.setProperty("dublincore", "title", "file ##");
assertEquals("file ##", file.getProperty("dublincore", "title"));
assertTrue(session.exists(new PathRef("/folder1")));
assertTrue(session.exists(new PathRef("/folder1/folder2")));
assertTrue(session.exists(new PathRef("/folder1/folder2/file")));
// need to save them before getting properties from schemas...
session.saveDocument(folder1);
session.saveDocument(folder2);
session.saveDocument(file);
session.save();
final DocumentRef[] ancestorRefs = session.getParentDocumentRefs(file.getRef());
assertNotNull(ancestorRefs);
assertEquals(3, ancestorRefs.length);
assertEquals(folder2.getRef(), ancestorRefs[0]);
assertEquals(folder1.getRef(), ancestorRefs[1]);
assertEquals(root.getRef(), ancestorRefs[2]);
final Object[] fieldValues = session.getDataModelsField(ancestorRefs, "dublincore", "title");
assertNotNull(fieldValues);
assertEquals(3, fieldValues.length);
assertEquals("folder #2", fieldValues[0]);
assertEquals("folder #1", fieldValues[1]);
final Object[] fieldValuesBis = session.getDataModelsFieldUp(file.getRef(), "dublincore", "title");
assertNotNull(fieldValuesBis);
assertEquals(4, fieldValuesBis.length);
assertEquals("file ##", fieldValuesBis[0]);
assertEquals("folder #2", fieldValuesBis[1]);
assertEquals("folder #1", fieldValuesBis[2]);
}
// TODO NXP-2514: fix and reenable.
@Test
@Ignore
public void testDocumentAdapter() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel file = new DocumentModelImpl(root.getPathAsString(), "file", "File");
file = createChildDocument(file);
/*
* AnnotatedDocument adoc = file.getAdapter(AnnotatedDocument.class); assertNotNull(adoc);
* adoc.putAnnotation("key1", "val1"); adoc.putAnnotation("key2", "val2"); assertEquals("val1",
* adoc.getAnnotation("key1")); assertEquals("val2", adoc.getAnnotation("key2")); adoc =
* file.getAdapter(AnnotatedDocument.class); assertEquals("val1", adoc.getAnnotation("key1"));
* assertEquals("val2", adoc.getAnnotation("key2"));
*/
}
@Test
public void testGetSourceId() {
DocumentModel root = session.getRootDocument();
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
childFile = createChildDocument(childFile);
// Same identifier here since no version yet.
String sourceId = childFile.getSourceId();
assertNotNull(sourceId);
assertEquals(childFile.getId(), sourceId);
session.save();
session.checkIn(childFile.getRef(), null, null);
// Different source ids now.
assertNotNull(childFile.getSourceId());
assertEquals(sourceId, childFile.getSourceId());
// TODO NXP-2514: look at this test.
// assertFalse(childFile.getId().equals(childFile.getSourceId()));
}
@Test
public void testGetRepositoryName() {
DocumentModel root = session.getRootDocument();
String name2 = "file#" + generateUnique();
DocumentModel childFile = new DocumentModelImpl(root.getPathAsString(), name2, "File");
childFile = createChildDocument(childFile);
assertNotNull(childFile.getRepositoryName());
assertEquals("test", childFile.getRepositoryName());
}
// TODO NXP-2514: fix and reenable, is this a bug?
@Test
@Ignore
public void testRetrieveProxies() {
DocumentModel root = session.getRootDocument();
// Section A
String name = "section" + generateUnique();
DocumentModel sectionA = new DocumentModelImpl(root.getPathAsString(), name, "Section");
sectionA = createChildDocument(sectionA);
assertEquals("Section", sectionA.getType());
assertEquals(name, sectionA.getName());
// Section B
name = "section" + generateUnique();
DocumentModel sectionB = new DocumentModelImpl(root.getPathAsString(), name, "Section");
sectionB = createChildDocument(sectionB);
assertEquals("Section", sectionB.getType());
assertEquals(name, sectionB.getName());
// File
name = "file" + generateUnique();
DocumentModel file = new DocumentModelImpl(root.getPathAsString(), name, "File");
file = createChildDocument(file);
assertEquals("File", file.getType());
assertEquals(name, file.getName());
// Versioning
// session.saveDocumentAsNewVersion(file);
// Publishing
session.publishDocument(file, sectionA);
// session.publishDocument(file, sectionB);
// Retrieving proxies
DocumentModelList proxies = session.getProxies(file.getRef(), sectionA.getRef());
assertFalse(proxies.isEmpty());
assertEquals(1, proxies.size());
// assertEquals(2, proxies.size());
}
@Test
public void testCreateDocumentModel() {
// first method: only the typename
DocumentModel docModel = session.createDocumentModel("File");
assertEquals("File", docModel.getType());
// bad type should fail
try {
session.createDocumentModel("NotAValidTypeName");
fail();
} catch (IllegalArgumentException e) {
}
// same as previously with path info
docModel = session.createDocumentModel("/path/to/parent", "some-id", "File");
assertEquals("File", docModel.getType());
assertEquals("/path/to/parent/some-id", docModel.getPathAsString());
// providing additional contextual data to feed a core event listener
// with
Map<String, Object> context = new HashMap<String, Object>();
context.put("Meteo", "Today is a beautiful day");
docModel = session.createDocumentModel("File", context);
assertEquals("File", docModel.getType());
}
@SuppressWarnings({ "unchecked" })
@Test
public void testCopyContent() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "original", "File");
doc.setProperty("dublincore", "title", "t");
doc.setProperty("dublincore", "description", "d");
doc.setProperty("dublincore", "subjects", new String[] { "a", "b" });
List<Object> files = new ArrayList<>(1);
Map<String, Object> f = new HashMap<>();
f.put("file", Blobs.createBlob("myfile", "text/test", "UTF-8"));
files.add(f);
doc.setProperty("files", "files", files);
// add a dynamic facet too
doc.addFacet("Aged");
doc.setPropertyValue("age:age", "123");
doc = session.createDocument(doc);
session.save();
DocumentModel copy = new DocumentModelImpl(root.getPathAsString(), "copy", "File");
copy.copyContent(doc);
copy = session.createDocument(copy);
session.save();
assertEquals("t", copy.getProperty("dublincore", "title"));
assertEquals("d", copy.getProperty("dublincore", "description"));
assertEquals(Arrays.asList("a", "b"), Arrays.asList((String[]) copy.getProperty("dublincore", "subjects")));
Object fileso = copy.getProperty("files", "files");
assertNotNull(fileso);
List<Map<String, Object>> newfiles = (List<Map<String, Object>>) fileso;
assertEquals(1, newfiles.size());
Blob bb = (Blob) newfiles.get(0).get("file");
assertNotNull(bb);
assertEquals("text/test", bb.getMimeType());
assertEquals("UTF-8", bb.getEncoding());
String content = bb.getString();
assertEquals("myfile", content);
// check dynamic facet
assertTrue(copy.hasFacet("Aged"));
assertEquals("123", copy.getPropertyValue("age:age"));
}
@Test
public void testCopyContentTransTyping() {
DocumentModel note = session.createDocumentModel("/", "original", "Note");
note.setPropertyValue("dc:title", "a title");
note.setPropertyValue("note:note", "this is a note");
note.setPropertyValue("note:mime_type", "text/plain");
// add a dynamic facet too
note.addFacet("Aged");
note.setPropertyValue("age:age", "123");
note = session.createDocument(note);
session.save();
DocumentModel copy = session.createDocumentModel("/", "copy", "File");
copy.copyContent(note);
copy = session.createDocument(copy);
session.save();
assertEquals("a title", copy.getPropertyValue("dc:title"));
// the note schema was dropped as it's not present in File
// check dynamic facet
assertTrue(copy.hasFacet("Aged"));
assertEquals("123", copy.getPropertyValue("age:age"));
}
// ------------------------------------
// ----- copied from TestLocalAPI -----
// ------------------------------------
@Test
public void testPropertyModel() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "theDoc", "MyDocType");
doc = session.createDocument(doc);
DocumentPart dp = doc.getPart("myschema");
Property p = dp.get("long");
assertTrue(p.isPhantom());
assertNull(p.getValue());
p.setValue(12);
assertEquals(new Long(12), p.getValue());
session.saveDocument(doc);
dp = doc.getPart("myschema");
p = dp.get("long");
assertFalse(p.isPhantom());
assertEquals(new Long(12), p.getValue());
p.setValue(null);
assertFalse(p.isPhantom());
assertNull(p.getValue());
session.saveDocument(doc);
dp = doc.getPart("myschema");
p = dp.get("long");
// assertTrue(p.isPhantom());
assertNull(p.getValue());
p.setValue(new Long(13));
p.remove();
assertTrue(p.isRemoved());
assertNull(p.getValue());
session.saveDocument(doc);
dp = doc.getPart("myschema");
p = dp.get("long");
// assertTrue(p.isPhantom()); not applicable to SQL
assertNull(p.getValue());
}
@Test
public void testOrdering() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel parent = new DocumentModelImpl(root.getPathAsString(), "theParent", "OrderedFolder");
parent = session.createDocument(parent);
DocumentModel doc1 = new DocumentModelImpl(parent.getPathAsString(), "the1", "File");
doc1 = session.createDocument(doc1);
DocumentModel doc2 = new DocumentModelImpl(parent.getPathAsString(), "the2", "File");
doc2 = session.createDocument(doc2);
session.save(); // XXX
String name1 = doc1.getName();
String name2 = doc2.getName();
DocumentModelList children = session.getChildren(parent.getRef());
assertEquals(2, children.size());
assertEquals(name1, children.get(0).getName());
assertEquals(name2, children.get(1).getName());
assertEquals(Long.valueOf(0), children.get(0).getPos());
assertEquals(Long.valueOf(1), children.get(1).getPos());
session.orderBefore(parent.getRef(), name2, name1);
children = session.getChildren(parent.getRef());
assertEquals(2, children.size());
assertEquals(name2, children.get(0).getName());
assertEquals(name1, children.get(1).getName());
assertEquals(Long.valueOf(0), children.get(0).getPos());
assertEquals(Long.valueOf(1), children.get(1).getPos());
session.orderBefore(parent.getRef(), name2, null);
children = session.getChildren(parent.getRef());
assertEquals(2, children.size());
assertEquals(name1, children.get(0).getName());
assertEquals(name2, children.get(1).getName());
assertEquals(Long.valueOf(0), children.get(0).getPos());
assertEquals(Long.valueOf(1), children.get(1).getPos());
// check in a non-ordered folder
DocumentModel parent2 = session.createDocumentModel("/", "folder", "Folder");
parent2 = session.createDocument(parent2);
DocumentModel doc3 = session.createDocumentModel("/folder", "doc3", "MyDocType");
doc3 = session.createDocument(doc3);
session.save();
doc3 = session.getDocument(doc3.getRef());
assertNull(doc3.getPos());
}
@Test
public void testOrderingAfterCopy() throws Exception {
DocumentModel folder = session.createDocumentModel("/", "folder", "OrderedFolder");
folder = session.createDocument(folder);
DocumentModel doc1 = session.createDocumentModel("/folder", "doc1", "File");
doc1 = session.createDocument(doc1);
DocumentModel doc2 = session.createDocumentModel("/folder", "doc2", "File");
doc2 = session.createDocument(doc2);
// copy doc1 as doc3, should be positioned last
session.copy(doc1.getRef(), folder.getRef(), "doc3");
DocumentModelList children = session.getChildren(folder.getRef());
assertEquals(3, children.size());
assertEquals("doc1", children.get(0).getName());
assertEquals("doc2", children.get(1).getName());
assertEquals("doc3", children.get(2).getName());
}
@Test
public void testPropertyXPath() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel parent = new DocumentModelImpl(root.getPathAsString(), "theParent", "OrderedFolder");
parent = session.createDocument(parent);
DocumentModel doc = new DocumentModelImpl(parent.getPathAsString(), "theDoc", "File");
doc.setProperty("dublincore", "title", "my title");
assertEquals("my title", doc.getPropertyValue("title"));
assertEquals("my title", doc.getPropertyValue("dc:title"));
}
@SuppressWarnings("rawtypes")
@Test
public void testComplexList() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "mydoc", "MyDocType");
doc = session.createDocument(doc);
List list = (List) doc.getProperty("testList", "attachments");
assertNotNull(list);
assertTrue(list.isEmpty());
ListDiff diff = new ListDiff();
/*
* diff.add(new Attachment("at1", "value1").asMap()); diff.add(new Attachment("at2", "value2").asMap());
* doc.setProperty("testList", "attachments", diff); doc = session.saveDocument(doc); list = (List)
* doc.getProperty("testList", "attachments"); assertNotNull(list); assertEquals(2, list.size()); Blob blob;
* blob = (Blob) ((Map) list.get(0)).get("content"); assertEquals("value1", blob.getString()); blob = (Blob)
* ((Map) list.get(1)).get("content"); assertEquals("value2", blob.getString()); diff = new ListDiff();
* diff.remove(0); diff.insert(0, new Attachment("at1.bis", "value1.bis").asMap()); doc.setProperty("testList",
* "attachments", diff); doc = session.saveDocument(doc); list = (List) doc.getProperty("testList",
* "attachments"); assertNotNull(list); assertEquals(2, list.size()); blob = (Blob) ((Map)
* list.get(0)).get("content"); assertEquals("value1.bis", blob.getString()); blob = (Blob) ((Map)
* list.get(1)).get("content"); assertEquals("value2", blob.getString()); diff = new ListDiff(); diff.move(0,
* 1); doc.setProperty("testList", "attachments", diff); doc = session.saveDocument(doc); list = (List)
* doc.getProperty("testList", "attachments"); assertNotNull(list); assertEquals(2, list.size()); blob = (Blob)
* ((Map) list.get(0)).get("content"); assertEquals("value2", blob.getString()); blob = (Blob) ((Map)
* list.get(1)).get("content"); assertEquals("value1.bis", blob.getString()); diff = new ListDiff();
* diff.removeAll(); doc.setProperty("testList", "attachments", diff); doc = session.saveDocument(doc); list =
* (List) doc.getProperty("testList", "attachments"); assertNotNull(list); assertEquals(0, list.size());
*/
}
@Test
public void testDataModel() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "mydoc", "Book");
doc = session.createDocument(doc);
DataModel dm = doc.getDataModel("book");
dm.setValue("title", "my title");
assertEquals("my title", dm.getValue("title"));
dm.setValue("title", "my title2");
assertEquals("my title2", dm.getValue("title"));
dm.setValue("price", 123);
assertEquals(123L, dm.getValue("price"));
dm.setValue("price", 124);
assertEquals(124L, dm.getValue("price"));
dm.setValue("author/pJob", "Programmer");
assertEquals("Programmer", dm.getValue("author/pJob"));
dm.setValue("author/pJob", "Programmer2");
assertEquals("Programmer2", dm.getValue("author/pJob"));
dm.setValue("author/pName/FirstName", "fname");
assertEquals("fname", dm.getValue("author/pName/FirstName"));
dm.setValue("author/pName/FirstName", "fname2");
assertEquals("fname2", dm.getValue("author/pName/FirstName"));
// list test
doc = new DocumentModelImpl(root.getPathAsString(), "mydoc2", "MyDocType");
doc = session.createDocument(doc);
List list = (List) doc.getProperty("testList", "attachments");
assertNotNull(list);
assertTrue(list.isEmpty());
ListDiff diff = new ListDiff();
/*
* diff.add(new Attachment("at1", "value1").asMap()); diff.add(new Attachment("at2", "value2").asMap());
* doc.setProperty("testList", "attachments", diff); doc = session.saveDocument(doc); dm =
* doc.getDataModel("testList"); dm.setValue("attachments/item[0]/name", "at1-modif"); assertEquals("at1-modif",
* dm.getValue("attachments/item[0]/name")); dm.setValue("attachments/item[0]/name", "at1-modif2");
* assertEquals("at1-modif2", dm.getValue("attachments/item[0]/name")); dm.setValue("attachments/item[1]/name",
* "at2-modif"); assertEquals("at2-modif", dm.getValue("attachments/item[1]/name"));
* dm.setValue("attachments/item[1]/name", "at2-modif2"); assertEquals("at2-modif2",
* dm.getValue("attachments/item[1]/name"));
*/
}
@Test
public void testGetChildrenRefs() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "mydoc", "Book");
doc = session.createDocument(doc);
DocumentModel doc2 = new DocumentModelImpl(root.getPathAsString(), "mydoc2", "MyDocType");
doc2 = session.createDocument(doc2);
List<DocumentRef> childrenRefs = session.getChildrenRefs(root.getRef(), null);
assertEquals(2, childrenRefs.size());
Set<String> expected = new HashSet<>();
expected.add(doc.getId());
expected.add(doc2.getId());
Set<String> actual = new HashSet<>();
actual.add(childrenRefs.get(0).toString());
actual.add(childrenRefs.get(1).toString());
assertEquals(expected, actual);
}
@Test
public void testProxyChildren() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc1 = new DocumentModelImpl(root.getPathAsString(), "doc1", "Book");
doc1 = session.createDocument(doc1);
DocumentModel doc2 = new DocumentModelImpl(root.getPathAsString(), "doc2", "Book");
doc2 = session.createDocument(doc2);
// create proxy pointing to doc1
DocumentModel proxy1 = session.publishDocument(doc1, root);
// check proxy1 children methods
DocumentModelList children = session.getChildren(proxy1.getRef());
assertEquals(0, children.size());
assertFalse(session.hasChildren(proxy1.getRef()));
// create proxy pointing to doc2, under proxy1
DocumentModel proxy2 = session.publishDocument(doc2, proxy1);
session.save();
// check that sub proxy really exists
assertEquals(proxy2, session.getDocument(proxy2.getRef()));
// check proxy1 children methods
children = session.getChildren(proxy1.getRef());
assertEquals(1, children.size());
assertEquals(proxy2, children.get(0));
assertEquals(proxy2, session.getChild(proxy1.getRef(), proxy2.getName()));
assertTrue(session.hasChildren(proxy1.getRef()));
}
public static byte[] createBytes(int size, byte val) {
byte[] bytes = new byte[size];
Arrays.fill(bytes, val);
return bytes;
}
@Test
public void testBlob2() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "mydoc", "File");
doc = session.createDocument(doc);
byte[] bytes = createBytes(1024 * 1024, (byte) 24);
Blob blob = Blobs.createBlob(bytes);
doc.getPart("file").get("content").setValue(blob);
doc = session.saveDocument(doc);
blob = (Blob) doc.getPart("file").get("content").getValue();
assertTrue(Arrays.equals(bytes, blob.getByteArray()));
// reset not implemented (not needed) for StorageBlob's Binary
// XXX blob.getStream().reset();
blob = (Blob) doc.getPart("file").get("content").getValue();
assertTrue(Arrays.equals(bytes, blob.getByteArray()));
}
@Test
public void testProxy() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "proxy_test", "File");
doc = session.createDocument(doc);
doc.setProperty("dublincore", "title", "the title");
doc = session.saveDocument(doc);
DocumentModel proxy = session.publishDocument(doc, root);
session.save();
// re-modify doc
doc.setProperty("dublincore", "title", "the title modified");
doc = session.saveDocument(doc);
assertEquals("the title", proxy.getProperty("dublincore", "title"));
assertEquals("the title modified", doc.getProperty("dublincore", "title"));
// make another proxy
maybeSleepToNextSecond();
session.publishDocument(doc, root);
DocumentModelList list = session.getChildren(root.getRef());
assertEquals(2, list.size());
for (DocumentModel model : list) {
assertEquals("File", model.getType());
}
session.removeDocument(proxy.getRef());
session.save();
waitForAsyncCompletion(); // orphan version removal
session.save(); // process invalidations
list = session.getChildren(root.getRef());
assertEquals(1, list.size());
// create folder to hold proxies
DocumentModel folder = new DocumentModelImpl(root.getPathAsString(), "folder", "Folder");
folder = session.createDocument(folder);
session.save();
folder = session.getDocument(folder.getRef());
// publishDocument API
proxy = session.publishDocument(doc, root);
session.save(); // needed for publish-by-copy to work
assertEquals(3, session.getChildrenRefs(root.getRef(), null).size());
assertTrue(proxy.isProxy());
assertFalse(proxy.isVersion());
assertTrue(proxy.isImmutable());
assertTrue(proxy.hasFacet(FacetNames.IMMUTABLE)); // dynamic facet
assertTrue(proxy.hasFacet(FacetNames.VERSIONABLE)); // facet from type
// republish a proxy
DocumentModel proxy2 = session.publishDocument(proxy, folder);
session.save();
assertTrue(proxy2.isProxy());
assertFalse(proxy2.isVersion());
assertTrue(proxy2.isImmutable());
assertEquals(1, session.getChildrenRefs(folder.getRef(), null).size());
assertEquals(3, session.getChildrenRefs(root.getRef(), null).size());
// a second time to check overwrite
session.publishDocument(proxy, folder);
session.save();
assertEquals(1, session.getChildrenRefs(folder.getRef(), null).size());
assertEquals(3, session.getChildrenRefs(root.getRef(), null).size());
// and without overwrite
session.publishDocument(proxy, folder, false);
session.save();
assertEquals(2, session.getChildrenRefs(folder.getRef(), null).size());
assertEquals(3, session.getChildrenRefs(root.getRef(), null).size());
// publish a restored version
List<DocumentRef> versions = session.getVersionsRefs(doc.getRef());
assertEquals(2, versions.size());
doc = session.restoreToVersion(doc.getRef(), versions.get(0));
assertEquals("0.1", doc.getVersionLabel());
proxy = session.publishDocument(doc, folder);
assertEquals("0.1", proxy.getVersionLabel());
// publish a version directly
DocumentModel ver = session.getLastDocumentVersion(doc.getRef());
DocumentModel proxy3 = session.publishDocument(ver, folder, false);
session.save();
assertFalse(proxy3.isVersion());
assertTrue(proxy3.isProxy());
assertEquals(doc.getVersionSeriesId(), proxy3.getVersionSeriesId());
assertEquals(ver.getVersionLabel(), proxy3.getVersionLabel());
}
@Test
public void testProxyLive() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "proxy_test", "File");
doc = session.createDocument(doc);
doc.setProperty("dublincore", "title", "the title");
doc = session.saveDocument(doc);
session.save();
// create live proxy
DocumentModel proxy = session.createProxy(doc.getRef(), root.getRef());
assertTrue(proxy.isProxy());
assertFalse(proxy.isVersion());
assertFalse(proxy.isImmutable());
session.save();
assertEquals("the title", proxy.getProperty("dublincore", "title"));
assertEquals("the title", doc.getProperty("dublincore", "title"));
// modify live doc
doc.setProperty("dublincore", "title", "the title modified");
doc = session.saveDocument(doc);
session.save();
// check visible from proxy
proxy = session.getDocument(proxy.getRef());
assertTrue(proxy.isProxy());
assertFalse(proxy.isVersion());
assertFalse(proxy.isImmutable());
assertEquals("the title modified", proxy.getProperty("dublincore", "title"));
// modify proxy
proxy.setProperty("dublincore", "title", "the title again");
proxy = session.saveDocument(proxy);
session.save();
// check visible from live doc
doc = session.getDocument(doc.getRef());
assertEquals("the title again", doc.getProperty("dublincore", "title"));
}
@Test
public void testProxySchemas() throws Exception {
DocumentModel folder = new DocumentModelImpl("/", "folder", "Folder");
folder = session.createDocument(folder);
DocumentModel doc = new DocumentModelImpl("/", "file", "File");
doc = session.createDocument(doc);
DocumentModel proxy = session.publishDocument(doc, folder);
session.save();
try {
doc.setPropertyValue("info:info", "docinfo");
doc = session.saveDocument(doc);
session.save();
} catch (PropertyNotFoundException e) {
assertTrue(e.getMessage().contains("info:info"));
}
assertNull(proxy.getPropertyValue("info:info"));
proxy.setPropertyValue("info:info", "proxyinfo");
proxy = session.saveDocument(proxy);
session.save();
// new session
reopenSession();
DocumentModel root = session.getRootDocument();
proxy = session.getDocument(proxy.getRef());
assertEquals("proxyinfo", proxy.getPropertyValue("info:info"));
// test a query
String nxql;
DocumentModelList list;
nxql = "SELECT * FROM Document WHERE info:info = 'proxyinfo' AND ecm:isProxy = 1";
list = session.query(nxql);
assertEquals(1, list.size());
nxql = "SELECT * FROM Document WHERE info:info = 'proxyinfo'";
list = session.query(nxql);
assertEquals(1, list.size());
nxql = "SELECT * FROM Document WHERE info:info = 'proxyinfo' AND ecm:isProxy = 0";
list = session.query(nxql);
assertEquals(0, list.size());
// queryAndFetch
nxql = "SELECT ecm:uuid, info:info FROM File WHERE info:info IS NOT NULL";
IterableQueryResult res = session.queryAndFetch(nxql, "NXQL");
Map<Serializable, String> actual = new HashMap<>();
for (Map<String, Serializable> map : res) {
Serializable uuid = map.get("ecm:uuid");
String info = (String) map.get("info:info");
actual.put(uuid.toString(), info); // toString() for sequence ids
}
res.close();
assertEquals(Collections.singletonMap(proxy.getId(), "proxyinfo"), actual);
// test that the copy has the extra schema values
session.copy(folder.getRef(), root.getRef(), "folderCopy");
DocumentModel proxyCopy = session.getDocument(new PathRef("/folderCopy/file"));
assertTrue(proxyCopy.isProxy());
assertEquals("proxyinfo", proxyCopy.getPropertyValue("info:info"));
}
@Test
public void testUpdatePublishedDocument() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "proxy_test", "File");
doc = session.createDocument(doc);
doc.setProperty("dublincore", "title", "the title");
doc = session.saveDocument(doc);
// create folder to hold proxies
DocumentModel folder = new DocumentModelImpl(root.getPathAsString(), "folder", "Folder");
folder = session.createDocument(folder);
session.save();
folder = session.getDocument(folder.getRef());
// publishDocument API
DocumentModel proxy = session.publishDocument(doc, folder);
session.save();
assertEquals(1, session.getChildrenRefs(folder.getRef(), null).size());
assertEquals("the title", proxy.getProperty("dublincore", "title"));
assertEquals("the title", doc.getProperty("dublincore", "title"));
assertTrue(proxy.isProxy());
assertFalse(proxy.isVersion());
// republish a proxy
DocumentModel proxy2 = session.publishDocument(doc, folder);
session.save();
assertTrue(proxy2.isProxy());
assertFalse(proxy2.isVersion());
assertEquals(1, session.getChildrenRefs(folder.getRef(), null).size());
assertEquals(proxy.getId(), proxy2.getId());
}
@Test
public void testImport() throws Exception {
DocumentModel folder = new DocumentModelImpl("/", "folder", "Folder");
folder.setProperty("dublincore", "title", "the title");
folder = session.createDocument(folder);
session.save();
String folderId = folder.getId();
// create a version by import
String id; // versionable
String vid; // ver id
String pid; // proxy id
if (folderId.length() == 36) {
id = "aaaaaaaa-1234-1234-1234-fedcba987654";
vid = "12345678-1234-1234-1234-fedcba987654";
pid = "00000000-1234-1234-1234-fedcba987654";
} else {
id = "888001";
vid = "777002";
pid = "666003";
}
String typeName = "File";
DocumentRef parentRef = null;
String name = "foobar";
DocumentModel ver = new DocumentModelImpl((String) null, typeName, vid, new Path(name), null, null, parentRef,
null, null, null, null);
Calendar vcr = new GregorianCalendar(2009, Calendar.JANUARY, 1, 2, 3, 4);
ver.putContextData(CoreSession.IMPORT_VERSION_VERSIONABLE_ID, id);
ver.putContextData(CoreSession.IMPORT_VERSION_CREATED, vcr);
ver.putContextData(CoreSession.IMPORT_VERSION_LABEL, "v1");
ver.putContextData(CoreSession.IMPORT_VERSION_DESCRIPTION, "v descr");
ver.putContextData(CoreSession.IMPORT_IS_VERSION, Boolean.TRUE);
ver.putContextData(CoreSession.IMPORT_VERSION_IS_LATEST, Boolean.TRUE);
ver.putContextData(CoreSession.IMPORT_VERSION_IS_LATEST_MAJOR, Boolean.FALSE);
ver.putContextData(CoreSession.IMPORT_VERSION_MAJOR, Long.valueOf(3));
ver.putContextData(CoreSession.IMPORT_VERSION_MINOR, Long.valueOf(14));
ver.putContextData(CoreSession.IMPORT_LIFECYCLE_POLICY, "v lcp");
ver.putContextData(CoreSession.IMPORT_LIFECYCLE_STATE, "v lcst");
ver.setProperty("dublincore", "title", "Ver title");
Calendar mod = new GregorianCalendar(2008, Calendar.JULY, 14, 12, 34, 56);
ver.setProperty("dublincore", "modified", mod);
session.importDocuments(Collections.singletonList(ver));
session.save();
reopenSession();
ver = session.getDocument(new IdRef(vid));
// assertEquals(name, doc.getName()); // no path -> no name...
assertEquals("Ver title", ver.getProperty("dublincore", "title"));
assertEquals(mod, ver.getProperty("dublincore", "modified"));
assertEquals("v lcp", ver.getLifeCyclePolicy());
assertEquals("v lcst", ver.getCurrentLifeCycleState());
assertEquals(Long.valueOf(3), ver.getProperty("uid", "major_version"));
assertEquals(Long.valueOf(14), ver.getProperty("uid", "minor_version"));
assertTrue(ver.isVersion());
assertFalse(ver.isProxy());
// lookup version by label
VersionModel versionModel = new VersionModelImpl();
versionModel.setLabel("v1");
ver = session.getVersion(id, versionModel);
assertNotNull(ver);
assertEquals(vid, ver.getId());
assertEquals("v descr", versionModel.getDescription());
assertEquals(vcr, versionModel.getCreated());
// create a proxy by import
typeName = CoreSession.IMPORT_PROXY_TYPE;
parentRef = new IdRef(folderId);
name = "myproxy";
DocumentModel proxy = new DocumentModelImpl((String) null, typeName, pid, new Path(name), null, null,
parentRef, null, null, null, null);
proxy.putContextData(CoreSession.IMPORT_PROXY_TARGET_ID, vid);
proxy.putContextData(CoreSession.IMPORT_PROXY_VERSIONABLE_ID, id);
session.importDocuments(Collections.singletonList(proxy));
session.save();
reopenSession();
proxy = session.getDocument(new IdRef(pid));
assertEquals(name, proxy.getName());
assertEquals("Ver title", proxy.getProperty("dublincore", "title"));
assertEquals(mod, proxy.getProperty("dublincore", "modified"));
assertEquals("v lcp", proxy.getLifeCyclePolicy());
assertEquals("v lcst", proxy.getCurrentLifeCycleState());
assertFalse(proxy.isVersion());
assertTrue(proxy.isProxy());
// create a normal doc by import
typeName = "File";
parentRef = new IdRef(folderId);
name = "mydoc";
DocumentModel doc = new DocumentModelImpl((String) null, typeName, id, new Path(name), null, null, parentRef,
null, null, null, null);
doc.putContextData(CoreSession.IMPORT_LIFECYCLE_POLICY, "lcp");
doc.putContextData(CoreSession.IMPORT_LIFECYCLE_STATE, "lcst");
Calendar lockCreated = new GregorianCalendar(2011, Calendar.JANUARY, 1, 5, 5, 5);
doc.putContextData(CoreSession.IMPORT_LOCK_OWNER, "bob");
doc.putContextData(CoreSession.IMPORT_LOCK_CREATED, lockCreated);
doc.putContextData(CoreSession.IMPORT_CHECKED_IN, Boolean.TRUE);
doc.putContextData(CoreSession.IMPORT_BASE_VERSION_ID, vid);
doc.putContextData(CoreSession.IMPORT_VERSION_MAJOR, Long.valueOf(8));
doc.putContextData(CoreSession.IMPORT_VERSION_MINOR, Long.valueOf(1));
doc.setProperty("dublincore", "title", "Live title");
session.importDocuments(Collections.singletonList(doc));
session.save();
reopenSession();
doc = session.getDocument(new IdRef(id));
assertEquals(name, doc.getName());
assertEquals("Live title", doc.getProperty("dublincore", "title"));
assertEquals(folderId, doc.getParentRef().toString());
assertEquals("lcp", doc.getLifeCyclePolicy());
assertEquals("lcst", doc.getCurrentLifeCycleState());
assertEquals(Long.valueOf(8), doc.getProperty("uid", "major_version"));
assertEquals(Long.valueOf(1), doc.getProperty("uid", "minor_version"));
assertTrue(doc.isLocked());
assertEquals("bob", doc.getLockInfo().getOwner());
assertEquals(lockCreated, doc.getLockInfo().getCreated());
assertFalse(doc.isVersion());
assertFalse(doc.isProxy());
}
/**
* Check that lifecycle and dc:issued can be updated on a version. (Fields defined in
* SQLDocumentLive#VERSION_WRITABLE_PROPS).
*/
@Test
public void testVersionUpdatableFields() throws Exception {
Calendar cal1 = new GregorianCalendar(2008, Calendar.JULY, 14, 12, 34, 56);
Calendar cal2 = new GregorianCalendar(2010, Calendar.JANUARY, 1, 0, 0, 0);
Calendar cal3 = new GregorianCalendar(2010, Calendar.APRIL, 11, 11, 11, 11);
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "doc", "File");
doc = session.createDocument(doc);
doc.setProperty("dublincore", "title", "t1");
doc.setProperty("dublincore", "issued", cal1);
doc = session.saveDocument(doc);
session.checkIn(doc.getRef(), null, null);
session.checkOut(doc.getRef());
doc.setProperty("dublincore", "title", "t2");
doc.setProperty("dublincore", "issued", cal2);
doc = session.saveDocument(doc);
// get version
DocumentModel ver = session.getLastDocumentVersion(doc.getRef());
assertTrue(ver.isVersion());
assertEquals("project", ver.getCurrentLifeCycleState());
assertEquals("t1", ver.getProperty("dublincore", "title"));
assertEquals(cal1, ver.getProperty("dublincore", "issued"));
// change lifecycle
ver.followTransition("approve");
// change dc:issued
ver.setProperty("dublincore", "issued", cal3);
session.saveDocument(ver);
session.save();
reopenSession();
doc = session.getDocument(new PathRef("/doc"));
ver = session.getLastDocumentVersion(doc.getRef());
assertEquals("t1", ver.getProperty("dublincore", "title"));
assertEquals("approved", ver.getCurrentLifeCycleState());
assertEquals(cal3, ver.getProperty("dublincore", "issued"));
}
/**
* Check that the "incrementBeforeUpdate" is not fired on a DocumentModel where the {@code isImmutable()} returns
* {@code true}.
*/
@Test
@LocalDeploy("org.nuxeo.ecm.core.test.tests:OSGI-INF/test-listeners-contrib.xml")
public void testDoNotFireIncrementBeforeUpdateEventsOnVersion() throws Exception {
DocumentModel root = session.getRootDocument();
DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "doc", "File");
doc = session.createDocument(doc);
doc.setProperty("dublincore", "title", "t1");
doc = session.saveDocument(doc);
session.checkIn(doc.getRef(), null, null);
session.checkOut(doc.getRef());
doc.setProperty("dublincore", "title", "t2");
doc = session.saveDocument(doc);
session.save();
// Reset the listener
DummyTestListener.clear();
DocumentModel versionDoc = session.getLastDocumentVersion(doc.getRef());
versionDoc.setProperty("dublincore", "issued", new GregorianCalendar());
session.saveDocument(versionDoc);
session.save();
assertEquals(1, DummyTestListener.EVENTS_RECEIVED.size());
assertEquals("beforeDocumentModification", DummyTestListener.EVENTS_RECEIVED.get(0).getName());
}
private static final List<String> IGNORED_EVENTS = Arrays.asList(DocumentEventTypes.SESSION_SAVED);
public static void assertEvents(String... expectedEventNames) {
assertEvents(IGNORED_EVENTS, expectedEventNames);
}
public static void assertEvents(List<String> ignored, String... expectedEventNames) {
assertEquals(Arrays.asList(expectedEventNames), getDummyListenerEvents(ignored));
}
protected static List<String> getDummyListenerEvents(List<String> ignored) {
List<String> actual = new ArrayList<>();
for (Event event : DummyTestListener.EVENTS_RECEIVED) {
String eventName = event.getName();
if (ignored != null && ignored.contains(eventName)) {
continue;
}
EventContext context = event.getContext();
if (context instanceof DocumentEventContext) {
DocumentModel doc = ((DocumentEventContext) context).getSourceDocument();
if (doc != null) {
if (doc.isProxy()) {
eventName += "/p";
} else if (doc.isVersion()) {
eventName += "/v";
} else if (doc.isFolder()) {
eventName += "/f";
}
}
}
actual.add(eventName);
}
return actual;
}
@Test
@LocalDeploy("org.nuxeo.ecm.core.test.tests:OSGI-INF/test-listeners-all-contrib.xml")
public void testVersioningEvents() throws Exception {
DocumentModel doc = new DocumentModelImpl("/", "doc", "File");
doc = session.createDocument(doc);
DocumentModel folder = new DocumentModelImpl("/", "fold", "Folder");
folder = session.createDocument(folder);
DummyTestListener.clear();
DocumentRef verRef = session.checkIn(doc.getRef(), null, null);
assertEvents( //
"aboutToCheckIn", //
"documentCheckedIn", //
"documentCreated/v");
DummyTestListener.clear();
session.checkOut(doc.getRef());
assertEvents( //
"aboutToCheckout", //
"documentCheckedOut");
DummyTestListener.clear();
session.createProxy(doc.getRef(), folder.getRef()); // live proxy
assertEvents( //
"documentCreated/p", //
"documentProxyPublished/p", //
"sectionContentPublished/f");
DummyTestListener.clear();
session.publishDocument(doc, folder, false);
assertEvents( //
"aboutToCheckIn", //
"documentCheckedIn", //
"documentCreated/v", //
"documentCreated/p", //
"documentProxyPublished/p", //
"sectionContentPublished/f");
// auto-checkout
DummyTestListener.clear();
doc.setPropertyValue("dc:title", "title2");
doc = session.saveDocument(doc);
assertEvents( //
"beforeDocumentModification", //
"aboutToCheckout", //
"documentCheckedOut", //
"documentModified");
// save with versioning
DummyTestListener.clear();
doc.setPropertyValue("dc:title", "title2");
doc.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MINOR);
doc = session.saveDocument(doc);
assertEvents( //
"beforeDocumentModification", //
"aboutToCheckIn", //
"documentCheckedIn", //
"documentCreated/v", //
"documentModified");
doc.checkOut();
// restore to version
DummyTestListener.clear();
session.restoreToVersion(doc.getRef(), verRef, false, false);
assertEvents( //
"aboutToCheckIn", //
"documentCheckedIn", //
"documentCreated/v", //
"beforeRestoringDocument", //
"documentRestored", //
"aboutToCheckout", //
"documentCheckedOut");
}
@Test
public void testPlacelessDocument() throws Exception {
DocumentModel doc = new DocumentModelImpl((String) null, "mydoc", "MyDocType");
doc.setProperty("dublincore", "title", "The title");
doc = session.createDocument(doc);
assertNull(doc.getParentRef()); // placeless
session.save();
DocumentModel doc2 = session.createDocumentModel(null, "other", "MyDocType");
doc2.setProperty("dublincore", "title", "Other");
doc2 = session.createDocument(doc2);
assertNull(doc2.getParentRef()); // placeless
session.save();
// ----- new session -----
reopenSession();
doc = session.getDocument(new IdRef(doc.getId()));
assertNull(doc.getParentRef());
assertEquals("The title", doc.getProperty("dublincore", "title"));
assertNull(doc.getProperty("dublincore", "description"));
doc2 = session.getDocument(new IdRef(doc2.getId()));
assertNull(doc2.getParentRef());
// remove
session.removeDocument(doc.getRef());
session.save();
}
@Test
public void testRelation() throws Exception {
DocumentModel rel = session.createDocumentModel(null, "myrel", "Relation");
rel.setProperty("relation", "source", "1234");
rel.setProperty("dublincore", "title", "My Rel");
rel = session.createDocument(rel);
assertNull(rel.getParentRef()); // placeless
session.save();
// query
String query = "SELECT * FROM Relation WHERE relation:source = '1234'";
DocumentModelList list = session.query(query);
assertEquals(1, list.size());
DocumentModel doc = list.get(0);
assertNull(doc.getParentRef());
assertEquals("My Rel", doc.getProperty("dublincore", "title"));
waitForAsyncCompletion(); // before remove
// remove
session.removeDocument(rel.getRef());
session.save();
list = session.query(query);
assertEquals(0, list.size());
}
/**
* Checks that a before document modification event can change the DocumentModel name and provoke a rename. And that
* PREVIOUS_DOCUMENT_MODEL received by the event holds the correct info.
*/
@Test
@LocalDeploy("org.nuxeo.ecm.core.test.tests:OSGI-INF/test-listener-beforemod-contrib.xml")
public void testBeforeModificationListenerRename() throws Exception {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
doc.setProperty("dublincore", "title", "t1");
doc = session.createDocument(doc);
session.save();
assertEquals("t1-rename", doc.getName());
doc.setProperty("dublincore", "title", "t2");
DummyBeforeModificationListener.previousTitle = null;
doc = session.saveDocument(doc);
session.save();
assertEquals("t2-rename", doc.getName());
assertEquals("/t2-rename", doc.getPathAsString());
assertEquals("t1", DummyBeforeModificationListener.previousTitle);
}
@Test
public void testObsoleteType() throws Throwable {
DocumentRef rootRef = session.getRootDocument().getRef();
DocumentModel doc = session.createDocumentModel("/", "doc", "MyDocType");
doc = session.createDocument(doc);
DocumentRef docRef = new IdRef(doc.getId());
session.save();
assertEquals(1, session.getChildren(rootRef).size());
assertNotNull(session.getDocument(docRef));
assertNotNull(session.getChild(rootRef, "doc"));
// remove MyDocType from known types
DocumentTypeDescriptor dtd = ((SchemaManagerImpl) schemaManager).getDocumentTypeDescriptor("MyDocType");
((SchemaManagerImpl) schemaManager).unregisterDocumentType(dtd);
reopenSession();
if (!isDBS()) {
// DBS does not do obsolete type check on hasChildren() due to cost
assertFalse(session.hasChildren(rootRef));
}
assertEquals(0, session.getChildren(rootRef).size());
try {
session.getDocument(docRef);
fail("shouldn't be able to get doc with obsolete type");
} catch (DocumentNotFoundException e) {
assertTrue(e.getMessage(), e.getMessage().contains("Unknown document type: MyDocType"));
}
try {
session.getChild(rootRef, "doc");
fail("shouldn't be able to get doc with obsolete type");
} catch (DocumentNotFoundException e) {
assertTrue(e.getMessage(), e.getMessage().contains("Unknown document type: MyDocType"));
}
}
@Test
public void testVersionParent() {
DocumentModel doc = session.createDocumentModel("/", "file", "File");
doc = session.createDocument(doc);
DocumentRef verRef = session.checkIn(doc.getRef(), null, null);
DocumentRef parentRef = session.getParentDocumentRef(verRef);
assertNotNull(parentRef);
assertEquals(session.getRootDocument().getRef(), parentRef);
DocumentModel ver = session.getDocument(verRef);
assertEquals("/file", ver.getPathAsString());
// now remove live doc
session.removeDocument(doc.getRef());
// version parent is now null
parentRef = session.getParentDocumentRef(verRef);
assertNull(parentRef);
DocumentModel parent = session.getParentDocument(verRef);
assertNull(parent);
ver = session.getDocument(verRef);
assertNull(ver.getPathAsString());
}
@Test
public void testRollback() {
DocumentModel file1 = session.createDocumentModel("/", "file1", "File");
file1.setPropertyValue("dc:title", "foo");
file1 = session.createDocument(file1);
DocumentModel file2 = session.createDocumentModel("/", "file2", "File");
file2.setPropertyValue("dc:title", "smurf");
file2 = session.createDocument(file2);
DocumentModel file3 = session.createDocumentModel("/", "file3", "File");
file3 = session.createDocument(file3);
session.save();
nextTransaction();
// start some changes
// modify file1 title
file1.setPropertyValue("dc:title", "bar");
session.saveDocument(file1);
// modify file2 title
file2.setPropertyValue("dc:title", "zap");
session.saveDocument(file2);
// remove file3
session.removeDocument(file3.getRef());
// create file4
DocumentModel file4 = session.createDocumentModel("/", "file4", "File");
file4 = session.createDocument(file4);
// create file5
DocumentModel file5 = session.createDocumentModel("/", "file5", "File");
file5 = session.createDocument(file5);
session.save();
// more changes
// modify again file1 title
file1.setPropertyValue("dc:title", "gee");
session.saveDocument(file1);
// remove file2
session.removeDocument(file2.getRef());
// modify file4
file4.setPropertyValue("dc:title", "moo");
session.saveDocument(file4);
// remove file5
session.removeDocument(file5.getRef());
session.save();
// abort the transaction
TransactionHelper.setTransactionRollbackOnly();
nextTransaction();
// check what we now have
// file1 title unchanged
file1 = session.getDocument(file1.getRef());
assertEquals("foo", file1.getPropertyValue("dc:title"));
// file2 title unchanged
file2 = session.getDocument(file2.getRef());
assertEquals("smurf", file2.getPropertyValue("dc:title"));
// file3 still present
assertTrue(session.exists(file3.getRef()));
// file4 not present
assertFalse(session.exists(file4.getRef()));
// file5 not present
assertFalse(session.exists(file5.getRef()));
}
@Test
public void testRollback2() {
DocumentModel file = session.createDocumentModel("/", "file", "File");
file.setPropertyValue("dc:title", "foo");
file = session.createDocument(file);
session.save();
nextTransaction();
// start some changes
file.setPropertyValue("dc:title", "bar");
session.saveDocument(file);
// abort the transaction
TransactionHelper.setTransactionRollbackOnly();
// attempt save in rollback-only state
session.save();
// more changes
file.setPropertyValue("dc:title", "gee");
session.saveDocument(file);
session.save();
nextTransaction();
// check what we now have file1 title unchanged
file = session.getDocument(file.getRef());
assertEquals("foo", file.getPropertyValue("dc:title"));
}
@Test
public void testRollback3() {
// create file 1
DocumentModel file1 = session.createDocumentModel("/", "file1", "File");
file1 = session.createDocument(file1);
session.save();
nextTransaction();
// create file 2 and rollback
DocumentModel file2 = session.createDocumentModel("/", "file2", "File");
file2 = session.createDocument(file2);
session.save();
TransactionHelper.setTransactionRollbackOnly();
nextTransaction();
// check just one file is here
DocumentModelList docs = session.query("SELECT * FROM File");
assertEquals(1, docs.size());
// re-try to create file 2 and re-rollback
file2 = session.createDocumentModel("/", "file2", "File");
file2 = session.createDocument(file2);
session.save();
TransactionHelper.setTransactionRollbackOnly();
nextTransaction();
// still just one file
docs = session.query("SELECT * FROM File");
assertEquals(1, docs.size());
}
@Test
public void testRollback4() {
TransactionHelper.commitOrRollbackTransaction();
TransactionHelper.startTransaction();
// set rollback-only
TransactionHelper.setTransactionRollbackOnly();
// then use the session (first use in this transaction, it will be reconnected)
try {
session.getDocument(new PathRef("/"));
fail("should not allow use of session when marked rollback-only");
} catch (NuxeoException e) {
assertEquals("Cannot reconnect a CoreSession when transaction is marked rollback-only", e.getMessage());
}
}
@Test
public void testRollback5() {
TransactionHelper.commitOrRollbackTransaction();
TransactionHelper.startTransaction();
// set rollback-only
TransactionHelper.setTransactionRollbackOnly();
// then create a session
try (CoreSession session2 = CoreInstance.openCoreSession(coreFeature.getRepositoryName())) {
fail("should not allow creation of session when marked rollback-only");
} catch (NuxeoException e) {
assertEquals("Cannot create a CoreSession when transaction is marked rollback-only", e.getMessage());
}
}
@Test
@ConditionalIgnoreRule.Ignore(condition = IgnoreWindows.class, cause = "Not enough time granularity")
public void testBinaryGC() throws Exception {
// GC binaries from previous tests
Thread.sleep(3 * 1000);
runBinariesGC(true, false);
// store some binaries
for (String str : Arrays.asList("ABC", "DEF", "GHI", "JKL")) {
addBinary(str, str);
addBinary(str, str + "2");
}
session.save();
nextTransaction();
BinaryManagerStatus status = runBinariesGC(true, false);
assertEquals(4, status.numBinaries); // ABC, DEF, GHI, JKL
assertEquals(4 * 3, status.sizeBinaries);
assertEquals(0, status.numBinariesGC);
assertEquals(0, status.sizeBinariesGC);
// remove some binaries
session.removeDocument(new PathRef("/ABC"));
session.removeDocument(new PathRef("/ABC2"));
session.removeDocument(new PathRef("/DEF"));
session.removeDocument(new PathRef("/DEF2"));
session.removeDocument(new PathRef("/GHI")); // GHI2 remains
// JKL and JKL2 remain
session.save();
nextTransaction();
// run GC in non-delete mode
Thread.sleep(3 * 1000); // sleep before GC to pass its time threshold
status = runBinariesGC(false, false);
assertEquals(2, status.numBinaries); // GHI, JKL
assertEquals(2 * 3, status.sizeBinaries);
assertEquals(2, status.numBinariesGC); // ABC, DEF
assertEquals(2 * 3, status.sizeBinariesGC);
// add a new binary during GC and revive one which was about to die
status = runBinariesGC(true, true);
assertEquals(4, status.numBinaries); // DEF3, GHI2, JKL, MNO
assertEquals(4 * 3, status.sizeBinaries);
assertEquals(1, status.numBinariesGC); // ABC
assertEquals(1 * 3, status.sizeBinariesGC);
Thread.sleep(3 * 1000);
status = runBinariesGC(true, false);
assertEquals(4, status.numBinaries); // DEF3, GHI2, JKL, MNO
assertEquals(4 * 3, status.sizeBinaries);
assertEquals(0, status.numBinariesGC);
assertEquals(0, status.sizeBinariesGC);
}
protected void addBinary(String content, String name) {
Blob blob = Blobs.createBlob(content);
DocumentModel doc = session.createDocumentModel("/", name, "File");
doc.setPropertyValue("file:content", (Serializable) blob);
session.createDocument(doc);
}
protected BinaryManagerStatus runBinariesGC(boolean delete, boolean addDuringGC) {
BlobProvider blobProvider = blobManager.getBlobProvider(session.getRepositoryName());
BinaryManager binaryManager = blobProvider.getBinaryManager();
BinaryGarbageCollector gc = binaryManager.getGarbageCollector();
Repository repository = repositoryService.getRepository(session.getRepositoryName());
assertFalse(gc.isInProgress());
gc.start();
assertTrue(gc.isInProgress());
repository.markReferencedBinaries();
if (addDuringGC) {
// while GC is in progress, add a new binary
addBinary("MNO", "MNO");
// and revive one that was about to be deleted
// note that this wouldn't work if we didn't recreate the Binary object from an InputStream
// and reused an old one
addBinary("DEF", "DEF3");
session.save();
nextTransaction();
}
gc.stop(delete);
return gc.getStatus();
}
/** Test that stores blobs in attachments (complex list). */
@Test
@ConditionalIgnoreRule.Ignore(condition = IgnoreWindows.class, cause = "Not enough time granularity")
public void testBinaryGC2() throws Exception {
// GC binaries from previous tests
Thread.sleep(3 * 1000);
runBinariesGC(true, false);
DocumentModel doc = session.createDocumentModel("/", "file", "File");
Map<String, Object> abc = Collections.singletonMap("file", Blobs.createBlob("ABC"));
Map<String, Object> def = Collections.singletonMap("file", Blobs.createBlob("DEF"));
Map<String, Object> ghi = Collections.singletonMap("file", Blobs.createBlob("GHI"));
doc.setPropertyValue("files", (Serializable) Arrays.asList(abc, def, ghi));
doc = session.createDocument(doc);
session.save();
// remove GHI
doc.setPropertyValue("files", (Serializable) Arrays.asList(abc, def));
doc = session.saveDocument(doc);
session.save();
nextTransaction();
// run GC in non-delete mode
Thread.sleep(3 * 1000); // sleep before GC to pass its time threshold
BinaryManagerStatus status = runBinariesGC(false, false);
assertEquals(2, status.numBinaries); // ABC, DEF
assertEquals(1, status.numBinariesGC); // GHI
// actual GC
status = runBinariesGC(true, false);
assertEquals(2, status.numBinaries); // ABC, DEF
assertEquals(1, status.numBinariesGC); // GHI
// again
status = runBinariesGC(true, false);
assertEquals(2, status.numBinaries); // ABC, DEF
assertEquals(0, status.numBinariesGC);
}
@Test
public void testLocking() throws Exception {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
doc = session.createDocument(doc);
DocumentRef docRef = doc.getRef();
ACP acp = new ACPImpl();
ACL acl = new ACLImpl();
acl.add(new ACE("pete", "WriteProperties"));
acp.addACL(acl);
session.setACP(docRef, acp, true);
session.save();
Lock lock = session.getLockInfo(docRef);
assertNull(lock);
lock = session.setLock(docRef);
assertNotNull(lock);
assertEquals("Administrator", lock.getOwner());
assertNotNull(lock.getCreated());
lock = session.getLockInfo(docRef);
assertNotNull(lock);
assertEquals("Administrator", lock.getOwner());
// nobody can re-lock without unlock, even Administrator
try {
session.setLock(docRef);
fail();
} catch (LockException e) {
assertTrue(e.getMessage(), e.getMessage().contains("Document already locked"));
}
// cannot remove lock as pete
try (CoreSession peteSession = openSessionAs("pete")) {
// try to remove lock as pete
try {
peteSession.removeLock(docRef);
fail();
} catch (LockException e) {
assertTrue(e.getMessage(), e.getMessage().contains("Document already locked"));
}
}
lock = session.removeLock(docRef);
assertNotNull(lock);
assertEquals("Administrator", lock.getOwner());
lock = session.getLockInfo(docRef);
assertNull(lock);
// removing lock on non-locked doesn't fail
lock = session.removeLock(docRef);
assertNull(lock);
// as pete
try (CoreSession peteSession = openSessionAs("pete")) {
// set lock as pete
lock = peteSession.setLock(docRef);
assertNotNull(lock);
assertEquals("pete", lock.getOwner());
// remove as pete
lock = peteSession.removeLock(docRef);
assertNotNull(lock);
}
}
@Test
public void testLockingBeforeSave() throws Exception {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
doc = session.createDocument(doc);
DocumentRef docRef = doc.getRef();
Lock lock = session.getLockInfo(docRef);
assertNull(lock);
lock = session.setLock(docRef);
assertNotNull(lock);
assertEquals("Administrator", lock.getOwner());
lock = session.removeLock(docRef);
assertNotNull(lock);
assertEquals("Administrator", lock.getOwner());
lock = session.setLock(docRef);
assertNotNull(lock);
assertEquals("Administrator", lock.getOwner());
session.save();
lock = session.getLockInfo(docRef);
assertNotNull(lock);
assertEquals("Administrator", lock.getOwner());
}
@Test
public void testChangeToken() {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
maybeCreateChangeToken(doc);
doc = session.createDocument(doc);
session.save();
String token = doc.getChangeToken();
// now change the doc
doc.setPropertyValue("dc:title", "Doc Changed");
maybeUpdateChangeToken(doc);
doc = session.saveDocument(doc);
session.save();
// the change token has been updated
String token2 = doc.getChangeToken();
assertNotEquals(token, token2);
// change token is available on a detached document
doc.detach(true);
assertEquals(token2, doc.getChangeToken());
}
@Test
public void testChangeTokenBatched() {
DocumentModel doc1 = session.createDocumentModel("/", "doc1", "File");
DocumentModel doc2 = session.createDocumentModel("/", "doc2", "File");
maybeCreateChangeToken(doc1);
maybeCreateChangeToken(doc2);
doc1 = session.createDocument(doc1);
doc2 = session.createDocument(doc2);
session.save();
String token1 = doc1.getChangeToken();
String token2 = doc2.getChangeToken();
// now change the docs
doc1.setPropertyValue("dc:title", "Doc 1 Changed");
doc2.setPropertyValue("dc:title", "Doc 2 Changed");
maybeUpdateChangeToken(doc1);
maybeUpdateChangeToken(doc2);
doc1 = session.saveDocument(doc1);
doc2 = session.saveDocument(doc2);
session.save();
// the change token has been updated
String token1b = doc1.getChangeToken();
String token2b = doc2.getChangeToken();
assertNotEquals(token1, token1b);
assertNotEquals(token2, token2b);
}
// query providers create "search" doc types to collect results
@Test
public void testChangeTokenOnFakeDocument() {
DocumentModel doc = session.createDocumentModel("File");
doc.setPropertyValue("dc:modified", Calendar.getInstance());
String token = doc.getChangeToken();
assertNotNull(token);
}
@Test
public void testChangeTokenForList() {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
maybeCreateChangeToken(doc);
doc = session.createDocument(doc);
session.save();
// do a first change to provoke the initial update VCS side effects (fulltext table)
doc.setPropertyValue("dc:title", "Doc Changed");
maybeUpdateChangeToken(doc);
doc = session.saveDocument(doc);
session.save();
// get the token
String token = doc.getChangeToken();
// change the doc by changing a list
doc.setPropertyValue("dc:subjects", (Serializable) Arrays.asList("foo", "bar"));
maybeUpdateChangeToken(doc);
doc = session.saveDocument(doc);
session.save();
// the change token has been updated
String token2 = doc.getChangeToken();
assertNotEquals(token, token2);
}
@Test
public void testChangeTokenForComplex() {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
maybeCreateChangeToken(doc);
doc = session.createDocument(doc);
session.save();
// do a first change to provoke the initial update VCS side effects (fulltext table)
doc.setPropertyValue("dc:title", "foo");
maybeUpdateChangeToken(doc);
doc = session.saveDocument(doc);
session.save();
// get the token
String token = doc.getChangeToken();
// change the doc by creating a complex property list
doc.setPropertyValue("relatedtext:relatedtextresources",
(Serializable) Arrays.asList(Collections.singletonMap("relatedtextid", "123")));
maybeUpdateChangeToken(doc);
doc = session.saveDocument(doc);
session.save();
// the change token has been updated
String token2 = doc.getChangeToken();
assertNotEquals(token, token2);
// change the doc by updating a complex property list
doc.setPropertyValue("relatedtext:relatedtextresources",
(Serializable) Arrays.asList(Collections.singletonMap("relatedtextid", "456")));
maybeUpdateChangeToken(doc);
doc = session.saveDocument(doc);
session.save();
// the change token has been updated again
String token3 = doc.getChangeToken();
assertNotEquals(token2, token3);
// change the doc by removing a complex property list
doc.setPropertyValue("relatedtext:relatedtextresources", (Serializable) Collections.emptyList());
maybeUpdateChangeToken(doc);
doc = session.saveDocument(doc);
session.save();
// the change token has been updated again
String token4 = doc.getChangeToken();
assertNotEquals(token3, token4);
}
@Test
public void testOptimisticLockingWithExplicitChangeToken() {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
maybeCreateChangeToken(doc);
doc = session.createDocument(doc);
session.save();
String token = doc.getChangeToken();
// now change the doc, using the appropriate change token
doc.setPropertyValue("dc:title", "foo");
doc.putContextData(CoreSession.CHANGE_TOKEN, token);
maybeUpdateChangeToken(doc);
doc = session.saveDocument(doc);
session.save(); // save succeeds
String token2 = doc.getChangeToken();
assertNotEquals(token, token2);
// change again the doc, using a wrong change token
doc.setPropertyValue("dc:title", "bar");
doc.putContextData(CoreSession.CHANGE_TOKEN, "wrongchangetoken");
maybeUpdateChangeToken(doc);
try {
session.saveDocument(doc);
fail("save should fail because of wrong change token");
} catch (ConcurrentUpdateException e) {
TransactionHelper.setTransactionRollbackOnly();
assertEquals(doc.getId(), e.getMessage());
}
}
// TODO this test fails randomly because of concurrent updates
@Test
public void testOptimisticLockingWithRandomParallelWork() {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
maybeCreateChangeToken(doc);
doc.setPropertyValue("dc:title", "foo");
doc = session.createDocument(doc);
session.save();
nextTransaction();
doc.setPropertyValue("dc:title", "bar");
maybeUpdateChangeToken(doc);
session.saveDocument(doc);
// save may fail due to concurrent exception
// this happens if the async fulltext-indexing job changing the document
// runs in a different session than the main one
// FIXME fix change token management for this case
assumeTrue("FIXME", !isChangeTokenEnabled());
session.save();
}
@Test
public void testOptimisticLockingWithParallelChange() throws Exception {
DocumentModel doc = session.createDocumentModel("/", "doc", "File");
// create row in VCS dublincore table to avoid later concurrent update upon its creation
doc.setPropertyValue("dc:title", "foo");
maybeCreateChangeToken(doc);
doc = session.createDocument(doc);
DocumentRef docRef = doc.getRef();
session.save();
// re-start a new transaction that hasn't done any writes
nextTransaction();
waitForAsyncCompletion();
reopenSession();
doc = session.getDocument(docRef);
// in other thread, update the doc as well
MutableObject<RuntimeException> me = new MutableObject<>();
Thread thread = new Thread(() -> {
TransactionHelper.runInTransaction(() -> {
try (CoreSession session2 = CoreInstance.openCoreSession(coreFeature.getRepositoryName())) {
DocumentModel doc2 = session2.getDocument(docRef);
doc2.setPropertyValue("dc:title", "bar parallel");
maybeUpdateChangeToken(doc2);
doc2 = session2.saveDocument(doc2);
session2.save(); // save succeeds
} catch (RuntimeException e) {
me.setValue(e);
}
});
});
thread.start();
thread.join();
if (me.getValue() != null) {
throw me.getValue();
}
// now try to save the doc, using the implicit change token
doc.setPropertyValue("dc:title", "bar");
maybeUpdateChangeToken(doc);
doc = session.saveDocument(doc);
try {
session.save();
if (isChangeTokenEnabled()) { // not failing for manual change tokens
fail("save should fail because of concurrent update in other transaction");
}
} catch (ConcurrentUpdateException e) {
if (!isChangeTokenEnabled()) {
// no exception expected for manual change token
throw e;
}
// ok
TransactionHelper.setTransactionRollbackOnly();
}
}
}