0001: /*
0002: * ====================================================================
0003: * Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
0004: *
0005: * This software is licensed as described in the file COPYING, which
0006: * you should have received as part of this distribution. The terms
0007: * are also available at http://svnkit.com/license.html
0008: * If newer versions of this license are posted there, you may use a
0009: * newer version instead, at your option.
0010: * ====================================================================
0011: */
0012:
0013: package org.tmatesoft.svn.core.internal.io.svn;
0014:
0015: import java.io.OutputStream;
0016: import java.util.Collection;
0017: import java.util.Date;
0018: import java.util.HashMap;
0019: import java.util.Iterator;
0020: import java.util.Map;
0021:
0022: import org.tmatesoft.svn.core.ISVNDirEntryHandler;
0023: import org.tmatesoft.svn.core.ISVNLogEntryHandler;
0024: import org.tmatesoft.svn.core.SVNAuthenticationException;
0025: import org.tmatesoft.svn.core.SVNCancelException;
0026: import org.tmatesoft.svn.core.SVNDirEntry;
0027: import org.tmatesoft.svn.core.SVNErrorCode;
0028: import org.tmatesoft.svn.core.SVNErrorMessage;
0029: import org.tmatesoft.svn.core.SVNException;
0030: import org.tmatesoft.svn.core.SVNLock;
0031: import org.tmatesoft.svn.core.SVNLogEntry;
0032: import org.tmatesoft.svn.core.SVNLogEntryPath;
0033: import org.tmatesoft.svn.core.SVNNodeKind;
0034: import org.tmatesoft.svn.core.SVNProperty;
0035: import org.tmatesoft.svn.core.SVNRevisionProperty;
0036: import org.tmatesoft.svn.core.SVNURL;
0037: import org.tmatesoft.svn.core.internal.delta.SVNDeltaReader;
0038: import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
0039: import org.tmatesoft.svn.core.internal.util.SVNTimeUtil;
0040: import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
0041: import org.tmatesoft.svn.core.io.ISVNEditor;
0042: import org.tmatesoft.svn.core.io.ISVNFileRevisionHandler;
0043: import org.tmatesoft.svn.core.io.ISVNLocationEntryHandler;
0044: import org.tmatesoft.svn.core.io.ISVNLockHandler;
0045: import org.tmatesoft.svn.core.io.ISVNReporter;
0046: import org.tmatesoft.svn.core.io.ISVNReporterBaton;
0047: import org.tmatesoft.svn.core.io.ISVNSession;
0048: import org.tmatesoft.svn.core.io.ISVNWorkspaceMediator;
0049: import org.tmatesoft.svn.core.io.SVNFileRevision;
0050: import org.tmatesoft.svn.core.io.SVNLocationEntry;
0051: import org.tmatesoft.svn.core.io.SVNRepository;
0052:
0053: /**
0054: * @version 1.1.1
0055: * @author TMate Software Ltd.
0056: */
0057: public class SVNRepositoryImpl extends SVNRepository implements
0058: ISVNReporter {
0059:
0060: private SVNConnection myConnection;
0061: private String myRealm;
0062: private String myExternalUserName;
0063:
0064: protected SVNRepositoryImpl(SVNURL location, ISVNSession options) {
0065: super (location, options);
0066: }
0067:
0068: public void testConnection() throws SVNException {
0069: try {
0070: openConnection();
0071: } catch (SVNException e) {
0072: closeSession();
0073: throw e;
0074: } finally {
0075: closeConnection();
0076: }
0077: }
0078:
0079: public void setLocation(SVNURL url, boolean forceReconnect)
0080: throws SVNException {
0081: if (url == null) {
0082: return;
0083: } else if (!url.getProtocol().equals(myLocation.getProtocol())) {
0084: SVNErrorMessage err = SVNErrorMessage
0085: .create(
0086: SVNErrorCode.RA_NOT_IMPLEMENTED,
0087: "SVNRepository URL could not be changed from ''{0}'' to ''{1}''; create new SVNRepository instance instead",
0088: new Object[] { myLocation, url });
0089: SVNErrorManager.error(err);
0090: }
0091: if (forceReconnect) {
0092: closeSession();
0093: myLocation = url;
0094: myRealm = null;
0095: myRepositoryRoot = null;
0096: myRepositoryUUID = null;
0097: return;
0098: }
0099: try {
0100: openConnection();
0101: if (reparent(url)) {
0102: myLocation = url;
0103: return;
0104: }
0105: setLocation(url, true);
0106: } catch (SVNException e) {
0107: // thrown by reparent or open connection.
0108: closeSession();
0109: throw e;
0110: } finally {
0111: closeConnection();
0112: }
0113: }
0114:
0115: private boolean reparent(SVNURL url) throws SVNException {
0116: if (myConnection != null) {
0117: if (getLocation().equals(url)) {
0118: return true;
0119: }
0120: try {
0121: Object[] buffer = new Object[] { "reparent",
0122: url.toString() };
0123: write("(w(s))", buffer);
0124: authenticate();
0125: read("[()]", null, true);
0126:
0127: String newLocation = url.toString();
0128: String rootLocation = myRepositoryRoot.toString();
0129:
0130: if (!(newLocation.startsWith(rootLocation) && (newLocation
0131: .length() == rootLocation.length() || (newLocation
0132: .length() > rootLocation.length() && newLocation
0133: .charAt(rootLocation.length()) == '/')))) {
0134: return false;
0135: }
0136:
0137: return true;
0138: } catch (SVNException e) {
0139: if (e instanceof SVNCancelException
0140: || e instanceof SVNAuthenticationException) {
0141: throw e;
0142: }
0143: }
0144: }
0145: return false;
0146: }
0147:
0148: public long getLatestRevision() throws SVNException {
0149: Object[] buffer = new Object[] { "get-latest-rev" };
0150: try {
0151: openConnection();
0152: write("(w())", buffer);
0153: authenticate();
0154: buffer = read("[(N)]", buffer, true);
0155: } catch (SVNException e) {
0156: closeSession();
0157: throw e;
0158: } finally {
0159: closeConnection();
0160: }
0161: return SVNReader.getLong(buffer, 0);
0162: }
0163:
0164: public long getDatedRevision(Date date) throws SVNException {
0165: if (date == null) {
0166: date = new Date(System.currentTimeMillis());
0167: }
0168: Object[] buffer = new Object[] { "get-dated-rev", date };
0169: try {
0170: openConnection();
0171: write("(w(s))", buffer);
0172: authenticate();
0173: buffer = read("[(N)]", buffer, true);
0174: } catch (SVNException e) {
0175: closeSession();
0176: throw e;
0177: } finally {
0178: closeConnection();
0179: }
0180: return SVNReader.getLong(buffer, 0);
0181: }
0182:
0183: public Map getRevisionProperties(long revision, Map properties)
0184: throws SVNException {
0185: assertValidRevision(revision);
0186: if (properties == null) {
0187: properties = new HashMap();
0188: }
0189: Object[] buffer = new Object[] { "rev-proplist",
0190: getRevisionObject(revision) };
0191: try {
0192: openConnection();
0193: write("(w(n))", buffer);
0194: authenticate();
0195: buffer[0] = properties;
0196: read("[((*P))]", buffer, true);
0197: } catch (SVNException e) {
0198: closeSession();
0199: throw e;
0200: } finally {
0201: closeConnection();
0202: }
0203: return properties;
0204: }
0205:
0206: public String getRevisionPropertyValue(long revision,
0207: String propertyName) throws SVNException {
0208: assertValidRevision(revision);
0209: Object[] buffer = new Object[] { "rev-prop",
0210: getRevisionObject(revision), propertyName };
0211: try {
0212: openConnection();
0213: write("(w(ns))", buffer);
0214: authenticate();
0215: buffer = read("[((?S))]", buffer, true);
0216: } catch (SVNException e) {
0217: closeSession();
0218: throw e;
0219: } finally {
0220: closeConnection();
0221: }
0222: return (String) buffer[0];
0223: }
0224:
0225: public SVNNodeKind checkPath(String path, long revision)
0226: throws SVNException {
0227: try {
0228: openConnection();
0229: path = getRepositoryPath(path);
0230: Object[] buffer = new Object[] { "check-path", path,
0231: getRevisionObject(revision) };
0232: write("(w(s(n)))", buffer);
0233: authenticate();
0234: read("[(W)]", buffer, true);
0235: return SVNNodeKind.parseKind((String) buffer[0]);
0236: } catch (SVNException e) {
0237: closeSession();
0238: throw e;
0239: } finally {
0240: closeConnection();
0241: }
0242: }
0243:
0244: public int getLocations(String path, long pegRevision,
0245: long[] revisions, ISVNLocationEntryHandler handler)
0246: throws SVNException {
0247: assertValidRevision(pegRevision);
0248: for (int i = 0; i < revisions.length; i++) {
0249: assertValidRevision(revisions[i]);
0250: }
0251: int count = 0;
0252: try {
0253: openConnection();
0254: path = getRepositoryPath(path);
0255: Object[] buffer = new Object[] { "get-locations", path,
0256: getRevisionObject(pegRevision), revisions };
0257: write("(w(sn(*n)))", buffer);
0258: authenticate();
0259: while (true) {
0260: try {
0261: read("(NS)", buffer, false);
0262: } catch (SVNException e) {
0263: break;
0264: }
0265: count++;
0266: if (handler != null) {
0267: long revision = SVNReader.getLong(buffer, 0);
0268: String location = SVNReader.getString(buffer, 1);
0269: if (location != null) {
0270: handler
0271: .handleLocationEntry(new SVNLocationEntry(
0272: revision, location));
0273: }
0274: }
0275: }
0276: read("x", buffer, true);
0277: read("[()]", buffer, true);
0278: } catch (SVNException e) {
0279: closeSession();
0280: handleUnsupportedCommand(e,
0281: "'get-locations' not implemented");
0282: } finally {
0283: closeConnection();
0284: }
0285: return count;
0286: }
0287:
0288: public long getFile(String path, long revision, Map properties,
0289: OutputStream contents) throws SVNException {
0290: Long rev = revision > 0 ? new Long(revision) : null;
0291: try {
0292: openConnection();
0293: Object[] buffer = new Object[] { "get-file",
0294: getRepositoryPath(path), rev,
0295: Boolean.valueOf(properties != null),
0296: Boolean.valueOf(contents != null) };
0297: write("(w(s(n)ww))", buffer);
0298: authenticate();
0299: buffer[2] = properties;
0300: buffer = read("[((?S)N(*P))]", buffer, true);
0301: if (properties != null) {
0302: properties.put(SVNProperty.REVISION, buffer[1]
0303: .toString());
0304: properties.put(SVNProperty.CHECKSUM, buffer[0]
0305: .toString());
0306: }
0307: if (contents != null) {
0308: Object[] buffer2 = new Object[] { contents };
0309: read("*I", buffer2, true);
0310: read("[()]", buffer2, true);
0311: }
0312: return SVNReader.getLong(buffer, 1);
0313: } catch (SVNException e) {
0314: closeSession();
0315: throw e;
0316: } finally {
0317: closeConnection();
0318: }
0319: }
0320:
0321: public long getDir(String path, long revision, Map properties,
0322: final ISVNDirEntryHandler handler) throws SVNException {
0323: Long rev = getRevisionObject(revision);
0324: try {
0325: openConnection();
0326:
0327: String fullPath = getFullPath(path);
0328: final SVNURL url = getLocation().setPath(fullPath, false);
0329: path = getRepositoryPath(path);
0330:
0331: Object[] buffer = new Object[] { "get-dir", path, rev,
0332: Boolean.valueOf(properties != null),
0333: Boolean.valueOf(handler != null) };
0334: write("(w(s(n)ww))", buffer);
0335: authenticate();
0336:
0337: buffer[1] = properties;
0338: buffer = read("[(N(*P)", buffer, true);
0339: revision = buffer[0] != null ? SVNReader.getLong(buffer, 0)
0340: : revision;
0341: ISVNDirEntryHandler nestedHandler = new ISVNDirEntryHandler() {
0342: public void handleDirEntry(SVNDirEntry dirEntry)
0343: throws SVNException {
0344: handler.handleDirEntry(new SVNDirEntry(url
0345: .appendPath(dirEntry.getName(), false),
0346: dirEntry.getName(), dirEntry.getKind(),
0347: dirEntry.getSize(), dirEntry
0348: .hasProperties(), dirEntry
0349: .getRevision(), dirEntry.getDate(),
0350: dirEntry.getAuthor()));
0351: }
0352: };
0353: if (handler != null) {
0354: buffer[0] = nestedHandler;
0355: read("(*D)))", buffer, true);
0356: } else {
0357: read("()))", null, true);
0358: }
0359: } catch (SVNException e) {
0360: closeSession();
0361: throw e;
0362: } finally {
0363: closeConnection();
0364: }
0365: return revision;
0366: }
0367:
0368: public SVNDirEntry getDir(String path, long revision,
0369: boolean includeComment, final Collection entries)
0370: throws SVNException {
0371: Long rev = getRevisionObject(revision);
0372: // convert path to path relative to repos root.
0373: SVNDirEntry parentEntry = null;
0374: try {
0375: openConnection();
0376: final SVNURL url = getLocation().setPath(getFullPath(path),
0377: false);
0378: ISVNDirEntryHandler handler = new ISVNDirEntryHandler() {
0379: public void handleDirEntry(SVNDirEntry dirEntry)
0380: throws SVNException {
0381: dirEntry = new SVNDirEntry(url.appendPath(dirEntry
0382: .getName(), false), dirEntry.getName(),
0383: dirEntry.getKind(), dirEntry.getSize(),
0384: dirEntry.hasProperties(), dirEntry
0385: .getRevision(), dirEntry.getDate(),
0386: dirEntry.getAuthor());
0387: entries.add(dirEntry);
0388: }
0389: };
0390: path = getRepositoryPath(path);
0391: // get parent
0392: Object[] buffer = new Object[] { "stat", path,
0393: getRevisionObject(revision) };
0394: write("(w(s(n)))", buffer);
0395: authenticate();
0396: read("[((?F))]", buffer, true);
0397: parentEntry = (SVNDirEntry) buffer[0];
0398: parentEntry = new SVNDirEntry(url, "", parentEntry
0399: .getKind(), parentEntry.getSize(), parentEntry
0400: .hasProperties(), parentEntry.getRevision(),
0401: parentEntry.getDate(), parentEntry.getAuthor());
0402:
0403: // get entries.
0404: buffer = new Object[] { "get-dir", path, rev,
0405: Boolean.FALSE, Boolean.TRUE };
0406: write("(w(s(n)ww))", buffer);
0407: authenticate();
0408: buffer = read("[(N(*P)", buffer, true);
0409: revision = buffer[0] != null ? SVNReader.getLong(buffer, 0)
0410: : revision;
0411: if (handler != null) {
0412: buffer[0] = handler;
0413: read("(*D)))", buffer, true);
0414: } else {
0415: read("()))", null, true);
0416: }
0417: // get comments.
0418: if (includeComment) {
0419: Map messages = new HashMap();
0420: for (Iterator ents = entries.iterator(); ents.hasNext();) {
0421: SVNDirEntry entry = (SVNDirEntry) ents.next();
0422: Long key = getRevisionObject(entry.getRevision());
0423: if (messages.containsKey(key)) {
0424: entry.setCommitMessage((String) messages
0425: .get(key));
0426: continue;
0427: }
0428: buffer = new Object[] { "rev-prop", key,
0429: SVNRevisionProperty.LOG };
0430: write("(w(ns))", buffer);
0431: authenticate();
0432: buffer = read("[((?S))]", buffer, true);
0433: messages.put(key, buffer[0]);
0434: entry.setCommitMessage((String) buffer[0]);
0435: }
0436: }
0437: } catch (SVNException e) {
0438: closeSession();
0439: throw e;
0440: } finally {
0441: closeConnection();
0442: }
0443: return parentEntry;
0444: }
0445:
0446: public int getFileRevisions(String path, long sRevision,
0447: long eRevision, ISVNFileRevisionHandler handler)
0448: throws SVNException {
0449: Long srev = getRevisionObject(sRevision);
0450: Long erev = getRevisionObject(eRevision);
0451: int count = 0;
0452: SVNDeltaReader deltaReader = new SVNDeltaReader();
0453: try {
0454: openConnection();
0455: Object[] buffer = new Object[] { "get-file-revs",
0456: getRepositoryPath(path), srev, erev };
0457: write("(w(s(n)(n)))", buffer);
0458: authenticate();
0459: buffer = new Object[5];
0460: while (true) {
0461: SVNFileRevision fileRevision = null;
0462: boolean skipDelta = false;
0463: try {
0464: buffer = read("(SN(*P)(*Z)?S", buffer, false);
0465: if (buffer[4] != null
0466: && ((String) buffer[4]).length() == 0) {
0467: buffer[4] = null;
0468: skipDelta = true;
0469: } else {
0470: read(")", null, false);
0471: }
0472: count++;
0473: } catch (SVNException e) {
0474: read("x", buffer, true);
0475: read("[()]", buffer, true);
0476: return count;
0477: }
0478: String name = null;
0479: if (handler != null) {
0480: name = (String) buffer[0];
0481: long revision = SVNReader.getLong(buffer, 1);
0482: Map properties = SVNReader.getMap(buffer, 2);
0483: Map propertiesDelta = SVNReader.getMap(buffer, 3);
0484: if (name != null) {
0485: fileRevision = new SVNFileRevision(name,
0486: revision, properties, propertiesDelta);
0487: }
0488: buffer[2] = null;
0489: buffer[3] = null;
0490: }
0491: if (handler != null && fileRevision != null) {
0492: handler.openRevision(fileRevision);
0493: }
0494: if (skipDelta) {
0495: if (handler != null) {
0496: handler.closeRevision(name == null ? path
0497: : name);
0498: }
0499: continue;
0500: }
0501: boolean windowRead = false;
0502: while (true) {
0503: byte[] line = (byte[]) read("?W?B", buffer, true)[1];
0504: if (line == null) {
0505: // may be failure
0506: read("[]", buffer, true);
0507: break;
0508: } else if (line.length == 0) {
0509: // empty line, delta end.
0510: break;
0511: }
0512: // apply delta here.
0513: if (!windowRead) {
0514: if (handler != null) {
0515: handler.applyTextDelta(name == null ? path
0516: : name, null);
0517: windowRead = true;
0518: }
0519: }
0520: deltaReader.nextWindow(line, 0, line.length,
0521: name == null ? path : name, handler);
0522: }
0523: deltaReader.reset(name == null ? path : name, handler);
0524: if (windowRead) {
0525: handler.textDeltaEnd(name == null ? path : name);
0526: }
0527: if (handler != null) {
0528: handler.closeRevision(name == null ? path : name);
0529: }
0530: }
0531: } catch (SVNException e) {
0532: closeSession();
0533: handleUnsupportedCommand(e,
0534: "'get-file-revs' not implemented");
0535: } finally {
0536: closeConnection();
0537: }
0538: return -1;
0539: }
0540:
0541: public long log(String[] targetPaths, long startRevision,
0542: long endRevision, boolean changedPaths, boolean strictNode,
0543: long limit, ISVNLogEntryHandler handler)
0544: throws SVNException {
0545: long count = 0;
0546:
0547: long latestRev = -1;
0548: if (isInvalidRevision(startRevision)) {
0549: startRevision = latestRev = getLatestRevision();
0550: }
0551: if (isInvalidRevision(endRevision)) {
0552: endRevision = latestRev != -1 ? latestRev
0553: : getLatestRevision();
0554: }
0555:
0556: try {
0557: openConnection();
0558: String[] repositoryPaths = getRepositoryPaths(targetPaths);
0559: if (repositoryPaths == null || repositoryPaths.length == 0) {
0560: repositoryPaths = new String[] { "" };
0561: }
0562: Object[] buffer = new Object[] { "log", repositoryPaths,
0563: getRevisionObject(startRevision),
0564: getRevisionObject(endRevision),
0565: Boolean.valueOf(changedPaths),
0566: Boolean.valueOf(strictNode),
0567: limit > 0 ? new Long(limit) : null };
0568: write("(w((*s)(n)(n)wwn))", buffer);
0569: authenticate();
0570: while (true) {
0571: try {
0572: read("((", buffer, false);
0573: Map changedPathsMap = null;
0574: if (changedPaths) {
0575: changedPathsMap = handler != null ? new HashMap()
0576: : null;
0577: while (true) {
0578: try {
0579: read("(SW(?S?N))", buffer, false);
0580: if (changedPathsMap != null) {
0581: String path = SVNReader.getString(
0582: buffer, 0);
0583: if (path != null
0584: && !"".equals(path.trim())) {
0585: String type = SVNReader
0586: .getString(buffer, 1);
0587: String copyPath = SVNReader
0588: .getString(buffer, 2);
0589: long copyRev = SVNReader
0590: .getLong(buffer, 3);
0591: changedPathsMap.put(path,
0592: new SVNLogEntryPath(
0593: path,
0594: type.charAt(0),
0595: copyPath,
0596: copyRev));
0597: }
0598: }
0599: } catch (SVNException e) {
0600: break;
0601: }
0602: }
0603: }
0604: read(")N(?S)(?S)(?S))", buffer, false);
0605: count++;
0606: if (handler != null
0607: && (limit <= 0 || count <= limit)) {
0608: long revision = SVNReader.getLong(buffer, 0);
0609: String author = SVNReader.getString(buffer, 1);
0610: Date date = SVNReader.getDate(buffer, 2);
0611: if (date == SVNTimeUtil.NULL) {
0612: date = null;
0613: }
0614: String message = SVNReader.getString(buffer, 3);
0615: handler.handleLogEntry(new SVNLogEntry(
0616: changedPathsMap, revision, author,
0617: date, message));
0618: }
0619: } catch (SVNException e) {
0620: if (e instanceof SVNCancelException
0621: || e instanceof SVNAuthenticationException) {
0622: throw e;
0623: }
0624: read("x", buffer, true);
0625: if (limit <= 0 || (limit > 0 && count <= limit)) {
0626: read("[()]", buffer, true);
0627: }
0628: return count;
0629: }
0630: }
0631: } catch (SVNException e) {
0632: closeSession();
0633: throw e;
0634: } finally {
0635: closeConnection();
0636: }
0637: }
0638:
0639: public void replay(long lowRevision, long highRevision,
0640: boolean sendDeltas, ISVNEditor editor) throws SVNException {
0641: Object[] buffer = new Object[] { "replay",
0642: getRevisionObject(highRevision),
0643: getRevisionObject(lowRevision),
0644: Boolean.valueOf(sendDeltas) };
0645: try {
0646: openConnection();
0647: write("(w(nnw))", buffer);
0648: authenticate();
0649: read("*E", new Object[] { editor }, true);
0650: read("[()]", null, true);
0651: } catch (SVNException e) {
0652: closeSession();
0653: handleUnsupportedCommand(e,
0654: "Server doesn't support the replay command");
0655: } finally {
0656: closeConnection();
0657: }
0658: }
0659:
0660: public void update(long revision, String target, boolean recursive,
0661: ISVNReporterBaton reporter, ISVNEditor editor)
0662: throws SVNException {
0663: target = target == null ? "" : target;
0664: Object[] buffer = new Object[] { "update",
0665: getRevisionObject(revision), target,
0666: Boolean.valueOf(recursive) };
0667: try {
0668: openConnection();
0669: write("(w((n)sw))", buffer);
0670: authenticate();
0671: reporter.report(this );
0672: authenticate();
0673: read("*E", new Object[] { editor }, true);
0674: write("(w())", new Object[] { "success" });
0675: read("[()]", null, true);
0676: } catch (SVNException e) {
0677: closeSession();
0678: throw e;
0679: } finally {
0680: closeConnection();
0681: }
0682: }
0683:
0684: public void update(SVNURL url, long revision, String target,
0685: boolean recursive, ISVNReporterBaton reporter,
0686: ISVNEditor editor) throws SVNException {
0687: target = target == null ? "" : target;
0688: if (url == null) {
0689: SVNErrorManager.error(SVNErrorMessage.create(
0690: SVNErrorCode.BAD_URL, "URL can not be NULL"));
0691: }
0692: Object[] buffer = new Object[] { "switch",
0693: getRevisionObject(revision), target,
0694: Boolean.valueOf(recursive), url.toString() };
0695: try {
0696: openConnection();
0697: write("(w((n)sws))", buffer);
0698: authenticate();
0699: reporter.report(this );
0700: authenticate();
0701: read("*E", new Object[] { editor }, true);
0702: write("(w())", new Object[] { "success" });
0703: read("[()]", null, true);
0704: } catch (SVNException e) {
0705: closeSession();
0706: throw e;
0707: } finally {
0708: closeConnection();
0709: }
0710: }
0711:
0712: public void diff(SVNURL url, long revision, String target,
0713: boolean ignoreAncestry, boolean recursive,
0714: ISVNReporterBaton reporter, ISVNEditor editor)
0715: throws SVNException {
0716: diff(url, revision, revision, target, ignoreAncestry,
0717: recursive, reporter, editor);
0718: }
0719:
0720: public void diff(SVNURL url, long tRevision, long revision,
0721: String target, boolean ignoreAncestry, boolean recursive,
0722: ISVNReporterBaton reporter, ISVNEditor editor)
0723: throws SVNException {
0724: diff(url, revision, revision, target, ignoreAncestry,
0725: recursive, true, reporter, editor);
0726: }
0727:
0728: public void diff(SVNURL url, long tRevision, long revision,
0729: String target, boolean ignoreAncestry, boolean recursive,
0730: boolean getContents, ISVNReporterBaton reporter,
0731: ISVNEditor editor) throws SVNException {
0732: target = target == null ? "" : target;
0733: if (url == null) {
0734: SVNErrorManager.error(SVNErrorMessage.create(
0735: SVNErrorCode.BAD_URL, "URL can not be NULL"));
0736: }
0737: Object[] buffer = getContents ? new Object[] { "diff",
0738: getRevisionObject(tRevision), target,
0739: Boolean.valueOf(recursive),
0740: Boolean.valueOf(ignoreAncestry), url.toString() }
0741: : new Object[] { "diff", getRevisionObject(tRevision),
0742: target, Boolean.valueOf(recursive),
0743: Boolean.valueOf(ignoreAncestry),
0744: url.toString(), Boolean.valueOf(getContents) };
0745: try {
0746: openConnection();
0747: write(getContents ? "(w((n)swws))" : "(w((n)swwsw))",
0748: buffer);
0749: authenticate();
0750: reporter.report(this );
0751: authenticate();
0752: read("*E", new Object[] { editor }, true);
0753: write("(w())", new Object[] { "success" });
0754: read("[()]", null, true);
0755: } catch (SVNException e) {
0756: closeSession();
0757: throw e;
0758: } finally {
0759: closeConnection();
0760: }
0761: }
0762:
0763: public void status(long revision, String target, boolean recursive,
0764: ISVNReporterBaton reporter, ISVNEditor editor)
0765: throws SVNException {
0766: target = target == null ? "" : target;
0767: Object[] buffer = new Object[] { "status", target,
0768: Boolean.valueOf(recursive), getRevisionObject(revision) };
0769: try {
0770: openConnection();
0771: write("(w(sw(n)))", buffer);
0772: authenticate();
0773: reporter.report(this );
0774: authenticate();
0775: read("*E", new Object[] { editor }, true);
0776: write("(w())", new Object[] { "success" });
0777: read("[()]", null, true);
0778: } catch (SVNException e) {
0779: closeSession();
0780: throw e;
0781: } finally {
0782: closeConnection();
0783: }
0784: }
0785:
0786: public void setRevisionPropertyValue(long revision,
0787: String propertyName, String propertyValue)
0788: throws SVNException {
0789: assertValidRevision(revision);
0790: Object[] buffer = new Object[] { "change-rev-prop",
0791: getRevisionObject(revision), propertyName,
0792: propertyValue };
0793: try {
0794: openConnection();
0795: write("(w(nss))", buffer);
0796: authenticate();
0797: read("[()]", buffer, true);
0798: } catch (SVNException e) {
0799: closeSession();
0800: throw e;
0801: } finally {
0802: closeConnection();
0803: }
0804: }
0805:
0806: public ISVNEditor getCommitEditor(String logMessage, Map locks,
0807: boolean keepLocks, final ISVNWorkspaceMediator mediator)
0808: throws SVNException {
0809: try {
0810: openConnection();
0811: if (locks != null) {
0812: write("(w(s(*l)w))", new Object[] { "commit",
0813: logMessage, locks, Boolean.valueOf(keepLocks) });
0814: } else {
0815: write("(w(s))", new Object[] { "commit", logMessage });
0816: }
0817: authenticate();
0818: read("[()]", null, true);
0819: return new SVNCommitEditor(this , myConnection,
0820: new SVNCommitEditor.ISVNCommitCallback() {
0821: public void run(SVNException error) {
0822: if (error != null) {
0823: closeSession();
0824: }
0825: closeConnection();
0826: }
0827: });
0828: } catch (SVNException e) {
0829: closeSession();
0830: closeConnection();
0831: throw e;
0832: }
0833: }
0834:
0835: public SVNLock getLock(String path) throws SVNException {
0836: try {
0837: openConnection();
0838: path = getRepositoryPath(path);
0839: Object[] buffer = new Object[] { "get-lock", path };
0840: write("(w(s))", buffer);
0841: authenticate();
0842: read("[((?L))]", buffer, true);
0843: return (SVNLock) buffer[0];
0844: } catch (SVNException e) {
0845: closeSession();
0846: handleUnsupportedCommand(e,
0847: "Server doesn't support the get-lock command");
0848: } finally {
0849: closeConnection();
0850: }
0851: return null;
0852: }
0853:
0854: public SVNLock[] getLocks(String path) throws SVNException {
0855: try {
0856: openConnection();
0857: path = getRepositoryPath(path);
0858: Object[] buffer = new Object[] { "get-locks", path };
0859: write("(w(s))", buffer);
0860: authenticate();
0861: read("[((*L))]", buffer, true);
0862: Collection lockObjects = (Collection) buffer[0];
0863: return lockObjects == null ? new SVNLock[0]
0864: : (SVNLock[]) lockObjects
0865: .toArray(new SVNLock[lockObjects.size()]);
0866: } catch (SVNException e) {
0867: closeSession();
0868: handleUnsupportedCommand(e,
0869: "Server doesn't support the get-lock command");
0870: } finally {
0871: closeConnection();
0872: }
0873: return null;
0874: }
0875:
0876: public void lock(Map pathsToRevisions, String comment,
0877: boolean force, ISVNLockHandler handler) throws SVNException {
0878: try {
0879: openConnection();
0880: Object[] buffer = new Object[] { "lock-many", comment,
0881: Boolean.valueOf(force) };
0882: write("(w((s)w(", buffer);
0883: buffer = new Object[2];
0884: for (Iterator paths = pathsToRevisions.keySet().iterator(); paths
0885: .hasNext();) {
0886: buffer[0] = paths.next();
0887: buffer[1] = pathsToRevisions.get(buffer[0]);
0888: write("(s(n))", buffer);
0889: }
0890: write(")))", buffer);
0891: try {
0892: authenticate();
0893: } catch (SVNException e) {
0894: if (e.getErrorMessage() != null
0895: && e.getErrorMessage().getErrorCode() == SVNErrorCode.RA_SVN_UNKNOWN_CMD) {
0896: closeSession();
0897: closeConnection();
0898: openConnection();
0899: lock12(pathsToRevisions, comment, force, handler);
0900: return;
0901: }
0902: closeSession();
0903: throw e;
0904: }
0905: for (Iterator paths = pathsToRevisions.keySet().iterator(); paths
0906: .hasNext();) {
0907: String path = (String) paths.next();
0908: SVNLock lock = null;
0909: SVNErrorMessage error = null;
0910: try {
0911: read("[L]", buffer, false);
0912: lock = (SVNLock) buffer[0];
0913: path = lock.getPath();
0914: } catch (SVNException e) {
0915: path = getRepositoryPath(path);
0916: error = e.getErrorMessage();
0917: }
0918: if (handler != null) {
0919: handler.handleLock(path, lock, error);
0920: }
0921: }
0922: read("x", buffer, true);
0923: read("[()]", buffer, true);
0924: } catch (SVNException e) {
0925: closeSession();
0926: handleUnsupportedCommand(e,
0927: "Server doesn't support the lock command");
0928: } finally {
0929: closeConnection();
0930: }
0931: }
0932:
0933: private void lock12(Map pathsToRevisions, String comment,
0934: boolean force, ISVNLockHandler handler) throws SVNException {
0935: for (Iterator paths = pathsToRevisions.keySet().iterator(); paths
0936: .hasNext();) {
0937: String path = (String) paths.next();
0938: Long revision = (Long) pathsToRevisions.get(path);
0939: path = getRepositoryPath(path);
0940: Object[] buffer = new Object[] { "lock", path, comment,
0941: Boolean.valueOf(force), revision };
0942: write("(w(s(s)w(n)))", buffer);
0943: authenticate();
0944: SVNErrorMessage error = null;
0945: try {
0946: read("[(L)]", buffer, false);
0947: } catch (SVNException e) {
0948: if (e.getErrorMessage() != null) {
0949: SVNErrorCode code = e.getErrorMessage()
0950: .getErrorCode();
0951: if (code == SVNErrorCode.FS_PATH_ALREADY_LOCKED
0952: || code == SVNErrorCode.FS_OUT_OF_DATE) {
0953: error = e.getErrorMessage();
0954: }
0955: }
0956: if (error == null) {
0957: throw e;
0958: }
0959: }
0960: if (handler != null) {
0961: SVNLock lock = (SVNLock) buffer[0];
0962: handler.handleLock(path, lock, error);
0963: }
0964: }
0965: }
0966:
0967: public void unlock(Map pathToTokens, boolean force,
0968: ISVNLockHandler handler) throws SVNException {
0969: try {
0970: openConnection();
0971: Object[] buffer = new Object[] { "unlock-many",
0972: Boolean.valueOf(force) };
0973: write("(w(w(", buffer);
0974: buffer = new Object[2];
0975: for (Iterator paths = pathToTokens.keySet().iterator(); paths
0976: .hasNext();) {
0977: buffer[0] = paths.next();
0978: buffer[1] = pathToTokens.get(buffer[0]);
0979: write("(s(s))", buffer);
0980: }
0981: write(")))", buffer);
0982: try {
0983: authenticate();
0984: } catch (SVNException e) {
0985: if (e.getErrorMessage() != null
0986: && e.getErrorMessage().getErrorCode() == SVNErrorCode.RA_SVN_UNKNOWN_CMD) {
0987: closeSession();
0988: closeConnection();
0989: openConnection();
0990: unlock12(pathToTokens, force, handler);
0991: return;
0992: }
0993: throw e;
0994: }
0995: for (Iterator paths = pathToTokens.keySet().iterator(); paths
0996: .hasNext();) {
0997: String path = (String) paths.next();
0998: String id = (String) pathToTokens.get(path);
0999: SVNErrorMessage error = null;
1000: try {
1001: read("[(S)]", buffer, false);
1002: path = (String) buffer[0];
1003: } catch (SVNException e) {
1004: error = e.getErrorMessage();
1005: }
1006: path = getRepositoryPath(path);
1007: if (handler != null) {
1008: handler.handleUnlock(path, new SVNLock(path, id,
1009: null, null, null, null), error);
1010: }
1011: }
1012: read("x", buffer, true);
1013: read("[()]", buffer, true);
1014: } catch (SVNException e) {
1015: closeSession();
1016: handleUnsupportedCommand(e,
1017: "Server doesn't support the unlock command");
1018: } finally {
1019: closeConnection();
1020: }
1021: }
1022:
1023: private void unlock12(Map pathToTokens, boolean force,
1024: ISVNLockHandler handler) throws SVNException {
1025: for (Iterator paths = pathToTokens.keySet().iterator(); paths
1026: .hasNext();) {
1027: String path = (String) paths.next();
1028: String id = (String) pathToTokens.get(path);
1029: path = getRepositoryPath(path);
1030: if (id == null) {
1031: Object[] buffer = new Object[] { "get-lock", path };
1032: write("(w(s))", buffer);
1033: authenticate();
1034: read("[((?L))]", buffer, true);
1035: SVNLock lock = (SVNLock) buffer[0];
1036: if (lock == null) {
1037: lock = new SVNLock(path, "", null, null, null, null);
1038: SVNErrorMessage err = SVNErrorMessage.create(
1039: SVNErrorCode.RA_NOT_LOCKED,
1040: "No lock on path ''{0}''", path);
1041: handler.handleUnlock(path, lock, err);
1042: continue;
1043: }
1044: id = lock.getID();
1045: }
1046: Object[] buffer = new Object[] { "unlock", path, id,
1047: Boolean.valueOf(force) };
1048: write("(w(s(s)w))", buffer);
1049: authenticate();
1050: SVNErrorMessage error = null;
1051: try {
1052: read("[()]", buffer, true);
1053: } catch (SVNException e) {
1054: if (e.getErrorMessage() != null
1055: && e.getErrorMessage().getErrorCode() == SVNErrorCode.RA_NOT_LOCKED) {
1056: error = e.getErrorMessage();
1057: error = SVNErrorMessage.create(
1058: error.getErrorCode(), error
1059: .getMessageTemplate(), path);
1060: } else {
1061: throw e;
1062: }
1063: }
1064: if (handler != null) {
1065: SVNLock lock = new SVNLock(path, id, null, null, null,
1066: null);
1067: handler.handleUnlock(path, lock, error);
1068: }
1069: }
1070: }
1071:
1072: public SVNDirEntry info(String path, long revision)
1073: throws SVNException {
1074: try {
1075: openConnection();
1076: String fullPath = getFullPath(path);
1077: SVNURL url = getLocation().setPath(fullPath, false);
1078: path = getRepositoryPath(path);
1079: Object[] buffer = new Object[] { "stat", path,
1080: getRevisionObject(revision) };
1081: write("(w(s(n)))", buffer);
1082: authenticate();
1083: read("[((?F))]", buffer, true);
1084: SVNDirEntry entry = (SVNDirEntry) buffer[0];
1085: if (entry != null) {
1086: entry = new SVNDirEntry(url, SVNPathUtil.tail(path),
1087: entry.getKind(), entry.getSize(), entry
1088: .hasProperties(), entry.getRevision(),
1089: entry.getDate(), entry.getAuthor());
1090: }
1091: return entry;
1092: } catch (SVNException e) {
1093: closeSession();
1094: handleUnsupportedCommand(e, "'stat' not implemented");
1095: } finally {
1096: closeConnection();
1097: }
1098: return null;
1099: }
1100:
1101: void updateCredentials(String uuid, SVNURL rootURL)
1102: throws SVNException {
1103: if (getRepositoryRoot(false) != null) {
1104: return;
1105: }
1106: setRepositoryCredentials(uuid, rootURL);
1107: }
1108:
1109: protected void openConnection() throws SVNException {
1110: lock();
1111: fireConnectionOpened();
1112: // check if connection is stale.
1113: if (myConnection != null && myConnection.isConnectionStale()) {
1114: closeSession();
1115: }
1116: if (myConnection != null) {
1117: if (reparent(getLocation())) {
1118: return;
1119: }
1120: closeSession();
1121: }
1122: ISVNConnector connector = SVNRepositoryFactoryImpl
1123: .getConnectorFactory().createConnector(this );
1124: myConnection = new SVNConnection(connector, this );
1125: try {
1126: myConnection.open(this );
1127: authenticate();
1128: } finally {
1129: if (myConnection != null) {
1130: myRealm = myConnection.getRealm();
1131: }
1132: }
1133: }
1134:
1135: protected void closeConnection() {
1136: if (!getOptions().keepConnection(this )) {
1137: closeSession();
1138: }
1139: unlock();
1140: fireConnectionClosed();
1141: }
1142:
1143: public String getRealm() {
1144: return myRealm;
1145: }
1146:
1147: void authenticate() throws SVNException {
1148: if (myConnection != null) {
1149: myConnection.authenticate(this );
1150: }
1151: }
1152:
1153: private void write(String template, Object[] values)
1154: throws SVNException {
1155: if (myConnection == null) {
1156: SVNErrorManager.error(SVNErrorMessage
1157: .create(SVNErrorCode.RA_SVN_CONNECTION_CLOSED));
1158: }
1159: myConnection.write(template, values);
1160: }
1161:
1162: private Object[] read(String template, Object[] values,
1163: boolean readMalformedData) throws SVNException {
1164: if (myConnection == null) {
1165: SVNErrorManager.error(SVNErrorMessage
1166: .create(SVNErrorCode.RA_SVN_CONNECTION_CLOSED));
1167: }
1168: return myConnection.read(template, values, readMalformedData);
1169: }
1170:
1171: /*
1172: * ISVNReporter methods
1173: */
1174:
1175: public void setPath(String path, String lockToken, long revision,
1176: boolean startEmpty) throws SVNException {
1177: assertValidRevision(revision);
1178: if (lockToken == null) {
1179: write("(w(snw))", new Object[] { "set-path", path,
1180: getRevisionObject(revision),
1181: Boolean.valueOf(startEmpty) });
1182: } else {
1183: write("(w(snw(s)))", new Object[] { "set-path", path,
1184: getRevisionObject(revision),
1185: Boolean.valueOf(startEmpty), lockToken });
1186: }
1187: }
1188:
1189: public void deletePath(String path) throws SVNException {
1190: write("(w(s))", new Object[] { "delete-path", path });
1191: }
1192:
1193: public void linkPath(SVNURL url, String path, String lockToken,
1194: long revison, boolean startEmpty) throws SVNException {
1195: assertValidRevision(revison);
1196: if (lockToken == null) {
1197: write("(w(ssnw))", new Object[] { "link-path", path,
1198: url.toString(), getRevisionObject(revison),
1199: Boolean.valueOf(startEmpty) });
1200: } else {
1201: write("(w(ssnw(s)))", new Object[] { "link-path", path,
1202: url.toString(), getRevisionObject(revison),
1203: Boolean.valueOf(startEmpty), lockToken });
1204: }
1205: }
1206:
1207: public void finishReport() throws SVNException {
1208: write("(w())", new Object[] { "finish-report" });
1209: }
1210:
1211: public void abortReport() throws SVNException {
1212: write("(w())", new Object[] { "abort-report" });
1213: }
1214:
1215: private String[] getRepositoryPaths(String[] paths)
1216: throws SVNException {
1217: if (paths == null || paths.length == 0) {
1218: return paths;
1219: }
1220: String[] fullPaths = new String[paths.length];
1221: for (int i = 0; i < paths.length; i++) {
1222: fullPaths[i] = getRepositoryPath(paths[i]);
1223: }
1224: return fullPaths;
1225: }
1226:
1227: // all paths are uri-decoded.
1228: //
1229: // get repository path (path starting with /, relative to repository root).
1230: // get full path (path starting with /, relative to host).
1231: // get relative path (repository path, now relative to repository location, not starting with '/').
1232:
1233: public void setExternalUserName(String userName) {
1234: myExternalUserName = userName;
1235: }
1236:
1237: public String getExternalUserName() {
1238: return myExternalUserName;
1239: }
1240:
1241: public void closeSession() {
1242: lock(true);
1243: try {
1244: if (myConnection != null) {
1245: try {
1246: myConnection.close();
1247: } catch (SVNException e) {
1248: //
1249: } finally {
1250: myConnection = null;
1251: }
1252: }
1253: } finally {
1254: unlock();
1255: }
1256: }
1257:
1258: private void handleUnsupportedCommand(SVNException e, String message)
1259: throws SVNException {
1260: if (e.getErrorMessage() != null
1261: && e.getErrorMessage().getErrorCode() == SVNErrorCode.RA_SVN_UNKNOWN_CMD) {
1262: SVNErrorMessage err = SVNErrorMessage.create(
1263: SVNErrorCode.RA_NOT_IMPLEMENTED, message);
1264: SVNErrorManager.error(err, e.getErrorMessage());
1265: }
1266: throw e;
1267: }
1268: }
|