diff --git a/source/java/org/alfresco/repo/webdav/GetMethod.java b/source/java/org/alfresco/repo/webdav/GetMethod.java index ed0a58bb5d..8ebecee20f 100644 --- a/source/java/org/alfresco/repo/webdav/GetMethod.java +++ b/source/java/org/alfresco/repo/webdav/GetMethod.java @@ -19,6 +19,7 @@ package org.alfresco.repo.webdav; import java.io.IOException; +import java.io.Serializable; import java.io.Writer; import java.net.SocketException; import java.text.ParseException; @@ -36,12 +37,15 @@ import org.alfresco.repo.web.util.HttpRangeProcessor; 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.ContentData; import org.alfresco.service.cmr.repository.ContentReader; 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.cmr.repository.Path; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.repository.datatype.TypeConverter; +import org.alfresco.service.namespace.QName; import org.springframework.extensions.surf.util.I18NUtil; /** @@ -431,9 +435,9 @@ public class GetMethod extends WebDAVMethod */ private void generateDirectoryListing(FileInfo fileInfo) { - FileFolderService fileFolderService = getFileFolderService(); MimetypeService mimeTypeService = getMimetypeService(); - + NodeService nodeService = getNodeService(); + Writer writer = null; try @@ -498,15 +502,16 @@ public class GetMethod extends WebDAVMethod { rootURL = rootURL + WebDAVHelper.PathSeperator; } + if (wasLink) { - Path pathToNode = getNodeService().getPath(fileInfo.getNodeRef()); + Path pathToNode = nodeService.getPath(fileInfo.getNodeRef()); if (pathToNode.size() > 2) { pathToNode = pathToNode.subPath(2, pathToNode.size() - 1); } - rootURL = getURLForPath(m_request, pathToNode.toDisplayPath(getNodeService(), getPermissionService()), true); + rootURL = getURLForPath(m_request, pathToNode.toDisplayPath(nodeService, getPermissionService()), true); if (rootURL.endsWith(WebDAVHelper.PathSeperator) == false) { rootURL = rootURL + WebDAVHelper.PathSeperator; @@ -560,19 +565,41 @@ public class GetMethod extends WebDAVMethod // size field writer.write(""); + + ContentData contentData = null; + if (!childNodeInfo.isFolder()) + { + Serializable contentPropertyName = nodeService.getProperty(childNodeInfo.getNodeRef(), ContentModel.PROP_CONTENT_PROPERTY_NAME); + QName contentPropertyQName = DefaultTypeConverter.INSTANCE.convert(QName.class, contentPropertyName); + + if (null == contentPropertyQName) + { + contentPropertyQName = ContentModel.PROP_CONTENT; + } + + Serializable contentProperty = nodeService.getProperty(childNodeInfo.getNodeRef(), contentPropertyQName); + + if (contentProperty instanceof ContentData) + { + contentData = (ContentData) contentProperty; + } + } + if (childNodeInfo.isFolder()) { writer.write(" "); } else { - ContentReader reader = fileFolderService.getReader(childNodeInfo.getNodeRef()); - long fsize = 0L; - if (reader != null) + if (null != contentData) { - fsize = reader.getSize(); + writer.write(formatSize(Long.toString(contentData.getSize()))); } - writer.write(formatSize(Long.toString(fsize))); + else + { + writer.write(" "); + } + } writer.write(""); @@ -583,21 +610,16 @@ public class GetMethod extends WebDAVMethod } else { - ContentReader reader = fileFolderService.getReader(childNodeInfo.getNodeRef()); String mimetype = " "; - if (reader != null) + if (null != contentData) { - mimetype = reader.getMimetype(); - String displayType = mimeTypeService.getDisplaysByMimetype().get(reader.getMimetype()); + mimetype = contentData.getMimetype(); + String displayType = mimeTypeService.getDisplaysByMimetype().get(mimetype); if (displayType != null) { mimetype = displayType; } - if (mimetype == null) - { - mimetype = reader.getMimetype(); - } } writer.write(mimetype); } diff --git a/source/test-java/org/alfresco/RemoteApi01TestSuite.java b/source/test-java/org/alfresco/RemoteApi01TestSuite.java index 9f2619ae52..ea7dd66396 100644 --- a/source/test-java/org/alfresco/RemoteApi01TestSuite.java +++ b/source/test-java/org/alfresco/RemoteApi01TestSuite.java @@ -69,6 +69,7 @@ public class RemoteApi01TestSuite extends TestSuite static void tests5(TestSuite suite) // { + suite.addTestSuite(org.alfresco.repo.webdav.GetMethodRegressionTest.class); suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.MoveMethodTest.class)); suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.UnlockMethodTest.class)); suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.webdav.LockMethodTest.class)); diff --git a/source/test-java/org/alfresco/repo/webdav/GetMethodRegressionTest.java b/source/test-java/org/alfresco/repo/webdav/GetMethodRegressionTest.java new file mode 100644 index 0000000000..7d9c01bfa5 --- /dev/null +++ b/source/test-java/org/alfresco/repo/webdav/GetMethodRegressionTest.java @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2005-2014 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.webdav; + +import java.io.Serializable; +import java.net.HttpURLConnection; +import java.util.Map; + +import javax.transaction.Status; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.audit.model.AuditModelRegistryImpl; +import org.alfresco.repo.node.archive.NodeArchiveService; +import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.audit.AuditQueryParameters; +import org.alfresco.service.cmr.audit.AuditService; +import org.alfresco.service.cmr.audit.AuditService.AuditQueryCallback; +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.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.apache.chemistry.opencmis.commons.spi.Holder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +/** + * Tests {@link GetMethod} in real environment, using {@link Mock} HTTP request and {@link Mock} HTTP response + * + * @author Dmitry Velichkevich + */ +@RunWith(MockitoJUnitRunner.class) +public class GetMethodRegressionTest extends TestCase +{ + private static final int DOCUMENTS_AMOUNT_FOR_GET_METHOD_TEST = 25; + + + private static final String HTTP_METHOD_GET = "GET"; + + private static final String TEST_ENCODING = "UTF-8"; + + private static final String TEST_MIMETYPE = "text/plain"; + + private static final String TEST_WEBDAV_URL_PREFIX = "/"; + + private static final String AUDIT_REGISTRY_BEAN_NAME = "Audit"; + + private static final String PROP_AUDIT_ALFRESCO_ACCESS_ENABLED = "audit.alfresco-access.enabled"; + + private static final String ROOT_TEST_FOLDER_NAME = "TestFolder-" + System.currentTimeMillis(); + + private static final String TEST_DOCUMENT_NAME_PATTERN = "TestDocument-%d-%d.pdf"; + + private static final String TEXT_DOCUMENT_CONTENT_PATTERN = "Text content for '%s' document"; + + + private ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext(); + + private WebDAVHelper davHelper; + + private AuditService auditService; + + private FileFolderService fileFolderService; + + private AuditModelRegistryImpl auditRegistry; + + private TransactionService transactionService; + + + private UserTransaction transaction; + + private GetMethod testingMethod; + + private NodeRef companyHomeNodeRef; + + private NodeRef rootTestFolder; + + private MockHttpServletResponse mockResponse; + + + @Before + public void setUp() throws Exception + { + ServiceRegistry registry = (ServiceRegistry) applicationContext.getBean(ServiceRegistry.SERVICE_REGISTRY); + davHelper = (WebDAVHelper) applicationContext.getBean(WebDAVHelper.BEAN_NAME); + auditRegistry = (AuditModelRegistryImpl) applicationContext.getBean(AUDIT_REGISTRY_BEAN_NAME); + + auditService = registry.getAuditService(); + fileFolderService = registry.getFileFolderService(); + transactionService = registry.getTransactionService(); + + testingMethod = new GetMethod(); + mockResponse = new MockHttpServletResponse(); + + restartTransaction(TransactionActionEnum.ACTION_NONE); + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + + companyHomeNodeRef = registry.getNodeLocatorService().getNode(CompanyHomeNodeLocator.NAME, null, null); + rootTestFolder = fileFolderService.create(companyHomeNodeRef, ROOT_TEST_FOLDER_NAME, ContentModel.TYPE_FOLDER).getNodeRef(); + } + + @After + public void tearDown() throws Exception + { + if ((null != transaction) && (Status.STATUS_ROLLEDBACK != transaction.getStatus()) && (Status.STATUS_COMMITTED != transaction.getStatus())) + { + transaction.rollback(); + } + + AuthenticationUtil.clearCurrentSecurityContext(); + } + + /** + * Test for MNT-10820 + * + * @throws Exception + */ + @Test + public void testAuditRecordsAdditionAsbsence() throws Exception + { + String url = new StringBuilder(TEST_WEBDAV_URL_PREFIX).append(ROOT_TEST_FOLDER_NAME).toString(); + MockHttpServletRequest mockRequest = new MockHttpServletRequest(HTTP_METHOD_GET, url); + testingMethod.setDetails(mockRequest, mockResponse, davHelper, companyHomeNodeRef); + + boolean auditEnabled = auditService.isAuditEnabled(); + + if (!auditEnabled) + { + auditService.setAuditEnabled(true); + } + + boolean alfrescoAccessEnabled = Boolean.valueOf(auditRegistry.getProperty(PROP_AUDIT_ALFRESCO_ACCESS_ENABLED)); + + if (!alfrescoAccessEnabled) + { + setAuditRegistryProperty(PROP_AUDIT_ALFRESCO_ACCESS_ENABLED, Boolean.TRUE.toString()); + } + + try + { + createTestContent(rootTestFolder, DOCUMENTS_AMOUNT_FOR_GET_METHOD_TEST); + + restartTransaction(TransactionActionEnum.ACTION_COMMIT); + + Long expectedLastTime = getLastAuditRecordTime(); + + testingMethod.executeImpl(); + assertEquals(HttpURLConnection.HTTP_OK, mockResponse.getStatus()); + + String contentAsString = mockResponse.getContentAsString(); + assertNotNull("WebDAV 'GET' method response is empty!", contentAsString); + assertTrue(contentAsString.contains(ROOT_TEST_FOLDER_NAME)); + + restartTransaction(TransactionActionEnum.ACTION_COMMIT); + + Long actualLastTime = getLastAuditRecordTime(); + + if (null == expectedLastTime) + { + assertNull("Audit entry table is not empty after 'GetMethod.executeImpl()' invocation. But it is expected to be empty!", actualLastTime); + } + else + { + assertEquals(expectedLastTime, actualLastTime); + } + } + finally + { + if (!alfrescoAccessEnabled) + { + setAuditRegistryProperty(PROP_AUDIT_ALFRESCO_ACCESS_ENABLED, Boolean.FALSE.toString()); + } + + if (!auditEnabled) + { + auditService.setAuditEnabled(false); + } + + fileFolderService.delete(rootTestFolder); + + NodeArchiveService archiveService = (NodeArchiveService) applicationContext.getBean("nodeArchiveService"); + archiveService.purgeAllArchivedNodes(rootTestFolder.getStoreRef()); + } + } + + private void setAuditRegistryProperty(String propertyName, String value) + { + assertTrue(("'" + propertyName + "' is not updatable!"), auditRegistry.isUpdateable(propertyName)); + + auditRegistry.stop(); + auditRegistry.setProperty(propertyName, value); + auditRegistry.start(); + } + + private void createTestContent(NodeRef parentNode, int documentsAmount) + { + for (int i = 0; i < documentsAmount; i++) + { + String testDocumentName = String.format(TEST_DOCUMENT_NAME_PATTERN, i, System.currentTimeMillis()); + FileInfo testDocument = fileFolderService.create(parentNode, testDocumentName, ContentModel.TYPE_CONTENT); + ContentWriter writer = fileFolderService.getWriter(testDocument.getNodeRef()); + writer.putContent(String.format(TEXT_DOCUMENT_CONTENT_PATTERN, testDocumentName)); + writer.setMimetype(TEST_MIMETYPE); + writer.setEncoding(TEST_ENCODING); + } + } + + private enum TransactionActionEnum + { + ACTION_NONE, + + ACTION_COMMIT, + + ACTION_ROLLBACK + } + + /** + * Commits or rolls back or does nothing with the current transaction and begins a new {@link UserTransaction} + * + * @param transactionAction - one of the {@link TransactionActionEnum} values which specifies action to be done for the current transaction + * @throws Exception + */ + private void restartTransaction(TransactionActionEnum transactionAction) throws Exception + { + if ((null != transaction) && (Status.STATUS_ROLLEDBACK != transaction.getStatus()) && (Status.STATUS_COMMITTED != transaction.getStatus())) + { + if (TransactionActionEnum.ACTION_COMMIT == transactionAction) + { + transaction.commit(); + } + else if (TransactionActionEnum.ACTION_ROLLBACK == transactionAction) + { + transaction.rollback(); + } + } + + transaction = transactionService.getUserTransaction(); + transaction.begin(); + } + + private Long getLastAuditRecordTime() + { + final Holder lastTime = new Holder(); + + AuditQueryParameters parameters = new AuditQueryParameters(); + parameters.setForward(false); + + auditService.auditQuery(new AuditQueryCallback() + { + @Override + public boolean valuesRequired() + { + return false; + } + + @Override + public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error) + { + return false; + } + + @Override + public boolean handleAuditEntry(Long entryId, String applicationName, String user, long time, Map values) + { + lastTime.setValue(time); + return false; + } + }, parameters, 1); + + return lastTime.getValue(); + } +}