diff --git a/source/java/org/alfresco/repo/webdav/WebDAVHelper.java b/source/java/org/alfresco/repo/webdav/WebDAVHelper.java index 74d480af2a..ebe1697eaf 100644 --- a/source/java/org/alfresco/repo/webdav/WebDAVHelper.java +++ b/source/java/org/alfresco/repo/webdav/WebDAVHelper.java @@ -1086,4 +1086,14 @@ public class WebDAVHelper { return LockUtils.isLockedAndReadOnly(nodeRef, m_serviceRegistry.getLockService()); } + + /** + * Indicates if the node is locked and the current user is not lock owner

+ * + * @param nodeRef the node reference + */ + public boolean isLockedAndNotLockOwner(final NodeRef nodeRef) + { + return LockUtils.isLockedAndNotLockOwner(nodeRef, m_serviceRegistry.getLockService()); + } } diff --git a/source/java/org/alfresco/repo/webdav/WebDAVMethod.java b/source/java/org/alfresco/repo/webdav/WebDAVMethod.java index 7d8076ccfe..93cfafc8ca 100644 --- a/source/java/org/alfresco/repo/webdav/WebDAVMethod.java +++ b/source/java/org/alfresco/repo/webdav/WebDAVMethod.java @@ -1010,7 +1010,7 @@ public abstract class WebDAVMethod NodeRef nodeRef = fileInfo.getNodeRef(); // Regardless of WebDAV locks, if we can't write to this node, then it's locked! - if (getDAVHelper().isLockedAndReadOnly(nodeRef)) + if (getDAVHelper().isLockedAndNotLockOwner(nodeRef)) { throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); } diff --git a/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java index c1b284b429..23c98b444f 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java @@ -480,7 +480,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes if (startFormData != null) { String formKey = startFormData.getFormKey(); - definitionTypeMap.put(processInfo.getProcessDefinitionId(), workflowFactory.getTaskFullTypeDefinition(formKey, true)); + definitionTypeMap.put(processInfo.getProcessDefinitionId(), getWorkflowFactory().getTaskFullTypeDefinition(formKey, true)); } } @@ -676,12 +676,22 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes } } } + else if (taskProperties.containsKey(propNameMap.get(variableName))) + { + PropertyDefinition propDef = taskProperties.get(propNameMap.get(variableName)); + DataTypeDefinition propDataType = propDef.getDataType(); + if ("java.util.Date".equalsIgnoreCase(propDataType.getJavaClassName())) + { + // fix for different ISO 8601 Date format classes in Alfresco (org.alfresco.util and Spring Surf) + variableValue = ISO8601DateFormat.parse((String) variableValue); + } + } if (variableValue instanceof Serializable) { startParams.put(propNameMap.get(variableName), (Serializable) variableValue); } - } + } } } } @@ -888,7 +898,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes formKey = startFormData.getFormKey(); } - TypeDefinition startTaskTypeDefinition = workflowFactory.getTaskFullTypeDefinition(formKey, true); + TypeDefinition startTaskTypeDefinition = getWorkflowFactory().getTaskFullTypeDefinition(formKey, true); // Convert raw variables to Variable objects List resultingVariables = restVariableHelper.getVariables(variables, startTaskTypeDefinition); diff --git a/source/java/org/alfresco/rest/workflow/api/impl/RestVariableHelper.java b/source/java/org/alfresco/rest/workflow/api/impl/RestVariableHelper.java index 3182f7dee6..39c0602c74 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/RestVariableHelper.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/RestVariableHelper.java @@ -59,7 +59,7 @@ public class RestVariableHelper private NamespaceService namespaceService; - private WorkflowQNameConverter qnameConverter; + private WorkflowQNameConverter qNameConverter; public static final Set INTERNAL_PROPERTIES = new HashSet(Arrays.asList(ActivitiConstants.VAR_TENANT_DOMAIN)); @@ -71,7 +71,15 @@ public class RestVariableHelper public void setNamespaceService(NamespaceService namespaceService) { this.namespaceService = namespaceService; - this.qnameConverter = new WorkflowQNameConverter(namespaceService); + } + + protected WorkflowQNameConverter getQNameConverter() + { + if (qNameConverter == null) + { + qNameConverter = new WorkflowQNameConverter(namespaceService); + } + return qNameConverter; } /** @@ -84,13 +92,13 @@ public class RestVariableHelper TypeDefinition startFormTypeDefinition, TypeDefinition taskTypeDefinition) { List result = new ArrayList(); - if (localVariables != null) + if (localVariables != null && localVariables.size() > 0) { TypeDefinitionContext context = new TypeDefinitionContext(taskTypeDefinition); addTaskVariables(result, localVariables, context, VariableScope.LOCAL); } - if (globalVariables != null) + if (globalVariables != null && globalVariables.size() > 0) { TypeDefinitionContext context = new TypeDefinitionContext(startFormTypeDefinition); addTaskVariables(result, globalVariables, context, VariableScope.GLOBAL); @@ -381,12 +389,12 @@ public class RestVariableHelper for (Entry entry : typeDefinition.getProperties().entrySet()) { - propertyDefinitions.put(qnameConverter.mapQNameToName(entry.getKey()), entry.getValue()); + propertyDefinitions.put(getQNameConverter().mapQNameToName(entry.getKey()), entry.getValue()); } for (Entry entry : typeDefinition.getAssociations().entrySet()) { - associationDefinitions.put(qnameConverter.mapQNameToName(entry.getKey()), entry.getValue()); + associationDefinitions.put(getQNameConverter().mapQNameToName(entry.getKey()), entry.getValue()); } } diff --git a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java index 443e80ebf7..6120a4cd45 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java @@ -487,7 +487,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks if (startFormData != null) { String formKey = startFormData.getFormKey(); - definitionTypeMap.put(task.getProcessDefinitionId(), workflowFactory.getTaskFullTypeDefinition(formKey, true)); + definitionTypeMap.put(task.getProcessDefinitionId(), getWorkflowFactory().getTaskFullTypeDefinition(formKey, true)); } } @@ -878,7 +878,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(taskInstance.getProcessDefinitionId()); if (startFormData != null) { - startFormTypeDefinition = workflowFactory.getTaskFullTypeDefinition(startFormData.getFormKey(), true); + startFormTypeDefinition = getWorkflowFactory().getTaskFullTypeDefinition(startFormData.getFormKey(), true); } else { diff --git a/source/test-java/org/alfresco/repo/webdav/WebDAVMethodTest.java b/source/test-java/org/alfresco/repo/webdav/WebDAVMethodTest.java index fc2118c2e2..811cfe7ffd 100644 --- a/source/test-java/org/alfresco/repo/webdav/WebDAVMethodTest.java +++ b/source/test-java/org/alfresco/repo/webdav/WebDAVMethodTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2012 Alfresco Software Limited. + * Copyright (C) 2005-2013 Alfresco Software Limited. * * This file is part of Alfresco * @@ -19,14 +19,32 @@ package org.alfresco.repo.webdav; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.tenant.TenantAdminService; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.repo.tenant.TenantUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +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.SearchService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.GUID; 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; +import java.util.List; + /** * Tests for the WebDAVMethod class. * @@ -39,7 +57,152 @@ public class WebDAVMethodTest private MockHttpServletRequest req; private MockHttpServletResponse resp; private @Mock WebDAVHelper davHelper; - + + private NodeService nodeService; + private SearchService searchService; + private NamespaceService namespaceService; + private TenantService tenantService; + private TransactionService transactionService; + private WebDAVHelper webDAVHelper; + private TenantAdminService tenantAdminService; + + private @Mock LockMethod lockMethod; + private @Mock PutMethod putMethod; + + public static final String TEST_RUN = System.currentTimeMillis()+""; + public static final String TEST_TENANT_DOMAIN = TEST_RUN+".my.test"; + public static final String DEFAULT_ADMIN_PW = "admin"; + + protected void setUpApplicationContext() + { + ApplicationContext appContext = ApplicationContextHelper.getApplicationContext(new String[] + { + "classpath:alfresco/application-context.xml", "classpath:alfresco/web-scripts-application-context.xml", + "classpath:alfresco/remote-api-context.xml" + }); + + this.nodeService = (NodeService) appContext.getBean("NodeService"); + this.searchService = (SearchService) appContext.getBean("SearchService"); + this.namespaceService = (NamespaceService) appContext.getBean("NamespaceService"); + this.tenantService = (TenantService) appContext.getBean("tenantService"); + this.transactionService = (TransactionService) appContext.getBean("transactionService"); + this.webDAVHelper = (WebDAVHelper) appContext.getBean("webDAVHelper"); + this.tenantAdminService = (TenantAdminService) appContext.getBean("tenantAdminService"); + + // Authenticate as system to create initial test data set + AuthenticationComponent authenticationComponent = (AuthenticationComponent) appContext.getBean("authenticationComponent"); + authenticationComponent.setSystemUserAsCurrentUser(); + } + + private void checkLockedNodeTestWork() throws WebDAVServerException + { + req = new MockHttpServletRequest(); + resp = new MockHttpServletResponse(); + + String rootPath = "/app:company_home"; + String storeName = "workspace://SpacesStore"; + StoreRef storeRef = new StoreRef(storeName); + NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef); + List nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false); + NodeRef defaultRootNode = nodeRefs.get(0); + + lockMethod = new LockMethod(); + NodeRef rootNodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, defaultRootNode); + String strPath = "/" + "testLockedNode" + GUID.generate(); + + lockMethod.createExclusive = true; + lockMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); + lockMethod.m_strPath = strPath; + + // Lock the node (will create a new one). + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable { + lockMethod.executeImpl(); + return null; + } + }); + + // Prepare for PUT + req.addHeader(WebDAV.HEADER_IF, "(<" + lockMethod.lockToken + ">)"); + putMethod = new PutMethod(); + putMethod.setDetails(req, resp, webDAVHelper, rootNodeRef); + putMethod.parseRequestHeaders(); + putMethod.m_strPath = strPath; + String content = "test content stream"; + req.setContent(content.getBytes()); + + // Issue a put request + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + putMethod.executeImpl(); + return null; + } + }); + } + + /** + * Call the org.alfresco.repo.webdav.WebDAVMethod#checkNode(org.alfresco.service.cmr.model.FileInfo, boolean, boolean) + * for a write locked node for tenant and non-tenant. + * See ALF-19915. + */ + @Test + public void checkLockedNodeTest() throws Exception + { + setUpApplicationContext(); + + // Create a tenant domain + TenantUtil.runAsSystemTenant(new TenantUtil.TenantRunAsWork() { + public Object doWork() throws Exception { + if (!tenantAdminService.existsTenant(TEST_TENANT_DOMAIN)) + { + tenantAdminService.createTenant(TEST_TENANT_DOMAIN, (DEFAULT_ADMIN_PW + " " + TEST_TENANT_DOMAIN).toCharArray(), null); + } + return null; + } + }, TenantService.DEFAULT_DOMAIN); + + // run as admin + try + { + TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork() + { + @Override + public Object doWork() throws Exception + { + checkLockedNodeTestWork(); + return null; + } + }, AuthenticationUtil.getAdminUserName(), TenantService.DEFAULT_DOMAIN); + } + catch (Exception e) + { + fail("Failed to lock and put content as admin with error: " + e.getCause()); + } + + // run as tenant admin + try + { + TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork() + { + @Override + public Object doWork() throws Exception + { + checkLockedNodeTestWork(); + return null; + } + }, AuthenticationUtil.getAdminUserName(), TEST_TENANT_DOMAIN); + } + catch (Exception e) + { + fail("Failed to lock and put content as tenant admin with error: " + e.getCause()); + } + } + @Test public void canGetStatusForAccessDeniedException() { diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java index 9a6f0dd080..a27ffdaceb 100644 --- a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java +++ b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java @@ -162,7 +162,7 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi JSONObject createProcessObject = new JSONObject(); createProcessObject.put("processDefinitionKey", "activitiAdhoc"); final JSONObject variablesObject = new JSONObject(); - variablesObject.put("bpm_dueDate", ISO8601DateFormat.format(new Date())); + variablesObject.put("bpm_dueDate", "2013-09-30T00:00:00.000+0300"); variablesObject.put("bpm_priority", 1); variablesObject.put("bpm_description", "test description"); TenantUtil.runAsUserTenant(new TenantRunAsWork() @@ -744,6 +744,15 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi assertEquals(1, processList.getList().size()); // include process variables as well + paramMap = new HashMap(); + paramMap.put("where", "(includeVariables=true)"); + paramMap.put("maxItems", "1"); + paramMap.put("skipCount", "0"); + processList = processesClient.getProcesses(paramMap); + assertNotNull(processList); + + assertEquals(1, processList.getList().size()); + paramMap = new HashMap(); paramMap.put("where", "(processDefinitionKey = 'activitiAdhoc' AND includeVariables = true)"); paramMap.put("maxItems", "1"); @@ -828,6 +837,37 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi } } + @Test + public void testGetProcessInstancesWithDifferentProcessDefs() throws Exception + { + final RequestContext requestContext = initApiClientWithTestUser(); + + final ProcessInfo process1 = startAdhocProcess(requestContext, null); + final ProcessInfo process2 = startParallelReviewProcess(requestContext); + final ProcessInfo process3 = startReviewPooledProcess(requestContext); + + try + { + ProcessesClient processesClient = publicApiClient.processesClient(); + Map paramMap = new HashMap(); + ListResponse processList = processesClient.getProcesses(paramMap); + assertNotNull(processList); + assertEquals(3, processList.getList().size()); + + // include process variables as well + paramMap = new HashMap(); + paramMap.put("where", "(includeVariables=true)"); + processList = processesClient.getProcesses(paramMap); + assertNotNull(processList); + + assertEquals(3, processList.getList().size()); + } + finally + { + cleanupProcessInstance(process1.getId(), process2.getId(), process3.getId()); + } + } + @Test public void testGetProcessInstancesWithPaging() throws Exception {