001: /*
002: * ====================================================================
003: * Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
004: *
005: * This software is licensed as described in the file COPYING, which
006: * you should have received as part of this distribution. The terms
007: * are also available at http://svnkit.com/license.html
008: * If newer versions of this license are posted there, you may use a
009: * newer version instead, at your option.
010: * ====================================================================
011: */
012: package org.tmatesoft.svn.core.wc.xml;
013:
014: import java.io.File;
015:
016: import org.tmatesoft.svn.core.SVNErrorCode;
017: import org.tmatesoft.svn.core.SVNErrorMessage;
018: import org.tmatesoft.svn.core.SVNException;
019: import org.tmatesoft.svn.core.internal.util.SVNTimeUtil;
020: import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
021: import org.tmatesoft.svn.core.wc.ISVNStatusHandler;
022: import org.tmatesoft.svn.core.wc.SVNStatus;
023: import org.tmatesoft.svn.core.wc.SVNStatusType;
024: import org.tmatesoft.svn.util.ISVNDebugLog;
025: import org.xml.sax.ContentHandler;
026: import org.xml.sax.SAXException;
027:
028: /**
029: * This is an implementation of the <b>ISVNStatusHandler</b> interface
030: * that writes XML formatted status information to a specified
031: * <b>ContentHandler</b>.
032: *
033: * @version 1.1.1
034: * @author TMate Software Ltd.
035: */
036: public class SVNXMLStatusHandler extends AbstractXMLHandler implements
037: ISVNStatusHandler {
038:
039: private static final String AGAINST_TAG = "against";
040: private static final String TARGET_TAG = "target";
041: public static final String EXPIRES_TAG = "expires";
042: public static final String CREATED_TAG = "created";
043: public static final String COMMENT_TAG = "comment";
044: public static final String OWNER_TAG = "owner";
045: public static final String TOKEN_TAG = "token";
046: public static final String DATE_TAG = "date";
047: public static final String AUTHOR_TAG = "author";
048: public static final String REVISION_ATTR = "revision";
049: public static final String SWITCHED_ATTR = "switched";
050: public static final String COPIED_ATTR = "copied";
051: public static final String WC_LOCKED_ATTR = "wc-locked";
052: public static final String PROPS_ATTR = "props";
053: public static final String ITEM_ATTR = "item";
054: public static final String PATH_ATTR = "path";
055: public static final String REMOTE_STATUS_TAG = "repos-status";
056: public static final String LOCK_TAG = "lock";
057: public static final String COMMIT_TAG = "commit";
058: public static final String WC_STATUS_TAG = "wc-status";
059: public static final String ENTRY_TAG = "entry";
060: public static final String STATUS_TAG = "status";
061:
062: private static final String TRUE = "true";
063:
064: private File myTargetPath;
065:
066: /**
067: * Creates a new status handler.
068: *
069: * @param saxHandler a <b>ContentHandler</b> to form
070: * an XML tree
071: */
072: public SVNXMLStatusHandler(ContentHandler saxHandler) {
073: this (saxHandler, null);
074: }
075:
076: /**
077: * Creates a new status handler.
078: *
079: * @param saxHandler a <b>ContentHandler</b> to form
080: * an XML tree
081: * @param log a debug logger
082: */
083: public SVNXMLStatusHandler(ContentHandler saxHandler,
084: ISVNDebugLog log) {
085: super (saxHandler, log);
086: }
087:
088: /**
089: * Begins an XML tree with the target path for which the
090: * status is run.
091: *
092: * @param path a WC target path
093: */
094: public void startTarget(File path) {
095: try {
096: myTargetPath = path;
097: addAttribute(PATH_ATTR, path.getPath());
098: openTag(TARGET_TAG);
099: } catch (SAXException e) {
100: getDebugLog().error(e);
101: }
102: }
103:
104: public void handleStatus(SVNStatus status) throws SVNException {
105: try {
106: sendToHandler(status);
107: } catch (SAXException th) {
108: getDebugLog().error(th);
109: SVNErrorMessage err = SVNErrorMessage.create(
110: SVNErrorCode.XML_MALFORMED, th
111: .getLocalizedMessage());
112: SVNErrorManager.error(err, th);
113: }
114: }
115:
116: /**
117: * Closes the formatted XML with the revision against which
118: * the status is run.
119: *
120: * @param revision a revision against which the status is run
121: */
122: public void endTarget(long revision) {
123: try {
124: myTargetPath = null;
125: if (revision >= 0) {
126: addAttribute(REVISION_ATTR, revision + "");
127: openTag(AGAINST_TAG);
128: closeTag(AGAINST_TAG);
129: }
130: closeTag(TARGET_TAG);
131: } catch (SAXException e) {
132: getDebugLog().error(e);
133: }
134: }
135:
136: private void sendToHandler(SVNStatus status) throws SAXException {
137: addAttribute(PATH_ATTR, getRelativePath(status.getFile()));
138: openTag(ENTRY_TAG);
139: addAttribute(PROPS_ATTR, status.getPropertiesStatus()
140: .toString());
141: addAttribute(ITEM_ATTR, status.getContentsStatus().toString());
142: if (status.isLocked()) {
143: addAttribute(WC_LOCKED_ATTR, TRUE);
144: }
145: if (status.isCopied()) {
146: addAttribute(COPIED_ATTR, TRUE);
147: }
148: if (status.isSwitched()) {
149: addAttribute(SWITCHED_ATTR, TRUE);
150: }
151: if (!status.isCopied() && status.getRevision() != null
152: && status.getRevision().getNumber() >= 0) {
153: addAttribute(REVISION_ATTR, status.getRevision().toString());
154: }
155: openTag(WC_STATUS_TAG);
156: if (status.getCommittedRevision() != null
157: && status.getCommittedRevision().getNumber() >= 0) {
158: addAttribute(REVISION_ATTR, status.getCommittedRevision()
159: .toString());
160: openTag(COMMIT_TAG);
161: addTag(AUTHOR_TAG, status.getAuthor());
162: if (status.getCommittedDate() != null) {
163: addTag(DATE_TAG, SVNTimeUtil.formatDate(status
164: .getCommittedDate()));
165: }
166: closeTag(COMMIT_TAG);
167: }
168: if (status.getLocalLock() != null) {
169: openTag(LOCK_TAG);
170: addTag(TOKEN_TAG, status.getLocalLock().getID());
171: addTag(OWNER_TAG, status.getLocalLock().getOwner());
172: addTag(COMMENT_TAG, status.getLocalLock().getComment());
173: addTag(CREATED_TAG, SVNTimeUtil.formatDate(status
174: .getLocalLock().getCreationDate()));
175: closeTag(LOCK_TAG);
176: }
177: closeTag(WC_STATUS_TAG);
178:
179: if (status.getRemoteContentsStatus() != SVNStatusType.STATUS_NONE
180: || status.getRemotePropertiesStatus() != SVNStatusType.STATUS_NONE
181: || status.getRemoteLock() != null) {
182: addAttribute(PROPS_ATTR, status.getRemotePropertiesStatus()
183: .toString());
184: addAttribute(ITEM_ATTR, status.getRemoteContentsStatus()
185: .toString());
186: openTag(REMOTE_STATUS_TAG);
187: if (status.getRemoteLock() != null) {
188: openTag(LOCK_TAG);
189: addTag(TOKEN_TAG, status.getRemoteLock().getID());
190: addTag(OWNER_TAG, status.getRemoteLock().getOwner());
191: addTag(COMMENT_TAG, status.getRemoteLock().getComment());
192: addTag(CREATED_TAG, SVNTimeUtil.formatDate(status
193: .getRemoteLock().getCreationDate()));
194: if (status.getRemoteLock().getExpirationDate() != null) {
195: addTag(EXPIRES_TAG, SVNTimeUtil.formatDate(status
196: .getRemoteLock().getExpirationDate()));
197: }
198: closeTag(LOCK_TAG);
199: }
200: closeTag(REMOTE_STATUS_TAG);
201: }
202: closeTag(ENTRY_TAG);
203: }
204:
205: protected String getRelativePath(File path) {
206: String fullPath = path.getAbsoluteFile().getAbsolutePath();
207: if (myTargetPath == null) {
208: return fullPath;
209: }
210: StringBuffer relativePath = new StringBuffer();
211: // collect path till target is met, then prepend target.
212: char pathSeparator = File.separatorChar;
213: boolean targetMeet = false;
214: if (!path.getAbsoluteFile().equals(
215: myTargetPath.getAbsoluteFile())) {
216: do {
217: if (relativePath.length() > 0) {
218: relativePath.insert(0, pathSeparator);
219: }
220: relativePath = relativePath.insert(0, path.getName());
221: path = path.getParentFile();
222: if (path != null) {
223: targetMeet = path.getAbsoluteFile().equals(
224: myTargetPath.getAbsoluteFile());
225: }
226: } while (path != null && !targetMeet);
227: } else {
228: return myTargetPath.getPath();
229: }
230:
231: if (path != null) {
232: if (relativePath.length() > 0) {
233: relativePath.insert(0, pathSeparator);
234: }
235: relativePath = relativePath.insert(0, myTargetPath
236: .getPath());
237: } else {
238: return fullPath;
239: }
240: return relativePath.toString();
241: }
242:
243: protected String getTargetPath() {
244: return getRelativePath(myTargetPath);
245: }
246:
247: protected String getHeaderName() {
248: return STATUS_TAG;
249: }
250: }
|