mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merged 5.0.N (5.0.4) to 5.2.N (5.2.1)
123880 rneamtu: Merged V4.2-BUG-FIX (4.2.7) to 5.0.N (5.0.4) 123574 amorarasu: Merged V4.2.6 (4.2.6) to V4.2-BUG-FIX (4.2.7) 123414 123524 amorarasu: MNT-15798: CLONE - call to guessMimetype() on a node that has no content creates a content property - Content Data should be created only when it has a binary, not as a side effect of getters on ScriptNode. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@123892 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1726,10 +1726,23 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
{
|
||||
Serializable value = (Serializable) this.properties.get(key);
|
||||
|
||||
QName qname = createQName(key);
|
||||
|
||||
// MNT-15798
|
||||
if (ContentModel.PROP_CONTENT.equals(qname) && isScriptContent(value))
|
||||
{
|
||||
ScriptContentData contentData = (ScriptContentData) value;
|
||||
// Do not persist the contentData if it was not touched
|
||||
if (!contentData.isDirty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// perform the conversion from script wrapper object to repo serializable values
|
||||
value = getValueConverter().convertValueForRepo(value);
|
||||
|
||||
props.put(createQName(key), value);
|
||||
props.put(qname, value);
|
||||
}
|
||||
this.nodeService.setProperties(this.nodeRef, props);
|
||||
}
|
||||
@@ -3768,6 +3781,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
{
|
||||
this.contentData = contentData;
|
||||
this.property = property;
|
||||
this.isDirty = ContentData.hasContent(contentData);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -3814,6 +3828,15 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the contentData has a binary (content URL) associated and the updates on contentData and related properties should be saved.
|
||||
* <code>false</code> if the contentData has a temporary value and no actual binary to be persisted.
|
||||
*/
|
||||
public boolean isDirty()
|
||||
{
|
||||
return this.isDirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content stream
|
||||
*
|
||||
@@ -3827,7 +3850,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
writer.putContent(content);
|
||||
|
||||
// update cached variables after putContent()
|
||||
this.contentData = (ContentData) services.getNodeService().getProperty(nodeRef, this.property);
|
||||
updateContentData(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3844,7 +3867,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
writer.putContent(content.getInputStream());
|
||||
|
||||
// update cached variables after putContent()
|
||||
this.contentData = (ContentData) services.getNodeService().getProperty(nodeRef, this.property);
|
||||
updateContentData(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3885,7 +3908,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
writer.putContent(is);
|
||||
|
||||
// update cached variables after putContent()
|
||||
this.contentData = (ContentData) services.getNodeService().getProperty(nodeRef, this.property);
|
||||
updateContentData(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3900,7 +3923,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
writer.putContent(inputStream);
|
||||
|
||||
// update cached variables after putContent()
|
||||
this.contentData = (ContentData) services.getNodeService().getProperty(nodeRef, this.property);
|
||||
updateContentData(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3923,7 +3946,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
writer.setEncoding(null);
|
||||
|
||||
// update cached variables after putContent()
|
||||
this.contentData = (ContentData) services.getNodeService().getProperty(nodeRef, this.property);
|
||||
updateContentData(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3976,18 +3999,14 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
{
|
||||
this.contentData = ContentData.setEncoding(this.contentData, encoding);
|
||||
services.getNodeService().setProperty(nodeRef, this.property, this.contentData);
|
||||
|
||||
// update cached variables after putContent()
|
||||
this.contentData = (ContentData) services.getNodeService().getProperty(nodeRef, this.property);
|
||||
updateContentData(false);
|
||||
}
|
||||
|
||||
public void setMimetype(String mimetype)
|
||||
{
|
||||
this.contentData = ContentData.setMimetype(this.contentData, mimetype);
|
||||
services.getNodeService().setProperty(nodeRef, this.property, this.contentData);
|
||||
|
||||
// update cached variables after putContent()
|
||||
this.contentData = (ContentData) services.getNodeService().getProperty(nodeRef, this.property);
|
||||
updateContentData(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4047,8 +4066,18 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
return encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cached contentData and the isDirty flag
|
||||
*/
|
||||
private void updateContentData(boolean touchContent)
|
||||
{
|
||||
this.contentData = (ContentData) services.getNodeService().getProperty(nodeRef, this.property);
|
||||
this.isDirty = touchContent ? true : this.isDirty;
|
||||
}
|
||||
|
||||
private ContentData contentData;
|
||||
private QName property;
|
||||
private boolean isDirty;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2014 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2016 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -35,6 +35,7 @@ import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.dictionary.DictionaryRepositoryBootstrap;
|
||||
import org.alfresco.repo.dictionary.RepositoryLocation;
|
||||
import org.alfresco.repo.i18n.MessageService;
|
||||
import org.alfresco.repo.jscript.ScriptNode.ScriptContentData;
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
@@ -47,6 +48,7 @@ import org.alfresco.repo.version.VersionableAspect;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
@@ -80,6 +82,8 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.RuleChain;
|
||||
import org.junit.rules.TestName;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
|
||||
|
||||
/**
|
||||
@@ -545,4 +549,93 @@ public class ScriptNodeTest
|
||||
|
||||
revertBootstrap();
|
||||
}
|
||||
|
||||
/**
|
||||
* MNT-15798 - Content Data should be created only when it has a binary, not as a side effect of getters on ScriptNode.
|
||||
*/
|
||||
@Test
|
||||
public void testContentDataCreation()
|
||||
{
|
||||
Repository repositoryHelper = (Repository) APP_CONTEXT_INIT.getApplicationContext().getBean("repositoryHelper");
|
||||
NodeRef companyHome = repositoryHelper.getCompanyHome();
|
||||
|
||||
NodeRef newNode1 = testNodes.createNode(companyHome, "theTestContent1", ContentModel.TYPE_CONTENT, AuthenticationUtil.getFullyAuthenticatedUser());
|
||||
|
||||
// test on content data
|
||||
ScriptNode sn = new ScriptNode(newNode1, SERVICE_REGISTRY);
|
||||
sn.setScope(getScope());
|
||||
|
||||
ContentData contentData = (ContentData) NODE_SERVICE.getProperty(newNode1, ContentModel.PROP_CONTENT);
|
||||
assertNull(contentData);
|
||||
|
||||
sn.setMimetype(MimetypeMap.MIMETYPE_PDF);
|
||||
sn.save();
|
||||
contentData = (ContentData) NODE_SERVICE.getProperty(newNode1, ContentModel.PROP_CONTENT);
|
||||
assertNull(contentData);
|
||||
|
||||
sn.setContent("Marks to prove it.");
|
||||
sn.save();
|
||||
contentData = (ContentData) NODE_SERVICE.getProperty(newNode1, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(contentData);
|
||||
assertEquals(true, ContentData.hasContent(contentData));
|
||||
|
||||
// test on ScriptContentData
|
||||
NodeRef newNode2 = testNodes.createNode(companyHome, "theTestContent2.txt", ContentModel.TYPE_CONTENT, AuthenticationUtil.getFullyAuthenticatedUser());
|
||||
ScriptNode sn2 = new ScriptNode(newNode2, SERVICE_REGISTRY);
|
||||
sn2.setScope(getScope());
|
||||
|
||||
ScriptContentData scd = sn2.new ScriptContentData(null, ContentModel.PROP_CONTENT);
|
||||
//set the "mocked" script content data on the script node
|
||||
sn2.getProperties().put(ContentModel.PROP_CONTENT.toString(), scd);
|
||||
|
||||
assertEquals(false, scd.isDirty());
|
||||
|
||||
scd.guessMimetype("theTestContent2.pdf");
|
||||
assertEquals(false, scd.isDirty());
|
||||
|
||||
scd.setMimetype("text/plain");
|
||||
assertEquals(false, scd.isDirty());
|
||||
|
||||
scd.setEncoding("UTF-8");
|
||||
assertEquals(false, scd.isDirty());
|
||||
|
||||
sn2.save();
|
||||
contentData = (ContentData) NODE_SERVICE.getProperty(newNode2, ContentModel.PROP_CONTENT);
|
||||
assertNull(contentData);
|
||||
|
||||
scd.setContent("Marks to prove it.");
|
||||
assertEquals(true, scd.isDirty());
|
||||
|
||||
scd.setEncoding("ISO-8859-1");
|
||||
assertEquals(true, scd.isDirty());
|
||||
|
||||
sn2.save();
|
||||
contentData = (ContentData) NODE_SERVICE.getProperty(newNode2, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(contentData);
|
||||
|
||||
NODE_SERVICE.removeProperty(newNode1, ContentModel.PROP_CONTENT);
|
||||
NODE_SERVICE.removeProperty(newNode2, ContentModel.PROP_CONTENT);
|
||||
}
|
||||
|
||||
private ScriptableObject getScope()
|
||||
{
|
||||
// Create a scope for the value conversion. This scope will be an empty scope exposing basic Object and Function, sufficient for value-conversion.
|
||||
// In case no context is active for the current thread, we can safely enter end exit one to get hold of a scope
|
||||
ScriptableObject scope;
|
||||
Context ctx = Context.getCurrentContext();
|
||||
boolean closeContext = false;
|
||||
if (ctx == null)
|
||||
{
|
||||
ctx = Context.enter();
|
||||
closeContext = true;
|
||||
}
|
||||
scope = ctx.initStandardObjects();
|
||||
scope.setParentScope(null);
|
||||
|
||||
if (closeContext)
|
||||
{
|
||||
Context.exit();
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user