Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2)

121563 jkaabimofrad: RA-640: Fixed encoding issue when updating binary content, as well as, multipart uploading.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@126412 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jamal Kaabi-Mofrad
2016-05-10 10:49:57 +00:00
parent 9bcca7763d
commit ca1de05fe7
4 changed files with 155 additions and 71 deletions

View File

@@ -105,6 +105,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.Content;
import org.springframework.extensions.webscripts.servlet.FormData;
import org.springframework.http.InvalidMediaTypeException;
import org.springframework.http.MediaType;
/**
* Centralises access to file/folder/node services and maps between representations.
@@ -712,7 +714,7 @@ public class NodesImpl implements Nodes
protected Set<QName> mapToNodeAspects(List<String> aspectNames)
{
Set<QName> nodeAspects = new HashSet<>(aspectNames.size());
Set<QName> nodeAspects = new HashSet<>(aspectNames.size());
for (String aspectName : aspectNames)
{
@@ -725,7 +727,7 @@ public class NodesImpl implements Nodes
}
else
{
throw new InvalidArgumentException("Unknown aspect: "+aspectName);
throw new InvalidArgumentException("Unknown aspect: " + aspectName);
}
}
@@ -738,7 +740,7 @@ public class NodesImpl implements Nodes
for (Entry<String, Object> entry : props.entrySet())
{
String propName = entry.getKey();
String propName = entry.getKey();
QName propQName = createQName(propName);
PropertyDefinition pd = dictionaryService.getProperty(propQName);
@@ -765,7 +767,7 @@ public class NodesImpl implements Nodes
}
else
{
throw new InvalidArgumentException("Unknown property: "+propName);
throw new InvalidArgumentException("Unknown property: " + propName);
}
}
@@ -986,7 +988,7 @@ public class NodesImpl implements Nodes
if (aspectNames != null)
{
// node aspects - set any additional aspects
Set<QName> aspectQNames = mapToNodeAspects(aspectNames);
Set<QName> aspectQNames = mapToNodeAspects(aspectNames);
for (QName aspectQName : aspectQNames)
{
if (EXCLUDED_ASPECTS.contains(aspectQName) || aspectQName.equals(ContentModel.ASPECT_AUDITABLE))
@@ -1002,17 +1004,7 @@ public class NodesImpl implements Nodes
{
// add empty file
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
String mimeType;
ContentInfo contentInfo = nodeInfo.getContent();
if (contentInfo != null && contentInfo.getMimeType() != null)
{
mimeType = contentInfo.getMimeType();
}
else
{
mimeType = mimetypeService.guessMimetype(nodeName);
}
writer.setMimetype(mimeType);
setWriterContentType(writer, new ContentInfoWrapper(nodeInfo.getContent()), nodeRef, false);
writer.putContent("");
}
@@ -1102,7 +1094,7 @@ public class NodesImpl implements Nodes
if (aspectNames != null)
{
// update aspects - note: can be empty (eg. to remove existing aspects+properties) but not cm:auditable, sys:referencable, sys:localized
Set<QName> aspectQNames = mapToNodeAspects(aspectNames);
Set<QName> existingAspects = nodeService.getAspects(nodeRef);
@@ -1295,18 +1287,7 @@ public class NodesImpl implements Nodes
}
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
String mimeType = contentInfo.getMimeType();
if (mimeType == null)
{
String fileName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
writer.guessMimetype(fileName);
}
else
{
writer.setMimetype(mimeType);
}
writer.guessEncoding();
setWriterContentType(writer, new ContentInfoWrapper(contentInfo), nodeRef, true);
writer.putContent(stream);
return getFolderOrDocumentFullInfo(nodeRef,
@@ -1315,6 +1296,33 @@ public class NodesImpl implements Nodes
parameters);
}
private void setWriterContentType(ContentWriter writer, ContentInfoWrapper contentInfo, NodeRef nodeRef, boolean guessEncodingIfNull)
{
String mimeType = contentInfo.mimeType;
// Manage MimeType
if (mimeType == null)
{
// the mimeType was not provided via the contentInfo, so try to guess
final String fileName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
mimeType = mimetypeService.guessMimetype(fileName);
}
writer.setMimetype(mimeType);
// Manage Encoding
if (contentInfo.encoding == null)
{
if (guessEncodingIfNull)
{
// the encoding was not provided, so try to guess
writer.guessEncoding();
}
}
else
{
writer.setEncoding(contentInfo.encoding);
}
}
@Override
public Node upload(String parentFolderNodeId, FormData formData, Parameters parameters)
{
@@ -1416,7 +1424,7 @@ public class NodesImpl implements Nodes
// else if (overwrite && nodeService.hasAspect(existingFile, ContentModel.ASPECT_VERSIONABLE))
// {
// // Upload component was configured to overwrite files if name clashes
// write(existingFile, content, fileName, false, true);
// write(existingFile, content);
//
// // Extract the metadata (The overwrite policy controls
// // which if any parts of the document's properties are updated from this)
@@ -1480,7 +1488,7 @@ public class NodesImpl implements Nodes
NodeRef newFile = createNodeImpl(parentNodeRef, fileName, nodeType, props);
// Write content
write(newFile, content, fileName, true, true);
write(newFile, content);
// Ensure the file is versionable (autoVersion = true, autoVersionProps = false)
ensureVersioningEnabled(newFile, true, false);
@@ -1506,40 +1514,13 @@ public class NodesImpl implements Nodes
*
* @param nodeRef the reference to the node having a content property
* @param content the content
* @param fileName the uploaded file name
* @param applyMimeType If true, apply the mimeType from the Content object,
* else leave the original mimeType (if the original type is null, then guess the mimeType)
* @param guessEncoding If true, guess the encoding from the underlying
* input stream, else use encoding set in the Content object as supplied
*/
protected void write(NodeRef nodeRef, Content content, String fileName, boolean applyMimeType, boolean guessEncoding)
protected void write(NodeRef nodeRef, Content content)
{
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
String mimeType = content.getMimetype();
// Per RA-637 requirement the mimeType provided by the client takes precedence, however,
// if the mimeType is null, then it will be retrieved or guessed.
if (mimeType == null || !applyMimeType)
{
ContentData existingContentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
if (existingContentData != null)
{
mimeType = existingContentData.getMimetype();
}
else
{
mimeType = mimetypeService.guessMimetype(fileName);
}
}
writer.setMimetype(mimeType);
if (guessEncoding)
{
writer.guessEncoding();
}
else
{
writer.setEncoding(content.getEncoding());
}
// if the mimeType is null, then it will be guessed.
setWriterContentType(writer, new ContentInfoWrapper(content), nodeRef, true);
writer.putContent(content.getInputStream());
}
@@ -1675,4 +1656,52 @@ public class NodesImpl implements Nodes
return result;
}
/**
* @author Jamal Kaabi-Mofrad
*/
private static class ContentInfoWrapper
{
private String mimeType;
private String encoding;
ContentInfoWrapper(BasicContentInfo basicContentInfo)
{
if (basicContentInfo != null)
{
this.mimeType = basicContentInfo.getMimeType();
this.encoding = basicContentInfo.getEncoding();
}
}
ContentInfoWrapper(ContentInfo contentInfo)
{
if (contentInfo != null)
{
this.mimeType = contentInfo.getMimeType();
this.encoding = contentInfo.getEncoding();
}
}
ContentInfoWrapper(Content content)
{
if (content != null && StringUtils.isNotEmpty(content.getMimetype()))
{
try
{
// TODO I think it makes sense to push contentType parsing into org.springframework.extensions.webscripts.servlet.FormData
MediaType media = MediaType.parseMediaType(content.getMimetype());
this.mimeType = media.getType() + '/' + media.getSubtype();
if (media.getCharSet() != null)
{
this.encoding = media.getCharSet().name();
}
}
catch (InvalidMediaTypeException ime)
{
throw new InvalidArgumentException(ime.getMessage());
}
}
}
}
}