Derek Hulley d22b8baa6c 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
2009-06-19 15:11:24 +00:00

304 lines
12 KiB
Java

/*
* 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);
}
}