/*
* 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 .
*/
package org.alfresco.repo.model.filefolder;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URL;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQueryFactory;
import org.alfresco.query.CannedQueryResults;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.domain.contentdata.ContentDataDAO;
import org.alfresco.repo.domain.locale.LocaleDAO;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.repo.domain.query.CannedQueryDAO;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor;
import org.alfresco.service.cmr.dictionary.DictionaryService;
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.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.Pair;
import org.alfresco.util.registry.NamedObjectRegistry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
/**
* GetChildren canned query - simple unit tests
*
* @author janv
* @since 4.0
*/
public class GetChildrenCannedQueryTest extends TestCase
{
private Log logger = LogFactory.getLog(getClass());
private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private Repository repositoryHelper;
private NodeService nodeService;
private ContentService contentService;
private MimetypeService mimetypeService;
private boolean setupOnce = false;
@SuppressWarnings("unchecked")
private NamedObjectRegistry cannedQueryRegistry;
@SuppressWarnings("unchecked")
@Override
public void setUp() throws Exception
{
if (! setupOnce)
{
repositoryHelper = (Repository)ctx.getBean("repositoryHelper");
nodeService = (NodeService)ctx.getBean("NodeService");
contentService = (ContentService)ctx.getBean("ContentService");
mimetypeService = (MimetypeService)ctx.getBean("MimetypeService");
cannedQueryRegistry = new NamedObjectRegistry();
cannedQueryRegistry.setStorageType(CannedQueryFactory.class);
GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = new GetChildrenCannedQueryFactory();
getChildrenCannedQueryFactory.setBeanName("getChildrenCannedQueryFactory");
getChildrenCannedQueryFactory.setRegistry(cannedQueryRegistry);
getChildrenCannedQueryFactory.setCannedQueryDAO((CannedQueryDAO)ctx.getBean("cannedQueryDAO"));
getChildrenCannedQueryFactory.setContentDataDAO((ContentDataDAO)ctx.getBean("contentDataDAO"));
getChildrenCannedQueryFactory.setDictionaryService((DictionaryService)ctx.getBean("dictionaryService"));
getChildrenCannedQueryFactory.setLocaleDAO((LocaleDAO)ctx.getBean("localeDAO"));
getChildrenCannedQueryFactory.setNodeDAO((NodeDAO)ctx.getBean("nodeDAO"));
getChildrenCannedQueryFactory.setQnameDAO((QNameDAO)ctx.getBean("qnameDAO"));
getChildrenCannedQueryFactory.setMethodSecurityInterceptor((MethodSecurityInterceptor)ctx.getBean("FileFolderService_security"));
getChildrenCannedQueryFactory.setMethodService((Object)ctx.getBean("fileFolderService"));
getChildrenCannedQueryFactory.setMethodName("list");
getChildrenCannedQueryFactory.afterPropertiesSet();
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
load(repositoryHelper.getCompanyHome(), "quick.jpg", "", "");
load(repositoryHelper.getCompanyHome(), "quick.txt", "ZZ title", "XX description");
load(repositoryHelper.getCompanyHome(), "quick.bmp", null, null);
load(repositoryHelper.getCompanyHome(), "quick.doc", "BB title", "BB description");
load(repositoryHelper.getCompanyHome(), "quick.pdf", "ZZ title", "YY description");
setupOnce = true;
}
}
public void testSetup() throws Exception
{
}
public void testSanityCheck() throws Exception
{
NodeRef parentNodeRef = repositoryHelper.getCompanyHome();
PagingResults results = list(parentNodeRef, -1, -1, 0, null);
assertTrue(results.getPage().size() > 0);
if (logger.isInfoEnabled())
{
logger.info("testSanityCheck: company home children = "+results.getPage().size());
}
}
public void testSimpleMaxItems() throws Exception
{
NodeRef parentNodeRef = repositoryHelper.getCompanyHome();
PagingResults results = list(parentNodeRef, -1, -1, 0, null);
assertFalse(results.hasMoreItems());
int totalCnt = results.getPage().size();
assertTrue(totalCnt > 2);
for (int i = 1; i <= totalCnt; i++)
{
results = list(parentNodeRef, 0, i, 0, null);
assertEquals(results.getPage().size(), i);
boolean hasMore = results.hasMoreItems();
assertTrue(hasMore == (i != totalCnt));
if (logger.isInfoEnabled())
{
logger.info("testSimpleMaxItems: [itemCnt="+i+",hasMore="+hasMore+"]");
}
}
}
public void testSimplePaging() throws Exception
{
NodeRef parentNodeRef = repositoryHelper.getCompanyHome();
PagingResults results = list(parentNodeRef, -1, -1, 0, null);
assertFalse(results.hasMoreItems());
int totalCnt = results.getPage().size();
int pageSize = 3;
assertTrue(totalCnt > pageSize);
int pageCnt = (totalCnt / pageSize) + 1;
assertTrue(pageCnt > 1);
for (int i = 1; i <= pageCnt; i++)
{
int skipCount = ((i - 1)* pageSize);
int maxItems = pageSize;
results = list(parentNodeRef, skipCount, maxItems, 0, null);
boolean hasMore = results.hasMoreItems();
int itemsCnt = results.getPage().size();
if (logger.isInfoEnabled())
{
logger.info("testSimplePaging: [pageNum="+i+",itemCnt="+itemsCnt+",hasMore="+hasMore+"]");
}
if (i != pageCnt)
{
// not last page
assertEquals(itemsCnt, maxItems);
assertTrue(hasMore);
}
else
{
// last page
assertTrue(itemsCnt <= maxItems);
assertFalse(hasMore);
}
}
}
public void testSimpleSorting() throws Exception
{
NodeRef parentNodeRef = repositoryHelper.getCompanyHome();
PagingResults results = list(parentNodeRef, -1, -1, 0, null);
assertTrue(results.getPage().size() > 2);
List sortQNames = new ArrayList(3);
// note: initial test list derived from default Share DocLib ("share-documentlibrary-config.xml")
sortQNames.add(ContentModel.PROP_NAME);
sortQNames.add(ContentModel.PROP_TITLE);
sortQNames.add(ContentModel.PROP_DESCRIPTION);
sortQNames.add(ContentModel.PROP_CREATED);
sortQNames.add(ContentModel.PROP_CREATOR);
sortQNames.add(ContentModel.PROP_MODIFIED);
sortQNames.add(ContentModel.PROP_MODIFIER);
sortQNames.add(GetChildrenCannedQuery.SORT_QNAME_CONTENT_SIZE);
sortQNames.add(GetChildrenCannedQuery.SORT_QNAME_CONTENT_MIMETYPE);
sortQNames.add(GetChildrenCannedQuery.SORT_QNAME_NODE_TYPE);
// TODO pending merge to HEAD: sortQNames.add(ContentModel... cm:likesRatingSchemeCount ...);
for (QName sortQName : sortQNames)
{
sortAndCheck(parentNodeRef, sortQName, false); // descending
sortAndCheck(parentNodeRef, sortQName, true); // ascending
}
// sort with two props
List> sortPairs = new ArrayList>(3);
sortPairs.add(new Pair(ContentModel.PROP_TITLE, false));
sortPairs.add(new Pair(ContentModel.PROP_DESCRIPTION, false));
results = list(parentNodeRef, -1, -1, 0, sortPairs);
assertEquals("quick.pdf", nodeService.getProperty(results.getPage().get(0), ContentModel.PROP_NAME)); // ZZ title + YY description
assertEquals("quick.txt", nodeService.getProperty(results.getPage().get(1), ContentModel.PROP_NAME)); // ZZ title + XX description
sortPairs = new ArrayList>(3);
sortPairs.add(new Pair(ContentModel.PROP_NAME, true));
sortPairs.add(new Pair(ContentModel.PROP_TITLE, true));
sortPairs.add(new Pair(ContentModel.PROP_DESCRIPTION, true));
// try to sort with more than two props
try
{
// -ve test
results = list(parentNodeRef, -1, -1, 0, sortPairs);
fail("Unexpected - cannot sort with more than two props");
}
catch (AlfrescoRuntimeException are)
{
// expected
}
}
private void sortAndCheck(NodeRef parentNodeRef, QName sortPropQName, boolean sortAscending)
{
List> sortPairs = new ArrayList>(1);
sortPairs.add(new Pair(sortPropQName, sortAscending));
PagingResults results = list(parentNodeRef, -1, -1, 0, sortPairs);
if (logger.isInfoEnabled())
{
logger.info("testSorting: "+sortPropQName+" - "+(sortAscending ? " ascending" : " descending"));
}
Collator collator = Collator.getInstance();
// check order
Serializable prevVal = null;
boolean allValsNull = true;
for (NodeRef nodeRef : results.getPage())
{
Serializable val = null;
if (sortPropQName.equals(GetChildrenCannedQuery.SORT_QNAME_CONTENT_SIZE) || sortPropQName.equals(GetChildrenCannedQuery.SORT_QNAME_CONTENT_MIMETYPE))
{
// content data properties (size or mimetype)
ContentData cd = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
if (cd != null)
{
if (sortPropQName.equals(GetChildrenCannedQuery.SORT_QNAME_CONTENT_SIZE))
{
val = cd.getSize();
}
else if (sortPropQName.equals(GetChildrenCannedQuery.SORT_QNAME_CONTENT_MIMETYPE))
{
val = cd.getMimetype();
}
}
}
else if (sortPropQName.equals(GetChildrenCannedQuery.SORT_QNAME_NODE_TYPE))
{
val = nodeService.getType(nodeRef);
}
else
{
val = nodeService.getProperty(nodeRef, sortPropQName);
}
if (logger.isInfoEnabled())
{
logger.info("testSorting: ["+nodeRef+", "+val+"]");
}
int result = 0;
if (val != null)
{
allValsNull = false;
}
if (prevVal == null)
{
result = (val == null ? 0 : 1);
}
else if (val == null)
{
result = -1;
}
else
{
if (val instanceof Date)
{
result = ((Date)val).compareTo((Date)prevVal);
}
else if (val instanceof String)
{
result = collator.compare((String)val, (String)prevVal);
}
else if (val instanceof Long)
{
result = ((Long)val).compareTo((Long)prevVal);
}
else if (val instanceof QName)
{
result = ((QName)val).compareTo((QName)prevVal);
}
else
{
fail("Unsupported sort type: "+val.getClass().getName());
}
if (! sortAscending)
{
assertTrue("Not descending", result <= 0);
}
else
{
assertTrue("Not ascending", result >= 0);
}
}
prevVal = val;
}
assertFalse("All values were null", allValsNull);
}
// test helper method
private PagingResults list(NodeRef parentNodeRef, final int skipCount, final int maxItems, final int requestTotalCountMax, List> sortProps)
{
PagingRequest pagingRequest = new PagingRequest()
{
public int getSkipCount()
{
return skipCount;
}
public int getMaxItems()
{
return maxItems;
}
public int getRequestTotalCountMax()
{
return requestTotalCountMax;
}
public String getQueryExecutionId()
{
return null;
}
};
// get canned query
GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject("getChildrenCannedQueryFactory");
GetChildrenCannedQuery cq = (GetChildrenCannedQuery)getChildrenCannedQueryFactory.getCannedQuery(parentNodeRef, null, pagingRequest, sortProps);
// execute canned query
CannedQueryResults results = cq.execute();
List nodeRefs = results.getPages().get(0);
Integer totalCount = null;
if (requestTotalCountMax > 0)
{
totalCount = results.getTotalResultCount().getFirst();
}
return new PagingNodeRefResultsImpl(nodeRefs, results.hasMoreItems(), totalCount, false, true);
}
private class PagingNodeRefResultsImpl implements PagingResults
{
private List nodeRefs;
private Boolean hasMorePages; // null => unknown
private Integer totalResultCount; // null => not requested (or unknown)
private Boolean isTotalResultCountCutoff; // null => unknown
public PagingNodeRefResultsImpl(List nodeRefs, Boolean hasMore, Integer totalResultCount, Boolean isTotalResultCountCutoff, boolean permissionsApplied)
{
this.nodeRefs = nodeRefs;
this.hasMorePages = hasMore;
this.totalResultCount= totalResultCount;
this.isTotalResultCountCutoff = isTotalResultCountCutoff;
}
public List getPage()
{
return nodeRefs;
}
public Boolean hasMoreItems()
{
return hasMorePages;
}
public Pair getTotalResultCount()
{
return new Pair(totalResultCount, (isTotalResultCountCutoff ? null : totalResultCount));
}
public String getQueryExecutionId()
{
return "";
}
}
private void load(NodeRef parentNodeRef, String fileName, String title, String description) throws IOException
{
// Create the node
Map properties = new HashMap();
properties.put(ContentModel.PROP_NAME, fileName);
properties.put(ContentModel.PROP_TITLE, title);
properties.put(ContentModel.PROP_DESCRIPTION, description);
NodeRef nodeRef = nodeService.getChildByName(parentNodeRef, ContentModel.ASSOC_CONTAINS, fileName);
if (nodeRef != null)
{
nodeService.deleteNode(nodeRef);
}
nodeRef = nodeService.createNode(parentNodeRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(fileName),
ContentModel.TYPE_CONTENT,
properties).getChildRef();
String classPath = "quick/" + fileName;
File file = null;
URL url = getClass().getClassLoader().getResource(classPath);
if (url != null)
{
file = new File(url.getFile());
if (!file.exists())
{
file = null;
}
}
if (file == null)
{
fail("Unable to find test file: " + classPath);
}
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
writer.setMimetype(mimetypeService.guessMimetype(fileName));
writer.putContent(file);
}
}