/*
* ====================================================================
* Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.wc.admin;
import java.util.Iterator;
import org.tmatesoft.svn.core.ISVNLogEntryHandler;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.wc.SVNAdminHelper;
import org.tmatesoft.svn.core.internal.wc.SVNCancellableEditor;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNSynchronizeEditor;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.ISVNReplayHandler;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.util.ISVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* <code>SVNReplayHandler</code> is an implementation of {@link ISVNReplayHandler} that is used in
* {@link SVNAdminClient#doSynchronize(org.tmatesoft.svn.core.SVNURL)}.
*
* @version 1.3
* @author TMate Software Ltd.
* @since 1.2
*/
public class SVNReplayHandler implements ISVNReplayHandler {
private SVNRepository myTargetRepository;
private boolean myHasCommitRevPropsCapability;
private ISVNLogEntryHandler myLogEntryHandler;
private ISVNDebugLog myDebugLog;
private ISVNEventHandler myCanceller;
private SVNSynchronizeEditor mySyncEditor;
private SVNAdminClient myAdminClient;
private int myNormalizedRevPropsCount;
/**
* Creates a new replay handler.
*
* @param targetRepository
* @param hasCommitRevPropsCapability
* @param logEntryHandler
* @param debugLog
* @param canceller
* @param adminClient
*/
public SVNReplayHandler(SVNRepository targetRepository, boolean hasCommitRevPropsCapability,
ISVNLogEntryHandler logEntryHandler, ISVNDebugLog debugLog, ISVNEventHandler canceller,
SVNAdminClient adminClient) {
myTargetRepository = targetRepository;
myHasCommitRevPropsCapability = hasCommitRevPropsCapability;
myLogEntryHandler = logEntryHandler;
myDebugLog = debugLog;
myCanceller = canceller;
myAdminClient = adminClient;
myNormalizedRevPropsCount = 0;
}
/**
* @param revision
* @param revisionProperties
* @return editor to replicate the revision
* @throws SVNException
*/
public ISVNEditor handleStartRevision(long revision, SVNProperties revisionProperties) throws SVNException {
myTargetRepository.setRevisionPropertyValue(0, SVNRevisionProperty.CURRENTLY_COPYING,
SVNPropertyValue.create(SVNProperty.toString(revision)));
SVNProperties filtered = new SVNProperties();
filterProperties(revisionProperties, filtered, true);
if (!filtered.containsName(SVNRevisionProperty.LOG)) {
filtered.put(SVNRevisionProperty.LOG, "");
}
SVNProperties normalizedProps = SVNAdminClient.normalizeRevisionProperties(filtered);
myNormalizedRevPropsCount += normalizedProps.size();
if (mySyncEditor == null) {
mySyncEditor = new SVNSynchronizeEditor(myTargetRepository, myLogEntryHandler, revision - 1, filtered);
} else {
mySyncEditor.reset(revision - 1, filtered);
}
ISVNEditor cancellableEditor = SVNCancellableEditor.newInstance(mySyncEditor, myCanceller, myDebugLog);
return cancellableEditor;
}
/**
* @param revision
* @param revisionProperties
* @param editor
* @throws SVNException
*/
public void handleEndRevision(long revision, SVNProperties revisionProperties, ISVNEditor editor) throws SVNException {
editor.closeEdit();
if (mySyncEditor.getCommitInfo().getNewRevision() != revision) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR,
"Commit created rev {0} but should have created {1}", new Object[] {
String.valueOf(mySyncEditor.getCommitInfo().getNewRevision()), String.valueOf(revision)
});
SVNErrorManager.error(err, SVNLogType.FSFS);
}
SVNProperties existingProperties = myTargetRepository.getRevisionProperties(revision, null);
SVNProperties filtered = new SVNProperties();
filterProperties(revisionProperties, filtered, false);
SVNProperties normalizedProps = SVNAdminClient.normalizeRevisionProperties(filtered);
myNormalizedRevPropsCount += normalizedProps.size();
int filteredCount = SVNAdminHelper.writeRevisionProperties(myTargetRepository, revision, filtered);
SVNAdminHelper.removePropertiesNotInSource(myTargetRepository, revision, revisionProperties,
existingProperties);
myTargetRepository.setRevisionPropertyValue(0, SVNRevisionProperty.LAST_MERGED_REVISION,
SVNPropertyValue.create(SVNProperty.toString(revision)));
myTargetRepository.setRevisionPropertyValue(0, SVNRevisionProperty.CURRENTLY_COPYING, null);
myAdminClient.handlePropertesCopied(filteredCount > 0, revision);
}
public int getNormalizedRevPropsCount() {
return myNormalizedRevPropsCount;
}
public int getNormalizedNodePropsCount() {
return mySyncEditor == null ? 0 : mySyncEditor.getNormalizedNodePropsCounter();
}
private int filterProperties(SVNProperties revProps, SVNProperties filteredProps, boolean isStart) {
int filteredCount = 0;
for (Iterator propNamesIter = revProps.nameSet().iterator(); propNamesIter.hasNext();) {
String propName = (String) propNamesIter.next();
SVNPropertyValue propValue = revProps.getSVNPropertyValue(propName);
boolean filter = false;
if (isStart) {
if (myHasCommitRevPropsCapability) {
filter = filterExcludeDateAuthorSync(propName);
} else {
filter = filterIncludeLog(propName);
}
} else {
if (myHasCommitRevPropsCapability) {
filter = filterIncludeDateAuthorSync(propName);
} else {
filter = filterExcludeLog(propName);
}
}
if (!filter) {
filteredProps.put(propName, propValue);
} else {
filteredCount += 1;
}
}
return filteredCount;
}
private boolean filterIncludeDateAuthorSync(String propName) {
return !filterExcludeDateAuthorSync(propName);
}
private boolean filterExcludeDateAuthorSync(String propName) {
return SVNRevisionProperty.AUTHOR.equals(propName) || SVNRevisionProperty.DATE.equals(propName) ||
propName.startsWith(SVNProperty.SVN_SYNC_PREFIX);
}
private boolean filterIncludeLog(String propName) {
return !filterExcludeLog(propName);
}
private boolean filterExcludeLog(String propName) {
return SVNRevisionProperty.LOG.equals(propName);
}
}