Merged V3.1 to HEAD

14955: Merged V2.2 to V3.1
      14352: Fixed ETWOTWO-1113: Creation date / modification date reset to current date during import
   14956: Fix for ETHREEOH-2198 and ALFCOM-2972
           - Thumbnail Service now allows creation of system managed thumbnails nodes by Consumer users or on Locked items
           - Explicit permission check to ensure user must at least be able to Read the original doc
           - Now correctly ensures that the 'modifier' properties are not updated on the original doc due to thumbnail generation

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14957 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2009-06-26 12:47:58 +00:00
parent 8139b17300
commit 6763cfabc1
7 changed files with 408 additions and 138 deletions

View File

@@ -388,6 +388,9 @@
<property name="auditableTransactionHelper"> <property name="auditableTransactionHelper">
<ref bean="auditableTransactionHelper" /> <ref bean="auditableTransactionHelper" />
</property> </property>
<property name="behaviourFilter">
<ref bean="policyBehaviourFilter" />
</property>
<property name="sessionFactory"> <property name="sessionFactory">
<ref bean="sessionFactory" /> <ref bean="sessionFactory" />
</property> </property>

View File

@@ -38,9 +38,11 @@
<!-- Thumbnail service implemenation bean --> <!-- Thumbnail service implemenation bean -->
<bean id="thumbnailService" class="org.alfresco.repo.thumbnail.ThumbnailServiceImpl"> <bean id="thumbnailService" class="org.alfresco.repo.thumbnail.ThumbnailServiceImpl">
<property name="nodeService" ref="NodeService"/> <property name="nodeService" ref="nodeService"/>
<property name="contentService" ref="ContentService"/> <property name="contentService" ref="contentService"/>
<property name="permissionService" ref="PermissionService"/>
<property name="mimetypeMap" ref="mimetypeService"/> <property name="mimetypeMap" ref="mimetypeService"/>
<property name="behaviourFilter" ref="policyBehaviourFilter" />
<property name="thumbnailRegistry" ref="thumbnailRegistry" /> <property name="thumbnailRegistry" ref="thumbnailRegistry" />
</bean> </bean>

View File

@@ -208,6 +208,65 @@ public class AuditableProperties
auditModified = dateStr; auditModified = dateStr;
} }
/**
* Set all <b>cm:auditable</b> parameters as required, giving precedence to the supplied
* property map.
*
* @param user the username
* @param date the creation or modification date
* @param properties the properties to override the user and date
*/
public void setAuditValues(String user, Date date, Map<QName, Serializable> properties)
{
String dateStr = DefaultTypeConverter.INSTANCE.convert(String.class, date);
if (properties.containsKey(ContentModel.PROP_CREATOR))
{
auditCreator = DefaultTypeConverter.INSTANCE.convert(
String.class,
properties.get(ContentModel.PROP_CREATOR));
}
else if (auditCreator == null)
{
auditCreator = user;
}
if (properties.containsKey(ContentModel.PROP_MODIFIER))
{
auditModifier = DefaultTypeConverter.INSTANCE.convert(
String.class,
properties.get(ContentModel.PROP_MODIFIER));
}
else if (auditModifier == null)
{
auditModifier = user;
}
if (properties.containsKey(ContentModel.PROP_CREATED))
{
auditCreated = DefaultTypeConverter.INSTANCE.convert(
String.class,
properties.get(ContentModel.PROP_CREATED));
}
else if (auditCreated == null)
{
auditCreated = dateStr;
}
if (properties.containsKey(ContentModel.PROP_MODIFIED))
{
auditModified = DefaultTypeConverter.INSTANCE.convert(
String.class,
properties.get(ContentModel.PROP_MODIFIED));
}
else if (auditModified == null)
{
auditModified = dateStr;
}
if (properties.containsKey(ContentModel.PROP_ACCESSED))
{
auditAccessed = DefaultTypeConverter.INSTANCE.convert(
String.class,
properties.get(ContentModel.PROP_ACCESSED));
}
}
/** /**
* For persistance use * For persistance use
*/ */

View File

@@ -26,14 +26,25 @@ package org.alfresco.repo.importer;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
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.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.view.ImporterService; import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.view.Location; import org.alfresco.service.cmr.view.Location;
import org.alfresco.service.cmr.view.ImporterBinding.UUID_BINDING; import org.alfresco.service.cmr.view.ImporterBinding.UUID_BINDING;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.BaseSpringTest; import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.debug.NodeStoreInspector; import org.alfresco.util.debug.NodeStoreInspector;
@@ -71,8 +82,7 @@ public class ImporterComponentTest extends BaseSpringTest
} }
public void testImport() public void testImport() throws Exception
throws Exception
{ {
InputStream test = getClass().getClassLoader().getResourceAsStream("org/alfresco/repo/importer/importercomponent_test.xml"); InputStream test = getClass().getClassLoader().getResourceAsStream("org/alfresco/repo/importer/importercomponent_test.xml");
InputStreamReader testReader = new InputStreamReader(test, "UTF-8"); InputStreamReader testReader = new InputStreamReader(test, "UTF-8");
@@ -81,6 +91,56 @@ public class ImporterComponentTest extends BaseSpringTest
System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef)); System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef));
} }
public void testImportWithAuditableProperties() throws Exception
{
InputStream test = getClass().getClassLoader().getResourceAsStream("org/alfresco/repo/importer/importercomponent_test.xml");
InputStreamReader testReader = new InputStreamReader(test, "UTF-8");
Location location = new Location(storeRef);
try
{
importerService.importView(
testReader,
location,
null,
new ImportTimerProgress());
}
finally
{
testReader.close();
}
NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(
rootNodeRef,
RegexQNamePattern.MATCH_ALL,
new RegexQNamePattern(NamespaceService.CONTENT_MODEL_1_0_URI, "SpaceWith.*"));
// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "SpaceWithAuditable"));
assertEquals("'SpaceWith*' path not found", 2, childAssocs.size());
NodeRef nodeRef = childAssocs.get(0).getChildRef();
Map<QName, Serializable> nodeProps = nodeService.getProperties(nodeRef);
String createdDate = DefaultTypeConverter.INSTANCE.convert(String.class, nodeProps.get(ContentModel.PROP_CREATED));
String creator = DefaultTypeConverter.INSTANCE.convert(String.class, nodeProps.get(ContentModel.PROP_CREATOR));
String modifiedDate = DefaultTypeConverter.INSTANCE.convert(String.class, nodeProps.get(ContentModel.PROP_MODIFIED));
String modifier = DefaultTypeConverter.INSTANCE.convert(String.class, nodeProps.get(ContentModel.PROP_MODIFIER));
// Check that the cm:auditable properties are correct
assertEquals("cm:created not preserved during import", "2009-05-01T00:00:00.000+01:00", createdDate);
assertEquals("cm:creator not preserved during import", "Import Creator", creator);
assertEquals("cm:modified not preserved during import", "2009-05-02T00:00:00.000+01:00", modifiedDate);
assertEquals("cm:modifier not preserved during import", "Import Modifier", modifier);
nodeRef = childAssocs.get(1).getChildRef();
nodeProps = nodeService.getProperties(nodeRef);
createdDate = DefaultTypeConverter.INSTANCE.convert(String.class, nodeProps.get(ContentModel.PROP_CREATED));
creator = DefaultTypeConverter.INSTANCE.convert(String.class, nodeProps.get(ContentModel.PROP_CREATOR));
modifiedDate = DefaultTypeConverter.INSTANCE.convert(String.class, nodeProps.get(ContentModel.PROP_MODIFIED));
modifier = DefaultTypeConverter.INSTANCE.convert(String.class, nodeProps.get(ContentModel.PROP_MODIFIER));
// Check that the cm:auditable properties are correct
assertEquals("cm:created not preserved during import", "2009-05-01T00:00:00.000+01:00", createdDate);
assertEquals("cm:creator not preserved during import", "Import Creator", creator);
assertEquals("cm:modifier not preserved during import", AuthenticationUtil.getSystemUserName(), modifier);
}
public void testImportWithUuidBinding() throws Exception public void testImportWithUuidBinding() throws Exception
{ {
Location location = new Location(storeRef); Location location = new Location(storeRef);

View File

@@ -78,6 +78,26 @@
<cm:content>contentUrl=classpath:org/alfresco/repo/importer/importercomponent_testfile.txt|mimetype=text|size=|encoding=</cm:content> <cm:content>contentUrl=classpath:org/alfresco/repo/importer/importercomponent_testfile.txt|mimetype=text|size=|encoding=</cm:content>
</cm:content> </cm:content>
<cm:folder view:childName="cm:SpaceWithAuditable">
<view:aspects>
<cm:auditable/>
</view:aspects>
<cm:name>SpaceWithAuditable</cm:name>
<cm:created>2009-05-01T00:00:00.000+01:00</cm:created>
<cm:creator>Import Creator</cm:creator>
<cm:modified>2009-05-02T00:00:00.000+01:00</cm:modified>
<cm:modifier>Import Modifier</cm:modifier>
</cm:folder>
<cm:folder view:childName="cm:SpaceWithPartialAuditable">
<view:aspects>
<cm:auditable/>
</view:aspects>
<cm:name>SpaceWithPartialAuditable"</cm:name>
<cm:created>2009-05-01T00:00:00.000+01:00</cm:created>
<cm:creator>Import Creator</cm:creator>
</cm:folder>
<cm:folder view:id="ML Text"> <cm:folder view:id="ML Text">
<view:aspects> <view:aspects>
<cm:auditable/> <cm:auditable/>

View File

@@ -73,6 +73,7 @@ import org.alfresco.repo.domain.hibernate.SessionSizeResourceManager;
import org.alfresco.repo.domain.hibernate.StoreImpl; import org.alfresco.repo.domain.hibernate.StoreImpl;
import org.alfresco.repo.domain.hibernate.TransactionImpl; import org.alfresco.repo.domain.hibernate.TransactionImpl;
import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.ACLType; import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.security.permissions.AccessControlListProperties; import org.alfresco.repo.security.permissions.AccessControlListProperties;
@@ -191,6 +192,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
private boolean enableTimestampPropagation; private boolean enableTimestampPropagation;
private RetryingTransactionHelper auditableTransactionHelper; private RetryingTransactionHelper auditableTransactionHelper;
private BehaviourFilter behaviourFilter;
/** A cache mapping StoreRef and NodeRef instances to the entity IDs (primary key) */ /** A cache mapping StoreRef and NodeRef instances to the entity IDs (primary key) */
private SimpleCache<EntityRef, Long> storeAndNodeIdCache; private SimpleCache<EntityRef, Long> storeAndNodeIdCache;
/** A cache for more performant lookups of the parent associations */ /** A cache for more performant lookups of the parent associations */
@@ -311,6 +313,16 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
this.auditableTransactionHelper = auditableTransactionHelper; this.auditableTransactionHelper = auditableTransactionHelper;
} }
/**
* Set the component to determine the correct aspect behaviours. This applies
* particularly to the <b>cm:auditable</b> case, where the setting of values
* is done automatically except when the behaviour is disabled.
*/
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
{
this.behaviourFilter = behaviourFilter;
}
/** /**
* Ste the transaction-aware cache to store Store and Root Node IDs by Store Reference * Ste the transaction-aware cache to store Store and Root Node IDs by Store Reference
* *
@@ -839,22 +851,57 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
} }
} }
/**
* Record the node update, setting the node's <b>cm:auditable</b> properties.
* The <b>cm:auditable</b> properties set implicity if the automatic behaviour
* {@link BehaviourFilter#isEnabled(NodeRef, QName) behaviour} is enabled.
*
* @see #recordNodeUpdate(Node, Map)
*/
private void recordNodeUpdate(Node node) private void recordNodeUpdate(Node node)
{
recordNodeUpdate(node, null);
}
/**
* Record the node update, setting the node's <b>cm:auditable</b> properties.
* The <b>cm:auditable</b> properties set implicity if the automatic behaviour
* {@link BehaviourFilter#isEnabled(NodeRef, QName) behaviour} is enabled,
* otherwise the properties are extracted from the properties passed in.
*
* @param node the node to operate on
* @param properties the node properties from which <b>cm:auditable</b> properties
* may be extracted
*/
private void recordNodeUpdate(Node node, Map<QName, Serializable> properties)
{ {
updateNodeStatus(node, false); updateNodeStatus(node, false);
// Handle cm:auditable // Handle cm:auditable
if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE)) if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE))
{ {
String currentUser = getCurrentUser(); NodeRef nodeRef = node.getNodeRef();
Date currentDate = new Date();
AuditableProperties auditableProperties = node.getAuditableProperties(); AuditableProperties auditableProperties = node.getAuditableProperties();
if (auditableProperties == null) if (auditableProperties == null)
{ {
auditableProperties = new AuditableProperties(); auditableProperties = new AuditableProperties();
node.setAuditableProperties(auditableProperties); node.setAuditableProperties(auditableProperties);
} }
String currentUser = getCurrentUser();
Date currentDate = new Date();
// Check if the cm:auditable aspect behaviour is enabled
if (behaviourFilter.isEnabled(nodeRef, ContentModel.ASPECT_AUDITABLE))
{
// Automatic cm:auditable behaviour
auditableProperties.setAuditValues(currentUser, currentDate, false); auditableProperties.setAuditValues(currentUser, currentDate, false);
} }
else if (properties != null)
{
// Manual cm:auditable behaviour
node.getAuditableProperties().setAuditValues(currentUser, currentDate, properties);
}
// else
// there are no properties, so there is nothing to set
}
// Propagate timestamps // Propagate timestamps
propagateTimestamps(node); propagateTimestamps(node);
} }
@@ -1398,7 +1445,9 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
addNodePropertyImpl(node, qname, propertyValue, localeId); addNodePropertyImpl(node, qname, propertyValue, localeId);
// Record change ID // Record change ID
recordNodeUpdate(node); recordNodeUpdate(
node,
Collections.singletonMap(qname, propertyValue));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -1410,12 +1459,16 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
for (Map.Entry<QName, Serializable> entry : properties.entrySet()) for (Map.Entry<QName, Serializable> entry : properties.entrySet())
{ {
QName qname = entry.getKey(); QName qname = entry.getKey();
if (AuditableProperties.isAuditableProperty(qname))
{
continue;
}
Serializable value = entry.getValue(); Serializable value = entry.getValue();
addNodePropertyImpl(node, qname, value, localeId); addNodePropertyImpl(node, qname, value, localeId);
} }
// Record change ID // Record change ID
recordNodeUpdate(node); recordNodeUpdate(node, properties);
} }
public void setNodeProperties(Long nodeId, Map<QName, Serializable> propertiesIncl) public void setNodeProperties(Long nodeId, Map<QName, Serializable> propertiesIncl)
@@ -1477,7 +1530,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
} }
// Record change ID // Record change ID
recordNodeUpdate(node); recordNodeUpdate(node, propertiesIncl);
} }
public void removeNodeProperties(Long nodeId, Set<QName> propertyQNamesIncl) public void removeNodeProperties(Long nodeId, Set<QName> propertyQNamesIncl)

View File

@@ -33,6 +33,9 @@ import java.util.Map;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentReader;
@@ -41,6 +44,8 @@ import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef; 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.TransformationOptions; import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.thumbnail.ThumbnailException; import org.alfresco.service.cmr.thumbnail.ThumbnailException;
import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails; import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails;
import org.alfresco.service.cmr.thumbnail.ThumbnailService; import org.alfresco.service.cmr.thumbnail.ThumbnailService;
@@ -71,9 +76,15 @@ public class ThumbnailServiceImpl implements ThumbnailService
/** Content service */ /** Content service */
private ContentService contentService; private ContentService contentService;
/** Permission service */
private PermissionService permissionService;
/** Mimetype map */ /** Mimetype map */
private MimetypeMap mimetypeMap; private MimetypeMap mimetypeMap;
/** Behaviour filter */
private BehaviourFilter behaviourFilter;
/** Thumbnail registry */ /** Thumbnail registry */
private ThumbnailRegistry thumbnailRegistry; private ThumbnailRegistry thumbnailRegistry;
@@ -97,6 +108,14 @@ public class ThumbnailServiceImpl implements ThumbnailService
this.contentService = contentService; this.contentService = contentService;
} }
/**
* @param permissionService permission service
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/** /**
* Sets the mimetype map * Sets the mimetype map
* *
@@ -107,6 +126,14 @@ public class ThumbnailServiceImpl implements ThumbnailService
this.mimetypeMap = mimetypeMap; this.mimetypeMap = mimetypeMap;
} }
/**
* @param behaviourFilter policy behaviour filter
*/
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
{
this.behaviourFilter = behaviourFilter;
}
/** /**
* Set thumbnail registry * Set thumbnail registry
* *
@@ -136,7 +163,8 @@ public class ThumbnailServiceImpl implements ThumbnailService
/** /**
* @see org.alfresco.service.cmr.thumbnail.ThumbnailService#createThumbnail(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions, java.lang.String, org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails) * @see org.alfresco.service.cmr.thumbnail.ThumbnailService#createThumbnail(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions, java.lang.String, org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails)
*/ */
public NodeRef createThumbnail(NodeRef node, QName contentProperty, String mimetype, TransformationOptions transformationOptions, String thumbnailName, ThumbnailParentAssociationDetails assocDetails) public NodeRef createThumbnail(final NodeRef node, final QName contentProperty, final String mimetype,
final TransformationOptions transformationOptions, final String thumbnailName, final ThumbnailParentAssociationDetails assocDetails)
{ {
// Parameter check // Parameter check
ParameterCheck.mandatory("node", node); ParameterCheck.mandatory("node", node);
@@ -149,7 +177,10 @@ public class ThumbnailServiceImpl implements ThumbnailService
logger.debug("Creating thumbnail (node=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype); logger.debug("Creating thumbnail (node=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype);
} }
NodeRef thumbnail = null; if (!permissionService.hasPermission(node, PermissionService.READ_PROPERTIES).equals(AccessStatus.ALLOWED))
{
throw new AccessDeniedException("Access Denied");
}
// Check for duplicate names // Check for duplicate names
if (thumbnailName != null && getThumbnailByName(node, contentProperty, thumbnailName) != null) if (thumbnailName != null && getThumbnailByName(node, contentProperty, thumbnailName) != null)
@@ -163,24 +194,40 @@ public class ThumbnailServiceImpl implements ThumbnailService
throw new ThumbnailException(ERR_DUPLICATE_NAME); throw new ThumbnailException(ERR_DUPLICATE_NAME);
} }
// Apply the thumbnailed aspect to the node if it doesn't already have it NodeRef thumbnail = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<NodeRef>()
if (this.nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == false)
{ {
this.nodeService.addAspect(node, ContentModel.ASPECT_THUMBNAILED, null); public NodeRef doWork() throws Exception
{
NodeRef thumbnail;
// Apply the thumbnailed aspect to the node if it doesn't already have it
if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == false)
{
// Ensure we do not update the 'modifier' due to thumbnail addition
behaviourFilter.disableBehaviour(node, ContentModel.ASPECT_AUDITABLE);
try
{
nodeService.addAspect(node, ContentModel.ASPECT_THUMBNAILED, null);
}
finally
{
behaviourFilter.enableBehaviour(node, ContentModel.ASPECT_AUDITABLE);
}
} }
// Get the name of the thumbnail and add to properties map // Get the name of the thumbnail and add to properties map
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(2); String thumbName = thumbnailName;
if (thumbnailName == null || thumbnailName.length() == 0) Map<QName, Serializable> properties = new HashMap<QName, Serializable>(4);
if (thumbName == null || thumbName.length() == 0)
{ {
thumbnailName = GUID.generate(); thumbName = GUID.generate();
} }
else else
{ {
String thumbnailFileName = generateThumbnailFileName(thumbnailName, mimetype); String thumbnailFileName = generateThumbnailFileName(thumbName, mimetype);
properties.put(ContentModel.PROP_NAME, thumbnailFileName); properties.put(ContentModel.PROP_NAME, thumbnailFileName);
} }
properties.put(ContentModel.PROP_THUMBNAIL_NAME, thumbnailName); properties.put(ContentModel.PROP_THUMBNAIL_NAME, thumbName);
// Add the name of the content property // Add the name of the content property
properties.put(ContentModel.PROP_CONTENT_PROPERTY_NAME, contentProperty); properties.put(ContentModel.PROP_CONTENT_PROPERTY_NAME, contentProperty);
@@ -189,17 +236,17 @@ public class ThumbnailServiceImpl implements ThumbnailService
if (assocDetails == null) if (assocDetails == null)
{ {
// Create the thumbnail using the thumbnails child association // Create the thumbnail using the thumbnails child association
thumbnail = this.nodeService.createNode( thumbnail = nodeService.createNode(
node, node,
ContentModel.ASSOC_THUMBNAILS, ContentModel.ASSOC_THUMBNAILS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName), QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbName),
ContentModel.TYPE_THUMBNAIL, ContentModel.TYPE_THUMBNAIL,
properties).getChildRef(); properties).getChildRef();
} }
else else
{ {
// Create the thumbnail using the specified parent assoc details // Create the thumbnail using the specified parent assoc details
thumbnail = this.nodeService.createNode( thumbnail = nodeService.createNode(
assocDetails.getParent(), assocDetails.getParent(),
assocDetails.getAssociationType(), assocDetails.getAssociationType(),
assocDetails.getAssociationName(), assocDetails.getAssociationName(),
@@ -207,21 +254,21 @@ public class ThumbnailServiceImpl implements ThumbnailService
properties).getChildRef(); properties).getChildRef();
// Associate the new thumbnail to the source // Associate the new thumbnail to the source
this.nodeService.addChild( nodeService.addChild(
node, node,
thumbnail, thumbnail,
ContentModel.ASSOC_THUMBNAILS, ContentModel.ASSOC_THUMBNAILS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName)); QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbName));
} }
// Get the content reader and writer for content nodes // Get the content reader and writer for content nodes
ContentReader reader = this.contentService.getReader(node, contentProperty); ContentReader reader = contentService.getReader(node, contentProperty);
ContentWriter writer = this.contentService.getWriter(thumbnail, ContentModel.PROP_CONTENT, true); ContentWriter writer = contentService.getWriter(thumbnail, ContentModel.PROP_CONTENT, true);
writer.setMimetype(mimetype); writer.setMimetype(mimetype);
writer.setEncoding(reader.getEncoding()); writer.setEncoding(reader.getEncoding());
// Catch the failure to create the thumbnail // Catch the failure to create the thumbnail
if (this.contentService.isTransformable(reader, writer, transformationOptions) == false) if (contentService.isTransformable(reader, writer, transformationOptions) == false)
{ {
if (logger.isDebugEnabled() == true) if (logger.isDebugEnabled() == true)
{ {
@@ -234,9 +281,13 @@ public class ThumbnailServiceImpl implements ThumbnailService
else else
{ {
// Do the thumbnail transformation // Do the thumbnail transformation
this.contentService.transform(reader, writer, transformationOptions); contentService.transform(reader, writer, transformationOptions);
} }
return thumbnail;
}
}, AuthenticationUtil.getSystemUserName());
// Return the created thumbnail // Return the created thumbnail
return thumbnail; return thumbnail;
} }
@@ -256,19 +307,28 @@ public class ThumbnailServiceImpl implements ThumbnailService
/** /**
* @see org.alfresco.service.cmr.thumbnail.ThumbnailService#updateThumbnail(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.TransformationOptions) * @see org.alfresco.service.cmr.thumbnail.ThumbnailService#updateThumbnail(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.TransformationOptions)
*/ */
public void updateThumbnail(NodeRef thumbnail, TransformationOptions transformationOptions) public void updateThumbnail(final NodeRef thumbnail, final TransformationOptions transformationOptions)
{ {
if (logger.isDebugEnabled() == true) if (logger.isDebugEnabled() == true)
{ {
logger.debug("Updating thumbnail (thumbnail=" + thumbnail.toString() + ")"); logger.debug("Updating thumbnail (thumbnail=" + thumbnail.toString() + ")");
} }
if (!permissionService.hasPermission(thumbnail, PermissionService.READ_PROPERTIES).equals(AccessStatus.ALLOWED))
{
throw new AccessDeniedException("Access Denied");
}
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork() throws Exception
{
// First check that we are dealing with a thumbnail // First check that we are dealing with a thumbnail
if (ContentModel.TYPE_THUMBNAIL.equals(this.nodeService.getType(thumbnail)) == true) if (ContentModel.TYPE_THUMBNAIL.equals(nodeService.getType(thumbnail)) == true)
{ {
// Get the node that is the source of the thumbnail // Get the node that is the source of the thumbnail
NodeRef node = null; NodeRef node = null;
List<ChildAssociationRef> parents = this.nodeService.getParentAssocs(thumbnail, ContentModel.ASSOC_THUMBNAILS, RegexQNamePattern.MATCH_ALL); List<ChildAssociationRef> parents = nodeService.getParentAssocs(thumbnail, ContentModel.ASSOC_THUMBNAILS, RegexQNamePattern.MATCH_ALL);
if (parents.size() == 0) if (parents.size() == 0)
{ {
if (logger.isDebugEnabled() == true) if (logger.isDebugEnabled() == true)
@@ -284,11 +344,11 @@ public class ThumbnailServiceImpl implements ThumbnailService
} }
// Get the content property // Get the content property
QName contentProperty = (QName)this.nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT_PROPERTY_NAME); QName contentProperty = (QName)nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT_PROPERTY_NAME);
// Get the reader and writer // Get the reader and writer
ContentReader reader = this.contentService.getReader(node, contentProperty); ContentReader reader = contentService.getReader(node, contentProperty);
ContentWriter writer = this.contentService.getWriter(thumbnail, ContentModel.PROP_CONTENT, true); ContentWriter writer = contentService.getWriter(thumbnail, ContentModel.PROP_CONTENT, true);
// Set the basic detail of the transformation options // Set the basic detail of the transformation options
transformationOptions.setSourceNodeRef(node); transformationOptions.setSourceNodeRef(node);
@@ -297,7 +357,7 @@ public class ThumbnailServiceImpl implements ThumbnailService
transformationOptions.setTargetContentProperty(ContentModel.PROP_CONTENT); transformationOptions.setTargetContentProperty(ContentModel.PROP_CONTENT);
// Catch the failure to create the thumbnail // Catch the failure to create the thumbnail
if (this.contentService.isTransformable(reader, writer, transformationOptions) == false) if (contentService.isTransformable(reader, writer, transformationOptions) == false)
{ {
if (logger.isDebugEnabled() == true) if (logger.isDebugEnabled() == true)
{ {
@@ -310,7 +370,7 @@ public class ThumbnailServiceImpl implements ThumbnailService
else else
{ {
// Do the thumbnail transformation // Do the thumbnail transformation
this.contentService.transform(reader, writer, transformationOptions); contentService.transform(reader, writer, transformationOptions);
} }
} }
else else
@@ -320,6 +380,9 @@ public class ThumbnailServiceImpl implements ThumbnailService
logger.debug("Updating thumbnail: cannot update a thumbnail node that isn't the correct thumbnail type (thumbnail=" + thumbnail.toString() + ")"); logger.debug("Updating thumbnail: cannot update a thumbnail node that isn't the correct thumbnail type (thumbnail=" + thumbnail.toString() + ")");
} }
} }
return null;
}
}, AuthenticationUtil.getSystemUserName());
} }
/** /**
@@ -341,6 +404,11 @@ public class ThumbnailServiceImpl implements ThumbnailService
logger.debug("Getting thumbnail by name (nodeRef=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; thumbnailName=" + thumbnailName + ")"); logger.debug("Getting thumbnail by name (nodeRef=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; thumbnailName=" + thumbnailName + ")");
} }
if (!permissionService.hasPermission(node, PermissionService.READ_PROPERTIES).equals(AccessStatus.ALLOWED))
{
throw new AccessDeniedException("Access Denied");
}
// Check that the node has the thumbnailed aspect applied // Check that the node has the thumbnailed aspect applied
if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true) if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true)
{ {
@@ -381,6 +449,11 @@ public class ThumbnailServiceImpl implements ThumbnailService
logger.debug("Getting thumbnails (nodeRef=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype + ")"); logger.debug("Getting thumbnails (nodeRef=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype + ")");
} }
if (!permissionService.hasPermission(node, PermissionService.READ_PROPERTIES).equals(AccessStatus.ALLOWED))
{
throw new AccessDeniedException("Access Denied");
}
// Check that the node has the thumbnailed aspect applied // Check that the node has the thumbnailed aspect applied
if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true) if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true)
{ {