Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)

92231: Merged 5.0.N (5.0.1) to HEAD-BUG-FIX (5.1/Cloud)
      91995: MNT-12925: Merged V4.2-BUG-FIX (4.2.5) to 5.0.N (5.0.1)
         91709 : MNT-12896: Merged V4.2.1 (4.2.1.17) to V4.2-BUG-FIX (4.2.5)
            89881: Merged DEV to PATCHES/V4.2.1 (4.2.1.16)
               89858 : MNT-12584 : Files are multiplying themselves when do a move out and move in
                  - UIDPLUS extension implemented : UID EXPUNGE command and APPENDUID and COPYUID response codes
               88997,89016 : MNT-12584 : Files are multiplying themselves when do a move out and move in
                  - UID SEARCH HEADER Message-Id implemented
               88824 : MNT-12585 : All files disappear from a folder if one file is moved out + one file is deleted
                  - greenmail-1.3-patched.jar was patched again to implement DELETED flag search.
                  - Updated source files and diff file for greenmail-1.3-patched.jar library.
               88774 : MNT-12546: Deleting a file in Share may not be reflected in IMAP Outlook 2011, then sync may create EML attachments in Share
                  - Removed force change of UID validity as it is not required.
               88585 : MNT-12518 : Outlook 2013: moving files to a folder and back to original leads to view discrepancies
                  - Test changed according to new delete/append behavior
               88360 : Merged DEV to DEV (V4.2.1-IMAP)
                  88280: MNT-12575: IMAP Needs to RETRY
                     - Incremented MAX-RETRIS parameter up to 20, wrapped Timer to RetryingTransactionHelper.
               88294,88343,88345 : MNT-12546: Deleting a file in Share may not be reflected in IMAP Outlook 2011, then sync may create EML attachments in Share
                  - Fixed IMAP caching of deleted files via Share.
               88291 : MNT-12518 : Outlook 2013: moving files to a folder and back to original leads to view discrepancies
                  - Implement Outlook 2013 move shuffle as copy
            90106: Merged DEV to PATCHES/V4.2.1 (4.2.1.16)
               89996 : MNT-12584 : Files are multiplying themselves when do a move out and move in
                  - Green mail source files have been updated
            90109: Merged DEV to PATCHES/V4.2.1 (4.2.1.16)
               90105 : MNT-12518 : Outlook 2013: moving files to a folder and back to original leads to view discrepancies
                  - Do not use APPENDUID response code to avoid usage of cached messages in Outlook 2013
            90307: Merged DEV to PATCHES/V4.2.1 (4.2.1.16)
               90268,90271 : MNT-12585 : All files disappear from a folder if one file is moved out + one file is deleted
                  - Squeeze UIDVALIDITY. Implement untagged EXPUNGE response
            91371: MNT-12856 : User cannot see document in repository if content was not checked by admin from IMAP
               - AccessDeniedException should not break IMAP response
            91708: MNT-12585 : All files disappear from a folder if one file is moved out + one file is deleted
               - Change reference to greenmail in the pom file.
                 Should have been when the jar changed, however this is not used in the build used to create the artefacts.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@94859 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2015-01-31 11:45:08 +00:00
parent 93ad20b14e
commit 63d0306f84
10 changed files with 258 additions and 62 deletions

View File

@@ -197,6 +197,16 @@
</associations>
</aspect>
<aspect name="imap:messageHeaders">
<title>IMAP Message Headers</title>
<properties>
<property name="imap:messageHeaders">
<title>Message Headers</title>
<type>d:text</type>
<multiple>true</multiple>
</property>
</properties>
</aspect>
</aspects>
</model>

View File

@@ -184,6 +184,11 @@
<property name="imapServerEnabled">
<value>${imap.server.enabled}</value>
</property>
<property name="messageHeadersToPersist">
<list>
<value>Message-Id</value>
</list>
</property>
</bean>
<!-- Public Imap Service -->

View File

@@ -38,7 +38,7 @@
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
<version>1.3-alfresco-20130711</version>
<version>1.3-alfresco-20141112</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>

View File

@@ -66,4 +66,9 @@ public interface ImapModel
static final QName ASPECT_IMAP_PREFERENCES = QName.createQName(IMAP_MODEL_1_0_URI, "imapPreferences");
static final QName ASSOC_IMAP_UNSUBSCRIBED = QName.createQName(IMAP_MODEL_1_0_URI, "imapUnsubscribed");
static final QName ASPECT_IMAP_MESSAGE_HEADERS = QName.createQName(IMAP_MODEL_1_0_URI, "messageHeaders");
static final QName PROP_MESSAGE_HEADERS = QName.createQName(IMAP_MODEL_1_0_URI, "messageHeaders");
static final String MESSAGE_HEADER_TO_PERSIST_SPLITTER = ":";
}

View File

@@ -49,7 +49,7 @@ public abstract class AbstractImapFolder implements MailFolder
private List<FolderListener> listeners = new LinkedList<FolderListener>();
protected ServiceRegistry serviceRegistry;
protected static int MAX_RETRIES = 1;
protected static int MAX_RETRIES = 20;
public AbstractImapFolder(ServiceRegistry serviceRegistry)
@@ -103,7 +103,7 @@ public abstract class AbstractImapFolder implements MailFolder
* @param uid - UID of the message
* @param toFolder - reference to the destination folder.
*/
public void copyMessage(final long uid, final MailFolder toFolder) throws FolderException
public long copyMessage(final long uid, final MailFolder toFolder) throws FolderException
{
AbstractImapFolder toImapMailFolder = (AbstractImapFolder) toFolder;
@@ -112,15 +112,14 @@ public abstract class AbstractImapFolder implements MailFolder
throw new FolderException(AlfrescoImapFolderException.PERMISSION_DENIED);
}
CommandCallback<Object> command = new CommandCallback<Object>()
CommandCallback<Long> command = new CommandCallback<Long>()
{
public Object command() throws Throwable
public Long command() throws Throwable
{
copyMessageInternal(uid, toFolder);
return null;
return copyMessageInternal(uid, toFolder);
}
};
command.runFeedback();
return command.runFeedback();
}
/**
@@ -161,6 +160,25 @@ public abstract class AbstractImapFolder implements MailFolder
command.runFeedback();
}
/**
* Deletes messages marked with {@link Flags.Flag#DELETED}. Note that this message deletes the messages with current uid
*/
public void expunge(final long uid) throws FolderException
{
if (isReadOnly())
{
throw new FolderException("Can't expunge - Permission denied");
}
CommandCallback<Object> command = new CommandCallback<Object>()
{
public Object command() throws Throwable
{
expungeInternal(uid);
return null;
}
};
command.runFeedback();
}
/**
* Returns message by its UID.
@@ -258,14 +276,21 @@ public abstract class AbstractImapFolder implements MailFolder
/**
* Simply returns UIDs of all messages in the folder.
* Searches the mailbox for messages that match the given searching criteria
*
* @param searchTerm - not used
* @param searchTerm - search term that contains search criteria.
* @return UIDs of the messages
*/
public long[] search(SearchTerm searchTerm)
public long[] search(final SearchTerm searchTerm)
{
return getMessageUids();
CommandCallback<long[]> command = new CommandCallback<long[]>()
{
public long[] command() throws Throwable
{
return searchInternal(searchTerm);
}
};
return command.run();
}
/**
@@ -377,12 +402,14 @@ public abstract class AbstractImapFolder implements MailFolder
protected abstract long appendMessageInternal(MimeMessage message, Flags flags, Date internalDate) throws Exception;
protected abstract void copyMessageInternal(long uid, MailFolder toFolder) throws Exception;
protected abstract long copyMessageInternal(long uid, MailFolder toFolder) throws Exception;
protected abstract void deleteAllMessagesInternal() throws Exception;
protected abstract void expungeInternal() throws Exception;
protected abstract void expungeInternal(long uid) throws Exception;
protected abstract SimpleStoredMessage getMessageInternal(long uid) throws Exception;
protected abstract List<SimpleStoredMessage> getMessagesInternal();
@@ -393,6 +420,8 @@ public abstract class AbstractImapFolder implements MailFolder
protected abstract void replaceFlagsInternal(Flags flags, long uid, FolderListener silentListener, boolean addUid) throws Exception;
protected abstract long[] searchInternal(SearchTerm searchTerm);
protected abstract void setFlagsInternal(Flags flags, boolean value, long uid, FolderListener silentListener, boolean addUid) throws Exception;
protected abstract class CommandCallback<T>

View File

@@ -23,6 +23,7 @@ import static org.alfresco.repo.imap.AlfrescoImapConst.X_ALF_NODEREF_ID;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -31,6 +32,7 @@ import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import org.alfresco.model.ImapModel;
import org.alfresco.repo.imap.ImapService.EmailBodyFormat;
import org.alfresco.repo.template.TemplateNode;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
@@ -38,6 +40,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -119,6 +122,31 @@ public abstract class AbstractMimeMessage extends MimeMessage
// Optional headers for further implementation of multiple Alfresco server support.
setHeader(X_ALF_NODEREF_ID, messageFileInfo.getNodeRef().getId());
// setHeader(X_ALF_SERVER_UID, imapService.getAlfrescoServerUID());
setPersistedHeaders();
}
private void setPersistedHeaders() throws MessagingException
{
NodeService nodeService = serviceRegistry.getNodeService();
if (nodeService.hasAspect(messageFileInfo.getNodeRef(), ImapModel.ASPECT_IMAP_MESSAGE_HEADERS))
{
@SuppressWarnings("unchecked")
List<String> messageHeaders = (List<String>)nodeService.getProperty(messageFileInfo.getNodeRef(), ImapModel.PROP_MESSAGE_HEADERS);
if (messageHeaders == null)
{
return;
}
for (String header : messageHeaders)
{
String headerValue = header.substring(header.indexOf(ImapModel.MESSAGE_HEADER_TO_PERSIST_SPLITTER) + 1);
String headerName = header.substring(0, header.indexOf(ImapModel.MESSAGE_HEADER_TO_PERSIST_SPLITTER));
setHeader(headerName, headerValue);
}
}
}

View File

@@ -21,6 +21,7 @@ package org.alfresco.repo.imap;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -33,21 +34,23 @@ import javax.mail.Flags;
import javax.mail.Flags.Flag;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.search.SearchTerm;
import org.alfresco.model.ContentModel;
import org.alfresco.model.ImapModel;
import org.alfresco.repo.imap.AlfrescoImapConst.ImapViewMode;
import org.alfresco.repo.imap.ImapService.FolderStatus;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
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.security.AccessStatus;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.FileFilterMode;
import org.alfresco.util.GUID;
import org.alfresco.util.Utf7;
@@ -284,8 +287,6 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
}
protected FolderStatus getFolderStatus()
{
if (this.folderStatus == null)
{
CommandCallback<FolderStatus> command = new CommandCallback<FolderStatus>()
{
@@ -294,9 +295,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
return imapService.getFolderStatus(userName, folderInfo.getNodeRef(), viewMode);
}
};
this.folderStatus = command.run();
}
return this.folderStatus;
return this.folderStatus = command.run();
}
/**
@@ -315,13 +314,9 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
{
long uid;
NodeRef sourceNodeRef = extractNodeRef(message);
if (isMoveOperation(sourceNodeRef))
if (sourceNodeRef != null)
{
uid = copyOrmoveNode(this.folderInfo, message, flags, sourceNodeRef, true);
}
else if (sourceNodeRef != null)
{
uid = copyOrmoveNode(this.folderInfo, message, flags, sourceNodeRef, false);
uid = copyOrMoveNode(this.folderInfo, message, flags, sourceNodeRef, false);
}
else
{
@@ -345,24 +340,33 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
* @throws FileNotFoundException
*/
@SuppressWarnings("deprecation")
private long copyOrmoveNode(FileInfo folderInfo, MimeMessage message, Flags flags, NodeRef sourceNodeRef, boolean move)
private long copyOrMoveNode(FileInfo folderInfo, MimeMessage message, Flags flags, NodeRef sourceNodeRef, boolean move)
throws FileExistsException, FileNotFoundException
{
FileFolderService fileFolderService = serviceRegistry.getFileFolderService();
FileFilterMode.setClient(FileFilterMode.Client.imap);
fileFolderService.setHidden(sourceNodeRef, false);
FileInfo messageFile = null;
if (move)
{
fileFolderService.setHidden(sourceNodeRef, false);
messageFile = fileFolderService.move(sourceNodeRef, folderInfo.getNodeRef(), null);
}
else
{
messageFile = fileFolderService.copy(sourceNodeRef, folderInfo.getNodeRef(), null);
NodeRef newNodeRef = serviceRegistry.getCopyService().copyAndRename(sourceNodeRef, folderInfo.getNodeRef(), ContentModel.ASSOC_CONTAINS, null, false);
fileFolderService.setHidden(newNodeRef, false);
messageFile = fileFolderService.getFileInfo(newNodeRef);
}
final long newMessageUid = (Long) messageFile.getProperties().get(ContentModel.PROP_NODE_DBID);
imapService.setFlag(messageFile, Flag.RECENT, true);
imapService.persistMessageHeaders(messageFile.getNodeRef(), message);
Flags newFlags = new Flags(flags);
newFlags.add(Flag.RECENT);
imapService.setFlags(messageFile, newFlags, true);
imapService.setFlag(messageFile, Flag.DELETED, false);
return newMessageUid;
}
@@ -472,7 +476,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
* @throws FileExistsException
*/
@Override
protected void copyMessageInternal(
protected long copyMessageInternal(
long uid, MailFolder toFolder)
throws MessagingException, FileExistsException, FileNotFoundException, IOException
{
@@ -486,13 +490,14 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
{
//Generate body of message
MimeMessage newMessage = new ImapModelMessage(sourceMessageFileInfo, serviceRegistry, true);
toImapMailFolder.appendMessageInternal(newMessage, imapService.getFlags(sourceMessageFileInfo), new Date());
return toImapMailFolder.appendMessageInternal(newMessage, imapService.getFlags(sourceMessageFileInfo), new Date());
}
else
{
String fileName = (String) serviceRegistry.getNodeService().getProperty(sourceMessageFileInfo.getNodeRef(), ContentModel.PROP_NAME);
String newFileName = imapService.generateUniqueFilename(destFolderNodeRef, fileName);
serviceRegistry.getFileFolderService().copy(sourceMessageFileInfo.getNodeRef(), destFolderNodeRef, newFileName);
FileInfo messageFileInfo = serviceRegistry.getFileFolderService().copy(sourceMessageFileInfo.getNodeRef(), destFolderNodeRef, newFileName);
return (Long)messageFileInfo.getProperties().get(ContentModel.PROP_NODE_DBID);
}
}
@@ -532,6 +537,22 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
}
}
/**
* Deletes messages marked with {@link Flags.Flag#DELETED}. Note that this message deletes the message with current uid
*/
@Override
protected void expungeInternal(long uid) throws Exception
{
if (isReadOnly())
{
throw new FolderException("Can't expunge - Permission denied");
}
FileInfo messageFileInfo = searchMails().get(uid);
imapService.expungeMessage(messageFileInfo);
}
/**
* Returns the MSN number of the first unseen message.
*
@@ -630,7 +651,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
{
try
{
result.add(imapService.createImapMessage(fileInfo, false));
result.add(imapService.createImapMessage(fileInfo, true));
if (logger.isDebugEnabled())
{
logger.debug("[convertToMessages] Message added: " + fileInfo.getName());
@@ -744,8 +765,18 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
return null;
}
};
try
{
command.run();
}
catch (AccessDeniedException ade)
{
if (logger.isDebugEnabled())
{
logger.debug("Access denied to reset RECENT FLAG");
}
}
}
return recent;
}
@@ -769,7 +800,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
@Override
public long getUidValidity()
{
return getFolderStatus().uidValidity + mountPointId;
return getFolderStatus().uidValidity / 1000L + mountPointId;
}
/**
@@ -812,6 +843,24 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
notifyFlagUpdate(msn, flags, uidNotification, silentListener);
}
@Override
protected long[] searchInternal(SearchTerm searchTerm)
{
List<SimpleStoredMessage> messages = getMessages();
long[] result = new long[messages.size()];
int i = 0;
for (SimpleStoredMessage message : messages)
{
if (searchTerm.match(message.getMimeMessage()))
{
result[i] = message.getUid();
i++;
}
}
return Arrays.copyOfRange(result, 0, i);
}
/**
* Sets flags for the message with the given UID. If {@code addUid} is set to {@code true}
* {@link FolderListener} objects defined for this folder will be notified.

View File

@@ -311,6 +311,8 @@ public interface ImapService
public String generateUniqueFilename(NodeRef destFolderNodeRef, String fileName);
public void persistMessageHeaders(NodeRef nodeRef, MimeMessage message);
static class FolderStatus
{
public final int messageCount;

View File

@@ -22,10 +22,12 @@ import static org.alfresco.repo.imap.AlfrescoImapConst.DICTIONARY_TEMPLATE_PREFI
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -40,6 +42,7 @@ import java.util.TreeMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.mail.Flags;
import javax.mail.Header;
import javax.mail.Flags.Flag;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
@@ -166,6 +169,8 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
private boolean imapServerEnabled = false;
private List<String> messageHeadersToPersist = Collections.<String>emptyList();
static
{
qNameToFlag = new HashMap<QName, Flags.Flag>();
@@ -343,6 +348,11 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
this.imapServerEnabled = enabled;
}
public void setMessageHeadersToPersist(List<String> headers)
{
this.messageHeadersToPersist = headers;
}
public boolean getImapServerEnabled()
{
return this.imapServerEnabled;
@@ -573,6 +583,11 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
{
@Override
public Void doWork() throws Exception
{
return serviceRegistry.getTransactionService().getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
// Ignore if it is NOT hidden: the shuffle may have finished; the operation may have failed
if (!nodeService.exists(nodeRef) || !fileFolderService.isHidden(nodeRef))
@@ -589,8 +604,11 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
// This is the transaction-aware service
fileFolderService.delete(nodeRef);
return null;
}
});
}
};
try
{
@@ -2030,6 +2048,50 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
return fileName;
}
@SuppressWarnings("unchecked")
public void persistMessageHeaders(NodeRef messageRef, MimeMessage message)
{
try
{
Enumeration<Header> headers = message.getAllHeaders();
List<String> messaheHeadersProperties = new ArrayList<String>();
while(headers.hasMoreElements())
{
Header header = headers.nextElement();
if (isPersistableHeader(header))
{
messaheHeadersProperties.add(header.getName() + ImapModel.MESSAGE_HEADER_TO_PERSIST_SPLITTER + header.getValue());
if (logger.isDebugEnabled())
{
logger.debug("[persistHeaders] Persisting Header " + header.getName() + " : " + header.getValue());
}
}
}
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
props.put(ImapModel.PROP_MESSAGE_HEADERS, (Serializable)messaheHeadersProperties);
serviceRegistry.getNodeService().addAspect(messageRef, ImapModel.ASPECT_IMAP_MESSAGE_HEADERS, props);
}
catch(MessagingException me)
{
}
}
private boolean isPersistableHeader(Header header)
{
for (String headerToPersist : messageHeadersToPersist)
{
if (headerToPersist.equalsIgnoreCase(header.getName()))
{
return true;
}
}
return false;
}
static class CacheItem
{
private Date modified;

View File

@@ -54,6 +54,7 @@ import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -912,13 +913,18 @@ public class ImapServiceImplTest extends TestCase
AlfrescoImapFolder destinationMailbox = imapService.getOrCreateMailbox(poweredUser, destinationPath, true, false);
destinationMailbox.appendMessage(origMessage.getMimeMessage(), flags, null);
// Check the destination has the original file and only this file
FileInfo movedNode = fileFolderService.getFileInfo(origFile.getNodeRef());
assertNotNull("The file should exist.", movedNode);
assertEquals("The file name should not change.", fileName, movedNode.getName());
NodeRef newParentNodeRef = nodeService.getPrimaryParent(origFile.getNodeRef()).getParentRef();
assertEquals("The parent should change to destination.", destinationNode.getNodeRef(), newParentNodeRef);
// original message should be deleted or about to
assertTrue(!nodeService.exists(origFile.getNodeRef()) || imapService.getFlags(origFile).contains(Flags.Flag.DELETED));
// new file should be in destination
assertEquals("There should be only one node in the destination folder", 1, nodeService.getChildAssocs(destinationNode.getNodeRef()).size());
NodeRef newNodeRef = nodeService.getChildAssocs(destinationNode.getNodeRef()).get(0).getChildRef();
FileInfo newNodeFileInfo = fileFolderService.getFileInfo(newNodeRef);
assertEquals("The file name should not change.", fileName, newNodeFileInfo.getName());
ContentReader reader = contentService.getReader(newNodeRef, ContentModel.PROP_CONTENT);
String contentString = reader.getContentString();
// new file content should be the same as original one
assertEquals(contentString, nodeContent);
}
/**