mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Integrated Content Properties Refactor and Content Purge
- MOB-30: Content Purge - MOB-415: Content Properties Refactor - Adds to MOB-214: Upgrade scripts for Ent DBs git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14810 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.domain.contentdata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.repo.content.ContentContext;
|
||||
import org.alfresco.repo.content.ContentStore;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.filestore.FileContentStore;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* @see ContentDataDAO
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 3.2
|
||||
*/
|
||||
public class ContentDataDAOTest extends TestCase
|
||||
{
|
||||
private ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private TransactionService transactionService;
|
||||
private RetryingTransactionHelper txnHelper;
|
||||
private ContentDataDAO contentDataDAO;
|
||||
private ContentStore contentStore;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
||||
transactionService = serviceRegistry.getTransactionService();
|
||||
txnHelper = transactionService.getRetryingTransactionHelper();
|
||||
|
||||
contentDataDAO = (ContentDataDAO) ctx.getBean("contentDataDAO");
|
||||
contentStore = new FileContentStore(ctx, TempFileProvider.getTempDir());
|
||||
}
|
||||
|
||||
private Pair<Long, ContentData> create(final ContentData contentData)
|
||||
{
|
||||
RetryingTransactionCallback<Pair<Long, ContentData>> callback = new RetryingTransactionCallback<Pair<Long, ContentData>>()
|
||||
{
|
||||
public Pair<Long, ContentData> execute() throws Throwable
|
||||
{
|
||||
Pair<Long, ContentData> contentDataPair = contentDataDAO.createContentData(contentData);
|
||||
return contentDataPair;
|
||||
}
|
||||
};
|
||||
return txnHelper.doInTransaction(callback, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and checks the ContentData for equality
|
||||
*/
|
||||
private void getAndCheck(final Long contentDataId, ContentData checkContentData)
|
||||
{
|
||||
RetryingTransactionCallback<Pair<Long, ContentData>> callback = new RetryingTransactionCallback<Pair<Long, ContentData>>()
|
||||
{
|
||||
public Pair<Long, ContentData> execute() throws Throwable
|
||||
{
|
||||
Pair<Long, ContentData> contentDataPair = contentDataDAO.getContentData(contentDataId);
|
||||
return contentDataPair;
|
||||
}
|
||||
};
|
||||
Pair<Long, ContentData> resultPair = txnHelper.doInTransaction(callback, true, false);
|
||||
assertNotNull("Failed to find result for ID " + contentDataId, resultPair);
|
||||
assertEquals("ContentData retrieved not the same as persisted: ", checkContentData, resultPair.getSecond());
|
||||
}
|
||||
|
||||
private ContentData getContentData()
|
||||
{
|
||||
ContentContext contentCtx = new ContentContext(null, null);
|
||||
String contentUrl = contentStore.getWriter(contentCtx).getContentUrl();
|
||||
ContentData contentData = new ContentData(
|
||||
contentUrl,
|
||||
MimetypeMap.MIMETYPE_TEXT_PLAIN,
|
||||
12335L,
|
||||
"UTF-8",
|
||||
Locale.FRENCH);
|
||||
return contentData;
|
||||
}
|
||||
|
||||
public void testGetWithInvalidId()
|
||||
{
|
||||
assertNull("Expected null for invalid ID", contentDataDAO.getContentData(-1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the <code>ContentData</code> is decoded and persisted correctly.
|
||||
*/
|
||||
public void testCreateContentDataSimple() throws Exception
|
||||
{
|
||||
ContentData contentData = getContentData();
|
||||
|
||||
Pair<Long, ContentData> resultPair = create(contentData);
|
||||
getAndCheck(resultPair.getFirst(), contentData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the <code>ContentData</code> is decoded and persisted correctly.
|
||||
*/
|
||||
public void testCreateContentDataNulls() throws Exception
|
||||
{
|
||||
ContentData contentData = new ContentData(null, null, 0L, null, null);
|
||||
|
||||
Pair<Long, ContentData> resultPair = create(contentData);
|
||||
getAndCheck(resultPair.getFirst(), contentData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that upper and lowercase URLs don't clash
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testEnsureCaseSensitiveStorage() throws Exception
|
||||
{
|
||||
ContentData contentData = getContentData();
|
||||
String contentUrlUpper = contentData.getContentUrl().toUpperCase();
|
||||
ContentData contentDataUpper = new ContentData(
|
||||
contentUrlUpper, MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, "UTF-8", new Locale("FR"));
|
||||
String contentUrlLower = contentData.getContentUrl().toLowerCase();
|
||||
ContentData contentDataLower = new ContentData(
|
||||
contentUrlLower, MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, "utf-8", new Locale("fr"));
|
||||
|
||||
Pair<Long, ContentData> resultPairUpper = create(contentDataUpper);
|
||||
getAndCheck(resultPairUpper.getFirst(), contentDataUpper);
|
||||
|
||||
Pair<Long, ContentData> resultPairLower = create(contentDataLower);
|
||||
getAndCheck(resultPairLower.getFirst(), contentDataLower);
|
||||
}
|
||||
|
||||
public void testDelete() throws Exception
|
||||
{
|
||||
ContentData contentData = getContentData();
|
||||
|
||||
Pair<Long, ContentData> resultPair = create(contentData);
|
||||
getAndCheck(resultPair.getFirst(), contentData);
|
||||
contentDataDAO.deleteContentData(resultPair.getFirst());
|
||||
try
|
||||
{
|
||||
getAndCheck(resultPair.getFirst(), contentData);
|
||||
fail("Entity still exists");
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
private static final String[] MIMETYPES = new String[]
|
||||
{
|
||||
MimetypeMap.MIMETYPE_ACP,
|
||||
MimetypeMap.MIMETYPE_EXCEL,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
MimetypeMap.MIMETYPE_JAVASCRIPT,
|
||||
MimetypeMap.MIMETYPE_RSS
|
||||
};
|
||||
private static final String[] ENCODINGS = new String[]
|
||||
{
|
||||
"utf-8",
|
||||
"ascii",
|
||||
"latin1",
|
||||
"wibbles",
|
||||
"iso-whatever"
|
||||
};
|
||||
private static final Locale[] LOCALES = new Locale[]
|
||||
{
|
||||
Locale.FRENCH,
|
||||
Locale.CHINESE,
|
||||
Locale.ITALIAN,
|
||||
Locale.JAPANESE,
|
||||
Locale.ENGLISH
|
||||
};
|
||||
|
||||
private List<Pair<Long, ContentData>> speedTestWrite(String name, int total)
|
||||
{
|
||||
System.out.println("Starting write speed test: " + name);
|
||||
long start = System.nanoTime();
|
||||
List<Pair<Long, ContentData>> pairs = new ArrayList<Pair<Long, ContentData>>(100000);
|
||||
// Loop and check for performance degradation
|
||||
for (int i = 0; i < (total / 200 / 5); i++)
|
||||
{
|
||||
for (int j = 0; j < 200; j++)
|
||||
{
|
||||
for (int k = 0; k < 5; k++)
|
||||
{
|
||||
ContentData contentData = getContentData();
|
||||
String contentUrl = contentData.getContentUrl();
|
||||
contentData = new ContentData(
|
||||
contentUrl,
|
||||
MIMETYPES[k],
|
||||
(long) j*k,
|
||||
ENCODINGS[k],
|
||||
LOCALES[k]);
|
||||
Pair<Long, ContentData> pair = create(contentData);
|
||||
pairs.add(pair);
|
||||
}
|
||||
}
|
||||
// That's 1000
|
||||
long now = System.nanoTime();
|
||||
double diffMs = (double) (now - start) / 1E6;
|
||||
double aveMs = diffMs / (double) pairs.size();
|
||||
String msg = String.format(
|
||||
" Wrote %7d rows; average is %5.2f ms per row or %5.2f rows per second",
|
||||
pairs.size(),
|
||||
aveMs,
|
||||
1000.0 / aveMs);
|
||||
System.out.println(msg);
|
||||
}
|
||||
// Done
|
||||
return pairs;
|
||||
}
|
||||
|
||||
private void speedTestRead(String name, List<Pair<Long, ContentData>> pairs)
|
||||
{
|
||||
System.out.println("Starting read speed test: " + name);
|
||||
long start = System.nanoTime();
|
||||
// Loop and check for performance degradation
|
||||
int num = 1;
|
||||
for (Pair<Long, ContentData> pair : pairs)
|
||||
{
|
||||
Long id = pair.getFirst();
|
||||
ContentData contentData = pair.getSecond();
|
||||
// Retrieve it
|
||||
getAndCheck(id, contentData);
|
||||
// Report
|
||||
if (num % 1000 == 0)
|
||||
{
|
||||
long now = System.nanoTime();
|
||||
double diffMs = (double) (now - start) / 1E6;
|
||||
double aveMs = diffMs / (double) num;
|
||||
String msg = String.format(
|
||||
" Read %7d rows; average is %5.2f ms per row or %5.2f rows per second",
|
||||
num,
|
||||
aveMs,
|
||||
1000.0 / aveMs);
|
||||
System.out.println(msg);
|
||||
}
|
||||
num++;
|
||||
}
|
||||
// Done
|
||||
}
|
||||
|
||||
public void testCreateSpeedIndividualTxns()
|
||||
{
|
||||
List<Pair<Long, ContentData>> pairs = speedTestWrite(getName(), 2000);
|
||||
speedTestRead(getName(), pairs);
|
||||
}
|
||||
|
||||
public void testCreateSpeedSingleTxn()
|
||||
{
|
||||
RetryingTransactionCallback<List<Pair<Long, ContentData>>> writeCallback = new RetryingTransactionCallback<List<Pair<Long, ContentData>>>()
|
||||
{
|
||||
public List<Pair<Long, ContentData>> execute() throws Throwable
|
||||
{
|
||||
return speedTestWrite(getName(), 10000);
|
||||
}
|
||||
};
|
||||
final List<Pair<Long, ContentData>> pairs = txnHelper.doInTransaction(writeCallback, false, false);
|
||||
RetryingTransactionCallback<Void> readCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
speedTestRead(getName(), pairs);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
txnHelper.doInTransaction(readCallback, false, false);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user