/*
* ====================================================================
* 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.internal.io.dav.handlers;
import java.util.Date;
import java.util.Map;
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.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.util.SVNDate;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
import org.xml.sax.Attributes;
/**
* @author TMate Software Ltd.
* @version 1.3
*/
public class DAVLogHandler extends BasicDAVHandler {
public static StringBuffer generateLogRequest(StringBuffer xmlBuffer, long startRevision, long endRevision,
boolean includeChangedPaths, boolean strictNodes, boolean includeMergedRevisions,
String[] revPropNames, long limit, String[] paths) {
xmlBuffer = xmlBuffer == null ? new StringBuffer() : xmlBuffer;
SVNXMLUtil.addXMLHeader(xmlBuffer);
SVNXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "log-report",
SVN_NAMESPACES_LIST, SVNXMLUtil.PREFIX_MAP, xmlBuffer);
if (startRevision >= 0) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "start-revision",
String.valueOf(startRevision), xmlBuffer);
}
if (endRevision >= 0) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "end-revision",
String.valueOf(endRevision), xmlBuffer);
}
if (limit > 0) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "limit", String.valueOf(limit), xmlBuffer);
}
if (includeChangedPaths) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "discover-changed-paths",
SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, xmlBuffer);
}
if (strictNodes) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "strict-node-history",
SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, xmlBuffer);
}
if (includeMergedRevisions) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "include-merged-revisions",
SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, xmlBuffer);
}
if (revPropNames != null) {
for (int i = 0; i < revPropNames.length; i++) {
String revPropName = revPropNames[i];
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "revprop", revPropName, xmlBuffer);
}
} else {
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "all-revprops",
SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, xmlBuffer);
}
for (int i = 0; i < paths.length; i++) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "path", paths[i], xmlBuffer);
}
SVNXMLUtil.addXMLFooter(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "log-report", xmlBuffer);
return xmlBuffer;
}
private static final DAVElement LOG_ITEM = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "log-item");
private static final DAVElement ADDED_PATH = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "added-path");
private static final DAVElement DELETED_PATH = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "deleted-path");
private static final DAVElement MODIFIED_PATH = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "modified-path");
private static final DAVElement REPLACED_PATH = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "replaced-path");
private static final DAVElement HAS_CHILDREN = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "has-children");
private static final DAVElement REVPROP = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "revprop");
private static final DAVElement SUBTRACTIVE_MERGE = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "subtractive-merge");
private ISVNLogEntryHandler myLogEntryHandler;
private long myRevision;
private Map myPaths;
private String myAuthor;
private Date myDate;
private String myComment;
private SVNLogEntryPath myPath;
private long myCount;
private long myLimit;
private int myNestLevel;
private boolean myIsCompatibleMode;
private boolean myHasChildren;
private boolean myIsWantAuthor;
private boolean myIsWantDate;
private boolean myIsWantComment;
private boolean myIsWantCustomRevProps;
private String myRevPropName;
private SVNProperties myRevProps;
private boolean myIsSubtractiveMerge;
public DAVLogHandler(ISVNLogEntryHandler handler, long limit, String[] revPropNames) {
myLogEntryHandler = handler;
myRevision = -1;
myCount = 0;
myLimit = limit;
if (revPropNames != null && revPropNames.length > 0) {
for (int i = 0; i < revPropNames.length; i++) {
String revPropName = revPropNames[i];
if (SVNRevisionProperty.AUTHOR.equals(revPropName)) {
myIsWantAuthor = true;
} else if (SVNRevisionProperty.LOG.equals(revPropName)) {
myIsWantComment = true;
} else if (SVNRevisionProperty.DATE.equals(revPropName)) {
myIsWantDate = true;
} else {
myIsWantCustomRevProps = true;
}
}
} else {
myIsWantAuthor = myIsWantComment = myIsWantDate = true;
}
init();
}
public boolean isWantCustomRevprops() {
return myIsWantCustomRevProps;
}
public boolean isCompatibleMode() {
return myIsCompatibleMode;
}
protected void startElement(DAVElement parent, DAVElement element, Attributes attrs) throws SVNException {
char type = 0;
String copyPath = null;
long copyRevision = -1;
if (element == REVPROP) {
myRevPropName = attrs.getValue("name");
if (myRevPropName == null) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_DAV_MALFORMED_DATA,
"Missing name attr in revprop element");
SVNErrorManager.error(err, SVNLogType.NETWORK);
}
} else if (element == HAS_CHILDREN) {
myHasChildren = true;
} else if (element == SUBTRACTIVE_MERGE) {
myIsSubtractiveMerge = true;
}
if (element == ADDED_PATH || element == REPLACED_PATH) {
type = element == ADDED_PATH ? SVNLogEntryPath.TYPE_ADDED : SVNLogEntryPath.TYPE_REPLACED;
copyPath = attrs.getValue("copyfrom-path");
String copyRevisionStr = attrs.getValue("copyfrom-rev");
if (copyPath != null && copyRevisionStr != null) {
try {
copyRevision = Long.parseLong(copyRevisionStr);
} catch (NumberFormatException e) {
}
}
} else if (element == MODIFIED_PATH) {
type = SVNLogEntryPath.TYPE_MODIFIED;
} else if (element == DELETED_PATH) {
type = SVNLogEntryPath.TYPE_DELETED;
}
if (type != 0) {
SVNNodeKind nodeKind = SVNNodeKind.UNKNOWN;
String nodeKindStr = attrs.getValue("node-kind");
if (nodeKindStr != null) {
nodeKind = SVNNodeKind.parseKind(nodeKindStr);
}
myPath = new SVNLogEntryPath(null, type, copyPath, copyRevision, nodeKind);
}
}
protected void endElement(DAVElement parent, DAVElement element, StringBuffer cdata) throws SVNException {
if (element == LOG_ITEM) {
if (myNestLevel == 0) {
myCount++;
}
if (myLimit > 0 && myCount > myLimit && myNestLevel == 0) {
myIsCompatibleMode = true;
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN);
SVNErrorManager.error(err, SVNLogType.NETWORK);
}
if (myLogEntryHandler != null) {
if (myPaths == null) {
myPaths = new SVNHashMap();
}
if (myRevProps == null) {
myRevProps = new SVNProperties();
}
if (myAuthor != null) {
myRevProps.put(SVNRevisionProperty.AUTHOR, myAuthor);
}
if (myComment != null) {
myRevProps.put(SVNRevisionProperty.LOG, myComment);
}
if (myDate != null) {
myRevProps.put(SVNRevisionProperty.DATE, SVNDate.formatDate(myDate));
}
SVNLogEntry logEntry = new SVNLogEntry(myPaths, myRevision, myRevProps, myHasChildren);
logEntry.setSubtractiveMerge(myIsSubtractiveMerge);
myLogEntryHandler.handleLogEntry(logEntry);
if (logEntry.hasChildren()) {
myNestLevel++;
}
if (logEntry.getRevision() < 0) {
myNestLevel = myNestLevel <= 0 ? 0 : myNestLevel -1;
}
}
myPaths = null;
myRevProps = null;
myRevision = -1;
myAuthor = null;
myDate = null;
myComment = null;
myRevPropName = null;
myHasChildren = false;
myIsSubtractiveMerge = false;
} else if (element == DAVElement.VERSION_NAME && cdata != null) {
try {
myRevision = Long.parseLong(cdata.toString());
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_MALFORMED_DATA, nfe), SVNLogType.NETWORK);
}
} else if (element == REVPROP) {
if (myRevProps == null) {
myRevProps = new SVNProperties();
}
if (myRevPropName != null && cdata != null) {
myRevProps.put(myRevPropName, cdata.toString());
}
} else if (element == DAVElement.CREATOR_DISPLAY_NAME && cdata != null) {
if (myIsWantAuthor) {
myAuthor = cdata.toString();
}
} else if (element == DAVElement.COMMENT && cdata != null) {
if (myIsWantComment) {
myComment = cdata.toString();
}
} else if (element == DAVElement.DATE && cdata != null) {
if (myIsWantDate) {
myDate = SVNDate.parseDate(cdata.toString());
}
} else if (element == ADDED_PATH || element == MODIFIED_PATH || element == REPLACED_PATH || element == DELETED_PATH) {
if (myPath != null && cdata != null) {
if (myPaths == null) {
myPaths = new SVNHashMap();
}
myPath.setPath(cdata.toString());
String path = myPath.getPath();
myPath.setPath(path);
myPaths.put(myPath.getPath(), myPath);
}
myPath = null;
}
}
public long getEntriesCount() {
return myCount;
}
}