Merged HEAD-QA to HEAD (4.2) (including moving test classes into separate folders)

51903 to 54309 


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@54310 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Samuel Langlois
2013-08-20 17:17:31 +00:00
parent 0a36e2af67
commit ab4ca7177f
1576 changed files with 36419 additions and 8603 deletions

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model;
import org.alfresco.repo.model.filefolder.FileFolderDuplicateChildTest;
import org.alfresco.repo.model.filefolder.FileFolderServiceImplTest;
import org.alfresco.repo.model.filefolder.HiddenAspectTest;
import org.alfresco.repo.model.ml.tools.ContentFilterLanguagesMapTest;
import org.alfresco.repo.model.ml.tools.EditionServiceImplTest;
import org.alfresco.repo.model.ml.tools.EmptyTranslationAspectTest;
import org.alfresco.repo.model.ml.tools.MLContainerTypeTest;
import org.alfresco.repo.model.ml.tools.MultilingualContentServiceImplTest;
import org.alfresco.repo.model.ml.tools.MultilingualDocumentAspectTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
/**
* Model test suite
*/
@RunWith(Suite.class)
@SuiteClasses({
ContentFilterLanguagesMapTest.class,
EmptyTranslationAspectTest.class,
MLContainerTypeTest.class,
MultilingualContentServiceImplTest.class,
MultilingualDocumentAspectTest.class,
EditionServiceImplTest.class,
HiddenAspectTest.class,
// Add the file folder tests
// These need to come afterwards, as they insert extra
// interceptors which would otherwise confuse things
FileFolderServiceImplTest.class,
FileFolderDuplicateChildTest.class,
})
public class ModelTestSuite
{
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model.filefolder;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ApplicationContext;
/**
* Checks that the duplicate child handling is done correctly.
*
* @see org.alfresco.repo.model.filefolder.FileFolderServiceImpl
*
* @author Derek Hulley
* @since 2.1.0
*/
public class FileFolderDuplicateChildTest extends TestCase
{
private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private AuthenticationComponent authenticationComponent;
private TransactionService transactionService;
private RetryingTransactionHelper retryingTransactionHelper;
private NodeService nodeService;
private FileFolderService fileFolderService;
private NodeRef rootNodeRef;
private NodeRef workingRootNodeRef;
@Override
public void setUp() throws Exception
{
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
transactionService = serviceRegistry.getTransactionService();
retryingTransactionHelper = transactionService.getRetryingTransactionHelper();
nodeService = serviceRegistry.getNodeService();
fileFolderService = serviceRegistry.getFileFolderService();
authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
RetryingTransactionCallback<NodeRef> callback = new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
// authenticate
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
// create a test store
StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, getName() + System.currentTimeMillis());
rootNodeRef = nodeService.getRootNode(storeRef);
// create a folder to import into
NodeRef nodeRef = nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.ALFRESCO_URI, "working root"),
ContentModel.TYPE_FOLDER).getChildRef();
// Done
return nodeRef;
}
};
workingRootNodeRef = retryingTransactionHelper.doInTransaction(callback, false, true);
}
public void tearDown() throws Exception
{
}
public void testDuplicateChildNameDetection() throws Exception
{
// First create a file name F1
RetryingTransactionCallback<FileInfo> callback = new CreateFileCallback(0);
FileInfo fileInfo = retryingTransactionHelper.doInTransaction(callback, false, true);
// Check that the filename is F0
assertEquals("Incorrect initial filename", "F0", fileInfo.getName());
// Now create a whole lot of threads that attempt file creation
int threadCount = 10;
CountDownLatch endLatch = new CountDownLatch(threadCount);
WorkerThread[] workers = new WorkerThread[threadCount];
for (int i = 0; i < threadCount; i++)
{
workers[i] = new WorkerThread(endLatch);
workers[i].start();
}
// Wait at the end gate
endLatch.await(300L, TimeUnit.SECONDS);
// Analyse
int failureCount = 0;
int didNotCompleteCount = 0;
for (int i = 0; i < threadCount; i++)
{
if (workers[i].error != null)
{
failureCount++;
}
else if (workers[i].success == null)
{
didNotCompleteCount++;
}
}
System.out.println("" + failureCount + " of the " + threadCount + " threads failed and " + didNotCompleteCount + " did not finish.");
assertEquals("Some failures", 0, failureCount);
assertEquals("Some non-finishes", 0, didNotCompleteCount);
}
/**
* Attempts to create a file "Fn" where n is the number supplied to the constructor.
*/
private class CreateFileCallback implements RetryingTransactionCallback<FileInfo>
{
private final int number;
public CreateFileCallback(int number)
{
this.number = number;
}
public FileInfo execute() throws Throwable
{
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
return fileFolderService.create(
workingRootNodeRef,
"F" + number,
ContentModel.TYPE_CONTENT);
}
}
private static ThreadGroup threadGroup = new ThreadGroup("FileFolderDuplicateChildTest");
private static int threadNumber = -1;
private class WorkerThread extends Thread
{
private CountDownLatch endLatch;
private Throwable error;
private FileInfo success;
public WorkerThread(CountDownLatch endLatch)
{
super(threadGroup, "Worker " + ++threadNumber);
this.endLatch = endLatch;
}
public void run()
{
FileInfo fileInfo = null;
// Start the count with a guaranteed failure
int number = 0;
while(true)
{
RetryingTransactionCallback<FileInfo> callback = new CreateFileCallback(number);
try
{
System.out.println("Thread " + getName() + " attempting file: " + number);
System.out.flush();
fileInfo = retryingTransactionHelper.doInTransaction(callback, false, true);
// It worked
success = fileInfo;
break;
}
catch (FileExistsException e)
{
// Try another number
number++;
}
catch (Throwable e)
{
// Oops
error = e;
break;
}
}
// Done
if (error != null)
{
System.err.println("Thread " + getName() + " failed to create file " + number + ":");
System.err.flush();
error.printStackTrace();
}
else
{
System.out.println("\t\t\tThread " + getName() + " created file: " + success.getName());
System.out.flush();
}
// Tick the latch
endLatch.countDown();
}
}
}

View File

@@ -0,0 +1,742 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model.filefolder;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
import org.alfresco.repo.dictionary.DictionaryDAO;
import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.ArgumentHelper;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Tests around some of the data structures that lead to performance
* degradation. We use the {@link org.alfresco.service.cmr.model.FileFolderService FileFolderService}
* as it provides the most convenient and most common test scenarios.
* <p>
* Note that this test is not designed to validate performance figures, but is
* rather a handy tool for doing benchmarking. It is therefore not named <i>*Test</i> as is the
* pattern for getting tests run by the continuous build.
*
* @author Derek Hulley
*/
public class FileFolderPerformanceTester extends TestCase
{
private static Log logger = LogFactory.getLog(FileFolderPerformanceTester.class);
protected static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
protected RetryingTransactionHelper retryingTransactionHelper;
protected NodeService nodeService;
private AuthenticationComponent authenticationComponent;
private FileFolderService fileFolderService;
private SearchService searchService;
private NamespaceService namespaceService;
private NodeRef rootFolderRef;
private File dataFile;
private String USERNAME = AuthenticationUtil.getAdminUserName(); // as admin
//private String USERNAME = AuthenticationUtil.getSystemUserName(); // as system (bypass permissions)
protected NodeService getNodeService()
{
return (NodeService)ctx.getBean("NodeService");
}
@Override
public void setUp() throws Exception
{
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
retryingTransactionHelper = (RetryingTransactionHelper) ctx.getBean("retryingTransactionHelper");
authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
fileFolderService = serviceRegistry.getFileFolderService();
searchService = serviceRegistry.getSearchService();
namespaceService = serviceRegistry.getNamespaceService();
nodeService = getNodeService();
authenticate(USERNAME);
rootFolderRef = getOrCreateRootFolder();
dataFile = AbstractContentTransformerTest.loadQuickTestFile("txt");
}
private void authenticate(String userName)
{
if (AuthenticationUtil.getSystemUserName().equals(userName))
{
authenticationComponent.setSystemUserAsCurrentUser();
}
else
{
authenticationComponent.setCurrentUser(userName);
}
}
public void testSetUp() throws Exception
{
assertNotNull(dataFile);
}
protected NodeRef getOrCreateRootFolder()
{
// find the company home folder
StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
List<NodeRef> results = searchService.selectNodes(
storeRootNodeRef,
"/app:company_home",
null,
namespaceService,
false,
SearchService.LANGUAGE_XPATH);
if (results.size() == 0)
{
throw new AlfrescoRuntimeException("Didn't find Company Home");
}
NodeRef companyHomeNodeRef = results.get(0);
return fileFolderService.create(
companyHomeNodeRef,
getName() + "_" + System.currentTimeMillis(),
ContentModel.TYPE_FOLDER).getNodeRef();
}
/**
* Creates <code>folderCount</code> folders below the given parent and populates each folder with
* <code>fileCount</code> files. The folders will be created as siblings in one go, but the files
* are added one to each folder until each folder has the presribed number of files within it.
* This can therefore be used to test the performance when the L2 cache sizes are exceeded.
* <p>
* Each creation (file or folder) uses the <b>PROPAGATION REQUIRED</b> transaction declaration.
*
* @param parentNodeRef the level zero parent
* @param randomOrder true if each thread must put the children into the folders in a random order
* @return Returns the average time (ms) to create the <b>files only</b>
*/
private void buildStructure(
final NodeRef parentNodeRef,
final int threadCount,
final boolean randomOrder,
final int folderCount,
final int batchCount,
final int filesPerBatch,
final double[] dumpPoints)
{
RetryingTransactionCallback<NodeRef[]> createFoldersCallback = new RetryingTransactionCallback<NodeRef[]>()
{
public NodeRef[] execute() throws Exception
{
NodeRef[] folders = new NodeRef[folderCount];
for (int i = 0; i < folderCount; i++)
{
FileInfo folderInfo = fileFolderService.create(
parentNodeRef,
GUID.generate(),
ContentModel.TYPE_FOLDER);
// keep the reference
folders[i] = folderInfo.getNodeRef();
}
return folders;
}
};
final NodeRef[] folders = retryingTransactionHelper.doInTransaction(createFoldersCallback);
// the worker that will load the files into the folders
Runnable runnable = new Runnable()
{
private long start;
public void run()
{
// authenticate
authenticate(USERNAME);
// progress around the folders until they have been populated
start = System.currentTimeMillis();
int nextDumpNumber = 0;
for (int i = 0; i < batchCount; i++)
{
// must we dump results
double completedCount = (double) i;
double nextDumpCount = (dumpPoints == null || dumpPoints.length == 0 || nextDumpNumber >= dumpPoints.length)
? -1.0
: (double) batchCount * dumpPoints[nextDumpNumber];
if ((nextDumpCount - 0.5) < completedCount && completedCount < (nextDumpCount + 0.5))
{
dumpResults(i);
nextDumpNumber++;
}
// shuffle folders if required
List<NodeRef> foldersList = Arrays.asList(folders);
if (randomOrder)
{
// shuffle folder list
Collections.shuffle(foldersList);
}
for (int j = 0; j < folders.length; j++)
{
final NodeRef folderRef = folders[j];
RetryingTransactionCallback<Void> createFileCallback = new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
for (int i = 0; i < filesPerBatch; i++)
{
FileInfo fileInfo = fileFolderService.create(
folderRef,
GUID.generate(),
ContentModel.TYPE_CONTENT);
NodeRef nodeRef = fileInfo.getNodeRef();
// write the content
ContentWriter writer = fileFolderService.getWriter(nodeRef);
writer.setEncoding("UTF-8");
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.putContent(dataFile);
}
// done
return null;
}
};
retryingTransactionHelper.doInTransaction(createFileCallback);
}
}
dumpResults(batchCount);
}
private void dumpResults(int currentBatchCount)
{
long end = System.currentTimeMillis();
long time = (end - start);
double average = (double) time / (double) (folderCount * currentBatchCount * filesPerBatch);
double percentComplete = (double) currentBatchCount / (double) batchCount * 100.0;
if (percentComplete > 0)
{
logger.debug("\n" +
"[" + Thread.currentThread().getName() + "] \n" +
" Created " + (currentBatchCount*filesPerBatch) + " files in each of " + folderCount +
" folders (" + (randomOrder ? "shuffled" : "in order") + "): \n" +
" Progress: " + String.format("%9.2f", percentComplete) + " percent complete \n" +
" Average: " + String.format("%10.2f", average) + " ms per file \n" +
" Average: " + String.format("%10.2f", 1000.0/average) + " files per second");
}
}
};
// kick off the required number of threads
logger.debug("\n" +
"Starting " + threadCount +
" threads loading " + (batchCount * filesPerBatch) +
" files in each of " + folderCount +
" folders (" +
(randomOrder ? "shuffled" : "in order") +
(filesPerBatch > 1 ? (" and " + filesPerBatch + " files per txn") : "") +
").");
ThreadGroup threadGroup = new ThreadGroup(getName());
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++)
{
threads[i] = new Thread(threadGroup, runnable, String.format("FileLoader-%02d", i));
threads[i].start();
}
// join each thread so that we wait for them all to finish
for (int i = 0; i < threads.length; i++)
{
try
{
threads[i].join();
}
catch (InterruptedException e)
{
// not too serious - the worker threads are non-daemon
}
}
}
private void readStructure(
final NodeRef parentNodeRef,
final int threadCount,
final int repetitions,
final double[] dumpPoints)
{
final List<FileInfo> children = fileFolderService.list(parentNodeRef);
Runnable runnable = new Runnable()
{
public void run()
{
// authenticate
authenticate(USERNAME);
for (int i = 0; i < repetitions; i++)
{
// read the contents of each folder
for (final FileInfo fileInfo : children)
{
final NodeRef folderRef = fileInfo.getNodeRef();
RetryingTransactionCallback<Object> readCallback = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
List<FileInfo> tmp = null;
if (fileInfo.isFolder())
{
long start = System.currentTimeMillis();
// read the children of the folder
tmp = fileFolderService.list(folderRef);
logger.debug("List "+tmp.size()+" items in "+(System.currentTimeMillis()-start)+" msecs");
}
else
{
throw new AlfrescoRuntimeException("Not a folder: "+folderRef);
}
// done
return null;
};
};
retryingTransactionHelper.doInTransaction(readCallback, true);
}
}
}
};
// kick off the required number of threads
logger.debug("\n" +
"Starting " + threadCount +
" threads reading properties and children of " + children.size() +
" folders " + repetitions +
" times.");
long start = System.currentTimeMillis();
ThreadGroup threadGroup = new ThreadGroup(getName());
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++)
{
threads[i] = new Thread(threadGroup, runnable, String.format("FileReader-%02d", i));
threads[i].start();
}
// join each thread so that we wait for them all to finish
for (int i = 0; i < threads.length; i++)
{
try
{
threads[i].join();
}
catch (InterruptedException e)
{
// not too serious - the worker threads are non-daemon
}
}
logger.debug("\nFinished reading in "+(System.currentTimeMillis()-start)+" msecs");
}
/*
// Load and read: 100 ordered files (into 1 folder) using 1 thread
public void test_1_ordered_1_1_100() throws Exception
{
buildStructure(rootFolderRef, 1, false, 1, 1, 100, new double[] {0.25, 0.50, 0.75});
readStructure(rootFolderRef, 1, 3, new double[] {0.25, 0.50, 0.75});
}
// Load and read: 300 ordered files per folder (into 2 folders) using 1 thread
public void test_1_ordered_2_3_100() throws Exception
{
buildStructure(rootFolderRef, 1, false, 2, 3, 100, new double[] {0.25, 0.50, 0.75});
readStructure(rootFolderRef, 1, 3, new double[] {0.25, 0.50, 0.75});
}
// Load and read: 5000 files per folder (into 1 folder) using 2 threads
public void test_2_ordered_1_2500_1() throws Exception
{
buildStructure(rootFolderRef, 2, false, 1, 2500, 1, new double[] {0.25, 0.50, 0.75});
readStructure(rootFolderRef, 2, 3, new double[] {0.25, 0.50, 0.75});
}
// Load and read: 10000 files per folder (into 1 folder) using 2 threads
public void test_2_ordered_1_10_500() throws Exception
{
buildStructure(rootFolderRef, 2, false, 1, 10, 500, new double[] {0.25, 0.50, 0.75});
readStructure(rootFolderRef, 2, 3, new double[] {0.25, 0.50, 0.75}); // note: will list each folder up to configured max items (eg. default 5000)
}
// Load and read: 1000 ordered files per folder (into 10 folders) using 4 threads
public void test_1_ordered_10_1_100() throws Exception
{
buildStructure(rootFolderRef, 1, false, 10, 1, 100, new double[] {0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
readStructure(rootFolderRef, 1, 3, new double[] {0.25, 0.50, 0.75});
}
// Load and read: 4000 ordered files per folder (into 10 folders) using 4 threads
public void test_4_ordered_10_1_100() throws Exception
{
buildStructure(rootFolderRef, 4, false, 10, 1, 100, new double[] {0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
readStructure(rootFolderRef, 4, 3, new double[] {0.25, 0.50, 0.75});
}
// Load and read: 4000 shuffled files per folder (into 10 folders) using 4 threads
public void test_4_shuffled_10_1_100() throws Exception
{
buildStructure(rootFolderRef, 4, true, 10, 1, 100, new double[] {0.25, 0.50, 0.75});
readStructure(rootFolderRef, 4, 1, new double[] {0.25, 0.50, 0.75});
}
// Load: 100 shuffled files per folder (into 100 folders) using 1 thread
public void test_1_ordered_100_1_100() throws Exception
{
buildStructure(
rootFolderRef,
1,
false,
100,
1,
100,
new double[] {0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
readStructure(rootFolderRef, 1, 1, new double[] {0.25, 0.50, 0.75});
}
// Load: 400 shuffled files per folder (into 10 folders) using 1 thread
public void test_1_shuffled_10_1_400() throws Exception
{
buildStructure(
rootFolderRef,
1,
true,
10,
1,
400,
new double[] {0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
readStructure(rootFolderRef, 1, 1, new double[] {0.25, 0.50, 0.75});
}
*/
// Load: 800 ordered files per folder (into 3 folders) using 4 threads
public void test_4_ordered_3_2_100() throws Exception
{
buildStructure(
rootFolderRef,
4,
false,
3,
2,
100,
new double[] {0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
System.out.println("rootFolderRef: "+rootFolderRef);
readStructure(rootFolderRef, 4, 5, new double[] {0.25, 0.50, 0.75});
}
// Load: 800 shuffled files per folder (into 3 folders) using 4 threads
public void test_4_shuffled_3_2_100() throws Exception
{
buildStructure(
rootFolderRef,
4,
true,
3,
2,
100,
new double[] {0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
System.out.println("rootFolderRef: "+rootFolderRef);
readStructure(rootFolderRef, 4, 5, new double[] {0.25, 0.50, 0.75});
}
/*
// Load: 50000 ordered files per folder (into 1 folder) using 1 thread
public void test_1_ordered_1_5000_10() throws Exception
{
buildStructure(
rootFolderRef,
1,
false,
1,
5000,
10,
new double[] {0.01, 0.02, 0.03, 0.04, 0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90});
readStructure(rootFolderRef, 1, 1, new double[] {0.25, 0.50, 0.75});
}
*/
/**
* Create a bunch of files and folders in a folder and then run multi-threaded directory
* listings against it.
*
* @param args <x> <y> where 'x' is the number of files in a folder and 'y' is the
* number of threads to list
*/
public static void main(String ... args)
{
ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) ApplicationContextHelper.getApplicationContext();
try
{
run(ctx, args);
}
catch (Throwable e)
{
System.out.println("Failed to run FileFolder performance test");
e.printStackTrace();
}
finally
{
ctx.close();
}
}
private static void run(final ApplicationContext ctx, String ... args) throws Throwable
{
ArgumentHelper argHelper = new ArgumentHelper(getUsage(), args);
final int fileCount = argHelper.getIntegerValue("files", true, 1, 10000);
final String folderRefStr = argHelper.getStringValue("folder", false, true);
final int threadCount = argHelper.getIntegerValue("threads", false, 1, 100);
final NodeRef selectedFolderNodeRef = folderRefStr == null ? null : new NodeRef(folderRefStr);
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
final MutableAuthenticationService authenticationService = serviceRegistry.getAuthenticationService();
final PermissionService permissionService = serviceRegistry.getPermissionService();
final NodeService nodeService = serviceRegistry.getNodeService();
final SearchService searchService = serviceRegistry.getSearchService();
final TransactionService transactionService = serviceRegistry.getTransactionService();
final FileFolderService fileFolderService = serviceRegistry.getFileFolderService();
RunAsWork<String> createUserRunAs = new RunAsWork<String>()
{
public String doWork() throws Exception
{
String user = GUID.generate();
authenticationService.createAuthentication(user, user.toCharArray());
return user;
}
};
final String user = AuthenticationUtil.runAs(createUserRunAs, AuthenticationUtil.getSystemUserName());
// Create the files
final RetryingTransactionCallback<NodeRef> createCallback = new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
AuthenticationUtil.pushAuthentication();
DictionaryDAO dictionaryDao = (DictionaryDAO) ctx.getBean("dictionaryDAO");
M2Model model = M2Model.createModel("tempModel");
model.createNamespace("test", "t");
model.createNamespace("testx", "");
for (int m = 0; m < 30; m++)
{
model.createAspect("t:aspect_" + m);
}
dictionaryDao.putModel(model);
NodeRef folderNodeRef = null;
try
{
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
if (selectedFolderNodeRef == null)
{
// find the guest folder
StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
ResultSet rs = searchService.query(storeRef, SearchService.LANGUAGE_XPATH, "/app:company_home");
try
{
if (rs.length() == 0)
{
throw new AlfrescoRuntimeException("Didn't find Company Home");
}
NodeRef companyHomeNodeRef = rs.getNodeRef(0);
folderNodeRef = fileFolderService.create(
companyHomeNodeRef,
"TOP_FOLDER_" + System.currentTimeMillis(),
ContentModel.TYPE_FOLDER).getNodeRef();
System.out.println("Created folder " + folderNodeRef + " with user " + user);
}
finally
{
rs.close();
}
// Grant permissions
permissionService.setPermission(folderNodeRef, user, PermissionService.ALL_PERMISSIONS, true);
}
else
{
folderNodeRef = selectedFolderNodeRef;
// Grant permissions
permissionService.setPermission(folderNodeRef, user, PermissionService.ALL_PERMISSIONS, true);
System.out.println("Reusing folder " + folderNodeRef + " with user " + user);
}
}
finally
{
AuthenticationUtil.popAuthentication();
}
if (selectedFolderNodeRef == null)
{
List<String> largeCollection = new ArrayList<String>(1000);
for (int i = 0; i < 50; i++)
{
largeCollection.add(String.format("Large-collection-value-%05d", i));
}
// Create the files
for (int i = 0; i < fileCount; i++)
{
FileInfo fileInfo = fileFolderService.create(
folderNodeRef,
String.format("FILE-%4d", i),
ContentModel.TYPE_CONTENT);
NodeRef nodeRef = fileInfo.getNodeRef();
nodeService.setProperty(
nodeRef,
QName.createQName("{test}mv"),
(Serializable) largeCollection);
for (int m = 0; m < 30; m++)
{
nodeService.addAspect(
nodeRef,
QName.createQName("{test}aspect_"+m), null);
}
// write the content
ContentWriter writer = fileFolderService.getWriter(nodeRef);
writer.setEncoding("UTF-8");
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.putContent("Some small text data");
}
System.out.println("Created " + fileCount + " files in folder " + folderNodeRef);
}
// Done
return folderNodeRef;
}
};
RunAsWork<NodeRef> createRunAs = new RunAsWork<NodeRef>()
{
public NodeRef doWork() throws Exception
{
return transactionService.getRetryingTransactionHelper().doInTransaction(createCallback);
}
};
final NodeRef folderNodeRef = AuthenticationUtil.runAs(createRunAs, user);
// Now wait for some input before commencing the read run
System.out.print("Hit any key to commence directory listing ...");
System.in.read();
final RunAsWork<List<FileInfo>> readRunAs = new RunAsWork<List<FileInfo>>()
{
public List<FileInfo> doWork() throws Exception
{
return fileFolderService.list(folderNodeRef);
}
};
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++)
{
Thread readThread = new Thread("FolderList-" + i)
{
int iteration = 0;
public void run()
{
while(++iteration <= 2)
{
runImpl();
}
}
private void runImpl()
{
String threadName = Thread.currentThread().getName();
long start = System.currentTimeMillis();
List<FileInfo> nodeRefs = AuthenticationUtil.runAs(readRunAs, user);
long time = System.currentTimeMillis() - start;
double average = (double) time / (double) (fileCount);
// Make sure that we have the correct number of entries
if (folderRefStr != null && nodeRefs.size() != fileCount)
{
System.err.println(
"WARNING: Thread " + threadName + " got " + nodeRefs.size() +
" but expected " + fileCount);
}
System.out.print("\n" +
"Thread " + threadName + ": \n" +
" Read " + String.format("%4d", fileCount) + " files \n" +
" Average: " + String.format("%10.2f", average) + " ms per file \n" +
" Average: " + String.format("%10.2f", 1000.0/average) + " files per second");
}
};
readThread.start();
threads[i] = readThread;
}
for (int i = 0; i < threads.length; i++)
{
threads[i].join();
}
}
private static String getUsage()
{
StringBuilder sb = new StringBuilder();
sb.append("FileFolderPerformanceTester usage: ").append("\n");
sb.append(" FileFolderPerformanceTester --files=<filecount> --threads=<threadcount> --folder=<folderref>").append("\n");
sb.append(" filecount: number of files in the folder").append("\n");
sb.append(" threadcount: number of threads to do the directory listing").append("\n");
return sb.toString();
}
}

View File

@@ -0,0 +1,853 @@
package org.alfresco.repo.model.filefolder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.dictionary.DictionaryNamespaceComponent;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback;
import org.alfresco.repo.imap.AlfrescoImapFolder;
import org.alfresco.repo.imap.AlfrescoImapUser;
import org.alfresco.repo.imap.ImapService;
import org.alfresco.repo.model.filefolder.HiddenAspect.Visibility;
import org.alfresco.repo.search.impl.lucene.LuceneQueryParser;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.FileFilterMode;
import org.alfresco.util.FileFilterMode.Client;
import org.alfresco.util.GUID;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyMap;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.springframework.context.ApplicationContext;
public class HiddenAspectTest
{
@Rule public TestName name = new TestName();
private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private HiddenAspect hiddenAspect;
private TransactionService transactionService;
private NodeDAO nodeDAO;
private NodeService nodeService;
private FileFolderService fileFolderService;
private MutableAuthenticationService authenticationService;
private PermissionService permissionService;
private UserTransaction txn;
private SearchService searchService;
private DictionaryNamespaceComponent namespacePrefixResolver;
private ImapService imapService;
private PersonService personService;
private FilenameFilteringInterceptor interceptor;
private StoreRef storeRef;
private NodeRef rootNodeRef;
private NodeRef topNodeRef;
private boolean imapEnabled;
private final String MAILBOX_NAME_A = "mailbox_a";
private final String MAILBOX_NAME_B = ".mailbox_a";
private String username;
private AlfrescoImapUser user;
@Before
public void setup() throws SystemException, NotSupportedException
{
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
transactionService = serviceRegistry.getTransactionService();
nodeService = serviceRegistry.getNodeService();
fileFolderService = serviceRegistry.getFileFolderService();
authenticationService = (MutableAuthenticationService) ctx.getBean("AuthenticationService");
hiddenAspect = (HiddenAspect) ctx.getBean("hiddenAspect");
interceptor = (FilenameFilteringInterceptor) ctx.getBean("filenameFilteringInterceptor");
namespacePrefixResolver = (DictionaryNamespaceComponent) ctx.getBean("namespaceService");
imapService = serviceRegistry.getImapService();
personService = serviceRegistry.getPersonService();
searchService = serviceRegistry.getSearchService();
permissionService = serviceRegistry.getPermissionService();
imapEnabled = serviceRegistry.getImapService().getImapServerEnabled();
nodeDAO = (NodeDAO)ctx.getBean("nodeDAO");
// start the transaction
txn = transactionService.getUserTransaction();
txn.begin();
username = "user" + System.currentTimeMillis();
PropertyMap testUser = new PropertyMap();
testUser.put(ContentModel.PROP_USERNAME, username);
testUser.put(ContentModel.PROP_FIRSTNAME, username);
testUser.put(ContentModel.PROP_LASTNAME, username);
testUser.put(ContentModel.PROP_EMAIL, username + "@alfresco.com");
testUser.put(ContentModel.PROP_JOBTITLE, "jobTitle");
// authenticate
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
personService.createPerson(testUser);
// create the ACEGI Authentication instance for the new user
authenticationService.createAuthentication(username, username.toCharArray());
user = new AlfrescoImapUser(username + "@alfresco.com", username, username);
// create a test store
storeRef = nodeService
.createStore(StoreRef.PROTOCOL_WORKSPACE, getName() + System.currentTimeMillis());
rootNodeRef = nodeService.getRootNode(storeRef);
permissionService.setPermission(rootNodeRef, username, PermissionService.CREATE_CHILDREN, true);
AuthenticationUtil.setFullyAuthenticatedUser(username);
topNodeRef = nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.ALFRESCO_URI, "working root"),
ContentModel.TYPE_FOLDER).getChildRef();
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
}
private String getName()
{
return name.getMethodName();
}
@After
public void tearDown() throws Exception
{
try
{
if (txn.getStatus() != Status.STATUS_ROLLEDBACK && txn.getStatus() != Status.STATUS_COMMITTED)
{
txn.commit();
}
}
catch (Throwable e)
{
e.printStackTrace();
}
}
@Test
public void testHiddenFilesEnhancedClient()
{
FileFilterMode.setClient(Client.webdav);
try
{
// check temporary file
NodeRef parent = fileFolderService.create(topNodeRef, "New Folder", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef child = fileFolderService.create(parent, "file.tmp", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY));
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
List<FileInfo> children = fileFolderService.list(parent);
assertEquals(1, children.size());
// check hidden files - should be hidden for an enhanced client
parent = fileFolderService.create(topNodeRef, "abc", ContentModel.TYPE_FOLDER).getNodeRef();
child = fileFolderService.create(parent, ".TemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef child1 = fileFolderService.create(child, "inTemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef();
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY));
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_TEMPORARY));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_INDEX_CONTROL));
ResultSet results = searchForName(".TemporaryItems");
assertEquals("", 0, results.length());
children = fileFolderService.list(parent);
assertEquals(1, children.size());
Client saveClient = FileFilterMode.setClient(Client.script);
try
{
children = fileFolderService.list(parent);
}
finally
{
FileFilterMode.setClient(saveClient);
}
assertEquals(0, children.size());
parent = fileFolderService.create(topNodeRef, "Folder 2", ContentModel.TYPE_FOLDER).getNodeRef();
child = fileFolderService.create(parent, "Thumbs.db", ContentModel.TYPE_CONTENT).getNodeRef();
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY));
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName("Thumbs.db");
assertEquals("", 0, results.length());
children = fileFolderService.list(parent);
assertEquals(1, children.size());
// set hidden attribute for cifs, webdav. ftp, nfs should be able to see, other clients not
assertEquals(Visibility.Visible, hiddenAspect.getVisibility(Client.ftp, child));
assertEquals(Visibility.Visible, hiddenAspect.getVisibility(Client.nfs, child));
assertEquals(Visibility.Visible, hiddenAspect.getVisibility(Client.webdav, child));
assertEquals(Visibility.HiddenAttribute, hiddenAspect.getVisibility(Client.cifs, child));
assertEquals(Visibility.NotVisible, hiddenAspect.getVisibility(Client.script, child));
assertEquals(Visibility.NotVisible, hiddenAspect.getVisibility(Client.webclient, child));
// surf-config should not be visible to any client
NodeRef node = fileFolderService.create(topNodeRef, "surf-config", ContentModel.TYPE_FOLDER).getNodeRef();
assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName("surf-config");
assertEquals("", 0, results.length());
for(Client client : hiddenAspect.getClients())
{
if(!client.equals(Client.admin))
{
assertEquals(Visibility.NotVisible, hiddenAspect.getVisibility(client, node));
}
}
// .DS_Store is a system path and so is visible in nfs and webdav, as a hidden file in cifs and hidden to all other clients
node = fileFolderService.create(topNodeRef, ".DS_Store", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName(".DS_Store");
assertEquals("", 0, results.length());
for(Client client : hiddenAspect.getClients())
{
if(client == Client.cifs)
{
assertEquals("Should have hidden attribute set for client " + client, Visibility.HiddenAttribute, hiddenAspect.getVisibility(client, node));
}
else if(client == Client.webdav || client == Client.nfs || client == Client.ftp)
{
assertEquals("Should be visible for client " + client, Visibility.Visible, hiddenAspect.getVisibility(client, node));
}
else if(client != Client.admin)
{
assertEquals("Should not be visible for client " + client, Visibility.NotVisible, hiddenAspect.getVisibility(client, node));
}
}
// Resource fork should not be visible to any client
node = fileFolderService.create(topNodeRef, "._resourceFork", ContentModel.TYPE_FOLDER).getNodeRef();
assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName("._resourceFork");
assertEquals("", 0, results.length());
for(Client client : hiddenAspect.getClients())
{
if(client != Client.admin)
{
assertEquals("Client " + client.toString(), Visibility.NotVisible, hiddenAspect.getVisibility(client, node));
}
}
}
finally
{
FileFilterMode.clearClient();
}
}
@Test
public void testClientControlled() throws Exception
{
// test that a client controlled hidden node is not subject to hidden file patterns
{
// node does not match a hidden file pattern
String nodeName = GUID.generate();
String hiddenNodeName = nodeName;
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(11);
properties.put(ContentModel.PROP_NAME, hiddenNodeName);
// create the node
QName assocQName = QName.createQName(
NamespaceService.CONTENT_MODEL_1_0_URI,
QName.createValidLocalName(hiddenNodeName));
ChildAssociationRef assocRef = null;
try
{
assocRef = nodeService.createNode(
topNodeRef,
ContentModel.ASSOC_CONTAINS,
assocQName,
ContentModel.TYPE_FOLDER,
properties);
}
catch (DuplicateChildNodeNameException e)
{
throw new FileExistsException(topNodeRef, hiddenNodeName);
}
NodeRef parent = assocRef.getChildRef();
NodeRef child = null;
NodeRef child1 = null;
Client saveClient = FileFilterMode.setClient(Client.cmis);
try
{
hiddenAspect.hideNode(parent, true, true, true);
child = fileFolderService.create(parent, "folder11", ContentModel.TYPE_FOLDER).getNodeRef();
child1 = fileFolderService.create(child, "folder21", ContentModel.TYPE_FOLDER).getNodeRef();
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_INDEX_CONTROL));
// renaming from a hidden file pattern to a non-hidden file pattern should leave the node as hidden
// because it is client-controlled.
fileFolderService.rename(parent, nodeName);
assertTrue(nodeService.hasAspect(parent, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(parent, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_INDEX_CONTROL));
}
finally
{
FileFilterMode.setClient(saveClient);
}
List<FileInfo> children = fileFolderService.list(parent);
assertEquals(0, children.size());
saveClient = FileFilterMode.setClient(Client.script);
try
{
children = fileFolderService.list(parent);
}
finally
{
FileFilterMode.setClient(saveClient);
}
assertEquals(0, children.size());
saveClient = FileFilterMode.setClient(Client.cmis);
try
{
children = fileFolderService.list(parent);
}
finally
{
FileFilterMode.setClient(saveClient);
}
assertEquals(0, children.size());
// remove the client-controlled hidden aspect from the parent and check that it is no longer hidden
saveClient = FileFilterMode.setClient(Client.cmis);
try
{
nodeService.removeAspect(parent, ContentModel.ASPECT_HIDDEN);
assertFalse(nodeService.hasAspect(parent, ContentModel.ASPECT_HIDDEN));
}
finally
{
FileFilterMode.setClient(saveClient);
}
}
// test that a cascading hidden pattern defined in model-specific-services-content.xml results in hidden files
// (node is not client-controlled hidden)
{
NodeRef parent = null;
NodeRef child = null;
NodeRef child1 = null;
Client saveClient = FileFilterMode.setClient(Client.cmis);
try
{
parent = fileFolderService.create(topNodeRef, "." + GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
child = fileFolderService.create(parent, "folder11", ContentModel.TYPE_FOLDER).getNodeRef();
child1 = fileFolderService.create(child, "folder21", ContentModel.TYPE_FOLDER).getNodeRef();
}
finally
{
FileFilterMode.setClient(saveClient);
}
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(child1, ContentModel.ASPECT_INDEX_CONTROL));
List<FileInfo> children = fileFolderService.list(parent);
assertEquals(0, children.size());
saveClient = FileFilterMode.setClient(Client.script);
try
{
children = fileFolderService.list(parent);
}
finally
{
FileFilterMode.setClient(saveClient);
}
assertEquals(0, children.size());
saveClient = FileFilterMode.setClient(Client.cmis);
try
{
children = fileFolderService.list(parent);
}
finally
{
FileFilterMode.setClient(saveClient);
}
assertEquals(0, children.size());
}
}
@Test
public void testImap()
{
if(imapEnabled)
{
FileFilterMode.setClient(Client.webdav);
try
{
// Test that hidden files don't apply to imap service
imapService.getOrCreateMailbox(user, MAILBOX_NAME_A, false, true);
imapService.renameMailbox(user, MAILBOX_NAME_A, MAILBOX_NAME_B);
assertFalse("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_A));
assertTrue("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_B));
assertEquals("Can't rename mailbox", 0, numMailboxes(user, MAILBOX_NAME_A));
assertEquals("Can't rename mailbox", 1, numMailboxes(user, MAILBOX_NAME_B));
}
finally
{
FileFilterMode.clearClient();
}
}
}
@Test
public void testRename()
{
FileFilterMode.setClient(Client.webdav);
try
{
// Test renaming
String nodeName = GUID.generate();
NodeRef node = fileFolderService.create(topNodeRef, nodeName, ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef node11 = fileFolderService.create(node, nodeName + ".11", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef node12 = fileFolderService.create(node, nodeName + ".12", ContentModel.TYPE_CONTENT).getNodeRef();
NodeRef node21 = fileFolderService.create(node11, nodeName + ".21", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef node22 = fileFolderService.create(node11, nodeName + ".22", ContentModel.TYPE_CONTENT).getNodeRef();
NodeRef node31 = fileFolderService.create(node21, ".31", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef node41 = fileFolderService.create(node31, nodeName + ".41", ContentModel.TYPE_CONTENT).getNodeRef();
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node11, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node11, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node21, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node21, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node22, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node22, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_INDEX_CONTROL));
ResultSet results = searchForName(nodeName);
assertEquals("", 1, results.length());
try
{
fileFolderService.rename(node, "." + nodeName);
}
catch (FileExistsException e)
{
fail();
}
catch (FileNotFoundException e)
{
fail();
}
assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node11, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node11, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node21, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node21, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node22, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node22, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName(nodeName);
assertEquals("", 0, results.length());
results = searchForName("." + nodeName);
assertEquals("", 0, results.length());
try
{
fileFolderService.rename(node, nodeName);
}
catch (FileExistsException e)
{
fail();
}
catch (FileNotFoundException e)
{
fail();
}
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node11, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node11, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node21, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node21, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(node22, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node22, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_INDEX_CONTROL));
assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_HIDDEN));
assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName(nodeName);
assertEquals("", 1, results.length());
}
finally
{
FileFilterMode.clearClient();
}
}
@Test
public void testHiddenFilesBasicClient()
{
if(imapEnabled)
{
FileFilterMode.setClient(Client.imap);
try
{
// check temporary file
NodeRef parent = fileFolderService.create(topNodeRef, "New Folder", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef child = fileFolderService.create(parent, "file.tmp", ContentModel.TYPE_CONTENT).getNodeRef();
assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY));
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_INDEX_CONTROL));
ResultSet results = searchForName("file.tmp");
assertEquals("", 1, results.length());
List<FileInfo> children = fileFolderService.list(parent);
assertEquals(1, children.size());
// check hidden files - should not be hidden for a basic client
parent = fileFolderService.create(topNodeRef, ".TemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef();
child = fileFolderService.create(parent, "inTemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef();
assertFalse(nodeService.hasAspect(parent, ContentModel.ASPECT_TEMPORARY));
assertFalse(nodeService.hasAspect(parent, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(parent, ContentModel.ASPECT_INDEX_CONTROL));
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY));
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName(".TemporaryItems");
assertEquals("", 1, results.length());
children = fileFolderService.list(parent);
assertEquals(1, children.size());
parent = fileFolderService.create(topNodeRef, "Folder 2", ContentModel.TYPE_FOLDER).getNodeRef();
child = fileFolderService.create(parent, "Thumbs.db", ContentModel.TYPE_CONTENT).getNodeRef();
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY));
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName("Thumbs.db");
assertEquals("", 1, results.length());
children = fileFolderService.list(parent);
assertEquals(1, children.size());
NodeRef node = fileFolderService.create(topNodeRef, "surf-config", ContentModel.TYPE_FOLDER).getNodeRef();
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName("surf-config");
assertEquals("", 1, results.length());
node = fileFolderService.create(topNodeRef, ".DS_Store", ContentModel.TYPE_CONTENT).getNodeRef();
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName(".DS_Store");
assertEquals("", 1, results.length());
for(Client client : hiddenAspect.getClients())
{
assertEquals("Should be visible for client " + client, Visibility.Visible, hiddenAspect.getVisibility(client, node));
}
node = fileFolderService.create(topNodeRef, "._resourceFork", ContentModel.TYPE_FOLDER).getNodeRef();
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName("._resourceFork");
assertEquals("", 1, results.length());
children = fileFolderService.list(parent);
assertEquals(1, children.size());
String nodeName = "Node" + System.currentTimeMillis();
node = fileFolderService.create(topNodeRef, nodeName, ContentModel.TYPE_CONTENT).getNodeRef();
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName(nodeName);
assertEquals("", 1, results.length());
try
{
fileFolderService.rename(node, "." + nodeName);
}
catch (FileExistsException e)
{
fail();
}
catch (FileNotFoundException e)
{
fail();
}
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName(nodeName);
assertEquals("", 1, results.length());
results = searchForName("." + nodeName);
assertEquals("", 1, results.length());
try
{
fileFolderService.rename(node, nodeName);
}
catch (FileExistsException e)
{
fail();
}
catch (FileNotFoundException e)
{
fail();
}
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN));
assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL));
results = searchForName("." + nodeName);
assertEquals("", 1, results.length());
imapService.getOrCreateMailbox(user, MAILBOX_NAME_A, false, true);
imapService.renameMailbox(user, MAILBOX_NAME_A, MAILBOX_NAME_B);
assertFalse("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_A));
assertTrue("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_B));
assertEquals("Can't rename mailbox", 0, numMailboxes(user, MAILBOX_NAME_A));
assertEquals("Can't rename mailbox", 1, numMailboxes(user, MAILBOX_NAME_B));
}
finally
{
FileFilterMode.clearClient();
}
}
}
@SuppressWarnings("unused")
@Test
public void testCheckHidden() throws Exception
{
String nodeName = GUID.generate();
interceptor.setEnabled(false);
try
{
// Create some nodes that should be hidden but aren't
NodeRef node = fileFolderService.create(topNodeRef, nodeName, ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef node11 = fileFolderService.create(node, nodeName + ".11", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef node12 = fileFolderService.create(node, ".12", ContentModel.TYPE_CONTENT).getNodeRef();
NodeRef node21 = fileFolderService.create(node11, nodeName + ".21", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef node22 = fileFolderService.create(node11, nodeName + ".22", ContentModel.TYPE_CONTENT).getNodeRef();
NodeRef node31 = fileFolderService.create(node21, ".31", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef node41 = fileFolderService.create(node31, nodeName + ".41", ContentModel.TYPE_CONTENT).getNodeRef();
assertEquals(1, searchForName(".12").length());
assertEquals(1, searchForName(".31").length());
assertEquals(1, searchForName(nodeName + ".41").length());
txn.commit();
}
finally
{
interceptor.setEnabled(true);
}
}
@Test
public void testHideNodeExplicit() throws Exception
{
FileFilterMode.setClient(Client.cifs);
try
{
// check temporary file
NodeRef parent = fileFolderService.create(topNodeRef, "New Folder", ContentModel.TYPE_FOLDER).getNodeRef();
NodeRef childA = fileFolderService.create(parent, "fileA", ContentModel.TYPE_CONTENT).getNodeRef();
NodeRef childB = fileFolderService.create(parent, "Thumbs.db", ContentModel.TYPE_CONTENT).getNodeRef();
hiddenAspect.hideNodeExplicit(childA);
// Nodes A and B should be hidden, one by pattern, one explicit
assertTrue("node a should be hidden", nodeService.hasAspect(childA, ContentModel.ASPECT_HIDDEN));
// assertFalse("node b should be hidden", nodeService.hasAspect(childB, ContentModel.ASPECT_HIDDEN));
{
List<FileInfo> children = fileFolderService.list(parent);
assertEquals(2, children.size());
}
hiddenAspect.unhideExplicit(childA);
hiddenAspect.unhideExplicit(childB);
// Node B should still be hidden, A should not
assertFalse(nodeService.hasAspect(childA, ContentModel.ASPECT_HIDDEN));
// assertTrue(nodeService.hasAspect(childB, ContentModel.ASPECT_HIDDEN));
// call checkHidden to maks sure it does not make a mistake
hiddenAspect.checkHidden(childA, true, false);
// hiddenAspect.checkHidden(childB, true);
{
List<FileInfo> children = fileFolderService.list(parent);
assertEquals(2, children.size());
}
// Node B should still be hidden, A should not
assertFalse(nodeService.hasAspect(childA, ContentModel.ASPECT_HIDDEN));
// assertTrue(nodeService.hasAspect(childB, ContentModel.ASPECT_HIDDEN));
{
List<FileInfo> children = fileFolderService.list(parent);
assertEquals(2, children.size());
}
}
finally
{
FileFilterMode.clearClient();
}
}
private List<NodeRef> getHiddenNodes(final StoreRef storeRef)
{
final List<NodeRef> nodes = new ArrayList<NodeRef>(20);
NodeRefQueryCallback resultsCallback = new NodeRefQueryCallback()
{
@Override
public boolean handle(Pair<Long, NodeRef> nodePair)
{
if(storeRef == null || nodePair.getSecond().getStoreRef().equals(storeRef))
{
nodes.add(nodePair.getSecond());
}
return true;
}
};
nodeDAO.getNodesWithAspects(Collections.singleton(ContentModel.ASPECT_HIDDEN), 0l, Long.MAX_VALUE, resultsCallback);
return nodes;
}
private int numMailboxes(AlfrescoImapUser user, String mailboxName)
{
int numMailboxes = 0;
try
{
List<AlfrescoImapFolder> folders = imapService.listMailboxes(user, mailboxName, false);
numMailboxes = folders.size();
}
catch (AlfrescoRuntimeException e)
{
fail("Unexpected exception: " + e.getMessage());
}
return numMailboxes;
}
private boolean checkMailbox(AlfrescoImapUser user, String mailboxName)
{
try
{
imapService.getOrCreateMailbox(user, mailboxName, true, false);
}
catch (AlfrescoRuntimeException e)
{
return false;
}
return true;
}
private ResultSet searchForName(String name)
{
SearchParameters sp = new SearchParameters();
sp.addStore(rootNodeRef.getStoreRef());
sp.setLanguage("lucene");
sp.setQuery("@" + LuceneQueryParser.escape(ContentModel.PROP_NAME.toString()) + ":\"" + name + "\"");
sp.addLocale(new Locale("en"));
return searchService.query(sp);
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model.ml.tools;
import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.archive.NodeArchiveService;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
import org.alfresco.service.cmr.ml.EditionService;
import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ApplicationContext;
/**
* Base multilingual test cases
*
* @author yanipig
*/
public abstract class AbstractMultilingualTestCases extends TestCase
{
protected static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
protected ServiceRegistry serviceRegistry;
protected AuthenticationComponent authenticationComponent;
protected TransactionService transactionService;
protected NodeService nodeService;
protected FileFolderService fileFolderService;
protected VersionService versionService;
protected MultilingualContentService multilingualContentService;
protected NodeRef folderNodeRef;
protected ContentFilterLanguagesService contentFilterLanguagesService;
protected NodeArchiveService nodeArchiveService;
protected EditionService editionService;
@Override
protected void setUp() throws Exception
{
nodeArchiveService = (NodeArchiveService) ctx.getBean("nodeArchiveService");
serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
authenticationComponent = (AuthenticationComponent) ctx.getBean("AuthenticationComponent");
transactionService = serviceRegistry.getTransactionService();
nodeService = serviceRegistry.getNodeService();
fileFolderService = serviceRegistry.getFileFolderService();
versionService = serviceRegistry.getVersionService();
multilingualContentService = (MultilingualContentService) ctx.getBean("MultilingualContentService");
contentFilterLanguagesService = (ContentFilterLanguagesService) ctx.getBean("ContentFilterLanguagesService");
editionService = (EditionService) ctx.getBean("EditionService");
// Run as admin
authenticationComponent.setCurrentUser(AuthenticationUtil.getAdminUserName());
// Create a folder to work in
RetryingTransactionCallback<NodeRef> createFolderCallback = new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Exception
{
StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
// Create the folder
NodeRef folderNodeRef = nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testFolder"),
ContentModel.TYPE_FOLDER).getChildRef();
// done
return folderNodeRef;
}
};
folderNodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(createFolderCallback);
}
@Override
protected void tearDown() throws Exception
{
// Clear authentication
try
{
authenticationComponent.clearCurrentSecurityContext();
}
catch (Throwable e)
{
e.printStackTrace();
}
}
protected NodeRef createContent()
{
String name = "" + System.currentTimeMillis();
return createContent(name);
}
protected NodeRef createContent(String name)
{
NodeRef contentNodeRef = fileFolderService.create(
folderNodeRef,
name,
ContentModel.TYPE_CONTENT).getNodeRef();
// add some content
ContentWriter contentWriter = fileFolderService.getWriter(contentNodeRef);
contentWriter.putContent("ABC");
// done
return contentNodeRef;
}
public void testSetup() throws Exception
{
// Ensure that content can be created
createContent();
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model.ml.tools;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/**
* Content filter language service test cases
*
* @see org.alfresco.service.cmr.ml.ContentFilterLanguagesService
* @see org.alfresco.repo.model.ml.ContentFilterLanguagesMap
*
* @author Yannick Pignot
*/
public class ContentFilterLanguagesMapTest extends AbstractMultilingualTestCases
{
public void testGetFilterLanguages() throws Exception
{
// get the list of content filter languages
List<String> lggs = contentFilterLanguagesService.getFilterLanguages();
// Ensure that the list is not null
assertNotNull("Language list is null", lggs);
// Ensure that the list is read-only
try
{
lggs.add("NEW LOCALE");
assertTrue("Add a value to the content filter language list is not permit, this list would be read only", false);
}
catch (Exception e)
{
// test case ok
}
try
{
lggs.remove(0);
assertTrue("Remove a value to the content filter language list is not permit, this list would be read only", false);
}
catch (Exception e)
{
// test case ok
}
}
@SuppressWarnings("unchecked")
public void testGetMissingLanguages() throws Exception
{
List<String> lggs = contentFilterLanguagesService.getFilterLanguages();
// get missing languages with null parameter
List<String> missingLggsNull = contentFilterLanguagesService.getMissingLanguages(null);
// Ensure that the returned list is not null
assertNotNull("Language list returned with the null parameter is null", missingLggsNull);
// Ensure that the returned list is entire
assertEquals("Language list returned with the null parameter corrupted", missingLggsNull.size(), lggs.size());
// get missing languages with empty collection parameter
List<String> missingLggsEmpty = contentFilterLanguagesService.getMissingLanguages(Collections.EMPTY_LIST);
// Ensure that the returned list is not null
assertNotNull("Language list returned with the empty parameter is null", missingLggsEmpty);
// Ensure that the returned list is entire
assertEquals("Language list returned with the empty parameter corrupted", missingLggsEmpty.size(), lggs.size());
// get missing languages with a two locale list
List<String> param = new ArrayList<String>();
param.add(0, lggs.get(0));
param.add(1, lggs.get(1));
List<String> missingLggsOk = contentFilterLanguagesService.getMissingLanguages(param);
// Ensure that the returned list is not null
assertNotNull("Language list returned with the correct parameter is null", missingLggsOk);
// Ensure that the returned list size is correct
assertEquals("Language list size returned with the correct parameter is not correct", missingLggsOk.size(), (lggs.size() - 2));
// Ensure that the returned list don't content the preceding locales
assertFalse("Language found : " + param.get(0), missingLggsOk.contains(param.get(0)));
assertFalse("Language found : " + param.get(1), missingLggsOk.contains(param.get(1)));
// get missing languages with a not found locale
param.add(2, "WRONG LOCALE CODE");
List<String> missingLggsWrong = contentFilterLanguagesService.getMissingLanguages(param);
// Ensure that the returned list is not null
assertNotNull("Language list returned with the wrong parameter is null", missingLggsWrong);
// Ensure that the returned list size is correct
assertEquals("Language list size returned with the correct parameter is not correct", missingLggsWrong.size(), (lggs.size() - 2));
// Ensure that the returned list don't content the wrong locale
assertFalse("Language found : " + param.get(0), missingLggsWrong.contains(param.get(0)));
assertFalse("Language found : " + param.get(1), missingLggsWrong.contains(param.get(1)));
assertFalse("Language found : " + param.get(2), missingLggsWrong.contains(param.get(2)));
}
public void testISOCodeConvertions() throws Exception
{
// New ISO code list
String[] newCode = {"he", "id", "yi"};
String[] oldCode = {"iw", "in", "ji"};
Locale loc0 = new Locale(newCode[0]);
Locale loc1 = new Locale(newCode[1]);
Locale loc2 = new Locale(newCode[2]);
// Ensure that java.util.Locale has converted the new ISO code into new iso code
assertEquals("java.util.Locale Convertion not correct for " + newCode[0], oldCode[0], loc0.getLanguage());
assertEquals("java.util.Locale Convertion not correct for " + newCode[1], oldCode[1], loc1.getLanguage());
assertEquals("java.util.Locale Convertion not correct for " + newCode[2], oldCode[2], loc2.getLanguage());
// Ensure that the convertion is correcte
assertEquals("Convertion of new ISO codes not correct for " + newCode[0], oldCode[0], contentFilterLanguagesService.convertToOldISOCode(newCode[0]));
assertEquals("Convertion of new ISO codes not correct for " + newCode[1], oldCode[1], contentFilterLanguagesService.convertToOldISOCode(newCode[1]));
assertEquals("Convertion of new ISO codes not correct for " + newCode[2], oldCode[2], contentFilterLanguagesService.convertToOldISOCode(newCode[2]));
assertEquals("Convertion of old ISO codes not correct for " + oldCode[0], newCode[0], contentFilterLanguagesService.convertToNewISOCode(oldCode[0]));
assertEquals("Convertion of old ISO codes not correct for " + oldCode[1], newCode[1], contentFilterLanguagesService.convertToNewISOCode(oldCode[1]));
assertEquals("Convertion of old ISO codes not correct for " + oldCode[2], newCode[2], contentFilterLanguagesService.convertToNewISOCode(oldCode[2]));
}
}

View File

@@ -0,0 +1,579 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model.ml.tools;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory;
import org.alfresco.service.cmr.version.VersionType;
/**
* Edition Service test cases
*
* @since 2.1
* @author Yannick Pignot
*/
public class EditionServiceImplTest extends AbstractMultilingualTestCases
{
private static String FRENCH_CONTENT = "FRENCH_CONTENT";
private static String CHINESE_CONTENT = "CHINESE_CONTENT";
private static String JAPANESE_CONTENT = "JAPANESE_CONTENT";
private ContentService contentService;
@Override
protected void setUp() throws Exception
{
super.setUp();
contentService = serviceRegistry.getContentService();
}
public void testAutoEdition() throws Exception
{
// create a mlContainer with some content
checkFirstVersion(this.createMLContainerWithContent());
}
public void testEditionLabels()
{
// create a mlContainer with some content
NodeRef mlContainerNodeRef = createMLContainerWithContent();
Map<String, Serializable> versionProperties = null;
List<Version> editions = null;
NodeRef pivot = multilingualContentService.getPivotTranslation(mlContainerNodeRef);
checkFirstVersion(mlContainerNodeRef);
/*
* at the creation (1.0)
*/
Version rootEdition = editionService.getEditions(mlContainerNodeRef).getAllVersions().iterator().next();
// Ensure that the version label is 1.0
assertTrue("The edition label would be 1.0 and not " + rootEdition.getVersionLabel(), rootEdition.getVersionLabel().equals("1.0"));
/*
* default (1.1)
*/
pivot = editionService.createEdition(pivot, versionProperties);
editions = new ArrayList<Version>(editionService.getEditions(mlContainerNodeRef).getAllVersions());
Version firstEdition = editions.get(0);
// Ensure that the version label is 1.1
assertTrue("The edition label would be 1.1 and not " + firstEdition.getVersionLabel(), firstEdition.getVersionLabel().equals("1.1"));
/*
* major (2.0)
*/
versionProperties = new HashMap<String, Serializable>();
versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR);
pivot = editionService.createEdition(pivot, versionProperties);
editions = new ArrayList<Version>(editionService.getEditions(mlContainerNodeRef).getAllVersions());
Version secondEdition = editions.get(0);
// Ensure that the version label is 2.0
assertTrue("The edition label would be 2.0 and not " + secondEdition.getVersionLabel(), secondEdition.getVersionLabel().equals("2.0"));
/*
* minor (2.1)
*/
versionProperties = new HashMap<String, Serializable>();
versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR);
pivot = editionService.createEdition(pivot, versionProperties);
editions = new ArrayList<Version>(editionService.getEditions(mlContainerNodeRef).getAllVersions());
Version thirdEdition = editions.get(0);
// Ensure that the version label is 2.1
assertTrue("The edition label would be 2.1 and not " + thirdEdition.getVersionLabel(), thirdEdition.getVersionLabel().equals("2.1"));
}
public void testCreateEdition() throws Exception
{
// create a mlContainer with some content
NodeRef mlContainerNodeRef = createMLContainerWithContent();
// get the french translation
NodeRef frenchContentNodeRef = multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH);
checkFirstVersion(mlContainerNodeRef);
// create a new edition form the french translation
NodeRef newStartingPoint = editionService.createEdition(frenchContentNodeRef, null);
// get the edition history
VersionHistory editionHistory = editionService.getEditions(mlContainerNodeRef);
// Ensure that the edition history contains two versions
assertTrue("The edition history must contain two versions", editionHistory.getAllVersions().size() == 2);
// Ensure that the locale of the container is changer
assertTrue("The locale of the conatiner should be changed", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE).equals(Locale.FRENCH));
// get the two editions
Version rootEdition = editionHistory.getVersion("1.0");
Version actualEdition = editionHistory.getVersion("1.1");
// get the translations of the root versions
List<VersionHistory> rootVersionTranslations = editionService.getVersionedTranslations(rootEdition);
// Ensure that the editions are not null
assertNotNull("The root edition can't be null", rootEdition);
assertNotNull("The actual edition can't be null", actualEdition);
assertNotNull("The translations list of the root edition can't be null", rootVersionTranslations);
// Ensure that the new starting document noderef is different that the initial one
assertFalse("The created starting document must be different that the starting document of the edition", frenchContentNodeRef.equals(newStartingPoint));
// Ensure that the new starting document is the pivot of the current translation
assertTrue("The new pivot must be equal to the created starting document", newStartingPoint.equals(multilingualContentService.getPivotTranslation(mlContainerNodeRef)));
int numberOfTranslations;
// Ensure that the current translations size is 1
numberOfTranslations = multilingualContentService.getTranslations(mlContainerNodeRef).size();
assertEquals("The number of translations must be 1 and not " + numberOfTranslations, 1, numberOfTranslations);
// Ensure that the number of translations of the current edition is 0
numberOfTranslations = editionService.getVersionedTranslations(actualEdition).size();
assertEquals("The number of translations must be 0 and not " + numberOfTranslations, 0, numberOfTranslations);
// Ensure that the number of translations of the root verions is 3
numberOfTranslations = rootVersionTranslations.size();
assertEquals("The number of translations must be 3 and not " + numberOfTranslations, 3, numberOfTranslations);
}
public void testReadVersionedContent() throws Exception
{
}
public void testReadVersionedProperties() throws Exception
{
}
//ALF-6275
public void testEditionServiceWithContent()
{
// create a mlContainer with some content
NodeRef mlContainerNodeRef = createMLContainerWithContent("1.0");
// get the french translation
NodeRef frenchContentNodeRef = multilingualContentService.getTranslationForLocale(mlContainerNodeRef,
Locale.FRENCH);
checkContentVersionValuesForEditions(mlContainerNodeRef);
// create a new edition starting from the french translation
NodeRef newStartingPoint = editionService.createEdition(frenchContentNodeRef, null);
frenchContentNodeRef = multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH);
modifyContent(frenchContentNodeRef, FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "1.1" + "-" + "0.2");
checkContentVersionValuesForEditions(mlContainerNodeRef);
modifyContent(frenchContentNodeRef, FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "1.1" + "-" + "0.3");
checkContentVersionValuesForEditions(mlContainerNodeRef);
modifyContent(frenchContentNodeRef, FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "1.1" + "-" + "0.4");
// checkContentVersionValuesForEditions(mlContainerNodeRef);
frenchContentNodeRef = multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH);
newStartingPoint = editionService.createEdition(frenchContentNodeRef, null);
frenchContentNodeRef = multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH);
modifyContent(frenchContentNodeRef, FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "1.2" + "-" + "0.2");
checkContentVersionValuesForEditions(mlContainerNodeRef);
modifyContent(frenchContentNodeRef, FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "1.2" + "-" + "0.3");
checkContentVersionValuesForEditions(mlContainerNodeRef);
NodeRef chineseContentNodeRef = createContent(CHINESE_CONTENT + "-" + Locale.CHINESE + "-" + "1.2" + "-1.0");
multilingualContentService.addTranslation(chineseContentNodeRef, mlContainerNodeRef, Locale.CHINESE);
checkContentVersionValuesForEditions(mlContainerNodeRef);
NodeRef japaneseContentNodeRef = createContent(JAPANESE_CONTENT + "-" + Locale.JAPANESE + "-" + "1.2" + "-1.0");
multilingualContentService.addTranslation(japaneseContentNodeRef, mlContainerNodeRef, Locale.JAPANESE);
checkContentVersionValuesForEditions(mlContainerNodeRef);
japaneseContentNodeRef = multilingualContentService
.getTranslationForLocale(mlContainerNodeRef, Locale.JAPANESE);
japaneseContentNodeRef = editionService.createEdition(japaneseContentNodeRef, null);
checkContentVersionValuesForEditions(mlContainerNodeRef);
japaneseContentNodeRef = multilingualContentService
.getTranslationForLocale(mlContainerNodeRef, Locale.JAPANESE);
modifyContent(japaneseContentNodeRef, JAPANESE_CONTENT + "-" + Locale.JAPANESE + "-" + "1.3" + "-0.2");
chineseContentNodeRef = createContent(CHINESE_CONTENT + "-" + Locale.CHINESE + "-" + "1.3" + "-1.0");
multilingualContentService.addTranslation(chineseContentNodeRef, mlContainerNodeRef, Locale.CHINESE);
checkContentVersionValuesForEditions(mlContainerNodeRef);
frenchContentNodeRef = createContent(FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "1.3" + "-1.0");
multilingualContentService.addTranslation(frenchContentNodeRef, mlContainerNodeRef, Locale.FRENCH);
checkContentVersionValuesForEditions(mlContainerNodeRef);
frenchContentNodeRef = multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH);
newStartingPoint = editionService.createEdition(frenchContentNodeRef, null);
frenchContentNodeRef = multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH);
modifyContent(frenchContentNodeRef, FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "1.4" + "-" + "0.2");
checkContentVersionValuesForEditions(mlContainerNodeRef);
japaneseContentNodeRef = multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.JAPANESE);
HashMap<String, Serializable> versionProperties = new HashMap<String, Serializable>();
versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR);
japaneseContentNodeRef = editionService.createEdition(japaneseContentNodeRef, versionProperties);
Collection<Version> editions = editionService.getEditions(mlContainerNodeRef).getAllVersions();
Version secondEdition = editions.iterator().next();
// Ensure that the version label is 2.0
assertTrue("The edition label would be 2.0 and not " + secondEdition.getVersionLabel(), secondEdition
.getVersionLabel().equals("2.0"));
frenchContentNodeRef = createContent(FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "1.0" + "-1.0");
modifyContent(frenchContentNodeRef, FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "1.0" + "-" + "1.1");
checkContentVersionValuesForEditions(mlContainerNodeRef);
frenchContentNodeRef = multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH);
versionProperties = new HashMap<String, Serializable>();
versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR);
frenchContentNodeRef = editionService.createEdition(frenchContentNodeRef, versionProperties);
editions = editionService.getEditions(mlContainerNodeRef).getAllVersions();
secondEdition = editions.iterator().next();
// Ensure that the version label is 3.0
assertTrue("The edition label would be 3.0 and not " + secondEdition.getVersionLabel(), secondEdition
.getVersionLabel().equals("3.0"));
modifyContent(frenchContentNodeRef, FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + "3.0" + "-" + "0.2");
checkContentVersionValuesForEditions(mlContainerNodeRef);
}
private void checkFirstVersion(NodeRef mlContainerNodeRef)
{
// get the edition list of edition
VersionHistory editionHistory = editionService.getEditions(mlContainerNodeRef);
// Ensure that the first edition of the mlContainer is created
assertNotNull("The edition history can't be null", editionHistory);
// Ensure that it contains only one version
assertTrue("The edition history must contain only one edition", editionHistory.getAllVersions().size() == 1);
// get the edition
Version currentEdition = editionHistory.getAllVersions().iterator().next();
// Ensure that this version is the edition of the mlContainer
assertTrue("The versioned mlContainer noderef of the editon must be the noderef of the created mlContainer", currentEdition.getVersionedNodeRef().equals(mlContainerNodeRef));
// get the list of translations
List<VersionHistory> translations = editionService.getVersionedTranslations(currentEdition);
// Ensure that the get versioned translations is empty
assertNotNull("The translations list of the current edition can't be null", translations);
// Ensure that the list is empty
assertTrue("The translations list of the current edition would be empty", translations.size() == 0);
}
private NodeRef createMLContainerWithContent()
{
NodeRef chineseContentNodeRef = createContent(CHINESE_CONTENT + "_1.0");
NodeRef frenchContentNodeRef = createContent(FRENCH_CONTENT + "_1.0");
NodeRef japaneseContentNodeRef = createContent(JAPANESE_CONTENT + "_1.0");
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
return multilingualContentService.getTranslationContainer(chineseContentNodeRef);
}
private void checkContentVersionValuesForEditions(NodeRef mlContainerNodeRef)
{
// the convention applied for this test is that the content MUST end up with
// _LOCALE_EDITION-VERION_INDIVIDUAL-VERSION
// get the edition list of edition
VersionHistory editionHistory = editionService.getEditions(mlContainerNodeRef);
// Ensure that the first edition of the mlContainer is created
assertNotNull("The edition history can't be null", editionHistory);
// Ensure that it contains only one version
assertTrue("The edition history must contain only one edition", editionHistory.getAllVersions().size() >= 1);
// iterate on editions
for (Version editionVersion : editionHistory.getAllVersions())
{
// getting the edition label
String editionLabel = editionVersion.getVersionLabel();
// check if it is the head version
if (editionHistory.getHeadVersion() == editionVersion)
{
// this is the living edition
System.out.println("Head version edition:" + editionLabel);
// dump content of head edition
Map<Locale, NodeRef> translations = multilingualContentService.getTranslations(mlContainerNodeRef);
Locale pivotLocale = (Locale) nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE);
Set<Locale> keySet = translations.keySet();
for (Locale locale : keySet)
{
NodeRef translatedNode = translations.get(locale);
// get content as string and compare
ContentReader reader = contentService.getReader(translatedNode, ContentModel.PROP_CONTENT);
String liveContent = reader.getContentString();
Triplet parsedTriplet = new Triplet(liveContent);
System.out.println("Content:" + liveContent);
// get all the version of current translation
VersionHistory versionHistory = versionService.getVersionHistory(translatedNode);
for (Version version : versionHistory.getAllVersions())
{
NodeRef frozenNodeRef = version.getFrozenStateNodeRef();
String versionLabel = version.getVersionLabel();
Locale versionLocale = (Locale) nodeService
.getProperty(frozenNodeRef, ContentModel.PROP_LOCALE);
// get content as string and compare
reader = contentService.getReader(frozenNodeRef, ContentModel.PROP_CONTENT);
String versionnedContent = reader.getContentString();
System.out.println("Individual version " + versionLabel + ":" + versionnedContent);
if (versionService.getCurrentVersion(translatedNode).getFrozenStateNodeRef().equals(
version.getFrozenStateNodeRef()))
{
// this is the head version of the translation therefore content should be equal
assertTrue(
"The content in head version should be equal to the content of the translation:",
versionnedContent.equals(liveContent));
}
// checking if content respects conventions XXX*locale*edition_version_*document_version
// the exception should be the version used to start the new edition with
// exception exist for root version because root version can be the first created
// and if is the pivot language then its content is a copy of the previous edition.
// This breaks the conventions and other checks must be done
if ((versionHistory.getRootVersion().getFrozenStateNodeRef().equals(version
.getFrozenStateNodeRef()))
&& (pivotLocale.equals(versionLocale)))
{
System.out.println("Some special on live version has to be done:" + versionnedContent);
// get previous edition
Version previousEditionVersion = editionHistory.getPredecessor(editionVersion);
if (previousEditionVersion != null)
{
String previousEditionLabel = previousEditionVersion.getVersionLabel();
System.out.println("Current edition Label:" + editionLabel + " Previous edition label:"
+ previousEditionLabel);
List<VersionHistory> versionTranslations = editionService
.getVersionedTranslations(previousEditionVersion);
// for all languages iterate to find the corresponding language
for (VersionHistory versionTranslation : versionTranslations)
{
// most recent first
Version newestVersion = versionTranslation.getHeadVersion();
NodeRef newestVersionFrozenNodeRef = newestVersion.getFrozenStateNodeRef();
String newestVersionVersionLabel = newestVersion.getVersionLabel();
ContentReader readerContentWeStartedWith = contentService.getReader(
newestVersionFrozenNodeRef, ContentModel.PROP_CONTENT);
Locale oldestVersionLocale = (Locale) nodeService.getProperty(
newestVersionFrozenNodeRef, ContentModel.PROP_LOCALE);
String contentWeStartedWith = readerContentWeStartedWith.getContentString();
System.out.println("CONTENT:" + contentWeStartedWith);
if (versionLocale.equals(oldestVersionLocale))
{
// content should match
assertTrue(
"The content in head version should be equal to the content we started with:",
contentWeStartedWith.equals(versionnedContent));
}
}
}
}
else
{
// it is not a root version therefore it should respect the conventions
Triplet testTriplet = new Triplet(versionnedContent);
assertEquals(testTriplet.locale, versionLocale.toString());
assertEquals(testTriplet.edition, editionLabel);
assertEquals(testTriplet.version, versionLabel);
}
}
}
}
else
{
// get pivot language of the current versionned edition
// This is not the current/head edition
Version nextEditionVersion = editionHistory.getSuccessors(editionVersion).iterator().next();
//get Next verion label
String nextEditionLabel = nextEditionVersion.getVersionLabel();
System.out.println("Edition:" + editionLabel + " Next edition label:" + nextEditionLabel);
// get the translations of the version
List<VersionHistory> versionTranslations = editionService.getVersionedTranslations(editionVersion);
// iterate on versionTranslations (all languages)
//strange that we have to go to the next edition to find the current pivot language.
//maybe there is a reason for that but not logical logical
dumpFrozenMetaData(editionVersion);
Locale editionPivotlanguage = (Locale) (editionService.getVersionedMetadatas(editionVersion)
.get(ContentModel.PROP_LOCALE));
System.out.println("Edition:" + editionLabel + " Previous pivot language:" + editionPivotlanguage + " Current pivot language:" + editionPivotlanguage);
for (VersionHistory versionTranslation : versionTranslations)
{
Collection<Version> versions = versionTranslation.getAllVersions();
// for a language, iterate on all versions
for (Version version : versions)
{
NodeRef frozenNodeRef = version.getFrozenStateNodeRef();
String versionLabel = version.getVersionLabel();
// get content language
Locale currentVersionLocale = (Locale) nodeService.getProperty(frozenNodeRef,
ContentModel.PROP_LOCALE);
System.out.println("Current version locale:" + currentVersionLocale
+ " Previous edition locale:" + editionPivotlanguage);
// get content as string and compare
ContentReader reader = contentService.getReader(frozenNodeRef, ContentModel.PROP_CONTENT);
String content = reader.getContentString();
System.out.println("Content:" + content);
// checking content respects conventions XXX*locale*edition_version_*document_version
// the exception should be the version used to start the new edition with
Version initialVersion = versionTranslation.getRootVersion();
if (initialVersion.equals(version) && currentVersionLocale.equals(editionPivotlanguage))
{
System.out.println("Some special test has to be done:" + content);
Version previousEditionVersion = editionHistory.getPredecessor(editionVersion);
if (previousEditionVersion != null)
{
String previousEditionLabel = previousEditionVersion.getVersionLabel();
System.out.println("Current edition Label:" + editionLabel + " Previous edition label:"
+ previousEditionLabel);
List<VersionHistory> versionTranslations2 = editionService
.getVersionedTranslations(previousEditionVersion);
// for all languages iterate to find the corresponding language
for (VersionHistory versionTranslation2 : versionTranslations2)
{
// most recent first
Version newestVersion = versionTranslation2.getHeadVersion();
NodeRef newestVersionFrozenNodeRef = newestVersion.getFrozenStateNodeRef();
String newestVersionVersionLabel = newestVersion.getVersionLabel();
ContentReader readerContentWeStartedWith = contentService.getReader(
newestVersionFrozenNodeRef, ContentModel.PROP_CONTENT);
Locale oldestVersionLocale = (Locale) nodeService.getProperty(
newestVersionFrozenNodeRef, ContentModel.PROP_LOCALE);
String contentWeStartedWith = readerContentWeStartedWith.getContentString();
System.out.println("CONTENT:" + contentWeStartedWith);
if (currentVersionLocale.equals(oldestVersionLocale))
{
// content should match
assertTrue(
"The content in head version should be equal to the content we started with:",
contentWeStartedWith.equals(content));
}
}
}
else
{
// normal invariant here because it is not the initial version
Triplet testTriplet = new Triplet(content);
assertTrue(testTriplet.locale.equals(currentVersionLocale.toString()));
assertTrue(testTriplet.edition.equals(editionLabel));
assertTrue(testTriplet.version.equals(versionLabel));
}
}
}
}
}
}
}
private
NodeRef createMLContainerWithContent(String editionSuffix)
{
NodeRef chineseContentNodeRef = createContent(CHINESE_CONTENT + "-" + Locale.CHINESE + "-" + editionSuffix
+ "-1.0");
NodeRef frenchContentNodeRef = createContent(FRENCH_CONTENT + "-" + Locale.FRENCH + "-" + editionSuffix
+ "-1.0");
NodeRef japaneseContentNodeRef = createContent(JAPANESE_CONTENT + "-" + Locale.JAPANESE + "-" + editionSuffix
+ "-1.0");
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
return multilingualContentService.getTranslationContainer(chineseContentNodeRef);
}
private void modifyContent(NodeRef nodeRef, String value)
{
ContentWriter contentWriter = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
contentWriter.putContent(value);
}
private void dumpFrozenMetaData(Version editionVersion)
{
System.out.println("---------------------------------------------------");
//Get current version label
System.out.println("Version Label: " + editionVersion.getVersionLabel());
System.out.println("---------------------------------------------------");
//Map<QName,Serializable> mapOfFrozenProps = editionService.getVersionedMetadatas(editionVersion);
Map<String,Serializable> mapOfFrozenProps = editionVersion.getVersionProperties();
if(mapOfFrozenProps == null )
{
System.out.println("Nul... ");
return;
}
for(String q: mapOfFrozenProps.keySet())
{
String val = mapOfFrozenProps.get(q)==null?"null":mapOfFrozenProps.get(q).toString();
System.out.println("QName:" + q + ":" + val);
}
}
/**
* Parse the content to extract the local,edition lablel,version label
*
* @author Philippe Dubois
*/
private class Triplet
{
public String locale;
public String edition;
public String version;
public Triplet(String content)
{
String[] tokens = content.split("-");
locale = tokens[1];
edition = tokens[2];
version = tokens[3];
}
}
protected NodeRef createContent(String name)
{
NodeRef contentNodeRef = fileFolderService.create(folderNodeRef, name+".txt", ContentModel.TYPE_CONTENT).getNodeRef();
// add some content
ContentWriter contentWriter = fileFolderService.getWriter(contentNodeRef);
contentWriter.putContent(name);
// done
return contentNodeRef;
}
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model.ml.tools;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Empty translations aspect test cases
*
* @see org.alfresco.service.cmr.ml.EmptyTranslationAspect
*
* @author Yannick Pignot
*/
public class EmptyTranslationAspectTest extends AbstractMultilingualTestCases {
protected ContentService contentService;
protected void setUp() throws Exception
{
contentService = (ContentService) ctx.getBean("ContentService");
super.setUp();
}
public void testCopy() throws Exception
{
NodeRef pivot = createContent();
NodeRef empty = null;
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
boolean exceptionCatched = false;
NodeRef copy = null;
try
{
copy = fileFolderService.copy(
empty,
nodeService.getPrimaryParent(empty).getParentRef(),
"copyOfEmpty" + System.currentTimeMillis()).getNodeRef();
// test failed
}
catch (Exception ignore)
{
exceptionCatched = true;
}
// Ensure that the copy of an empty translation throws an exception
assertTrue("The copy of a translation must throws an exception", exceptionCatched);
// Ensure that the copy node is null
assertNull("The copy must fail ", copy);
}
public void testDeleteNode() throws Exception
{
NodeRef pivot = createContent();
NodeRef empty = null;
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
nodeService.getParentAssocs(empty);
nodeService.deleteNode(empty);
// Ensure that the empty translation is removed from the workspace
assertFalse("The empty translation must be removed from the wokspace", nodeService.exists(empty));
// Ensure that the empty translation is not archived
assertFalse("The empty translation must be removed from the wokspace", nodeService.exists(nodeArchiveService.getArchivedNode(empty)));
}
public void testGetContent() throws Exception
{
NodeRef pivot = createContent();
NodeRef otherTranslation = createContent();
NodeRef empty = null;
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot);
multilingualContentService.addTranslation(otherTranslation, pivot, Locale.KOREAN);
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
// Modify the content of the pivot
String contentString = fileFolderService.getReader(pivot).getContentString();
contentString += "_TEST_";
fileFolderService.getWriter(pivot).putContent(contentString);
// Ensure that the content retourned by a get reader of the empty document is the same as the pivot
assertEquals("The content retourned of the empty translation must be the same that the content of the pivot",
fileFolderService.getReader(pivot).getContentString(),
fileFolderService.getReader(empty).getContentString());
// Ensure that the content retourned by a get reader of the empty document is different to the non-pivot translation
assertNotSame("The content retourned of the empty translation must be different that the content of a non-pivot translation",
fileFolderService.getReader(otherTranslation).getContentString(),
fileFolderService.getReader(empty).getContentString());
// modify the pivot
Map<QName, Serializable> props = nodeService.getProperties(mlContainer);
props.put(ContentModel.PROP_LOCALE, Locale.KOREAN);
nodeService.setProperties(mlContainer, props);
// Ensure that the modicfication of the pivot is take in account
assertEquals("The modification of the pivot is not take in account",
fileFolderService.getReader(otherTranslation).getContentString(),
fileFolderService.getReader(empty).getContentString());
}
public void testUpdateContent() throws Exception
{
NodeRef pivot = createContent();
NodeRef empty = null;
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
// update the empty translation content
ContentWriter writer = contentService.getWriter(empty, ContentModel.PROP_CONTENT, true);
writer.setMimetype("text/plain");
writer.putContent("ANY_CONTENT");
// Ensure that the URL property of the empty translation content is not null
assertNotNull("The url of an updated (ex)empty transation can't be null", ((ContentData) nodeService.getProperty(empty, ContentModel.PROP_CONTENT)).getContentUrl());
// Ensure that the mlEmptyTranslation aspect is removed
assertFalse("The " + ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION + " aspect of an updated (ex)empty translation must be removed", nodeService.hasAspect(empty, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION));
// Ensure that the mlDocument aspect is not removed
assertTrue("The " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect of an updated (ex)empty translation must be keeped", nodeService.hasAspect(empty, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
// Ensure that the content is written
assertEquals("The content of the (ex)empty translation is not correct",
fileFolderService.getReader(empty).getContentString(),
"ANY_CONTENT");
// Ensure that the content is different that the content of the pivot
assertNotSame("The content of the (ex)empty translation is not updated and is the same as the content of the pivot",
fileFolderService.getReader(empty).getContentString(),
fileFolderService.getReader(pivot).getContentString());
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model.ml.tools;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Multilingual container type test cases
*
* @see org.alfresco.service.cmr.ml.MLContainerType
*
* @author Yannick Pignot
*/
public class MLContainerTypeTest extends AbstractMultilingualTestCases
{
@SuppressWarnings("unused")
public void testEditLocale() throws Exception
{
NodeRef trans1 = createContent();
NodeRef trans2 = createContent();
NodeRef trans3 = createContent();
NodeRef empty = null;
multilingualContentService.makeTranslation(trans1, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(trans1);
multilingualContentService.addTranslation(trans2, trans1, Locale.GERMAN);
multilingualContentService.addTranslation(trans3, trans1, Locale.ITALIAN);
empty = multilingualContentService.addEmptyTranslation(trans1, "EMPTY_" + System.currentTimeMillis(), Locale.JAPANESE);
// 1. Locale as null
// Setting a null locale has no effect on any node
assertFalse("The setting of the locale of a mlContainer must throws an exception",
setLocaleProp(mlContainer, null));
// Ensure that the locale of the mlContainer is not changed
assertEquals("The locale of the mlContainer would not be changed",
Locale.FRENCH,
nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
// 2. Set an non-existing locale
// Ensure that the setting of the locale of the mlContainer as a non-existing translation language throws an excpetion
assertTrue("The setting of the locale of a mlContainer as a non-existing translation language must throws an exception",
setLocaleProp(mlContainer, Locale.US));
// Ensure that the locale of the mlContainer is not changed
assertEquals("The locale of the mlContainer would not be changed",
Locale.FRENCH,
nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
// 3. Set the locale of a empty translation
// Ensure that the setting of the locale of the mlContainer as an empty translation language throws an excpetion
assertTrue("The setting of the locale of a mlContainer as an empty translation language must throws an exception",
setLocaleProp(mlContainer, Locale.JAPANESE));
// Ensure that the locale of the mlContainer is not changed
assertEquals("The locale of the mlContainer would not be changed",
Locale.FRENCH,
nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
// 4. Set an existing and valid locale
// Ensure that the setting of the locale of the mlContainer as an existing and a non-empty translation DOESN'T throw an excpetion
assertFalse("The setting of the locale of a mlContainer as an existing and a non-empty translation DOESN'T throw an excpetion",
setLocaleProp(mlContainer, Locale.ITALIAN));
// Ensure that the locale of the mlContainer is not changed
assertEquals("The locale of the mlContainer would be changed",
Locale.ITALIAN,
nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
}
private boolean setLocaleProp(NodeRef node, Locale locale) throws Exception
{
Map<QName, Serializable> props = nodeService.getProperties(node);
props.put(ContentModel.PROP_LOCALE, locale);
boolean exceptionCatched = false;
try
{
nodeService.setProperties(node, props);
}
catch (IllegalArgumentException ignore)
{
exceptionCatched = true;
}
catch(Exception ex)
{
throw new Exception(ex);
}
return exceptionCatched;
}
}

View File

@@ -0,0 +1,666 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model.ml.tools;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.util.GUID;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* @see org.alfresco.repo.ml.MultilingualContentServiceImpl
*
* @author Derek Hulley
* @author Philippe Dubois
*/
public class MultilingualContentServiceImplTest extends AbstractMultilingualTestCases
{
public void testMakeTranslation() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
// Turn the content into a translation with the appropriate structures
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// Check it
assertNotNull("Container not created", mlContainerNodeRef);
// Check the container child count
assertEquals("Incorrect number of child nodes", 1, nodeService.getChildAssocs(mlContainerNodeRef).size());
}
public void testAddTranslationUsingContent() throws Exception
{
// Make a container with a single translation
NodeRef chineseContentNodeRef = createContent();
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// Create some more content
NodeRef frenchContentNodeRef = createContent();
// Make this a translation of the Chinese
multilingualContentService.addTranslation(
frenchContentNodeRef,
chineseContentNodeRef,
Locale.FRENCH);
NodeRef newMLContainerNodeRef = multilingualContentService.getTranslationContainer(frenchContentNodeRef);
// Make sure that the original container was used
assertEquals("Existing container should have been used", mlContainerNodeRef, newMLContainerNodeRef);
// Check the container child count
assertEquals("Incorrect number of child nodes", 2, nodeService.getChildAssocs(mlContainerNodeRef).size());
}
public void testGetMissingTranslation() throws Exception
{
List<String> langList = contentFilterLanguagesService.getFilterLanguages();
int langListSize = langList.size();
// make sure that it exists at least tree language filter
assertFalse("The testGetMissingTranslation test case needs at least three language", langListSize < 3);
// get the first tree locale of the content filter language list
Locale loc1 = I18NUtil.parseLocale(langList.get(0));
Locale loc2 = I18NUtil.parseLocale(langList.get(1));
Locale loc3 = I18NUtil.parseLocale(langList.get(2));
// create three content
NodeRef nodeRef1 = createContent();
NodeRef nodeRef2 = createContent();
NodeRef nodeRef3 = createContent();
multilingualContentService.makeTranslation(nodeRef1, loc1);
List<Locale> missing = multilingualContentService.getMissingTranslations(nodeRef1, false);
// make sure that the missing language list size is correct
assertFalse("Missing Translation Size false. " +
"Real size : " + missing.size() + ". Normal Size " + (langListSize - 1), missing.size() != (langListSize - 1));
// make sure that the missing language list is correct
assertFalse("Missing Translation List false. Locale " + loc1 + " found", missing.contains(loc1.toString()));
multilingualContentService.addTranslation(nodeRef2, nodeRef1, loc2);
multilingualContentService.addTranslation(nodeRef3, nodeRef1, loc3);
// Add the missing translations in
missing = multilingualContentService.getMissingTranslations(nodeRef1, false);
// Make sure that the missing language list size is correct
assertFalse("Missing Translation Size false. " +
"Real size : " + missing.size() + ". Normal Size " + (langListSize - 3), missing.size() != (langListSize - 3));
// make sure that the missing language list is correct
assertFalse("Missing Translation List false. Locale " + loc2.toString() + " or " + loc3.toString() + " found", missing.contains(loc2) || missing.contains(loc3));
}
public void testGetTranslationForLocale() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef frenchContentNodeRef = createContent();
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
// Get the chinese translation
assertEquals("Chinese translation should be present",
chineseContentNodeRef,
multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.CHINESE));
// Get the french translation
assertEquals("French translation should be present",
frenchContentNodeRef,
multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.FRENCH));
// The Italian should return the pivot
assertEquals("French translation should be present",
chineseContentNodeRef,
multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.ITALIAN));
}
public void testGetPivotTranslation() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// make sure that the pivot language is set
assertNotNull("Pivot language not set", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE));
// make sure that the pivot language is correctly set
assertEquals("Pivot language not correctly set", Locale.CHINESE, nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE));
NodeRef frenchContentNodeRef = createContent();
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
// make sure that the pivot noderef is correct
assertEquals("Unable to get pivot from container", chineseContentNodeRef, multilingualContentService.getPivotTranslation(mlContainerNodeRef));
assertEquals("Unable to get pivot from translation", chineseContentNodeRef, multilingualContentService.getPivotTranslation(frenchContentNodeRef));
// modify the pivot language
nodeService.setProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE, Locale.FRENCH);
// make sure that the modified pivot noderef is correct
assertEquals("Pivot node ref not correct", frenchContentNodeRef, multilingualContentService.getPivotTranslation(mlContainerNodeRef));
}
/**
* Testing unmakeTranslation
* @throws Exception
*/
public void testUnmakeTranslation() throws Exception
{
NodeRef frenchContentNodeRef = createContent();
multilingualContentService.makeTranslation(frenchContentNodeRef, Locale.FRENCH);
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(frenchContentNodeRef);
NodeRef englishContentNodeRef = createContent();
multilingualContentService.addTranslation(englishContentNodeRef, frenchContentNodeRef, Locale.ENGLISH);
NodeRef germanContentNodeRef = createContent();
multilingualContentService.addTranslation(germanContentNodeRef, frenchContentNodeRef, Locale.GERMAN);
multilingualContentService.unmakeTranslation(englishContentNodeRef);
multilingualContentService.unmakeTranslation(germanContentNodeRef);
//multilingualContentService.unmakeTranslation(frenchContentNodeRef);
//calling unmakeTranslation() dissolves the multiligual document.
//none of the documents composing the multilingual document
assertTrue("The document should not be multilingual!",
!multilingualContentService.isTranslation(englishContentNodeRef) &&
!multilingualContentService.isTranslation(germanContentNodeRef));
}
/**
* Testing unmakeTranslation() on pivot
* @throws Exception
*/
public void testUnmakeTranslationOnPivot() throws Exception
{
NodeRef frenchContentNodeRef = createContent();
multilingualContentService.makeTranslation(frenchContentNodeRef, Locale.FRENCH);
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(frenchContentNodeRef);
NodeRef englishContentNodeRef = createContent();
multilingualContentService.addTranslation(englishContentNodeRef, frenchContentNodeRef, Locale.ENGLISH);
NodeRef germanContentNodeRef = createContent();
multilingualContentService.addTranslation(germanContentNodeRef, frenchContentNodeRef, Locale.GERMAN);
multilingualContentService.unmakeTranslation(frenchContentNodeRef);
//calling unmakeTranslation() dissolves the multiligual document.
//none of the documents composing the multilingual document
assertTrue("The document should not be multilingual!",
!multilingualContentService.isTranslation(frenchContentNodeRef) &&
!multilingualContentService.isTranslation(englishContentNodeRef) &&
!multilingualContentService.isTranslation(germanContentNodeRef));
}
@SuppressWarnings("unused")
public void testCreateEmptyTranslation() throws Exception
{
NodeRef chineseContentNodeRef = createContent("Document.txt");
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
// This should use the pivot language
NodeRef emptyNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, "Document.txt", Locale.CANADA);
// Ensure that the empty translation is not null
assertNotNull("The creation of the empty document failed ", emptyNodeRef);
// Ensure that the empty translation has the mlDocument aspect
assertTrue("The empty document must have the mlDocument aspect",
nodeService.hasAspect(emptyNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
// Ensure that the empty translation has the mlEmptyTranslation aspect
assertTrue("The empty document must have the mlEmptyTranslation aspect",
nodeService.hasAspect(emptyNodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION));
// Check that the auto renaming worked
String emptyName = DefaultTypeConverter.INSTANCE.convert(String.class,
nodeService.getProperty(emptyNodeRef, ContentModel.PROP_NAME));
assertEquals("Empty auto-rename didn't work for same-named document", "Document_en_CA.txt", emptyName);
// Check that the content is identical
ContentData chineseContentData = fileFolderService.getReader(chineseContentNodeRef).getContentData();
ContentData emptyContentData = fileFolderService.getReader(emptyNodeRef).getContentData();
}
public void testCreateEmptyTranslationNames() throws Exception
{
NodeRef chineseContentNodeRef = createContent("Document.txt");
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef koreanContentNodeRef = createContent("Document_ko.txt");
multilingualContentService.addTranslation(koreanContentNodeRef, chineseContentNodeRef, Locale.KOREAN);
// The pivot translation (base language) is Chinese
// (It won't matter which language we query to check this)
assertEquals(
"The wrong language was set as the pivot translation",
chineseContentNodeRef,
multilingualContentService.getPivotTranslation(chineseContentNodeRef)
);
assertEquals(
"The wrong language was set as the pivot translation",
chineseContentNodeRef,
multilingualContentService.getPivotTranslation(koreanContentNodeRef)
);
// Create with a null name, and off a non-pivot just to be sure
// The locale will be added to the pivot's file name to create a unique one
NodeRef nullNameNodeRef = multilingualContentService.addEmptyTranslation(
koreanContentNodeRef,
null,
Locale.CANADA);
String nullName = fileFolderService.getFileInfo(nullNameNodeRef).getName();
assertEquals("Empty translation name not generated correctly.", "Document_en_CA.txt", nullName);
// This will be referencing the same pivot still
assertEquals(
"The wrong language was set as the pivot translation",
chineseContentNodeRef,
multilingualContentService.getPivotTranslation(nullNameNodeRef)
);
// Create with the same name as the document we're the translation of
// The locale will be added to the supplied file name to create a unique one
NodeRef sameNameNodeRef = multilingualContentService.addEmptyTranslation(
chineseContentNodeRef,
"Document.txt",
Locale.CANADA_FRENCH);
String sameName = fileFolderService.getFileInfo(sameNameNodeRef).getName();
assertEquals("Empty translation name not generated correctly.", "Document_fr_CA.txt", sameName);
// Still correctly referencing the pivot
assertEquals(
"The wrong language was set as the pivot translation",
chineseContentNodeRef,
multilingualContentService.getPivotTranslation(sameNameNodeRef)
);
// Create with a different name
// As there's no clash, the locale won't be added
NodeRef differentNameNodeRef = multilingualContentService.addEmptyTranslation(
chineseContentNodeRef,
"Document2.txt",
Locale.JAPANESE);
String differentName = fileFolderService.getFileInfo(differentNameNodeRef).getName();
assertEquals("Empty translation name not generated correctly.", "Document2.txt", differentName);
// If we tried to add a 2nd language with the different name,
// it would fail as the name isn't used
// (The automatic appending of the locale to avoid duplicates only
// works on the Pivot version's name, it isn't allowed for
// the names of non-pivot versions)
try {
multilingualContentService.addEmptyTranslation(
chineseContentNodeRef,
"Document2.txt",
Locale.FRENCH);
fail("A duplicate translation filename was created");
} catch(FileExistsException e) {
// Good, this was spotted
}
}
public void testGetTranslationContainerPermissions() throws Exception
{
// Grant the guest user rights to our working folder
PermissionService permissionService = serviceRegistry.getPermissionService();
AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
permissionService.setPermission(
folderNodeRef,
AuthenticationUtil.getGuestUserName(),
PermissionService.ALL_PERMISSIONS,
true);
// Get the current authentication
AuthenticationUtil.pushAuthentication();
try
{
authenticationComponent.setGuestUserAsCurrentUser();
// Create some documents
NodeRef chineseContentNodeRef = createContent();
// Make a translation
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.getTranslationContainer(chineseContentNodeRef);
}
finally
{
AuthenticationUtil.popAuthentication();
}
}
/**
* Check whether non-admin users can take part in ML document manipulation
*/
public void testPermissions() throws Exception
{
// Grant the guest user rights to our working folder
PermissionService permissionService = serviceRegistry.getPermissionService();
AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
permissionService.setPermission(
folderNodeRef,
AuthenticationUtil.getGuestUserName(),
PermissionService.ALL_PERMISSIONS,
true);
// Push the current authentication
AuthenticationUtil.pushAuthentication();
try
{
authenticationComponent.setGuestUserAsCurrentUser();
// Create some documents
NodeRef chineseContentNodeRef = createContent();
NodeRef frenchContentNodeRef = createContent();
// Do ML work
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.JAPANESE);
}
finally
{
AuthenticationUtil.popAuthentication();
}
}
public void testDeleteMultilingualContent() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
NodeRef frenchContentNodeRef = createContent();
NodeRef japaneseContentNodeRef = createContent();
NodeRef emptyGermanContentNodeRef = null;
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
// the mlContainer to remove
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// Ensure that the the mlContainer is correctly created
assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
// remove the mlContainer
multilingualContentService.deleteTranslationContainer(mlContainerNodeRef);
// get the archived node ref
NodeRef archivedChineseContentNodeRef = nodeArchiveService.getArchivedNode(chineseContentNodeRef);
NodeRef archivedFrenchContentNodeRef = nodeArchiveService.getArchivedNode(frenchContentNodeRef);
NodeRef archivedJapaneseContentNodeRef = nodeArchiveService.getArchivedNode(japaneseContentNodeRef);
NodeRef archivedEmptyGermanContentNodeRef = nodeArchiveService.getArchivedNode(emptyGermanContentNodeRef);
NodeRef archivedMlContainerNodeRef = nodeArchiveService.getArchivedNode(mlContainerNodeRef);
// Ensure that the mlContainer is removed
assertFalse("The multilingual container must be removed", nodeService.exists(mlContainerNodeRef));
// Ensure that the mlContainer IS NOT archived
assertFalse("The multilingual container can't be archived", nodeService.exists(archivedMlContainerNodeRef));
// Ensure that the translations are removed
assertFalse("The translation must be removed: " + Locale.CHINESE, nodeService.exists(chineseContentNodeRef));
assertFalse("The translation must be removed: " + Locale.JAPANESE, nodeService.exists(japaneseContentNodeRef));
assertFalse("The translation must be removed: " + Locale.FRENCH, nodeService.exists(frenchContentNodeRef));
assertFalse("The empty translation must be removed: " + Locale.GERMAN, nodeService.exists(emptyGermanContentNodeRef));
// Ensure that the translations ARE archived
assertTrue("The translation must be archived: " + Locale.CHINESE, nodeService.exists(archivedChineseContentNodeRef));
assertTrue("The translation must be archived: " + Locale.JAPANESE, nodeService.exists(archivedJapaneseContentNodeRef));
assertTrue("The translation must be archived: " + Locale.FRENCH, nodeService.exists(archivedFrenchContentNodeRef));
// Ensure that the empty translation IS NOT archived
assertFalse("The empty document can't be archived: " + Locale.GERMAN, nodeService.exists(archivedEmptyGermanContentNodeRef));
// Ensure that the mlDocument aspect is removed
assertFalse("The " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect must be removed for " + Locale.CHINESE, nodeService.hasAspect(archivedChineseContentNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
assertFalse("The " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect must be removed for " + Locale.JAPANESE, nodeService.hasAspect(archivedJapaneseContentNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
assertFalse("The " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect must be removed for " + Locale.FRENCH, nodeService.hasAspect(archivedFrenchContentNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
}
@SuppressWarnings("unused")
public void testCopyMLContainerInNewSpace() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
NodeRef frenchContentNodeRef = createContent();
NodeRef japaneseContentNodeRef = createContent();
NodeRef emptyGermanContentNodeRef = null;
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
// the mlContainer to copy
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// Ensure that the the mlContainer is correctly created
assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
// get the actual space
NodeRef actualSpace = folderNodeRef;
// create a new space
NodeRef destinationSpace = fileFolderService.create(folderNodeRef, "testCopyMLContainerInNewSpace" + GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
// Ensure that the new space is created
assertTrue("The destiation space is not created " + destinationSpace, nodeService.exists(destinationSpace));
// copy the mlContainer
NodeRef newMLContainer = multilingualContentService.copyTranslationContainer(mlContainerNodeRef, destinationSpace, "");
assertEquals("Incorrect number of translations for the new mlContainer", 4, multilingualContentService.getTranslations(newMLContainer).size());
// Ensure that a new mlContainer is created
assertTrue("The new mlContainer is not created ", nodeService.exists(newMLContainer));
// Ensure that the newMLContainer is a copy of the source mlContainer
assertFalse("The newMLContainer is not a copy of the source mlContainer, the ref is the same " + newMLContainer , newMLContainer.equals(mlContainerNodeRef));
assertEquals("The newMLContainer is not a copy of the source mlContainer, the locales are not the same " + newMLContainer ,
nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE),
nodeService.getProperty(newMLContainer, ContentModel.PROP_LOCALE));
assertEquals("The newMLContainer is not a copy of the source mlContainer, the authors are not the same " + newMLContainer ,
nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_AUTHOR),
nodeService.getProperty(newMLContainer, ContentModel.PROP_AUTHOR));
// get the source translations
Map<Locale, NodeRef> sourceTranslations = multilingualContentService.getTranslations(mlContainerNodeRef);
// get the copies
Map<Locale, NodeRef> copyTranslations = multilingualContentService.getTranslations(newMLContainer);
// Ensure that the translations are copies from the source translations
assertEquals("They are not the same number of translation in the source mlContainer and in its copy", sourceTranslations.size(), copyTranslations.size());
for(Map.Entry<Locale, NodeRef> entry : sourceTranslations.entrySet())
{
Locale locale = entry.getKey();
NodeRef sourceNodeRef = entry.getValue();
NodeRef sourceParent = nodeService.getPrimaryParent(sourceNodeRef).getParentRef();
NodeRef copyTranslation = multilingualContentService.getTranslationForLocale(newMLContainer, locale);
NodeRef copyParent = nodeService.getPrimaryParent(copyTranslation).getParentRef();
// Ensure that the copy exists
assertNotNull("No copy found for the locale " + locale, copyTranslation);
assertTrue("No copy exists for the locale " + locale, nodeService.exists(copyTranslation));
// Ensure that the copy has the mlDocument aspect
assertTrue("The copy must have the mlDocument aspect",
nodeService.hasAspect(copyTranslation, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
// Ensure that the copy is an empty translation if the source too
assertEquals("The call of nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION) must return the same result for the source and the copy",
nodeService.hasAspect(sourceNodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION),
nodeService.hasAspect(copyTranslation, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION));
// Ensure that the copy and the source are different
assertNotSame("The copy has the same ref as the source", sourceNodeRef, copyTranslation);
// Ensure that the parent of the source is correct
assertEquals("The source would not be moved", sourceParent, actualSpace);
// Ensure that the parent of the copy is correct
assertEquals("The copy is not in the right space", copyParent, destinationSpace);
}
}
@SuppressWarnings("unused")
public void testCopyMLContainerInSameSpace() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
NodeRef frenchContentNodeRef = createContent();
NodeRef japaneseContentNodeRef = createContent();
NodeRef emptyGermanContentNodeRef = null;
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
// the mlContainer to copy
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// Ensure that the the mlContainer is correctly created
assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
// get the actual space
NodeRef actualSpace = folderNodeRef;
try
{
// copy the mlContainer
NodeRef newMLContainer = multilingualContentService.copyTranslationContainer(mlContainerNodeRef, actualSpace, "");
fail("The copy of the mlContainer in the same space would faile");
}
catch(Exception e)
{
// test asserted
}
}
@SuppressWarnings("unused")
public void testCopyAndRenameMLContainer() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
NodeRef frenchContentNodeRef = createContent();
NodeRef japaneseContentNodeRef = createContent();
NodeRef emptyGermanContentNodeRef = null;
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
// the mlContainer to copy
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// Ensure that the the mlContainer is correctly created
assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
// get the actual space
NodeRef actualSpace = folderNodeRef;
// create a new space
NodeRef destinationSpace = fileFolderService.create(folderNodeRef, "testCopyMLContainerInNewSpace" + GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
// Ensure that the new space is created
assertTrue("The destiation space is not created " + destinationSpace, nodeService.exists(destinationSpace));
String PREFIX = "COPY OF " ;
NodeRef newMLContainer = multilingualContentService.copyTranslationContainer(mlContainerNodeRef, destinationSpace, PREFIX);
// Ensure that a new mlContainer is created
assertTrue("The new mlContainer is not created ", nodeService.exists(newMLContainer));
// Ensure that the newMLContainer is a copy of the source mlContainer
assertFalse("The newMLContainer is not a copy of the source mlContainer, the ref is the same " + newMLContainer , newMLContainer.equals(mlContainerNodeRef));
// get the source translations
Map<Locale, NodeRef> sourceTranslations = multilingualContentService.getTranslations(mlContainerNodeRef);
// get the copies
Map<Locale, NodeRef> copyTranslations = multilingualContentService.getTranslations(newMLContainer);
// Ensure that the translations are copies from the source translations
assertEquals("They are not the same number of translation in the source mlContainer and in its copy", sourceTranslations.size(), copyTranslations.size());
for(Map.Entry<Locale, NodeRef> entry : sourceTranslations.entrySet())
{
Locale locale = entry.getKey();
NodeRef sourceNodeRef = entry.getValue();
NodeRef copyNodeRef = multilingualContentService.getTranslationForLocale(newMLContainer, locale);
String sourceName = (String) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME);
String copyName = (String) nodeService.getProperty(copyNodeRef, ContentModel.PROP_NAME);
String theoricalCopyName = PREFIX + sourceName;
// Ensure that the name of the copy is correct
assertTrue("The name of the copied translation is incorect: " + copyName + " and should be " + theoricalCopyName, theoricalCopyName.equals(copyName));
}
}
@SuppressWarnings("unused")
public void testMoveMLContainer() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
NodeRef frenchContentNodeRef = createContent();
NodeRef japaneseContentNodeRef = createContent();
NodeRef emptyGermanContentNodeRef = null;
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
// the mlContainer to copy
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// Ensure that the the mlContainer is correctly created
assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
// get the actual space
NodeRef actualSpace = folderNodeRef;
// create a new space
NodeRef destinationSpace = fileFolderService.create(folderNodeRef, "testCopyMLContainerInNewSpace", ContentModel.TYPE_FOLDER).getNodeRef();
// Ensure that the new space is created
assertTrue("The destiation space is not created " + destinationSpace, nodeService.exists(destinationSpace));
// move the mlContainer
multilingualContentService.moveTranslationContainer(mlContainerNodeRef, destinationSpace);
// Esure that the nodes are moved
assertEquals("The node should be moved", destinationSpace, nodeService.getPrimaryParent(chineseContentNodeRef).getParentRef());
assertEquals("The node should be moved", destinationSpace, nodeService.getPrimaryParent(frenchContentNodeRef).getParentRef());
assertEquals("The node should be moved", destinationSpace, nodeService.getPrimaryParent(japaneseContentNodeRef).getParentRef());
assertEquals("The node should be moved", destinationSpace, nodeService.getPrimaryParent(emptyGermanContentNodeRef).getParentRef());
// Ensure the mlContainer is not changed
assertEquals("The mlContainer should not be changed", mlContainerNodeRef, multilingualContentService.getTranslationContainer(chineseContentNodeRef));
assertEquals("The mlContainer should not be changed", mlContainerNodeRef, multilingualContentService.getTranslationContainer(frenchContentNodeRef));
assertEquals("The mlContainer should not be changed", mlContainerNodeRef, multilingualContentService.getTranslationContainer(japaneseContentNodeRef));
assertEquals("The mlContainer should not be changed", mlContainerNodeRef, multilingualContentService.getTranslationContainer(emptyGermanContentNodeRef));
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.model.ml.tools;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Multilingual document aspect test cases
*
* @see org.alfresco.service.cmr.ml.MultilingualDocumentAspect
*
* @author Yannick Pignot
*/
public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCases
{
public void testCopy() throws Exception
{
NodeRef original = createContent();
multilingualContentService.makeTranslation(original, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(original);
NodeRef copy =
fileFolderService.copy(original, nodeService.getPrimaryParent(original).getParentRef(), "COPY" + System.currentTimeMillis()).getNodeRef();
// Ensure that the copy removes the mlDocument aspect
assertFalse("The copy of a mlDocument can't have the multilingual aspect", nodeService.hasAspect(copy, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
// Ensure that the copy removes the association between the mlConatiner and the new node
assertEquals("The copy of a mlDocument can't be a children of the mlContainer", 1, multilingualContentService.getTranslations(mlContainer).size());
}
public void testDeleteNode() throws Exception
{
NodeRef trad1 = createContent();
NodeRef trad2 = createContent();
NodeRef trad3 = createContent();
NodeRef parent = nodeService.getPrimaryParent(trad1).getParentRef();
multilingualContentService.makeTranslation(trad1, Locale.FRENCH);
multilingualContentService.addTranslation(trad2, trad1, Locale.GERMAN);
multilingualContentService.addTranslation(trad3, trad1, Locale.ITALIAN);
nodeService.deleteNode(trad3);
// Ensure that the deleted node is romoved from its space
assertEquals("The deleted node must be removed to the space", 2, nodeService.getChildAssocs(parent).size());
// Ensure that the mlContainer doesn't keep an association to the deleted node
assertEquals("The deleted node must be removed to the child associations of the mlContainer", 2, multilingualContentService.getTranslations(trad1).size());
// retore the deleted node
NodeRef restoredNode = nodeArchiveService.restoreArchivedNode(nodeArchiveService.getArchivedNode(trad3)).getRestoredNodeRef();
// Ensure that the restored node is restored to it s original space
assertEquals("The restored node must be restaured to the the space", 3, nodeService.getChildAssocs(parent).size());
// Ensure that the restored node is not linked to the mlContainer
assertEquals("The restored node would not be restaured to the mlContainer", 2, multilingualContentService.getTranslations(trad1).size());
// Ensure that the restored node doesn't keep the mlDocument aspect
assertFalse("The restored node can't keep the multilingual aspect", nodeService.hasAspect(restoredNode, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
}
public void testDeletePivot() throws Exception
{
NodeRef pivot = createContent();
NodeRef trans1 = createContent();
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot);
multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
//nodeService.deleteNode(trans1);
nodeService.deleteNode(pivot);
// Ensure that pivot is removed
assertFalse("The pivot would be removed", nodeService.exists(pivot));
// Ensure that the mlContainer is removed
assertFalse("The mlContainer must be removed if the pivot is removed", nodeService.exists(mlContainer));
// Ensure that trans1 is NOT removed
assertTrue("The last translation would not be removed", nodeService.exists(trans1));
// Ensure that trans1 has no mlDocument aspect
assertFalse("The last translation can't keep the multilingual aspect", nodeService.hasAspect(trans1, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
}
public void testDeleteLastNode() throws Exception
{
NodeRef pivot = createContent();
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot);
nodeService.deleteNode(pivot);
// Ensure that the mlContainer is removed too
assertFalse("The mlContainer must be removed if the last translation is removed", nodeService.exists(mlContainer));
}
public void testRemoveAspect() throws Exception
{
// entierly covered by the delete tests
}
public void testUpdateLocale() throws Exception
{
NodeRef pivot = createContent();
NodeRef trans1 = createContent();
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot);
multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
// modify the locale for the translation
Map<QName, Serializable> props = nodeService.getProperties(trans1);
props.put(ContentModel.PROP_LOCALE, Locale.GERMAN);
nodeService.setProperties(trans1, props);
// Ensure that the pivot reference is not changed for the mlContainer and the locale is changed for the translation
assertEquals("The locale for the pivot would be changed ",Locale.GERMAN, nodeService.getProperty(trans1, ContentModel.PROP_LOCALE));
assertEquals("The pivot reference would not be changed in the mlContainer", Locale.FRENCH, nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
// modify the locale for the pivot
props = nodeService.getProperties(pivot);
props.put(ContentModel.PROP_LOCALE, Locale.US);
nodeService.setProperties(pivot, props);
// Ensure that the pivot reference is changed (in the pivot and in the mlContainer)
assertEquals("The locale for the pivot would be changed ", Locale.US, nodeService.getProperty(pivot, ContentModel.PROP_LOCALE));
assertEquals("The pivot reference would be changes in the mlContainer", Locale.US, nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
}
public void testUpdateRedundantLocale() throws Exception
{
NodeRef pivot = createContent();
NodeRef trans1 = createContent();
NodeRef trans2 = createContent();
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
multilingualContentService.addTranslation(trans2, pivot, Locale.JAPANESE);
// 1. Try with redundant locale
// modify the locale for the translation 2
Map<QName, Serializable> props = nodeService.getProperties(trans2);
props.put(ContentModel.PROP_LOCALE, Locale.KOREAN);
boolean exceptionCatched = false;
try
{
nodeService.setProperties(trans2, props);
// test failed
} catch (Exception ignore)
{
exceptionCatched = true;
}
// Ensure that the the exception was catched.
assertTrue("The modification of this locale must catch an exception because it is already in use in another translation", exceptionCatched);
// Ensure that the locale of the trans2 is unchanged
assertEquals("The locale must not be changed",
Locale.JAPANESE,
(Locale) nodeService.getProperty(trans2, ContentModel.PROP_LOCALE));
// 2. Try with a non-redundant locale
props = nodeService.getProperties(trans2);
props.put(ContentModel.PROP_LOCALE, Locale.ITALIAN);
exceptionCatched = false;
try
{
nodeService.setProperties(trans2, props);
} catch (Exception ignore)
{
// test failed
exceptionCatched = true;
}
// Ensure that the exception was not catched
assertFalse("The modification of the locale would not throws an exception", exceptionCatched);
// Ensure that the locale is modified
assertEquals("The locale must be changed",
Locale.ITALIAN,
(Locale) nodeService.getProperty(trans2, ContentModel.PROP_LOCALE));
}
}