Merged V2.1 to HEAD

6368: Change home folder provider to use User Homes and not company home
   6370: Fixed BDE-50: Empty line in the clean_tomcat.sh script file
   6373: Working copy nodes don't get sys:temporary aspect applied.
            Node archival ignores working copy nodes.
   6375: Fixed AR-1154: Benchmark override sample
   6377: Documentation updates.
   6379: Moved old installer files.
   6381: Fixed AR-782: Early detection of property conversion issues
   6382: Fixed AR-1414: Serializable property values are immediately disconnected from the client's instance.
   6384: Fix AR-1642 : Pooled task is not auto-assigned when task is completed by user, but user has not first 'taken ownership'
   6385: AR-1621 Workflow bootstrap is not sensitive to system read-only mode
            Resolved conflicted state of 'root\projects\repository\source\java\org\alfresco\repo\workflow\WorkflowInterpreter.java'


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6726 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2007-09-10 15:21:52 +00:00
parent 60ea2805cc
commit 1050a3cb98
10 changed files with 172 additions and 42 deletions

View File

@@ -251,7 +251,7 @@
<ref bean="policyComponent" /> <ref bean="policyComponent" />
</property> </property>
<property name="defaultProvider"> <property name="defaultProvider">
<ref bean="personalHomeFolderProvider" /> <ref bean="userHomesHomeFolderProvider" />
</property> </property>
</bean> </bean>

View File

@@ -12,6 +12,9 @@
<property name="authenticationComponent" ref="authenticationComponent" /> <property name="authenticationComponent" ref="authenticationComponent" />
<property name="workflowService" ref="WorkflowService" /> <property name="workflowService" ref="WorkflowService" />
<property name="dictionaryDAO" ref="dictionaryDAO"/> <property name="dictionaryDAO" ref="dictionaryDAO"/>
<property name="allowWrite">
<value>${server.transaction.allow-writes}</value>
</property>
</bean> </bean>
<bean id="workflowServiceImpl" class="org.alfresco.repo.workflow.WorkflowServiceImpl"> <bean id="workflowServiceImpl" class="org.alfresco.repo.workflow.WorkflowServiceImpl">

View File

@@ -259,10 +259,6 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService
workingCopyProperties.put(ContentModel.PROP_WORKING_COPY_OWNER, userName); workingCopyProperties.put(ContentModel.PROP_WORKING_COPY_OWNER, userName);
this.nodeService.addAspect(workingCopy, ContentModel.ASPECT_WORKING_COPY, workingCopyProperties); this.nodeService.addAspect(workingCopy, ContentModel.ASPECT_WORKING_COPY, workingCopyProperties);
// Apply the sys:temporary aspect to tag the working copy as a temporary node
// so it doesn't get archived when checked in
this.nodeService.addAspect(workingCopy, ContentModel.ASPECT_TEMPORARY, null);
// Lock the origional node // Lock the origional node
this.lockService.lock(nodeRef, LockType.READ_ONLY_LOCK); this.lockService.lock(nodeRef, LockType.READ_ONLY_LOCK);

View File

@@ -24,6 +24,10 @@
*/ */
package org.alfresco.repo.domain; package org.alfresco.repo.domain;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -512,6 +516,11 @@ public class PropertyValue implements Cloneable, Serializable
} }
else else
{ {
// Convert the value to the type required. This ensures that any type conversion issues
// are caught early and prevent the scenario where the data in the DB cannot be given
// back out because it is unconvertable.
ValueType valueType = makeValueType(typeQName);
value = valueType.convert(value);
// get the persisted type // get the persisted type
ValueType persistedValueType = this.actualType.getPersistedType(value); ValueType persistedValueType = this.actualType.getPersistedType(value);
// convert to the persistent type // convert to the persistent type
@@ -679,7 +688,7 @@ public class PropertyValue implements Cloneable, Serializable
this.attributeValue = (Attribute) value; this.attributeValue = (Attribute) value;
break; break;
case SERIALIZABLE: case SERIALIZABLE:
this.serializableValue = (Serializable) value; this.serializableValue = cloneSerializable(value);
break; break;
default: default:
throw new AlfrescoRuntimeException("Unrecognised value type: " + persistedType); throw new AlfrescoRuntimeException("Unrecognised value type: " + persistedType);
@@ -688,6 +697,37 @@ public class PropertyValue implements Cloneable, Serializable
this.persistedType = persistedType; this.persistedType = persistedType;
} }
/**
* Clones a serializable object to disconnect the original instance from the persisted instance.
*
* @param original the original object
* @return the new cloned object
*/
private Serializable cloneSerializable(Serializable original)
{
try
{
// Connect the pipes
PipedOutputStream pipeOut = new PipedOutputStream();
PipedInputStream pipeIn = new PipedInputStream();
pipeOut.connect(pipeIn);
ObjectOutputStream objectOut = new ObjectOutputStream(pipeOut);
ObjectInputStream objectIn = new ObjectInputStream(pipeIn);
// Now write the object
objectOut.writeObject(original);
// Read the new object in
Object newObj = objectIn.readObject();
// Done
return (Serializable) newObj;
}
catch (Throwable e)
{
throw new AlfrescoRuntimeException("Failed to clone serializable object: " + original, e);
}
}
/** /**
* @return Returns the persisted value, keying off the persisted value type * @return Returns the persisted value, keying off the persisted value type
*/ */

View File

@@ -671,8 +671,8 @@ public abstract class AbstractNodeServiceImpl implements NodeService
/** /**
* Extracts the externally-visible property from the {@link PropertyValue propertyValue}. * Extracts the externally-visible property from the {@link PropertyValue propertyValue}.
* *
* @param propertyDef * @param propertyDef the model property definition - may be <tt>null</tt>
* @param propertyValue * @param propertyValue the persisted property
* @return Returns the value of the property in the format dictated by the property * @return Returns the value of the property in the format dictated by the property
* definition, or null if the property value is null * definition, or null if the property value is null
*/ */
@@ -711,8 +711,8 @@ public abstract class AbstractNodeServiceImpl implements NodeService
/** /**
* Sets the default property values * Sets the default property values
* *
* @param classDefinition * @param classDefinition the model type definition for which to get defaults
* @param properties * @param properties the properties of the node
*/ */
protected void addDefaultPropertyValues(ClassDefinition classDefinition, Map<QName, Serializable> properties) protected void addDefaultPropertyValues(ClassDefinition classDefinition, Map<QName, Serializable> properties)
{ {

View File

@@ -53,6 +53,7 @@ import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.dictionary.ClassDefinition; import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryException; import org.alfresco.service.cmr.dictionary.DictionaryException;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition;
@@ -68,12 +69,14 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path; import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.TypeConversionException;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.BaseSpringTest; import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap;
import org.hibernate.Session; import org.hibernate.Session;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@@ -556,11 +559,22 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
} }
Map<QName,PropertyDefinition> propertyDefs = classDef.getProperties(); Map<QName,PropertyDefinition> propertyDefs = classDef.getProperties();
// make up a property value for each property // make up a property value for each property
for (QName propertyName : propertyDefs.keySet()) for (Map.Entry<QName, PropertyDefinition> entry : propertyDefs.entrySet())
{ {
Serializable value = new Long(System.currentTimeMillis()); QName propertyQName = entry.getKey();
QName propertyTypeQName = entry.getValue().getDataType().getName();
// Get the property type
Serializable value = null;
if (propertyTypeQName.equals(DataTypeDefinition.CONTENT))
{
value = new ContentData(null, MimetypeMap.EXTENSION_BINARY, 0L, "UTF-8");
}
else
{
value = new Long(System.currentTimeMillis());
}
// add it // add it
properties.put(propertyName, value); properties.put(propertyQName, value);
} }
} }
@@ -1829,10 +1843,10 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
ContentModel.TYPE_CONTENT, ContentModel.TYPE_CONTENT,
props).getChildRef(); props).getChildRef();
this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_TITLED, null); nodeService.addAspect(nodeRef, ContentModel.ASPECT_TITLED, null);
this.nodeService.setProperty(nodeRef, ContentModel.PROP_DESCRIPTION, "my description"); nodeService.setProperty(nodeRef, ContentModel.PROP_DESCRIPTION, "my description");
this.nodeService.setProperty(nodeRef, ContentModel.PROP_TITLE, "my title"); nodeService.setProperty(nodeRef, ContentModel.PROP_TITLE, "my title");
JavaBehaviour behaviour = new JavaBehaviour(this, "onUpdateProperties"); JavaBehaviour behaviour = new JavaBehaviour(this, "onUpdateProperties");
PolicyComponent policyComponent = (PolicyComponent)this.applicationContext.getBean("policyComponent"); PolicyComponent policyComponent = (PolicyComponent)this.applicationContext.getBean("policyComponent");
@@ -1844,7 +1858,7 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
behaviourExecuted = false; behaviourExecuted = false;
// Update the title property and check that the behaviour has been fired // Update the title property and check that the behaviour has been fired
this.nodeService.setProperty(nodeRef, ContentModel.PROP_TITLE, "changed title"); nodeService.setProperty(nodeRef, ContentModel.PROP_TITLE, "changed title");
assertTrue("The onUpdateProperties behaviour has not been fired.", behaviourExecuted); assertTrue("The onUpdateProperties behaviour has not been fired.", behaviourExecuted);
} }
@@ -1868,4 +1882,51 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
} }
} }
/**
* Checks that unconvertable property values cannot be persisted.
*/
public void testAR782() throws Exception
{
Map<QName, Serializable> properties = nodeService.getProperties(rootNodeRef);
// Set cm:created correctly
properties.put(ContentModel.PROP_CREATED, new Date());
nodeService.setProperties(rootNodeRef, properties);
try
{
// Set cm:created using something that can't be converted to a Date
properties.put(ContentModel.PROP_CREATED, "blah");
nodeService.setProperties(rootNodeRef, properties);
fail("Failed to catch type conversion issue early.");
}
catch (TypeConversionException e)
{
// Expected
}
}
/**
* Helper test class for {@link BaseNodeServiceTest#testAR1414()}.
*/
private static class AR1414Blob implements Serializable
{
private static final long serialVersionUID = 5616094206968290908L;
int i = 0;
}
/**
* Check that Serializable properties do not remain connected to the L1 session
*/
public void testAR1414() throws Exception
{
AR1414Blob blob = new AR1414Blob();
QName propertyQName = QName.createQName(NAMESPACE, "testAR1414Prop");
nodeService.setProperty(rootNodeRef, propertyQName, blob);
// Modify our original blob
blob.i = 100;
// Get the property
AR1414Blob checkBlob = (AR1414Blob) nodeService.getProperty(rootNodeRef, propertyQName);
assertNotNull(checkBlob);
assertEquals("Blob was modified while persisted", 0, checkBlob.i);
}
} }

View File

@@ -774,10 +774,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// check if we need to archive the node // check if we need to archive the node
StoreRef archiveStoreRef = null; StoreRef archiveStoreRef = null;
if (nodeAspectQNames.contains(ContentModel.ASPECT_TEMPORARY)) if (nodeAspectQNames.contains(ContentModel.ASPECT_TEMPORARY) ||
nodeAspectQNames.contains(ContentModel.ASPECT_WORKING_COPY))
{ {
// the node has the temporary aspect meaning // The node is either temporary or a working copy.
// it can not be archived // It can not be archived.
requiresDelete = true; requiresDelete = true;
} }
else else

View File

@@ -63,6 +63,7 @@ public class WorkflowDeployer extends AbstractLifecycleBean
public static final String REDEPLOY = "redeploy"; public static final String REDEPLOY = "redeploy";
// Dependencies // Dependencies
private boolean allowWrite = true;
private TransactionService transactionService; private TransactionService transactionService;
private WorkflowService workflowService; private WorkflowService workflowService;
private AuthenticationComponent authenticationComponent; private AuthenticationComponent authenticationComponent;
@@ -72,6 +73,16 @@ public class WorkflowDeployer extends AbstractLifecycleBean
private List<String> resourceBundles = new ArrayList<String>(); private List<String> resourceBundles = new ArrayList<String>();
/**
* Set whether we write or not
*
* @param write true (default) if the import must go ahead, otherwise no import will occur
*/
public void setAllowWrite(boolean write)
{
this.allowWrite = write;
}
/** /**
* Sets the Transaction Service * Sets the Transaction Service
* *
@@ -200,6 +211,13 @@ public class WorkflowDeployer extends AbstractLifecycleBean
ClassPathResource workflowResource = new ClassPathResource(location); ClassPathResource workflowResource = new ClassPathResource(location);
// deploy workflow definition // deploy workflow definition
if (!allowWrite)
{
// we're in read-only node
logger.warn("Repository is in read-only mode; not deploying workflow " + location);
}
else
{
if (!redeploy && workflowService.isDefinitionDeployed(engineId, workflowResource.getInputStream(), mimetype)) if (!redeploy && workflowService.isDefinitionDeployed(engineId, workflowResource.getInputStream(), mimetype))
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
@@ -213,6 +231,7 @@ public class WorkflowDeployer extends AbstractLifecycleBean
} }
} }
} }
}
userTransaction.commit(); userTransaction.commit();
} }

View File

@@ -114,8 +114,11 @@ public class WorkflowInterpreter extends BaseInterpreter
{ {
setCurrentUserName(BaseInterpreter.DEFAULT_ADMIN); setCurrentUserName(BaseInterpreter.DEFAULT_ADMIN);
if (!transactionService.isReadOnly())
{
interpretCommand("var bpm:package package 1"); interpretCommand("var bpm:package package 1");
interpretCommand("var bpm:assignee person admin"); interpretCommand("var bpm:assignee person admin");
}
setCurrentUserName(null); setCurrentUserName(null);
} }

View File

@@ -28,6 +28,7 @@ import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.workflow.WorkflowModel; import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.workflow.WorkflowException; import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -110,6 +111,12 @@ public class WorkflowTaskInstance extends TaskInstance
@Override @Override
public void end(Transition transition) public void end(Transition transition)
{ {
// Force assignment of task if transition is taken, but no owner has yet been assigned
if (actorId == null)
{
actorId = AuthenticationUtil.getCurrentUserName();
}
// Set task properties on completion of task // Set task properties on completion of task
// NOTE: Set properties first, so they're available during the submission of // NOTE: Set properties first, so they're available during the submission of
// task variables to the process context // task variables to the process context