Source Code Cross Referenced for SVNWCClient.java in  » Source-Control » tmatesoft-SVN » org » tmatesoft » svn » core » wc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Source Control » tmatesoft SVN » org.tmatesoft.svn.core.wc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:        package org.tmatesoft.svn.core.wc;
0013:
0014:        import java.io.File;
0015:        import java.io.IOException;
0016:        import java.io.InputStream;
0017:        import java.io.OutputStream;
0018:        import java.util.ArrayList;
0019:        import java.util.Collection;
0020:        import java.util.Collections;
0021:        import java.util.Date;
0022:        import java.util.HashMap;
0023:        import java.util.HashSet;
0024:        import java.util.Iterator;
0025:        import java.util.Map;
0026:
0027:        import org.tmatesoft.svn.core.SVNCancelException;
0028:        import org.tmatesoft.svn.core.SVNDirEntry;
0029:        import org.tmatesoft.svn.core.SVNErrorCode;
0030:        import org.tmatesoft.svn.core.SVNErrorMessage;
0031:        import org.tmatesoft.svn.core.SVNException;
0032:        import org.tmatesoft.svn.core.SVNLock;
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.auth.ISVNAuthenticationManager;
0038:        import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
0039:        import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
0040:        import org.tmatesoft.svn.core.internal.util.SVNTimeUtil;
0041:        import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
0042:        import org.tmatesoft.svn.core.internal.wc.SVNAdminUtil;
0043:        import org.tmatesoft.svn.core.internal.wc.SVNCancellableOutputStream;
0044:        import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
0045:        import org.tmatesoft.svn.core.internal.wc.SVNEventFactory;
0046:        import org.tmatesoft.svn.core.internal.wc.SVNExternalInfo;
0047:        import org.tmatesoft.svn.core.internal.wc.SVNFileListUtil;
0048:        import org.tmatesoft.svn.core.internal.wc.SVNFileType;
0049:        import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
0050:        import org.tmatesoft.svn.core.internal.wc.SVNPropertiesManager;
0051:        import org.tmatesoft.svn.core.internal.wc.SVNStatusEditor;
0052:        import org.tmatesoft.svn.core.internal.wc.SVNWCManager;
0053:        import org.tmatesoft.svn.core.internal.wc.admin.SVNLog;
0054:        import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminArea;
0055:        import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaInfo;
0056:        import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
0057:        import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator;
0058:        import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslatorOutputStream;
0059:        import org.tmatesoft.svn.core.internal.wc.admin.SVNVersionedProperties;
0060:        import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
0061:        import org.tmatesoft.svn.core.io.ISVNLockHandler;
0062:        import org.tmatesoft.svn.core.io.SVNRepository;
0063:        import org.tmatesoft.svn.util.SVNDebugLog;
0064:
0065:        /**
0066:         * The <b>SVNWCClient</b> class combines a number of version control 
0067:         * operations mainly intended for local work with Working Copy items. This class
0068:         * includes those operations that are destined only for local work on a 
0069:         * Working Copy as well as those that are moreover able to access  a repository. 
0070:         * 
0071:         * <p>
0072:         * Here's a list of the <b>SVNWCClient</b>'s methods 
0073:         * matched against corresponing commands of the SVN command line 
0074:         * client:
0075:         * 
0076:         * <table cellpadding="3" cellspacing="1" border="0" width="70%" bgcolor="#999933">
0077:         * <tr bgcolor="#ADB8D9" align="left">
0078:         * <td><b>SVNKit</b></td>
0079:         * <td><b>Subversion</b></td>
0080:         * </tr>   
0081:         * <tr bgcolor="#EAEAEA" align="left">
0082:         * <td>doAdd()</td><td>'svn add'</td>
0083:         * </tr>
0084:         * <tr bgcolor="#EAEAEA" align="left">
0085:         * <td>doDelete()</td><td>'svn delete'</td>
0086:         * </tr>
0087:         * <tr bgcolor="#EAEAEA" align="left">
0088:         * <td>doCleanup()</td><td>'svn cleanup'</td>
0089:         * </tr>
0090:         * <tr bgcolor="#EAEAEA" align="left">
0091:         * <td>doInfo()</td><td>'svn info'</td>
0092:         * </tr>
0093:         * <tr bgcolor="#EAEAEA" align="left">
0094:         * <td>doLock()</td><td>'svn lock'</td>
0095:         * </tr>
0096:         * <tr bgcolor="#EAEAEA" align="left">
0097:         * <td>doUnlock()</td><td>'svn unlock'</td>
0098:         * </tr>
0099:         * <tr bgcolor="#EAEAEA" align="left">
0100:         * <td>
0101:         * doSetProperty()
0102:         * </td>
0103:         * <td>
0104:         * 'svn propset PROPNAME PROPVAL PATH'<br />
0105:         * 'svn propdel PROPNAME PATH'<br />
0106:         * 'svn propedit PROPNAME PATH'
0107:         * </td>
0108:         * </tr>
0109:         * <tr bgcolor="#EAEAEA" align="left">
0110:         * <td>doSetRevisionProperty()</td>
0111:         * <td>
0112:         * 'svn propset PROPNAME --revprop -r REV PROPVAL [URL]'<br />
0113:         * 'svn propdel PROPNAME --revprop -r REV [URL]'<br />
0114:         * 'svn propedit PROPNAME --revprop -r REV [URL]'
0115:         * </td>
0116:         * </tr>
0117:         * <tr bgcolor="#EAEAEA" align="left">
0118:         * <td>
0119:         * doGetProperty()
0120:         * </td>
0121:         * <td>
0122:         * 'svn propget PROPNAME PATH'<br />
0123:         * 'svn proplist PATH'
0124:         * </td>
0125:         * <tr bgcolor="#EAEAEA" align="left">
0126:         * <td>doGetRevisionProperty()</td>
0127:         * <td>
0128:         * 'svn propget PROPNAME --revprop -r REV [URL]'<br />
0129:         * 'svn proplist --revprop -r REV [URL]'
0130:         * </td>
0131:         * </tr>
0132:         * </tr>
0133:         * <tr bgcolor="#EAEAEA" align="left">
0134:         * <td>doResolve()</td><td>'svn resolved'</td>
0135:         * </tr>
0136:         * <tr bgcolor="#EAEAEA" align="left">
0137:         * <td>doRevert()</td><td>'svn revert'</td>
0138:         * </tr>
0139:         * </table>
0140:         * 
0141:         * @version 1.1.1
0142:         * @author  TMate Software Ltd.
0143:         * @see     <a target="_top" href="http://svnkit.com/kb/examples/">Examples</a>
0144:         */
0145:        public class SVNWCClient extends SVNBasicClient {
0146:
0147:            public static ISVNAddParameters DEFAULT_ADD_PARAMETERS = new ISVNAddParameters() {
0148:                public Action onInconsistentEOLs(File file) {
0149:                    return ISVNAddParameters.REPORT_ERROR;
0150:                }
0151:            };
0152:
0153:            private ISVNAddParameters myAddParameters;
0154:
0155:            /**
0156:             * Constructs and initializes an <b>SVNWCClient</b> object
0157:             * with the specified run-time configuration and authentication 
0158:             * drivers.
0159:             * 
0160:             * <p>
0161:             * If <code>options</code> is <span class="javakeyword">null</span>,
0162:             * then this <b>SVNWCClient</b> will be using a default run-time
0163:             * configuration driver  which takes client-side settings from the 
0164:             * default SVN's run-time configuration area but is not able to
0165:             * change those settings (read more on {@link ISVNOptions} and {@link SVNWCUtil}).  
0166:             * 
0167:             * <p>
0168:             * If <code>authManager</code> is <span class="javakeyword">null</span>,
0169:             * then this <b>SVNWCClient</b> will be using a default authentication
0170:             * and network layers driver (see {@link SVNWCUtil#createDefaultAuthenticationManager()})
0171:             * which uses server-side settings and auth storage from the 
0172:             * default SVN's run-time configuration area (or system properties
0173:             * if that area is not found).
0174:             * 
0175:             * @param authManager an authentication and network layers driver
0176:             * @param options     a run-time configuration options driver     
0177:             */
0178:            public SVNWCClient(ISVNAuthenticationManager authManager,
0179:                    ISVNOptions options) {
0180:                super (authManager, options);
0181:            }
0182:
0183:            public SVNWCClient(ISVNRepositoryPool repositoryPool,
0184:                    ISVNOptions options) {
0185:                super (repositoryPool, options);
0186:            }
0187:
0188:            public void setAddParameters(ISVNAddParameters addParameters) {
0189:                myAddParameters = addParameters;
0190:            }
0191:
0192:            protected ISVNAddParameters getAddParameters() {
0193:                if (myAddParameters == null) {
0194:                    return DEFAULT_ADD_PARAMETERS;
0195:                }
0196:
0197:                return myAddParameters;
0198:            }
0199:
0200:            /**
0201:             * Gets contents of a file. 
0202:             * If <vode>revision</code> is one of:
0203:             * <ul>
0204:             * <li>{@link SVNRevision#BASE BASE}
0205:             * <li>{@link SVNRevision#WORKING WORKING}
0206:             * <li>{@link SVNRevision#COMMITTED COMMITTED}
0207:             * </ul>
0208:             * then the file contents are taken from the Working Copy file item. 
0209:             * Otherwise the file item's contents are taken from the repository
0210:             * at a particular revision. 
0211:             *  
0212:             * @param  path               a Working Copy file item
0213:             * @param  pegRevision        a revision in which the file item is first looked up
0214:             * @param  revision           a target revision
0215:             * @param  expandKeywords     if <span class="javakeyword">true</span> then
0216:             *                            all keywords presenting in the file and listed in 
0217:             *                            the file's {@link org.tmatesoft.svn.core.SVNProperty#KEYWORDS svn:keywords}
0218:             *                            property (if set) will be substituted, otherwise not 
0219:             * @param  dst                the destination where the file contents will be written to
0220:             * @throws SVNException       if one of the following is true:
0221:             *                            <ul>
0222:             *                            <li><code>path</code> refers to a directory 
0223:             *                            <li><code>path</code> does not exist 
0224:             *                            <li><code>path</code> is not under version control
0225:             *                            </ul>
0226:             * @see                       #doGetFileContents(SVNURL, SVNRevision, SVNRevision, boolean, OutputStream)                           
0227:             */
0228:            public void doGetFileContents(File path, SVNRevision pegRevision,
0229:                    SVNRevision revision, boolean expandKeywords,
0230:                    OutputStream dst) throws SVNException {
0231:                if (dst == null) {
0232:                    return;
0233:                }
0234:                if (revision == null || !revision.isValid()) {
0235:                    revision = SVNRevision.BASE;
0236:                } else if (revision == SVNRevision.COMMITTED) {
0237:                    revision = SVNRevision.BASE;
0238:                }
0239:                if ((!pegRevision.isValid() || pegRevision == SVNRevision.BASE || pegRevision == SVNRevision.WORKING)
0240:                        && (!revision.isValid() || revision == SVNRevision.BASE || revision == SVNRevision.WORKING)) {
0241:                    if (pegRevision == null || !pegRevision.isValid()) {
0242:                        pegRevision = SVNRevision.BASE;
0243:                    } else if (pegRevision == SVNRevision.COMMITTED) {
0244:                        pegRevision = SVNRevision.BASE;
0245:                    }
0246:                    doGetLocalFileContents(path, dst, revision, expandKeywords);
0247:                } else {
0248:                    SVNRepository repos = createRepository(null, path,
0249:                            pegRevision, revision);
0250:                    checkCancelled();
0251:                    long revNumber = getRevisionNumber(revision, repos, path);
0252:                    SVNNodeKind kind = repos.checkPath("", revNumber);
0253:                    if (kind == SVNNodeKind.DIR) {
0254:                        SVNErrorMessage err = SVNErrorMessage.create(
0255:                                SVNErrorCode.CLIENT_IS_DIRECTORY,
0256:                                "URL ''{0}'' refers to a directory", repos
0257:                                        .getLocation());
0258:                        SVNErrorManager.error(err);
0259:                    }
0260:                    checkCancelled();
0261:                    if (!expandKeywords) {
0262:                        repos.getFile("", revNumber, null,
0263:                                new SVNCancellableOutputStream(dst, this ));
0264:                    } else {
0265:                        Map properties = new HashMap();
0266:                        repos.getFile("", revNumber, properties, null);
0267:                        checkCancelled();
0268:
0269:                        String keywords = (String) properties
0270:                                .get(SVNProperty.KEYWORDS);
0271:                        String eol = (String) properties
0272:                                .get(SVNProperty.EOL_STYLE);
0273:                        if (keywords != null || eol != null) {
0274:                            String cmtRev = (String) properties
0275:                                    .get(SVNProperty.COMMITTED_REVISION);
0276:                            String cmtDate = (String) properties
0277:                                    .get(SVNProperty.COMMITTED_DATE);
0278:                            String author = (String) properties
0279:                                    .get(SVNProperty.LAST_AUTHOR);
0280:                            Map keywordsMap = SVNTranslator.computeKeywords(
0281:                                    keywords, expandKeywords ? repos
0282:                                            .getLocation().toString() : null,
0283:                                    author, cmtDate, cmtRev, getOptions());
0284:                            OutputStream translatingStream = new SVNTranslatorOutputStream(
0285:                                    dst, SVNTranslator.getEOL(eol), false,
0286:                                    keywordsMap, expandKeywords);
0287:                            repos.getFile("", revNumber, null,
0288:                                    new SVNCancellableOutputStream(
0289:                                            translatingStream,
0290:                                            getEventDispatcher()));
0291:                            try {
0292:                                translatingStream.close();
0293:                            } catch (IOException e) {
0294:                                SVNErrorManager.error(SVNErrorMessage.create(
0295:                                        SVNErrorCode.IO_ERROR, e.getMessage()));
0296:                            }
0297:                        } else {
0298:                            repos.getFile("", revNumber, null,
0299:                                    new SVNCancellableOutputStream(dst,
0300:                                            getEventDispatcher()));
0301:                        }
0302:                    }
0303:                    try {
0304:                        dst.flush();
0305:                    } catch (IOException e) {
0306:                        SVNErrorManager.error(SVNErrorMessage.create(
0307:                                SVNErrorCode.IO_ERROR, e.getMessage()));
0308:                    }
0309:                }
0310:            }
0311:
0312:            /**
0313:             * Gets contents of a file of a particular revision from a repository. 
0314:             * 
0315:             * @param  url                a file item's repository location 
0316:             * @param  pegRevision        a revision in which the file item is first looked up
0317:             * @param  revision           a target revision
0318:             * @param  expandKeywords     if <span class="javakeyword">true</span> then
0319:             *                            all keywords presenting in the file and listed in 
0320:             *                            the file's {@link org.tmatesoft.svn.core.SVNProperty#KEYWORDS svn:keywords}
0321:             *                            property (if set) will be substituted, otherwise not 
0322:             * @param  dst                the destination where the file contents will be written to
0323:             * @throws SVNException       if one of the following is true:
0324:             *                            <ul>
0325:             *                            <li><code>url</code> refers to a directory 
0326:             *                            <li>it's impossible to create temporary files
0327:             *                            ({@link java.io.File#createTempFile(java.lang.String, java.lang.String) createTempFile()}
0328:             *                            fails) necessary for file translating
0329:             *                            </ul> 
0330:             * @see                       #doGetFileContents(File, SVNRevision, SVNRevision, boolean, OutputStream)                           
0331:             */
0332:            public void doGetFileContents(SVNURL url, SVNRevision pegRevision,
0333:                    SVNRevision revision, boolean expandKeywords,
0334:                    OutputStream dst) throws SVNException {
0335:                revision = revision == null || !revision.isValid() ? SVNRevision.HEAD
0336:                        : revision;
0337:                // now get contents from URL.
0338:                SVNRepository repos = createRepository(url, null, pegRevision,
0339:                        revision);
0340:                checkCancelled();
0341:                long revNumber = getRevisionNumber(revision, repos, null);
0342:                checkCancelled();
0343:                SVNNodeKind nodeKind = repos.checkPath("", revNumber);
0344:                checkCancelled();
0345:                if (nodeKind == SVNNodeKind.DIR) {
0346:                    SVNErrorMessage err = SVNErrorMessage.create(
0347:                            SVNErrorCode.CLIENT_IS_DIRECTORY,
0348:                            "URL ''{0}'' refers to a directory", url,
0349:                            SVNErrorMessage.TYPE_WARNING);
0350:                    SVNErrorManager.error(err);
0351:                }
0352:                checkCancelled();
0353:                if (!expandKeywords) {
0354:                    repos.getFile("", revNumber, null,
0355:                            new SVNCancellableOutputStream(dst, this ));
0356:                } else {
0357:                    Map properties = new HashMap();
0358:                    repos.getFile("", revNumber, properties, null);
0359:                    checkCancelled();
0360:
0361:                    String keywords = (String) properties
0362:                            .get(SVNProperty.KEYWORDS);
0363:                    String eol = (String) properties.get(SVNProperty.EOL_STYLE);
0364:                    if (keywords != null || eol != null) {
0365:                        String cmtRev = (String) properties
0366:                                .get(SVNProperty.COMMITTED_REVISION);
0367:                        String cmtDate = (String) properties
0368:                                .get(SVNProperty.COMMITTED_DATE);
0369:                        String author = (String) properties
0370:                                .get(SVNProperty.LAST_AUTHOR);
0371:                        Map keywordsMap = SVNTranslator.computeKeywords(
0372:                                keywords, expandKeywords ? repos.getLocation()
0373:                                        .toString() : null, author, cmtDate,
0374:                                cmtRev, getOptions());
0375:                        OutputStream translatingStream = new SVNTranslatorOutputStream(
0376:                                dst, SVNTranslator.getEOL(eol), false,
0377:                                keywordsMap, expandKeywords);
0378:                        repos
0379:                                .getFile("", revNumber, null,
0380:                                        new SVNCancellableOutputStream(
0381:                                                translatingStream,
0382:                                                getEventDispatcher()));
0383:                        try {
0384:                            translatingStream.close();
0385:                        } catch (IOException e) {
0386:                            SVNErrorManager.error(SVNErrorMessage.create(
0387:                                    SVNErrorCode.IO_ERROR, e.getMessage()));
0388:                        }
0389:                    } else {
0390:                        repos.getFile("", revNumber, null,
0391:                                new SVNCancellableOutputStream(dst,
0392:                                        getEventDispatcher()));
0393:                    }
0394:                }
0395:                try {
0396:                    dst.flush();
0397:                } catch (IOException e) {
0398:                    SVNErrorManager.error(SVNErrorMessage.create(
0399:                            SVNErrorCode.IO_ERROR, e.getMessage()));
0400:                }
0401:            }
0402:
0403:            /**
0404:             * Recursively cleans up the working copy, removing locks and resuming 
0405:             * unfinished operations. 
0406:             * 
0407:             * <p>
0408:             * If you ever get a "working copy locked" error, use this method 
0409:             * to remove stale locks and get your working copy into a usable 
0410:             * state again.
0411:             * 
0412:             * @param  path             a WC path to start a cleanup from 
0413:             * @throws SVNException     if one of the following is true:
0414:             *                          <ul>
0415:             *                          <li><code>path</code> does not exist
0416:             *                          <li><code>path</code>'s parent directory
0417:             *                          is not under version control
0418:             *                          </ul>
0419:             */
0420:            public void doCleanup(File path) throws SVNException {
0421:                doCleanup(path, false);
0422:            }
0423:
0424:            public void doCleanup(File path, boolean deleteWCProperties)
0425:                    throws SVNException {
0426:                SVNFileType fType = SVNFileType.getType(path);
0427:                if (fType == SVNFileType.NONE) {
0428:                    SVNErrorMessage err = SVNErrorMessage.create(
0429:                            SVNErrorCode.WC_PATH_NOT_FOUND,
0430:                            "''{0}'' does not exist", path);
0431:                    SVNErrorManager.error(err);
0432:                } else if (fType == SVNFileType.FILE
0433:                        || fType == SVNFileType.SYMLINK) {
0434:                    path = path.getParentFile();
0435:                }
0436:                SVNWCAccess wcAccess = createWCAccess();
0437:                try {
0438:                    SVNAdminArea adminArea = wcAccess.open(path, true, true, 0);
0439:                    adminArea.cleanup();
0440:                    if (deleteWCProperties) {
0441:                        SVNPropertiesManager.deleteWCProperties(adminArea,
0442:                                null, true);
0443:                    }
0444:                } catch (SVNException e) {
0445:                    if (e instanceof  SVNCancelException) {
0446:                        throw e;
0447:                    } else if (!SVNAdminArea.isSafeCleanup()) {
0448:                        throw e;
0449:                    }
0450:                    SVNDebugLog.getDefaultLog().info(
0451:                            "CLEANUP FAILED for " + path);
0452:                    SVNDebugLog.getDefaultLog().info(e);
0453:                } finally {
0454:                    wcAccess.close();
0455:                    sleepForTimeStamp();
0456:                }
0457:            }
0458:
0459:            /**
0460:             * Sets, edits or deletes a property on a file or directory item(s).
0461:             * 
0462:             * <p> 
0463:             * To set or edit a property simply provide a <code>propName</code> 
0464:             * and a <code>propValue</code>. To delete a property set 
0465:             * <code>propValue</code> to <span class="javakeyword">null</span> 
0466:             * and the property <code>propName</code> will be deleted.
0467:             * 
0468:             * @param  path             a WC item which properties are to be 
0469:             *                          modified
0470:             * @param  propName         a property name
0471:             * @param  propValue        a property value
0472:             * @param  force            <span class="javakeyword">true</span> to
0473:             *                          force the operation to run
0474:             * @param  recursive        <span class="javakeyword">true</span> to
0475:             *                          descend recursively
0476:             * @param  handler          a caller's property handler
0477:             * @throws SVNException     if one of the following is true:
0478:             *                          <ul>
0479:             *                          <li><code>propName</code> is a revision 
0480:             *                          property 
0481:             *                          <li><code>propName</code> starts
0482:             *                          with the {@link org.tmatesoft.svn.core.SVNProperty#SVN_WC_PREFIX
0483:             *                          svn:wc:} prefix
0484:             *                          </ul>
0485:             * @see                     #doSetRevisionProperty(File, SVNRevision, String, String, boolean, ISVNPropertyHandler)
0486:             * @see                     #doGetProperty(File, String, SVNRevision, SVNRevision, boolean)
0487:             * @see                     #doGetRevisionProperty(File, String, SVNRevision, ISVNPropertyHandler)
0488:             */
0489:            public void doSetProperty(File path, String propName,
0490:                    String propValue, boolean force, boolean recursive,
0491:                    ISVNPropertyHandler handler) throws SVNException {
0492:                propName = validatePropertyName(propName);
0493:                if (SVNRevisionProperty.isRevisionProperty(propName)) {
0494:                    SVNErrorMessage err = SVNErrorMessage
0495:                            .create(
0496:                                    SVNErrorCode.CLIENT_PROPERTY_NAME,
0497:                                    "Revision property ''{0}'' not allowed in this context",
0498:                                    propName);
0499:                    SVNErrorManager.error(err);
0500:                } else if (SVNProperty.isWorkingCopyProperty(propName)) {
0501:                    SVNErrorMessage err = SVNErrorMessage
0502:                            .create(
0503:                                    SVNErrorCode.CLIENT_PROPERTY_NAME,
0504:                                    "''{0}'' is a wcprop, thus not accessible to clients",
0505:                                    propName);
0506:                    SVNErrorManager.error(err);
0507:                } else if (SVNProperty.isEntryProperty(propName)) {
0508:                    SVNErrorMessage err = SVNErrorMessage
0509:                            .create(
0510:                                    SVNErrorCode.CLIENT_PROPERTY_NAME,
0511:                                    "''{0}'' is an entry property, thus not accessible to clients",
0512:                                    propName);
0513:                    SVNErrorManager.error(err);
0514:                }
0515:                propValue = validatePropertyValue(propName, propValue, force);
0516:                SVNWCAccess wcAccess = createWCAccess();
0517:                try {
0518:                    SVNAdminArea area = wcAccess.probeOpen(path, true,
0519:                            recursive ? SVNWCAccess.INFINITE_DEPTH : 1);//wcAccess.open(path, true, recursive ? SVNWCAccess2.INFINITE_DEPTH : 1);
0520:                    SVNEntry entry = wcAccess.getEntry(path, false);
0521:                    if (entry == null) {
0522:                        SVNErrorMessage err = SVNErrorMessage.create(
0523:                                SVNErrorCode.UNVERSIONED_RESOURCE,
0524:                                "''{0}'' is not under version control", path);
0525:                        SVNErrorManager.error(err);
0526:                    }
0527:                    doSetLocalProperty(area, entry.isDirectory() ? area
0528:                            .getThisDirName() : entry.getName(), propName,
0529:                            propValue, force, recursive, true, handler);
0530:                } finally {
0531:                    wcAccess.close();
0532:                }
0533:            }
0534:
0535:            /**
0536:             * Sets, edits or deletes an unversioned revision property.
0537:             * This method uses a Working Copy item to obtain the URL of 
0538:             * the repository which revision properties are to be changed.
0539:             * 
0540:             * <p> 
0541:             * To set or edit a property simply provide a <code>propName</code> 
0542:             * and a <code>propValue</code>. To delete a revision property set 
0543:             * <code>propValue</code> to <span class="javakeyword">null</span> 
0544:             * and the property <code>propName</code> will be deleted.
0545:             * 
0546:             * @param  path            a Working Copy item           
0547:             * @param  revision        a revision which properties are to be
0548:             *                         modified
0549:             * @param  propName        a property name
0550:             * @param  propValue       a property value
0551:             * @param  force           <span class="javakeyword">true</span> to
0552:             *                         force the operation to run
0553:             * @param  handler         a caller's property handler
0554:             * @throws SVNException    if one of the following is true:
0555:             *                         <ul>
0556:             *                         <li>the operation can not be performed 
0557:             *                         without forcing 
0558:             *                         <li><code>propName</code> starts
0559:             *                         with the {@link org.tmatesoft.svn.core.SVNProperty#SVN_WC_PREFIX
0560:             *                         svn:wc:} prefix
0561:             *                         </ul>
0562:             * @see                    #doSetRevisionProperty(SVNURL, SVNRevision, String, String, boolean, ISVNPropertyHandler)
0563:             * @see                    #doSetProperty(File, String, String, boolean, boolean, ISVNPropertyHandler)
0564:             * @see                    #doGetProperty(File, String, SVNRevision, SVNRevision, boolean)
0565:             * @see                    #doGetRevisionProperty(File, String, SVNRevision, ISVNPropertyHandler)                         
0566:             */
0567:            public void doSetRevisionProperty(File path, SVNRevision revision,
0568:                    String propName, String propValue, boolean force,
0569:                    ISVNPropertyHandler handler) throws SVNException {
0570:                propName = validatePropertyName(propName);
0571:                propValue = validatePropertyValue(propName, propValue, force);
0572:                SVNURL url = getURL(path);
0573:                doSetRevisionProperty(url, revision, propName, propValue,
0574:                        force, handler);
0575:            }
0576:
0577:            /**
0578:             * Sets, edits or deletes an unversioned revision property.
0579:             * This method uses a URL pointing to a repository which revision 
0580:             * properties are to be changed.
0581:             * 
0582:             * <p> 
0583:             * To set or edit a property simply provide a <code>propName</code> 
0584:             * and a <code>propValue</code>. To delete a revision property set 
0585:             * <code>propValue</code> to <span class="javakeyword">null</span> 
0586:             * and the property <code>propName</code> will be deleted.
0587:             * 
0588:             * @param  url             a URL pointing to a repository location
0589:             * @param  revision        a revision which properties are to be
0590:             *                         modified
0591:             * @param  propName        a property name
0592:             * @param  propValue       a property value
0593:             * @param  force           <span class="javakeyword">true</span> to
0594:             *                         force the operation to run
0595:             * @param  handler         a caller's property handler
0596:             * @throws SVNException    if one of the following is true:
0597:             *                         <ul>
0598:             *                         <li>the operation can not be performed 
0599:             *                         without forcing 
0600:             *                         <li><code>propName</code> starts
0601:             *                         with the {@link org.tmatesoft.svn.core.SVNProperty#SVN_WC_PREFIX
0602:             *                         svn:wc:} prefix
0603:             *                         </ul>
0604:             * @see                    #doSetRevisionProperty(File, SVNRevision, String, String, boolean, ISVNPropertyHandler)
0605:             * @see                    #doSetProperty(File, String, String, boolean, boolean, ISVNPropertyHandler)
0606:             * @see                    #doGetProperty(File, String, SVNRevision, SVNRevision, boolean)
0607:             * @see                    #doGetRevisionProperty(File, String, SVNRevision, ISVNPropertyHandler)                         
0608:             */
0609:            public void doSetRevisionProperty(SVNURL url, SVNRevision revision,
0610:                    String propName, String propValue, boolean force,
0611:                    ISVNPropertyHandler handler) throws SVNException {
0612:                propName = validatePropertyName(propName);
0613:                propValue = validatePropertyValue(propName, propValue, force);
0614:                if (!force && SVNRevisionProperty.AUTHOR.equals(propName)
0615:                        && propValue != null && propValue.indexOf('\n') >= 0) {
0616:                    SVNErrorMessage err = SVNErrorMessage
0617:                            .create(
0618:                                    SVNErrorCode.CLIENT_REVISION_AUTHOR_CONTAINS_NEWLINE,
0619:                                    "Value will not be set unless forced");
0620:                    SVNErrorManager.error(err);
0621:                }
0622:                if (propName.startsWith(SVNProperty.SVN_WC_PREFIX)) {
0623:                    SVNErrorMessage err = SVNErrorMessage
0624:                            .create(
0625:                                    SVNErrorCode.CLIENT_PROPERTY_NAME,
0626:                                    "''{0}'' is a wcprop , thus not accessible to clients",
0627:                                    propName);
0628:                    SVNErrorManager.error(err);
0629:                }
0630:                SVNRepository repos = createRepository(url, null,
0631:                        SVNRevision.UNDEFINED, revision);
0632:                long revNumber = getRevisionNumber(revision, repos, null);
0633:                repos.setRevisionPropertyValue(revNumber, propName, propValue);
0634:                if (handler != null) {
0635:                    handler.handleProperty(revNumber, new SVNPropertyData(
0636:                            propName, propValue));
0637:                }
0638:            }
0639:
0640:            /**
0641:             * Gets an item's versioned property. It's possible to get either a local 
0642:             * property (from a Working Copy) or a remote one (located in a repository). 
0643:             * If <vode>revision</code> is one of:
0644:             * <ul>
0645:             * <li>{@link SVNRevision#BASE BASE}
0646:             * <li>{@link SVNRevision#WORKING WORKING}
0647:             * <li>{@link SVNRevision#COMMITTED COMMITTED}
0648:             * </ul>
0649:             * then the result is a WC item's property. Otherwise the 
0650:             * property is taken from a repository (using the item's URL). 
0651:             * 
0652:             * @param  path           a WC item's path
0653:             * @param  propName       an item's property name; if it's 
0654:             *                        <span class="javakeyword">null</span> then
0655:             *                        all the item's properties will be retrieved
0656:             *                        but only the first of them returned 
0657:             *                        
0658:             * @param  pegRevision    a revision in which the item is first looked up
0659:             * @param  revision       a target revision; 
0660:             *                         
0661:             * @param  recursive      <span class="javakeyword">true</span> to
0662:             *                        descend recursively
0663:             * @return                the item's property
0664:             * @throws SVNException   if one of the following is true:
0665:             *                        <ul>
0666:             *                        <li><code>propName</code> starts
0667:             *                        with the {@link org.tmatesoft.svn.core.SVNProperty#SVN_WC_PREFIX
0668:             *                        svn:wc:} prefix 
0669:             *                        <li><code>path</code> is not under version control
0670:             *                        </ul>
0671:             * @see                   #doGetProperty(File, String, SVNRevision, SVNRevision, boolean, ISVNPropertyHandler)
0672:             * @see                   #doSetProperty(File, String, String, boolean, boolean, ISVNPropertyHandler)
0673:             */
0674:            public SVNPropertyData doGetProperty(final File path,
0675:                    String propName, SVNRevision pegRevision,
0676:                    SVNRevision revision, boolean recursive)
0677:                    throws SVNException {
0678:                final SVNPropertyData[] data = new SVNPropertyData[1];
0679:                doGetProperty(path, propName, pegRevision, revision, recursive,
0680:                        new ISVNPropertyHandler() {
0681:                            public void handleProperty(File file,
0682:                                    SVNPropertyData property) {
0683:                                if (data[0] == null && path.equals(file)) {
0684:                                    data[0] = property;
0685:                                }
0686:                            }
0687:
0688:                            public void handleProperty(SVNURL url,
0689:                                    SVNPropertyData property) {
0690:                            }
0691:
0692:                            public void handleProperty(long revision,
0693:                                    SVNPropertyData property) {
0694:                            }
0695:                        });
0696:                return data[0];
0697:            }
0698:
0699:            /**
0700:             * Gets an item's versioned property from a repository.  
0701:             * This method is useful when having no Working Copy at all.
0702:             * 
0703:             * @param  url             an item's repository location
0704:             * @param  propName        an item's property name; if it's 
0705:             *                         <span class="javakeyword">null</span> then
0706:             *                         all the item's properties will be retrieved
0707:             *                         but only the first of them returned
0708:             * @param  pegRevision     a revision in which the item is first looked up
0709:             * @param  revision        a target revision
0710:             * @param  recursive       <span class="javakeyword">true</span> to
0711:             *                         descend recursively
0712:             * @return                 the item's property
0713:             * @throws SVNException    if <code>propName</code> starts
0714:             *                         with the {@link org.tmatesoft.svn.core.SVNProperty#SVN_WC_PREFIX
0715:             *                         svn:wc:} prefix
0716:             * @see                    #doGetProperty(SVNURL, String, SVNRevision, SVNRevision, boolean, ISVNPropertyHandler)
0717:             * @see                    #doSetProperty(File, String, String, boolean, boolean, ISVNPropertyHandler)
0718:             */
0719:            public SVNPropertyData doGetProperty(final SVNURL url,
0720:                    String propName, SVNRevision pegRevision,
0721:                    SVNRevision revision, boolean recursive)
0722:                    throws SVNException {
0723:                final SVNPropertyData[] data = new SVNPropertyData[1];
0724:                doGetProperty(url, propName, pegRevision, revision, recursive,
0725:                        new ISVNPropertyHandler() {
0726:                            public void handleProperty(File file,
0727:                                    SVNPropertyData property) {
0728:                            }
0729:
0730:                            public void handleProperty(long revision,
0731:                                    SVNPropertyData property) {
0732:                            }
0733:
0734:                            public void handleProperty(SVNURL location,
0735:                                    SVNPropertyData property)
0736:                                    throws SVNException {
0737:                                if (data[0] == null
0738:                                        && url.toString().equals(
0739:                                                location.toString())) {
0740:                                    data[0] = property;
0741:                                }
0742:                            }
0743:                        });
0744:                return data[0];
0745:            }
0746:
0747:            /**
0748:             * Gets an item's versioned property and passes it to a provided property
0749:             * handler. It's possible to get either a local property (from a Working 
0750:             * Copy) or a remote one (located in a repository). 
0751:             * If <vode>revision</code> is one of:
0752:             * <ul>
0753:             * <li>{@link SVNRevision#BASE BASE}
0754:             * <li>{@link SVNRevision#WORKING WORKING}
0755:             * <li>{@link SVNRevision#COMMITTED COMMITTED}
0756:             * </ul>
0757:             * then the result is a WC item's property. Otherwise the 
0758:             * property is taken from a repository (using the item's URL). 
0759:             * 
0760:             * @param  path           a WC item's path
0761:             * @param  propName       an item's property name; if it's 
0762:             *                        <span class="javakeyword">null</span> then
0763:             *                        all the item's properties will be retrieved
0764:             *                        and passed to <code>handler</code> for
0765:             *                        processing 
0766:             * @param  pegRevision    a revision in which the item is first looked up
0767:             * @param  revision       a target revision; 
0768:             *                         
0769:             * @param  recursive      <span class="javakeyword">true</span> to
0770:             *                        descend recursively
0771:             * @param  handler        a caller's property handler
0772:             * @throws SVNException   if one of the following is true:
0773:             *                        <ul>
0774:             *                        <li><code>propName</code> starts
0775:             *                        with the {@link org.tmatesoft.svn.core.SVNProperty#SVN_WC_PREFIX
0776:             *                        svn:wc:} prefix 
0777:             *                        <li><code>path</code> is not under version control
0778:             *                        </ul>
0779:             * @see                   #doGetProperty(File, String, SVNRevision, SVNRevision, boolean)
0780:             * @see                   #doSetProperty(File, String, String, boolean, boolean, ISVNPropertyHandler)
0781:             */
0782:            public void doGetProperty(File path, String propName,
0783:                    SVNRevision pegRevision, SVNRevision revision,
0784:                    boolean recursive, ISVNPropertyHandler handler)
0785:                    throws SVNException {
0786:                if (propName != null
0787:                        && propName.startsWith(SVNProperty.SVN_WC_PREFIX)) {
0788:                    SVNErrorMessage err = SVNErrorMessage
0789:                            .create(
0790:                                    SVNErrorCode.CLIENT_PROPERTY_NAME,
0791:                                    "''{0}'' is a wcprop , thus not accessible to clients",
0792:                                    propName);
0793:                    SVNErrorManager.error(err);
0794:                }
0795:                if (revision == null || !revision.isValid()) {
0796:                    revision = SVNRevision.WORKING;
0797:                }
0798:                SVNWCAccess wcAccess = createWCAccess();
0799:
0800:                try {
0801:                    SVNAdminArea area = wcAccess.probeOpen(path, false,
0802:                            recursive ? SVNWCAccess.INFINITE_DEPTH : 0);
0803:                    SVNEntry entry = wcAccess.getEntry(path, false);
0804:                    if (entry == null) {
0805:                        SVNErrorMessage err = SVNErrorMessage.create(
0806:                                SVNErrorCode.ENTRY_NOT_FOUND,
0807:                                "''{0}'' is not under version control", path);
0808:                        SVNErrorManager.error(err);
0809:                    }
0810:                    if (revision != SVNRevision.WORKING
0811:                            && revision != SVNRevision.BASE
0812:                            && revision != SVNRevision.COMMITTED) {
0813:                        SVNURL url = entry.getSVNURL();
0814:                        SVNRepository repository = createRepository(null, path,
0815:                                pegRevision, revision);
0816:                        long revisionNumber = getRevisionNumber(revision,
0817:                                repository, path);
0818:                        revision = SVNRevision.create(revisionNumber);
0819:                        doGetRemoteProperty(url, "", repository, propName,
0820:                                revision, recursive, handler);
0821:                    } else {
0822:                        boolean base = revision == SVNRevision.BASE;
0823:                        if (entry.getKind() == SVNNodeKind.DIR && recursive) {
0824:                            // area is path itself.
0825:                            doGetLocalProperty(area, propName, base, handler);
0826:                        } else {
0827:                            // area could only be path itself or child file in it.
0828:                            if ((base && entry.isScheduledForAddition())
0829:                                    || (!base && entry.isScheduledForDeletion())) {
0830:                                return;
0831:                            }
0832:                            SVNVersionedProperties properties = base ? area
0833:                                    .getBaseProperties(entry.getName()) : area
0834:                                    .getProperties(entry.getName());
0835:                            if (propName != null) {
0836:                                String propValue = properties
0837:                                        .getPropertyValue(propName);
0838:                                if (propValue != null) {
0839:                                    handler.handleProperty(path,
0840:                                            new SVNPropertyData(propName,
0841:                                                    propValue));
0842:                                }
0843:                            } else {
0844:                                Map allProps = properties.asMap();
0845:                                for (Iterator names = allProps.keySet()
0846:                                        .iterator(); names.hasNext();) {
0847:                                    String name = (String) names.next();
0848:                                    String val = (String) allProps.get(name);
0849:                                    handler.handleProperty(area.getFile(entry
0850:                                            .getName()), new SVNPropertyData(
0851:                                            name, val));
0852:                                }
0853:                            }
0854:                        }
0855:                    }
0856:                } finally {
0857:                    wcAccess.close();
0858:                }
0859:            }
0860:
0861:            /**
0862:             * Gets an item's versioned property from a repository and passes it to 
0863:             * a provided property handler. This method is useful when having no 
0864:             * Working Copy at all.
0865:             * 
0866:             * @param  url             an item's repository location
0867:             * @param  propName        an item's property name; if it's 
0868:             *                         <span class="javakeyword">null</span> then
0869:             *                         all the item's properties will be retrieved
0870:             *                         and passed to <code>handler</code> for
0871:             *                         processing
0872:             * @param  pegRevision     a revision in which the item is first looked up
0873:             * @param  revision        a target revision
0874:             * @param  recursive       <span class="javakeyword">true</span> to
0875:             *                         descend recursively
0876:             * @param  handler         a caller's property handler
0877:             * @throws SVNException    if <code>propName</code> starts
0878:             *                         with the {@link org.tmatesoft.svn.core.SVNProperty#SVN_WC_PREFIX
0879:             *                         svn:wc:} prefix
0880:             * @see                    #doGetProperty(SVNURL, String, SVNRevision, SVNRevision, boolean)
0881:             * @see                    #doSetProperty(File, String, String, boolean, boolean, ISVNPropertyHandler)
0882:             */
0883:            public void doGetProperty(SVNURL url, String propName,
0884:                    SVNRevision pegRevision, SVNRevision revision,
0885:                    boolean recursive, ISVNPropertyHandler handler)
0886:                    throws SVNException {
0887:                if (propName != null
0888:                        && propName.startsWith(SVNProperty.SVN_WC_PREFIX)) {
0889:                    SVNErrorMessage err = SVNErrorMessage
0890:                            .create(
0891:                                    SVNErrorCode.CLIENT_PROPERTY_NAME,
0892:                                    "''{0}'' is a wcprop , thus not accessible to clients",
0893:                                    propName);
0894:                    SVNErrorManager.error(err);
0895:                }
0896:                if (revision == null || !revision.isValid()) {
0897:                    revision = SVNRevision.HEAD;
0898:                }
0899:                SVNRepository repos = createRepository(url, null, pegRevision,
0900:                        revision);
0901:                doGetRemoteProperty(url, "", repos, propName, revision,
0902:                        recursive, handler);
0903:            }
0904:
0905:            /**
0906:             * Gets an unversioned revision property from a repository (getting
0907:             * a repository URL from a Working Copy) and passes it to a provided 
0908:             * property handler. 
0909:             *  
0910:             * @param  path             a local Working Copy item which repository
0911:             *                          location is used to connect to a repository 
0912:             * @param  propName         a revision property name; if this parameter 
0913:             *                          is <span class="javakeyword">null</span> then
0914:             *                          all the revision properties will be retrieved
0915:             *                          and passed to <code>handler</code> for
0916:             *                          processing
0917:             * @param  revision         a revision which property is to be retrieved  
0918:             * @param  handler          a caller's property handler
0919:             * @throws SVNException     if one of the following is true:
0920:             *                          <ul>
0921:             *                          <li><code>revision</code> is invalid 
0922:             *                          <li><code>propName</code> starts with the 
0923:             *                          {@link org.tmatesoft.svn.core.SVNProperty#SVN_WC_PREFIX
0924:             *                          svn:wc:} prefix
0925:             *                          </ul>
0926:             * @see                     #doGetRevisionProperty(SVNURL, String, SVNRevision, ISVNPropertyHandler)
0927:             * @see                     #doSetRevisionProperty(File, SVNRevision, String, String, boolean, ISVNPropertyHandler)
0928:             */
0929:            public void doGetRevisionProperty(File path, String propName,
0930:                    SVNRevision revision, ISVNPropertyHandler handler)
0931:                    throws SVNException {
0932:                if (propName != null
0933:                        && propName.startsWith(SVNProperty.SVN_WC_PREFIX)) {
0934:                    SVNErrorMessage err = SVNErrorMessage
0935:                            .create(
0936:                                    SVNErrorCode.CLIENT_PROPERTY_NAME,
0937:                                    "''{0}'' is a wcprop , thus not accessible to clients",
0938:                                    propName);
0939:                    SVNErrorManager.error(err);
0940:                }
0941:                if (!revision.isValid()) {
0942:                    SVNErrorMessage err = SVNErrorMessage
0943:                            .create(SVNErrorCode.CLIENT_BAD_REVISION,
0944:                                    "Valid revision have to be specified to fetch revision property");
0945:                    SVNErrorManager.error(err);
0946:                }
0947:                SVNRepository repository = createRepository(null, path,
0948:                        SVNRevision.UNDEFINED, revision);
0949:                long revisionNumber = getRevisionNumber(revision, repository,
0950:                        path);
0951:                doGetRevisionProperty(repository, propName, revisionNumber,
0952:                        handler);
0953:            }
0954:
0955:            /**
0956:             * Gets an unversioned revision property from a repository and passes 
0957:             * it to a provided property handler. 
0958:             * 
0959:             * @param  url              a URL pointing to a repository location
0960:             *                          which revision property is to be got
0961:             * @param  propName         a revision property name; if this parameter 
0962:             *                          is <span class="javakeyword">null</span> then
0963:             *                          all the revision properties will be retrieved
0964:             *                          and passed to <code>handler</code> for
0965:             *                          processing
0966:             * @param  revision         a revision which property is to be retrieved  
0967:             * @param  handler          a caller's property handler
0968:             * @throws SVNException     if one of the following is true:
0969:             *                          <ul>
0970:             *                          <li><code>revision</code> is invalid 
0971:             *                          <li><code>propName</code> starts with the 
0972:             *                          {@link org.tmatesoft.svn.core.SVNProperty#SVN_WC_PREFIX
0973:             *                          svn:wc:} prefix
0974:             *                          </ul>
0975:             * @see                     #doGetRevisionProperty(File, String, SVNRevision, ISVNPropertyHandler)
0976:             * @see                     #doSetRevisionProperty(SVNURL, SVNRevision, String, String, boolean, ISVNPropertyHandler)
0977:             */
0978:            public void doGetRevisionProperty(SVNURL url, String propName,
0979:                    SVNRevision revision, ISVNPropertyHandler handler)
0980:                    throws SVNException {
0981:                if (propName != null
0982:                        && propName.startsWith(SVNProperty.SVN_WC_PREFIX)) {
0983:                    SVNErrorMessage err = SVNErrorMessage
0984:                            .create(
0985:                                    SVNErrorCode.CLIENT_PROPERTY_NAME,
0986:                                    "''{0}'' is a wcprop , thus not accessible to clients",
0987:                                    propName);
0988:                    SVNErrorManager.error(err);
0989:                }
0990:                if (!revision.isValid()) {
0991:                    SVNErrorMessage err = SVNErrorMessage
0992:                            .create(SVNErrorCode.CLIENT_BAD_REVISION,
0993:                                    "Valid revision have to be specified to fetch revision property");
0994:                    SVNErrorManager.error(err);
0995:                }
0996:                SVNRepository repos = createRepository(url, true);
0997:                long revNumber = getRevisionNumber(revision, repos, null);
0998:                doGetRevisionProperty(repos, propName, revNumber, handler);
0999:            }
1000:
1001:            private void doGetRevisionProperty(SVNRepository repos,
1002:                    String propName, long revNumber, ISVNPropertyHandler handler)
1003:                    throws SVNException {
1004:                if (propName != null) {
1005:                    String value = repos.getRevisionPropertyValue(revNumber,
1006:                            propName);
1007:                    if (value != null) {
1008:                        handler.handleProperty(revNumber, new SVNPropertyData(
1009:                                propName, value));
1010:                    }
1011:                } else {
1012:                    Map props = new HashMap();
1013:                    repos.getRevisionProperties(revNumber, props);
1014:                    for (Iterator names = props.keySet().iterator(); names
1015:                            .hasNext();) {
1016:                        String name = (String) names.next();
1017:                        String value = (String) props.get(name);
1018:                        handler.handleProperty(revNumber, new SVNPropertyData(
1019:                                name, value));
1020:                    }
1021:                }
1022:            }
1023:
1024:            /**
1025:             * Schedules a Working Copy item for deletion.
1026:             * 
1027:             * @param  path           a WC item to be deleted 
1028:             * @param  force          <span class="javakeyword">true</span> to
1029:             *                        force the operation to run
1030:             * @param  dryRun         <span class="javakeyword">true</span> only to
1031:             *                        try the delete operation without actual deleting
1032:             * @throws SVNException   if one of the following is true:
1033:             *                        <ul>
1034:             *                        <li><code>path</code> is not under version control
1035:             *                        <li>can not delete <code>path</code> without forcing
1036:             *                        </ul>
1037:             * @see                   #doDelete(File, boolean, boolean, boolean)
1038:             */
1039:            public void doDelete(File path, boolean force, boolean dryRun)
1040:                    throws SVNException {
1041:                doDelete(path, force, true, dryRun);
1042:            }
1043:
1044:            /**
1045:             * Schedules a Working Copy item for deletion. This method allows to
1046:             * choose - whether file item(s) are to be deleted from the filesystem or 
1047:             * not. Another version of the {@link #doDelete(File, boolean, boolean) doDelete()}
1048:             * method is similar to the corresponding SVN client's command - <code>'svn delete'</code> 
1049:             * as it always deletes files from the filesystem.
1050:             * 
1051:             * 
1052:             * @param  path           a WC item to be deleted 
1053:             * @param  force          <span class="javakeyword">true</span> to
1054:             *                        force the operation to run
1055:             * @param  deleteFiles    if <span class="javakeyword">true</span> then
1056:             *                        files will be scheduled for deletion as well as
1057:             *                        deleted from the filesystem, otherwise files will
1058:             *                        be only scheduled for addition and still be present
1059:             *                        in the filesystem
1060:             * @param  dryRun         <span class="javakeyword">true</span> only to
1061:             *                        try the delete operation without actual deleting
1062:             * @throws SVNException   if one of the following is true:
1063:             *                        <ul>
1064:             *                        <li><code>path</code> is not under version control
1065:             *                        <li>can not delete <code>path</code> without forcing
1066:             *                        </ul>
1067:             */
1068:            public void doDelete(File path, boolean force, boolean deleteFiles,
1069:                    boolean dryRun) throws SVNException {
1070:                SVNWCAccess wcAccess = createWCAccess();
1071:                path = new File(SVNPathUtil.validateFilePath(path
1072:                        .getAbsolutePath())).getAbsoluteFile();
1073:                try {
1074:                    if (!force) {
1075:                        SVNWCManager.canDelete(path, getOptions(), this );
1076:                    }
1077:                    SVNAdminArea root = wcAccess.open(path.getParentFile(),
1078:                            true, 0);
1079:                    if (!dryRun) {
1080:                        SVNWCManager.delete(wcAccess, root, path, deleteFiles,
1081:                                true);
1082:                    }
1083:                } finally {
1084:                    wcAccess.close();
1085:                }
1086:            }
1087:
1088:            /**
1089:             * Schedules an unversioned item for addition to a repository thus 
1090:             * putting it under version control.
1091:             * 
1092:             * <p>
1093:             * To create and add to version control a new directory, set <code>mkdir</code>
1094:             * to <span class="javakeyword">true</span>. 
1095:             * 
1096:             * <p>
1097:             * Calling this method is equivalent to 
1098:             * <code>doAdd(path, force, mkdir, climbUnversionedParents, recursive, false)</code>. 
1099:             * 
1100:             * @param  path                        a path to be put under version 
1101:             *                                     control (will be added to a repository
1102:             *                                     in next commit)
1103:             * @param  force                       when <span class="javakeyword">true</span> forces the operation 
1104:             *                                     to run on already versioned files or directories without reporting 
1105:             *                                     error. When ran recursively, all unversioned files and directories 
1106:             *                                     in a tree will be scheduled for addition.
1107:             * @param  mkdir                       if <span class="javakeyword">true</span> - 
1108:             *                                     creates a new directory and schedules it for
1109:             *                                     addition
1110:             * @param  climbUnversionedParents     if <span class="javakeyword">true</span> and
1111:             *                                     <code>path</code> is located in an unversioned
1112:             *                                     parent directory then the parent will be automatically
1113:             *                                     scheduled for addition, too 
1114:             * @param  recursive                   <span class="javakeyword">true</span> to
1115:             *                                     descend recursively (relevant for directories)
1116:             * @throws SVNException                if one of the following is true:
1117:             *                                     <ul>
1118:             *                                     <li><code>path</code> doesn't belong
1119:             *                                     to a Working Copy 
1120:             *                                     <li><code>path</code> doesn't exist and
1121:             *                                     <code>mkdir</code> is <span class="javakeyword">false</span>
1122:             *                                     <li><code>path</code> is the root directory of the Working Copy
1123:             */
1124:            public void doAdd(File path, boolean force, boolean mkdir,
1125:                    boolean climbUnversionedParents, boolean recursive)
1126:                    throws SVNException {
1127:                doAdd(path, force, mkdir, climbUnversionedParents, recursive,
1128:                        false);
1129:            }
1130:
1131:            /**
1132:             * Schedules an unversioned item for addition to a repository thus 
1133:             * putting it under version control.
1134:             * 
1135:             * <p>
1136:             * To create and add to version control a new directory, set <code>mkdir</code>
1137:             * to <span class="javakeyword">true</span>. 
1138:             * 
1139:             * @param  path                        a path to be put under version 
1140:             *                                     control (will be added to a repository
1141:             *                                     in next commit)
1142:             * @param  force                       when <span class="javakeyword">true</span> forces the operation 
1143:             *                                     to run on already versioned files or directories without reporting 
1144:             *                                     error. When ran recursively, all unversioned files and directories 
1145:             *                                     in a tree will be scheduled for addition.
1146:             * @param  mkdir                       if <span class="javakeyword">true</span> - 
1147:             *                                     creates a new directory and schedules it for
1148:             *                                     addition
1149:             * @param  climbUnversionedParents     if <span class="javakeyword">true</span> and
1150:             *                                     <code>path</code> is located in an unversioned
1151:             *                                     parent directory then the parent will be automatically
1152:             *                                     scheduled for addition, too 
1153:             * @param  recursive                   <span class="javakeyword">true</span> to
1154:             *                                     descend recursively (relevant for directories)
1155:             * @param  includeIgnored              controls whether ignored items must be also added
1156:             * @throws SVNException                if one of the following is true:
1157:             *                                     <ul>
1158:             *                                     <li><code>path</code> doesn't belong
1159:             *                                     to a Working Copy 
1160:             *                                     <li><code>path</code> doesn't exist and
1161:             *                                     <code>mkdir</code> is <span class="javakeyword">false</span>
1162:             *                                     <li><code>path</code> is the root directory of the Working Copy
1163:             *                                     </ul>
1164:             * @since                              1.1
1165:             */
1166:            public void doAdd(File path, boolean force, boolean mkdir,
1167:                    boolean climbUnversionedParents, boolean recursive,
1168:                    boolean includeIgnored) throws SVNException {
1169:                path = new File(SVNPathUtil.validateFilePath(path
1170:                        .getAbsolutePath()));
1171:                if (!mkdir && climbUnversionedParents
1172:                        && path.getParentFile() != null) {
1173:                    // check if parent is versioned. if not, add it.
1174:                    SVNWCAccess wcAccess = createWCAccess();
1175:                    try {
1176:                        wcAccess.open(path.getParentFile(), false, 0);
1177:                    } catch (SVNException e) {
1178:                        if (e.getErrorMessage().getErrorCode() == SVNErrorCode.WC_NOT_DIRECTORY) {
1179:                            doAdd(path.getParentFile(), false, false,
1180:                                    climbUnversionedParents, false);
1181:                        } else {
1182:                            throw e;
1183:                        }
1184:                    } finally {
1185:                        wcAccess.close();
1186:                    }
1187:                }
1188:                if (force && mkdir
1189:                        && SVNFileType.getType(path) == SVNFileType.DIRECTORY) {
1190:                    // directory is already there.
1191:                    doAdd(path, force, false, true, false, true);
1192:                    return;
1193:                } else if (mkdir) {
1194:                    // attempt to create dir
1195:                    File parent = path;
1196:                    File firstCreated = path;
1197:                    while (parent != null
1198:                            && SVNFileType.getType(parent) == SVNFileType.NONE) {
1199:                        firstCreated = parent;
1200:                        parent = parent.getParentFile();
1201:                    }
1202:                    boolean created = path.mkdirs();
1203:                    if (!created) {
1204:                        // delete created dirs.
1205:                        SVNErrorMessage err = SVNErrorMessage.create(
1206:                                SVNErrorCode.IO_ERROR,
1207:                                "Cannot create new directory ''{0}''", path);
1208:                        while (parent == null ? path != null : !path
1209:                                .equals(parent)) {
1210:                            SVNFileUtil.deleteAll(path, true);
1211:                            path = path.getParentFile();
1212:                        }
1213:                        SVNErrorManager.error(err);
1214:                    }
1215:                    try {
1216:                        doAdd(firstCreated, false, false,
1217:                                climbUnversionedParents, true, true);
1218:                    } catch (SVNException e) {
1219:                        SVNFileUtil.deleteAll(firstCreated, true);
1220:                        throw e;
1221:                    }
1222:                    return;
1223:                }
1224:                SVNWCAccess wcAccess = createWCAccess();
1225:                try {
1226:                    SVNAdminArea dir = null;
1227:                    if (path.isDirectory()) {
1228:                        dir = wcAccess.open(
1229:                                SVNWCUtil.isVersionedDirectory(path
1230:                                        .getParentFile()) ? path
1231:                                        .getParentFile() : path, true, 0);
1232:                    } else {
1233:                        dir = wcAccess.open(path.getParentFile(), true, 0);
1234:                    }
1235:                    SVNFileType fileType = SVNFileType.getType(path);
1236:                    if (fileType == SVNFileType.DIRECTORY && recursive) {
1237:                        addDirectory(path, dir, force, includeIgnored);
1238:                    } else if (fileType == SVNFileType.FILE
1239:                            || fileType == SVNFileType.SYMLINK) {
1240:                        addFile(path, fileType, dir);
1241:                    } else {
1242:                        SVNWCManager
1243:                                .add(path, dir, null, SVNRevision.UNDEFINED);
1244:                    }
1245:                } catch (SVNException e) {
1246:                    if (!(force && e.getErrorMessage().getErrorCode() == SVNErrorCode.ENTRY_EXISTS)) {
1247:                        throw e;
1248:                    }
1249:                } finally {
1250:                    wcAccess.close();
1251:                }
1252:            }
1253:
1254:            private void addDirectory(File path, SVNAdminArea parentDir,
1255:                    boolean force, boolean noIgnore) throws SVNException {
1256:                checkCancelled();
1257:                try {
1258:                    SVNWCManager.add(path, parentDir, null,
1259:                            SVNRevision.UNDEFINED);
1260:                } catch (SVNException e) {
1261:                    if (!(force && e.getErrorMessage().getErrorCode() == SVNErrorCode.ENTRY_EXISTS)) {
1262:                        throw e;
1263:                    }
1264:                }
1265:                SVNWCAccess access = parentDir.getWCAccess();
1266:                SVNAdminArea dir = access.retrieve(path);
1267:                Collection ignores = Collections.EMPTY_SET;
1268:                if (!noIgnore) {
1269:                    ignores = SVNStatusEditor.getIgnorePatterns(dir,
1270:                            SVNStatusEditor.getGlobalIgnores(getOptions()));
1271:                }
1272:                File[] children = SVNFileListUtil.listFiles(dir.getRoot());
1273:                for (int i = 0; children != null && i < children.length; i++) {
1274:                    checkCancelled();
1275:                    if (SVNFileUtil.getAdminDirectoryName().equals(
1276:                            children[i].getName())) {
1277:                        continue;
1278:                    }
1279:                    if (!noIgnore
1280:                            && SVNStatusEditor.isIgnored(ignores, children[i]
1281:                                    .getName())) {
1282:                        continue;
1283:                    }
1284:                    SVNFileType childType = SVNFileType.getType(children[i]);
1285:                    if (childType == SVNFileType.DIRECTORY) {
1286:                        addDirectory(children[i], dir, force, noIgnore);
1287:                    } else if (childType != SVNFileType.UNKNOWN) {
1288:                        try {
1289:                            addFile(children[i], childType, dir);
1290:                        } catch (SVNException e) {
1291:                            if (force
1292:                                    && e.getErrorMessage().getErrorCode() == SVNErrorCode.ENTRY_EXISTS) {
1293:                                continue;
1294:                            }
1295:                            throw e;
1296:                        }
1297:                    }
1298:                }
1299:
1300:            }
1301:
1302:            private void addFile(File path, SVNFileType type, SVNAdminArea dir)
1303:                    throws SVNException {
1304:                ISVNEventHandler handler = dir.getWCAccess().getEventHandler();
1305:                dir.getWCAccess().setEventHandler(null);
1306:                SVNWCManager.add(path, dir, null, SVNRevision.UNDEFINED);
1307:                dir.getWCAccess().setEventHandler(handler);
1308:
1309:                String mimeType = null;
1310:                if (type == SVNFileType.SYMLINK) {
1311:                    SVNPropertiesManager
1312:                            .setProperty(
1313:                                    dir.getWCAccess(),
1314:                                    path,
1315:                                    SVNProperty.SPECIAL,
1316:                                    SVNProperty
1317:                                            .getValueOfBooleanProperty(SVNProperty.SPECIAL),
1318:                                    false);
1319:                } else {
1320:                    Map props = SVNPropertiesManager.computeAutoProperties(
1321:                            getOptions(), path);
1322:                    for (Iterator names = props.keySet().iterator(); names
1323:                            .hasNext();) {
1324:                        String propName = (String) names.next();
1325:                        String propValue = (String) props.get(propName);
1326:                        try {
1327:                            SVNPropertiesManager.setProperty(dir.getWCAccess(),
1328:                                    path, propName, propValue, false);
1329:                        } catch (SVNException e) {
1330:                            if (SVNProperty.EOL_STYLE.equals(propName)
1331:                                    && e.getErrorMessage().getErrorCode() == SVNErrorCode.ILLEGAL_TARGET
1332:                                    && e.getErrorMessage().getMessage()
1333:                                            .indexOf("newlines") >= 0) {
1334:                                ISVNAddParameters.Action action = getAddParameters()
1335:                                        .onInconsistentEOLs(path);
1336:                                if (action == ISVNAddParameters.REPORT_ERROR) {
1337:                                    throw e;
1338:                                } else if (action == ISVNAddParameters.ADD_AS_IS) {
1339:                                    SVNPropertiesManager.setProperty(dir
1340:                                            .getWCAccess(), path, propName,
1341:                                            null, false);
1342:                                } else if (action == ISVNAddParameters.ADD_AS_BINARY) {
1343:                                    SVNPropertiesManager.setProperty(dir
1344:                                            .getWCAccess(), path, propName,
1345:                                            null, false);
1346:                                    mimeType = SVNFileUtil.BINARY_MIME_TYPE;
1347:                                }
1348:                            } else {
1349:                                throw e;
1350:                            }
1351:                        }
1352:                    }
1353:                    if (mimeType != null) {
1354:                        SVNPropertiesManager.setProperty(dir.getWCAccess(),
1355:                                path, SVNProperty.MIME_TYPE, mimeType, false);
1356:                    } else {
1357:                        mimeType = (String) props.get(SVNProperty.MIME_TYPE);
1358:                    }
1359:                }
1360:                SVNEvent event = SVNEventFactory.createAddedEvent(dir, path
1361:                        .getName(), SVNNodeKind.FILE, mimeType);
1362:                dispatchEvent(event);
1363:            }
1364:
1365:            /**
1366:             * Reverts all local changes made to a Working Copy item(s) thus
1367:             * bringing it to a 'pristine' state.
1368:             * 
1369:             * @param  path            a WC path to perform a revert on
1370:             * @param  recursive       <span class="javakeyword">true</span> to
1371:             *                         descend recursively (relevant for directories)
1372:             * @throws SVNException    if one of the following is true:
1373:             *                         <ul>
1374:             *                         <li><code>path</code> is not under version control
1375:             *                         <li>when trying to revert an addition of a directory
1376:             *                         from within the directory itself
1377:             *                         </ul>
1378:             * @see #doRevert(File[], boolean)
1379:             */
1380:            public void doRevert(File path, boolean recursive)
1381:                    throws SVNException {
1382:                doRevert(new File[] { path }, recursive);
1383:            }
1384:
1385:            /**
1386:             * Reverts all local changes made to a Working Copy item(s) thus
1387:             * bringing it to a 'pristine' state.
1388:             * 
1389:             * @param  paths           a WC paths to perform a revert on
1390:             * @param  recursive       <span class="javakeyword">true</span> to
1391:             *                         descend recursively (relevant for directories)
1392:             * @throws SVNException    if one of the following is true:
1393:             *                         <ul>
1394:             *                         <li><code>path</code> is not under version control
1395:             *                         <li>when trying to revert an addition of a directory
1396:             *                         from within the directory itself
1397:             *                         </ul>
1398:             *                         
1399:             *                         Exception will not be thrown if there are multiple paths passed. 
1400:             *                         Instead caller should process events received by <code>ISVNEventHandler</code>
1401:             *                         instance to get information on whether certain path was reverted or not.  
1402:             */
1403:            public void doRevert(File[] paths, boolean recursive)
1404:                    throws SVNException {
1405:                boolean reverted = false;
1406:                try {
1407:                    for (int i = 0; i < paths.length; i++) {
1408:                        File path = paths[i];
1409:                        path = new File(SVNPathUtil.validateFilePath(path
1410:                                .getAbsolutePath()));
1411:                        SVNWCAccess wcAccess = createWCAccess();
1412:                        try {
1413:                            SVNAdminAreaInfo info = wcAccess.openAnchor(path,
1414:                                    true,
1415:                                    recursive ? SVNWCAccess.INFINITE_DEPTH : 0);
1416:                            SVNEntry entry = wcAccess.getEntry(path, false);
1417:                            if (entry != null && entry.isDirectory()
1418:                                    && entry.isScheduledForAddition()) {
1419:                                if (!recursive) {
1420:                                    getDebugLog().info(
1421:                                            "Forcing revert on path '" + path
1422:                                                    + "' to recurse");
1423:                                    recursive = true;
1424:                                    wcAccess.close();
1425:                                    info = wcAccess.openAnchor(path, true,
1426:                                            SVNWCAccess.INFINITE_DEPTH);
1427:                                }
1428:                            }
1429:
1430:                            boolean useCommitTimes = getOptions()
1431:                                    .isUseCommitTimes();
1432:                            reverted |= doRevert(path, info.getAnchor(),
1433:                                    recursive, useCommitTimes);
1434:                        } catch (SVNException e) {
1435:                            reverted |= true;
1436:                            SVNErrorCode code = e.getErrorMessage()
1437:                                    .getErrorCode();
1438:                            if (code == SVNErrorCode.ENTRY_NOT_FOUND
1439:                                    || code == SVNErrorCode.UNVERSIONED_RESOURCE) {
1440:                                SVNEvent event = SVNEventFactory
1441:                                        .createSkipEvent(path.getParentFile(),
1442:                                                path, SVNEventAction.SKIP,
1443:                                                SVNEventAction.REVERT, null);
1444:                                dispatchEvent(event);
1445:                            }
1446:                            if (paths.length == 1) {
1447:                                throw e;
1448:                            }
1449:                        } finally {
1450:                            wcAccess.close();
1451:                        }
1452:                    }
1453:                } finally {
1454:                    if (reverted) {
1455:                        sleepForTimeStamp();
1456:                    }
1457:                }
1458:            }
1459:
1460:            private boolean doRevert(File path, SVNAdminArea parent,
1461:                    boolean recursive, boolean useCommitTimes)
1462:                    throws SVNException {
1463:                checkCancelled();
1464:                SVNAdminArea dir = parent.getWCAccess().probeRetrieve(path);
1465:                SVNEntry entry = dir.getWCAccess().getEntry(path, false);
1466:                if (entry == null) {
1467:                    SVNErrorMessage err = SVNErrorMessage
1468:                            .create(
1469:                                    SVNErrorCode.UNVERSIONED_RESOURCE,
1470:                                    "Cannot revert: ''{0}'' is not under version control",
1471:                                    path);
1472:                    SVNErrorManager.error(err);
1473:                }
1474:                if (entry.getKind() == SVNNodeKind.DIR) {
1475:                    SVNFileType fileType = SVNFileType.getType(path);
1476:                    if (fileType != SVNFileType.DIRECTORY
1477:                            && !entry.isScheduledForAddition()) {
1478:                        SVNEvent event = SVNEventFactory
1479:                                .createNotRevertedEvent(dir, entry);
1480:                        dispatchEvent(event);
1481:                        return false;
1482:                    }
1483:                }
1484:                if (entry.getKind() != SVNNodeKind.DIR
1485:                        && entry.getKind() != SVNNodeKind.FILE) {
1486:                    SVNErrorMessage err = SVNErrorMessage
1487:                            .create(
1488:                                    SVNErrorCode.UNSUPPORTED_FEATURE,
1489:                                    "Cannot revert ''{0}'': unsupported entry node kind",
1490:                                    path);
1491:                    SVNErrorManager.error(err);
1492:                }
1493:                SVNFileType fileType = SVNFileType.getType(path);
1494:                if (fileType == SVNFileType.UNKNOWN) {
1495:                    SVNErrorMessage err = SVNErrorMessage
1496:                            .create(
1497:                                    SVNErrorCode.UNSUPPORTED_FEATURE,
1498:                                    "Cannot revert ''{0}'': unsupported node kind in working copy",
1499:                                    path);
1500:                    SVNErrorManager.error(err);
1501:                }
1502:                boolean reverted = false;
1503:                if (entry.isScheduledForAddition()) {
1504:                    boolean wasDeleted = false;
1505:                    if (entry.getKind() == SVNNodeKind.FILE) {
1506:                        wasDeleted = entry.isDeleted();
1507:                        parent.removeFromRevisionControl(path.getName(), false,
1508:                                false);
1509:                    } else if (entry.getKind() == SVNNodeKind.DIR) {
1510:                        SVNEntry entryInParent = parent.getEntry(
1511:                                path.getName(), true);
1512:                        if (entryInParent != null) {
1513:                            wasDeleted = entryInParent.isDeleted();
1514:                        }
1515:                        if (fileType == SVNFileType.NONE) {
1516:                            parent.deleteEntry(path.getName());
1517:                            parent.saveEntries(false);
1518:                        } else {
1519:                            dir.removeFromRevisionControl("", false, false);
1520:                        }
1521:                    }
1522:                    reverted = true;
1523:                    recursive = false;
1524:                    if (wasDeleted) {
1525:                        SVNEntry entryInParent = parent.getEntry(
1526:                                path.getName(), true);
1527:                        if (entryInParent == null) {
1528:                            entryInParent = parent.addEntry(path.getName());
1529:                        }
1530:                        entryInParent.setKind(entry.getKind());
1531:                        entryInParent.setDeleted(true);
1532:                        parent.saveEntries(false);
1533:                    }
1534:                } else if (entry.getSchedule() == null
1535:                        || entry.isScheduledForDeletion()
1536:                        || entry.isScheduledForReplacement()) {
1537:                    if (entry.getKind() == SVNNodeKind.FILE) {
1538:                        reverted = revert(parent, entry.getName(), entry,
1539:                                useCommitTimes);
1540:                    } else if (entry.getKind() == SVNNodeKind.DIR) {
1541:                        boolean notScheduled = entry.getSchedule() == null;
1542:                        reverted = revert(dir, dir.getThisDirName(), entry,
1543:                                useCommitTimes);
1544:                        if (entry.isScheduledForReplacement()) {
1545:                            recursive = true;
1546:                        }
1547:                        // check parent entry for schedule.
1548:                        if (reverted && parent != dir) {
1549:                            SVNEntry entryInParent = parent.getEntry(path
1550:                                    .getName(), false);
1551:                            revert(parent, path.getName(), entryInParent,
1552:                                    useCommitTimes);
1553:                            parent.saveEntries(false);
1554:                        } else if (notScheduled && parent != dir) {
1555:                            SVNEntry entryInParent = parent.getEntry(path
1556:                                    .getName(), false);
1557:                            if (entryInParent.getSchedule() != null) {
1558:                                entryInParent.setSchedule(null);
1559:                                parent.saveEntries(false);
1560:                            }
1561:                        }
1562:                    }
1563:                }
1564:                if (reverted) {
1565:                    SVNEvent event = SVNEventFactory.createRevertedEvent(dir,
1566:                            entry);
1567:                    dispatchEvent(event);
1568:                }
1569:                if (recursive && entry.getKind() == SVNNodeKind.DIR) {
1570:                    for (Iterator entries = dir.entries(false); entries
1571:                            .hasNext();) {
1572:                        SVNEntry childEntry = (SVNEntry) entries.next();
1573:                        if (dir.getThisDirName().equals(childEntry.getName())) {
1574:                            continue;
1575:                        }
1576:                        File childPath = new File(path, childEntry.getName());
1577:                        reverted |= doRevert(childPath, dir, true,
1578:                                useCommitTimes);
1579:                    }
1580:                }
1581:                return reverted;
1582:            }
1583:
1584:            private boolean revert(SVNAdminArea dir, String name,
1585:                    SVNEntry entry, boolean useCommitTime) throws SVNException {
1586:                SVNLog log = dir.getLog();
1587:                boolean reverted = false;
1588:                boolean revertBase = false;
1589:                SVNVersionedProperties baseProperties = null;
1590:                Map command = new HashMap();
1591:
1592:                if (entry.isScheduledForReplacement()) {
1593:                    String propRevertPath = SVNAdminUtil.getPropRevertPath(
1594:                            name, entry.getKind(), false);
1595:                    File propRevertFile = dir.getFile(propRevertPath);
1596:                    revertBase = true;
1597:                    if (!propRevertFile.isFile()) {
1598:                        propRevertPath = SVNAdminUtil.getPropBasePath(name,
1599:                                entry.getKind(), false);
1600:                        revertBase = false;
1601:                    }
1602:                    if (dir.getFile(propRevertPath).isFile()) {
1603:                        baseProperties = revertBase ? dir
1604:                                .getRevertProperties(name) : dir
1605:                                .getBaseProperties(name);
1606:                        if (revertBase) {
1607:                            command.put(SVNLog.NAME_ATTR, propRevertPath);
1608:                            log.addCommand(SVNLog.DELETE, command, false);
1609:                            command.clear();
1610:                        }
1611:                        reverted = true;
1612:                    }
1613:                }
1614:                boolean reinstallWorkingFile = false;
1615:                if (baseProperties == null) {
1616:                    if (dir.hasPropModifications(name)) {
1617:                        baseProperties = dir.getBaseProperties(name);
1618:                        SVNVersionedProperties propDiff = dir.getProperties(
1619:                                name).compareTo(baseProperties);
1620:                        Collection propNames = propDiff.getPropertyNames(null);
1621:                        reinstallWorkingFile = propNames
1622:                                .contains(SVNProperty.EXECUTABLE)
1623:                                || propNames.contains(SVNProperty.KEYWORDS)
1624:                                || propNames.contains(SVNProperty.EOL_STYLE)
1625:                                || propNames.contains(SVNProperty.SPECIAL)
1626:                                || propNames.contains(SVNProperty.NEEDS_LOCK);
1627:                    }
1628:                }
1629:                if (baseProperties != null) {
1630:                    // save base props both to base and working. 
1631:                    Map newProperties = baseProperties.asMap();
1632:                    SVNVersionedProperties originalBaseProperties = dir
1633:                            .getBaseProperties(name);
1634:                    SVNVersionedProperties workProperties = dir
1635:                            .getProperties(name);
1636:                    if (revertBase) {
1637:                        originalBaseProperties.removeAll();
1638:                    }
1639:                    workProperties.removeAll();
1640:                    for (Iterator names = newProperties.keySet().iterator(); names
1641:                            .hasNext();) {
1642:                        String propName = (String) names.next();
1643:                        if (revertBase) {
1644:                            originalBaseProperties.setPropertyValue(propName,
1645:                                    (String) newProperties.get(propName));
1646:                        }
1647:                        workProperties.setPropertyValue(propName,
1648:                                (String) newProperties.get(propName));
1649:                    }
1650:                    dir.saveVersionedProperties(log, false);
1651:                    reverted = true;
1652:                }
1653:                Map newEntryProperties = new HashMap();
1654:                if (entry.isScheduledForReplacement() && entry.isCopied()) {
1655:                    newEntryProperties.put(SVNProperty
1656:                            .shortPropertyName(SVNProperty.COPIED), null);
1657:                    reverted = true;
1658:                }
1659:                if (entry.getKind() == SVNNodeKind.FILE) {
1660:                    if (!reinstallWorkingFile) {
1661:                        SVNFileType fileType = SVNFileType.getType(dir
1662:                                .getFile(name));
1663:                        if (fileType == SVNFileType.NONE) {
1664:                            reinstallWorkingFile = true;
1665:                        }
1666:                    }
1667:                    String basePath = SVNAdminUtil.getTextBasePath(name, false);
1668:                    if (!dir.getFile(basePath).isFile()) {
1669:                        SVNErrorMessage err = SVNErrorMessage.create(
1670:                                SVNErrorCode.IO_ERROR,
1671:                                "Error restoring text for ''{0}''", dir
1672:                                        .getFile(name));
1673:                        SVNErrorManager.error(err);
1674:                    }
1675:                    File revertFile = dir.getFile(SVNAdminUtil
1676:                            .getTextRevertPath(name, false));
1677:                    if (revertFile.isFile()) {
1678:                        command.put(SVNLog.NAME_ATTR, SVNAdminUtil
1679:                                .getTextRevertPath(name, false));
1680:                        command.put(SVNLog.DEST_ATTR, SVNAdminUtil
1681:                                .getTextBasePath(name, false));
1682:                        log.addCommand(SVNLog.MOVE, command, false);
1683:                        command.clear();
1684:                        reinstallWorkingFile = true;
1685:                    }
1686:                    if (!reinstallWorkingFile) {
1687:                        reinstallWorkingFile = dir.hasTextModifications(name,
1688:                                false, false, false);
1689:                    }
1690:                    if (reinstallWorkingFile) {
1691:                        command.put(SVNLog.NAME_ATTR, SVNAdminUtil
1692:                                .getTextBasePath(name, false));
1693:                        command.put(SVNLog.DEST_ATTR, name);
1694:                        log.addCommand(SVNLog.COPY_AND_TRANSLATE, command,
1695:                                false);
1696:                        command.clear();
1697:                        if (useCommitTime && entry.getCommittedDate() != null) {
1698:                            command.put(SVNLog.NAME_ATTR, name);
1699:                            command.put(SVNLog.TIMESTAMP_ATTR, entry
1700:                                    .getCommittedDate());
1701:                            log
1702:                                    .addCommand(SVNLog.SET_TIMESTAMP, command,
1703:                                            false);
1704:                            command.clear();
1705:                        } else {
1706:                            command.put(SVNLog.NAME_ATTR, name);
1707:                            command.put(SVNLog.TIMESTAMP_ATTR, SVNTimeUtil
1708:                                    .formatDate(new Date(System
1709:                                            .currentTimeMillis())));
1710:                            log
1711:                                    .addCommand(SVNLog.SET_TIMESTAMP, command,
1712:                                            false);
1713:                            command.clear();
1714:                        }
1715:                        command.put(SVNLog.NAME_ATTR, name);
1716:                        command.put(SVNProperty
1717:                                .shortPropertyName(SVNProperty.TEXT_TIME),
1718:                                SVNLog.WC_TIMESTAMP);
1719:                        log.addCommand(SVNLog.MODIFY_ENTRY, command, false);
1720:                        command.clear();
1721:                    }
1722:                    reverted |= reinstallWorkingFile;
1723:                }
1724:                if (entry.getConflictNew() != null) {
1725:                    command.put(SVNLog.NAME_ATTR, entry.getConflictNew());
1726:                    log.addCommand(SVNLog.DELETE, command, false);
1727:                    command.clear();
1728:                    newEntryProperties.put(SVNProperty
1729:                            .shortPropertyName(SVNProperty.CONFLICT_NEW), null);
1730:                    if (!reverted) {
1731:                        reverted |= dir.getFile(entry.getConflictNew())
1732:                                .exists();
1733:                    }
1734:                }
1735:                if (entry.getConflictOld() != null) {
1736:                    command.put(SVNLog.NAME_ATTR, entry.getConflictOld());
1737:                    log.addCommand(SVNLog.DELETE, command, false);
1738:                    command.clear();
1739:                    newEntryProperties.put(SVNProperty
1740:                            .shortPropertyName(SVNProperty.CONFLICT_OLD), null);
1741:                    if (!reverted) {
1742:                        reverted |= dir.getFile(entry.getConflictOld())
1743:                                .exists();
1744:                    }
1745:                }
1746:                if (entry.getConflictWorking() != null) {
1747:                    command.put(SVNLog.NAME_ATTR, entry.getConflictWorking());
1748:                    log.addCommand(SVNLog.DELETE, command, false);
1749:                    command.clear();
1750:                    newEntryProperties.put(SVNProperty
1751:                            .shortPropertyName(SVNProperty.CONFLICT_WRK), null);
1752:                    if (!reverted) {
1753:                        reverted |= dir.getFile(entry.getConflictWorking())
1754:                                .exists();
1755:                    }
1756:                }
1757:                if (entry.getPropRejectFile() != null) {
1758:                    command.put(SVNLog.NAME_ATTR, entry.getPropRejectFile());
1759:                    log.addCommand(SVNLog.DELETE, command, false);
1760:                    command.clear();
1761:                    newEntryProperties.put(SVNProperty
1762:                            .shortPropertyName(SVNProperty.PROP_REJECT_FILE),
1763:                            null);
1764:                    if (!reverted) {
1765:                        reverted |= dir.getFile(entry.getPropRejectFile())
1766:                                .exists();
1767:                    }
1768:                }
1769:                if (entry.getSchedule() != null) {
1770:                    newEntryProperties.put(SVNProperty
1771:                            .shortPropertyName(SVNProperty.SCHEDULE), null);
1772:                    reverted = true;
1773:                }
1774:                if (!newEntryProperties.isEmpty()) {
1775:                    newEntryProperties.put(SVNLog.NAME_ATTR, name);
1776:                    log.addCommand(SVNLog.MODIFY_ENTRY, newEntryProperties,
1777:                            false);
1778:                }
1779:                log.save();
1780:                dir.runLogs();
1781:                return reverted;
1782:            }
1783:
1784:            /**
1785:             * Resolves a 'conflicted' state on a Working Copy item. 
1786:             * 
1787:             * @param  path            a WC item to be resolved
1788:             * @param  recursive       <span class="javakeyword">true</span> to
1789:             *                         descend recursively (relevant for directories) - this
1790:             *                         will resolve the entire tree
1791:             * @throws SVNException    if <code>path</code> is not under version control
1792:             */
1793:            public void doResolve(File path, boolean recursive)
1794:                    throws SVNException {
1795:                path = path.getAbsoluteFile();
1796:                SVNWCAccess wcAccess = createWCAccess();
1797:                try {
1798:                    wcAccess.probeOpen(path, true,
1799:                            recursive ? SVNWCAccess.INFINITE_DEPTH : 0);
1800:                    if (!recursive) {
1801:                        SVNEntry entry = wcAccess.getEntry(path, false);
1802:                        if (entry == null) {
1803:                            SVNErrorMessage err = SVNErrorMessage.create(
1804:                                    SVNErrorCode.ENTRY_NOT_FOUND,
1805:                                    "''{0}'' is not under version control",
1806:                                    path);
1807:                            SVNErrorManager.error(err);
1808:                        }
1809:                        resolveEntry(wcAccess, path, entry);
1810:                    } else {
1811:                        resolveAll(wcAccess, path);
1812:                    }
1813:                } finally {
1814:                    wcAccess.close();
1815:                }
1816:            }
1817:
1818:            private void resolveEntry(SVNWCAccess wcAccess, File path,
1819:                    SVNEntry entry) throws SVNException {
1820:                if (entry.getKind() == SVNNodeKind.DIR
1821:                        && !"".equals(entry.getName())) {
1822:                    return;
1823:                }
1824:                File dirPath = path;
1825:                if (entry.getKind() == SVNNodeKind.FILE) {
1826:                    dirPath = path.getParentFile();
1827:                }
1828:                SVNAdminArea dir = wcAccess.retrieve(dirPath);
1829:                if (dir.markResolved(entry.getName(), true, true)) {
1830:                    SVNEvent event = SVNEventFactory.createResolvedEvent(null,
1831:                            dir, entry);
1832:                    dispatchEvent(event);
1833:                }
1834:            }
1835:
1836:            private void resolveAll(SVNWCAccess access, File path)
1837:                    throws SVNException {
1838:                checkCancelled();
1839:                SVNEntry entry = access.getEntry(path, false);
1840:                resolveEntry(access, path, entry);
1841:                if (entry.isDirectory()) {
1842:                    SVNAdminArea dir = access.retrieve(path);
1843:                    for (Iterator ents = dir.entries(false); ents.hasNext();) {
1844:                        SVNEntry childEntry = (SVNEntry) ents.next();
1845:                        if (dir.getThisDirName().equals(childEntry.getName())) {
1846:                            continue;
1847:                        }
1848:                        resolveAll(access, dir.getFile(childEntry.getName()));
1849:                    }
1850:                }
1851:            }
1852:
1853:            /**
1854:             * Locks file items in a Working Copy as well as in a repository so that 
1855:             * no other user can commit changes to them.
1856:             * 
1857:             * @param  paths         an array of local WC file paths that should be locked 
1858:             * @param  stealLock     if <span class="javakeyword">true</span> then all existing
1859:             *                       locks on the specified <code>paths</code> will be "stolen"
1860:             * @param  lockMessage   an optional lock comment  
1861:             * @throws SVNException  if one of the following is true:
1862:             *                       <ul>
1863:             *                       <li>a path to be locked is not under version control
1864:             *                       <li>can not obtain a URL of a local path to lock it in 
1865:             *                       the repository - there's no such entry
1866:             *                       <li><code>paths</code> to be locked belong to different repositories
1867:             *                       </ul>
1868:             * @see                  #doLock(SVNURL[], boolean, String)
1869:             */
1870:            public void doLock(File[] paths, boolean stealLock,
1871:                    String lockMessage) throws SVNException {
1872:                final Map entriesMap = new HashMap();
1873:                Map pathsRevisionsMap = new HashMap();
1874:                final SVNWCAccess wcAccess = createWCAccess();
1875:                try {
1876:                    final SVNURL topURL = collectLockInfo(wcAccess, paths,
1877:                            entriesMap, pathsRevisionsMap, true, stealLock);
1878:                    SVNRepository repository = createRepository(topURL, true);
1879:                    final SVNURL rootURL = repository.getRepositoryRoot(true);
1880:
1881:                    repository.lock(pathsRevisionsMap, lockMessage, stealLock,
1882:                            new ISVNLockHandler() {
1883:                                public void handleLock(String path,
1884:                                        SVNLock lock, SVNErrorMessage error)
1885:                                        throws SVNException {
1886:                                    SVNURL fullURL = rootURL.appendPath(path,
1887:                                            false);
1888:                                    LockInfo lockInfo = (LockInfo) entriesMap
1889:                                            .get(fullURL);
1890:                                    SVNAdminArea dir = wcAccess
1891:                                            .probeRetrieve(lockInfo.myFile);
1892:                                    if (error == null) {
1893:                                        SVNEntry entry = wcAccess.getEntry(
1894:                                                lockInfo.myFile, false);
1895:                                        if (entry == null) {
1896:                                            SVNErrorMessage err = SVNErrorMessage
1897:                                                    .create(
1898:                                                            SVNErrorCode.UNVERSIONED_RESOURCE,
1899:                                                            "''{0}'' is not under version control",
1900:                                                            lockInfo.myFile);
1901:                                            SVNErrorManager.error(err);
1902:                                        }
1903:                                        entry.setLockToken(lock.getID());
1904:                                        entry.setLockComment(lock.getComment());
1905:                                        entry.setLockOwner(lock.getOwner());
1906:                                        entry.setLockCreationDate(SVNTimeUtil
1907:                                                .formatDate(lock
1908:                                                        .getCreationDate()));
1909:                                        // get properties and values.
1910:                                        SVNVersionedProperties props = dir
1911:                                                .getProperties(entry.getName());
1912:
1913:                                        if (props
1914:                                                .getPropertyValue(SVNProperty.NEEDS_LOCK) != null) {
1915:                                            SVNFileUtil.setReadonly(dir
1916:                                                    .getFile(entry.getName()),
1917:                                                    false);
1918:                                        }
1919:                                        SVNFileUtil
1920:                                                .setExecutable(
1921:                                                        dir.getFile(entry
1922:                                                                .getName()),
1923:                                                        props
1924:                                                                .getPropertyValue(SVNProperty.EXECUTABLE) != null);
1925:                                        dir.saveEntries(false);
1926:                                        handleEvent(SVNEventFactory
1927:                                                .createLockEvent(dir, entry
1928:                                                        .getName(),
1929:                                                        SVNEventAction.LOCKED,
1930:                                                        lock, null),
1931:                                                ISVNEventHandler.UNKNOWN);
1932:                                    } else {
1933:                                        handleEvent(
1934:                                                SVNEventFactory
1935:                                                        .createLockEvent(
1936:                                                                dir,
1937:                                                                lockInfo.myFile
1938:                                                                        .getName(),
1939:                                                                SVNEventAction.LOCK_FAILED,
1940:                                                                lock, error),
1941:                                                ISVNEventHandler.UNKNOWN);
1942:                                    }
1943:                                }
1944:
1945:                                public void handleUnlock(String path,
1946:                                        SVNLock lock, SVNErrorMessage error) {
1947:                                }
1948:                            });
1949:                } finally {
1950:                    wcAccess.close();
1951:                }
1952:            }
1953:
1954:            /**
1955:             * Locks file items in a repository so that no other user can commit 
1956:             * changes to them.
1957:             * 
1958:             * @param  urls          an array of URLs to be locked 
1959:             * @param  stealLock     if <span class="javakeyword">true</span> then all existing
1960:             *                       locks on the specified <code>urls</code> will be "stolen"
1961:             * @param  lockMessage   an optional lock comment  
1962:             * @throws SVNException  
1963:             * @see                  #doLock(File[], boolean, String)
1964:             */
1965:            public void doLock(SVNURL[] urls, boolean stealLock,
1966:                    String lockMessage) throws SVNException {
1967:                Collection paths = new HashSet();
1968:                SVNURL topURL = SVNURLUtil.condenceURLs(urls, paths, false);
1969:                if (paths.isEmpty()) {
1970:                    paths.add("");
1971:                }
1972:                Map pathsToRevisions = new HashMap();
1973:                for (Iterator p = paths.iterator(); p.hasNext();) {
1974:                    String path = (String) p.next();
1975:                    path = SVNEncodingUtil.uriDecode(path);
1976:                    pathsToRevisions.put(path, null);
1977:                }
1978:                checkCancelled();
1979:                SVNRepository repository = createRepository(topURL, true);
1980:                repository.lock(pathsToRevisions, lockMessage, stealLock,
1981:                        new ISVNLockHandler() {
1982:                            public void handleLock(String path, SVNLock lock,
1983:                                    SVNErrorMessage error) throws SVNException {
1984:                                if (error != null) {
1985:                                    handleEvent(SVNEventFactory
1986:                                            .createLockEvent(null, path,
1987:                                                    SVNEventAction.LOCK_FAILED,
1988:                                                    lock, error),
1989:                                            ISVNEventHandler.UNKNOWN);
1990:                                } else {
1991:                                    handleEvent(SVNEventFactory
1992:                                            .createLockEvent(null, path,
1993:                                                    SVNEventAction.LOCKED,
1994:                                                    lock, null),
1995:                                            ISVNEventHandler.UNKNOWN);
1996:                                }
1997:                            }
1998:
1999:                            public void handleUnlock(String path, SVNLock lock,
2000:                                    SVNErrorMessage error) throws SVNException {
2001:                            }
2002:
2003:                        });
2004:            }
2005:
2006:            /**
2007:             * Unlocks file items in a Working Copy as well as in a repository.
2008:             * 
2009:             * @param  paths          an array of local WC file paths that should be unlocked
2010:             * @param  breakLock      if <span class="javakeyword">true</span> and there are locks
2011:             *                        that belong to different users then those locks will be also
2012:             *                        unlocked - that is "broken"
2013:             * @throws SVNException   if one of the following is true:
2014:             *                        <ul>
2015:             *                        <li>a path is not under version control
2016:             *                        <li>can not obtain a URL of a local path to unlock it in 
2017:             *                        the repository - there's no such entry
2018:             *                        <li>if a path is not locked in the Working Copy
2019:             *                        and <code>breakLock</code> is <span class="javakeyword">false</span>
2020:             *                        <li><code>paths</code> to be unlocked belong to different repositories
2021:             *                        </ul>
2022:             * @see                   #doUnlock(SVNURL[], boolean)                       
2023:             */
2024:            public void doUnlock(File[] paths, boolean breakLock)
2025:                    throws SVNException {
2026:                final Map entriesMap = new HashMap();
2027:                Map pathsTokensMap = new HashMap();
2028:                final SVNWCAccess wcAccess = createWCAccess();
2029:                try {
2030:                    final SVNURL topURL = collectLockInfo(wcAccess, paths,
2031:                            entriesMap, pathsTokensMap, false, breakLock);
2032:                    checkCancelled();
2033:                    SVNRepository repository = createRepository(topURL, true);
2034:                    final SVNURL rootURL = repository.getRepositoryRoot(true);
2035:                    repository.unlock(pathsTokensMap, breakLock,
2036:                            new ISVNLockHandler() {
2037:                                public void handleLock(String path,
2038:                                        SVNLock lock, SVNErrorMessage error)
2039:                                        throws SVNException {
2040:                                }
2041:
2042:                                public void handleUnlock(String path,
2043:                                        SVNLock lock, SVNErrorMessage error)
2044:                                        throws SVNException {
2045:                                    SVNURL fullURL = rootURL.appendPath(path,
2046:                                            false);
2047:                                    LockInfo lockInfo = (LockInfo) entriesMap
2048:                                            .get(fullURL);
2049:                                    SVNEventAction action = null;
2050:                                    SVNAdminArea dir = wcAccess
2051:                                            .probeRetrieve(lockInfo.myFile);
2052:                                    if (error == null
2053:                                            || (error != null && error
2054:                                                    .getErrorCode() != SVNErrorCode.FS_LOCK_OWNER_MISMATCH)) {
2055:                                        SVNEntry entry = wcAccess.getEntry(
2056:                                                lockInfo.myFile, false);
2057:                                        if (entry == null) {
2058:                                            SVNErrorMessage err = SVNErrorMessage
2059:                                                    .create(
2060:                                                            SVNErrorCode.UNVERSIONED_RESOURCE,
2061:                                                            "''{0}'' is not under version control",
2062:                                                            lockInfo.myFile);
2063:                                            SVNErrorManager.error(err);
2064:                                        }
2065:                                        entry.setLockToken(null);
2066:                                        entry.setLockComment(null);
2067:                                        entry.setLockOwner(null);
2068:                                        entry.setLockCreationDate(null);
2069:
2070:                                        SVNVersionedProperties props = dir
2071:                                                .getProperties(entry.getName());
2072:
2073:                                        if (props
2074:                                                .getPropertyValue(SVNProperty.NEEDS_LOCK) != null) {
2075:                                            SVNFileUtil.setReadonly(dir
2076:                                                    .getFile(entry.getName()),
2077:                                                    true);
2078:                                        }
2079:                                        dir.saveEntries(false);
2080:                                        action = SVNEventAction.UNLOCKED;
2081:                                    }
2082:                                    if (error != null) {
2083:                                        action = SVNEventAction.UNLOCK_FAILED;
2084:                                    }
2085:                                    if (action != null) {
2086:                                        handleEvent(SVNEventFactory
2087:                                                .createLockEvent(dir,
2088:                                                        lockInfo.myFile
2089:                                                                .getName(),
2090:                                                        action, lock, error),
2091:                                                ISVNEventHandler.UNKNOWN);
2092:                                    }
2093:                                }
2094:                            });
2095:                } finally {
2096:                    wcAccess.close();
2097:                }
2098:            }
2099:
2100:            /**
2101:             * Unlocks file items in a repository.
2102:             * 
2103:             * @param  urls            an array of URLs that should be unlocked
2104:             * @param  breakLock       if <span class="javakeyword">true</span> and there are locks
2105:             *                         that belong to different users then those locks will be also
2106:             *                         unlocked - that is "broken"
2107:             * @throws SVNException
2108:             * @see                    #doUnlock(File[], boolean)
2109:             */
2110:            public void doUnlock(SVNURL[] urls, boolean breakLock)
2111:                    throws SVNException {
2112:                Collection paths = new HashSet();
2113:                SVNURL topURL = SVNURLUtil.condenceURLs(urls, paths, false);
2114:                if (paths.isEmpty()) {
2115:                    paths.add("");
2116:                }
2117:                Map pathsToTokens = new HashMap();
2118:                for (Iterator p = paths.iterator(); p.hasNext();) {
2119:                    String path = (String) p.next();
2120:                    path = SVNEncodingUtil.uriDecode(path);
2121:                    pathsToTokens.put(path, null);
2122:                }
2123:
2124:                checkCancelled();
2125:                SVNRepository repository = createRepository(topURL, true);
2126:                if (!breakLock) {
2127:                    pathsToTokens = fetchLockTokens(repository, pathsToTokens);
2128:                }
2129:                repository.unlock(pathsToTokens, breakLock,
2130:                        new ISVNLockHandler() {
2131:                            public void handleLock(String path, SVNLock lock,
2132:                                    SVNErrorMessage error) throws SVNException {
2133:                            }
2134:
2135:                            public void handleUnlock(String path, SVNLock lock,
2136:                                    SVNErrorMessage error) throws SVNException {
2137:                                if (error != null) {
2138:                                    handleEvent(
2139:                                            SVNEventFactory
2140:                                                    .createLockEvent(
2141:                                                            null,
2142:                                                            path,
2143:                                                            SVNEventAction.UNLOCK_FAILED,
2144:                                                            null, error),
2145:                                            ISVNEventHandler.UNKNOWN);
2146:                                } else {
2147:                                    handleEvent(SVNEventFactory
2148:                                            .createLockEvent(null, path,
2149:                                                    SVNEventAction.UNLOCKED,
2150:                                                    null, null),
2151:                                            ISVNEventHandler.UNKNOWN);
2152:                                }
2153:                            }
2154:                        });
2155:            }
2156:
2157:            private SVNURL collectLockInfo(SVNWCAccess wcAccess, File[] files,
2158:                    Map lockInfo, Map lockPaths, boolean lock, boolean stealLock)
2159:                    throws SVNException {
2160:                String[] paths = new String[files.length];
2161:                for (int i = 0; i < files.length; i++) {
2162:                    paths[i] = files[i].getAbsolutePath();
2163:                    paths[i] = paths[i].replace(File.separatorChar, '/');
2164:                }
2165:                Collection condencedPaths = new ArrayList();
2166:                String commonParentPath = SVNPathUtil.condencePaths(paths,
2167:                        condencedPaths, false);
2168:                if (condencedPaths.isEmpty()) {
2169:                    condencedPaths.add(SVNPathUtil.tail(commonParentPath));
2170:                    commonParentPath = SVNPathUtil.removeTail(commonParentPath);
2171:                }
2172:                if (commonParentPath == null || "".equals(commonParentPath)) {
2173:                    SVNErrorMessage err = SVNErrorMessage
2174:                            .create(SVNErrorCode.UNSUPPORTED_FEATURE,
2175:                                    "No common parent found, unable to operate on dijoint arguments");
2176:                    SVNErrorManager.error(err);
2177:                }
2178:                paths = (String[]) condencedPaths
2179:                        .toArray(new String[condencedPaths.size()]);
2180:                int depth = 0;
2181:                for (int i = 0; i < paths.length; i++) {
2182:                    int segments = SVNPathUtil.getSegmentsCount(paths[i]);
2183:                    if (depth < segments) {
2184:                        depth = segments;
2185:                    }
2186:                }
2187:                wcAccess.probeOpen(
2188:                        new File(commonParentPath).getAbsoluteFile(), true,
2189:                        depth);
2190:                for (int i = 0; i < paths.length; i++) {
2191:                    File file = new File(commonParentPath, paths[i]);
2192:                    SVNEntry entry = wcAccess.getEntry(file, false);
2193:                    if (entry == null) {
2194:                        SVNErrorMessage err = SVNErrorMessage.create(
2195:                                SVNErrorCode.UNVERSIONED_RESOURCE,
2196:                                "''{0}'' is not under version control", file
2197:                                        .getName());
2198:                        SVNErrorManager.error(err);
2199:                    }
2200:                    if (entry.getURL() == null) {
2201:                        SVNErrorMessage err = SVNErrorMessage.create(
2202:                                SVNErrorCode.ENTRY_MISSING_URL,
2203:                                "''{0}'' has no URL", file);
2204:                        SVNErrorManager.error(err);
2205:                    }
2206:                    if (lock) {
2207:                        SVNRevision revision = stealLock ? SVNRevision.UNDEFINED
2208:                                : SVNRevision.create(entry.getRevision());
2209:                        lockInfo.put(entry.getSVNURL(), new LockInfo(file,
2210:                                revision));
2211:                    } else {
2212:                        if (!stealLock && entry.getLockToken() == null) {
2213:                            SVNErrorMessage err = SVNErrorMessage
2214:                                    .create(
2215:                                            SVNErrorCode.CLIENT_MISSING_LOCK_TOKEN,
2216:                                            "''{0}'' is not locked in this working copy",
2217:                                            file);
2218:                            SVNErrorManager.error(err);
2219:                        }
2220:                        lockInfo.put(entry.getSVNURL(), new LockInfo(file,
2221:                                entry.getLockToken()));
2222:                    }
2223:                }
2224:                checkCancelled();
2225:                SVNURL[] urls = (SVNURL[]) lockInfo.keySet().toArray(
2226:                        new SVNURL[lockInfo.size()]);
2227:                Collection urlPaths = new HashSet();
2228:                final SVNURL topURL = SVNURLUtil.condenceURLs(urls, urlPaths,
2229:                        false);
2230:                if (urlPaths.isEmpty()) {
2231:                    urlPaths.add("");
2232:                }
2233:                if (topURL == null) {
2234:                    SVNErrorMessage err = SVNErrorMessage
2235:                            .create(SVNErrorCode.UNSUPPORTED_FEATURE,
2236:                                    "Unable to lock/unlock across multiple repositories");
2237:                    SVNErrorManager.error(err);
2238:                }
2239:                // prepare Map for SVNRepository (decoded path : revision/lock token).
2240:                for (Iterator encodedPaths = urlPaths.iterator(); encodedPaths
2241:                        .hasNext();) {
2242:                    String encodedPath = (String) encodedPaths.next();
2243:                    // get LockInfo for it.
2244:                    SVNURL fullURL = topURL.appendPath(encodedPath, true);
2245:                    LockInfo info = (LockInfo) lockInfo.get(fullURL);
2246:                    encodedPath = SVNEncodingUtil.uriDecode(encodedPath);
2247:                    if (lock) {
2248:                        if (info.myRevision == SVNRevision.UNDEFINED) {
2249:                            lockPaths.put(encodedPath, null);
2250:                        } else {
2251:                            lockPaths.put(encodedPath, new Long(info.myRevision
2252:                                    .getNumber()));
2253:                        }
2254:                    } else {
2255:                        lockPaths.put(encodedPath, info.myToken);
2256:                    }
2257:                }
2258:                return topURL;
2259:            }
2260:
2261:            /**
2262:             * Collects information about Working Copy item(s) and passes it to an 
2263:             * info handler. 
2264:             * 
2265:             * <p>
2266:             * If <code>revision</code> is valid and not local,  
2267:             * then information will be collected on remote items (that is taken from
2268:             * a repository). Otherwise information is gathered on local items not
2269:             * accessing a repository.
2270:             * 
2271:             * @param  path            a WC item on which info should be obtained
2272:             * @param  revision        a target revision 
2273:             * @param  recursive       <span class="javakeyword">true</span> to
2274:             *                         descend recursively (relevant for directories)
2275:             * @param  handler         a caller's info handler
2276:             * @throws SVNException    if one of the following is true:
2277:             *                         <ul>
2278:             *                         <li><code>path</code> is not under version control
2279:             *                         <li>can not obtain a URL corresponding to <code>path</code> to 
2280:             *                         get its information from the repository - there's no such entry
2281:             *                         <li>if a remote info: <code>path</code> is an item that does not exist in
2282:             *                         the specified <code>revision</code>
2283:             *                         </ul>
2284:             * @see                    #doInfo(File, SVNRevision)
2285:             * @see                    #doInfo(SVNURL, SVNRevision, SVNRevision, boolean, ISVNInfoHandler)
2286:             */
2287:            public void doInfo(File path, SVNRevision revision,
2288:                    boolean recursive, ISVNInfoHandler handler)
2289:                    throws SVNException {
2290:                doInfo(path, SVNRevision.UNDEFINED, revision, recursive,
2291:                        handler);
2292:            }
2293:
2294:            /**
2295:             * Collects information about Working Copy item(s) and passes it to an 
2296:             * info handler. 
2297:             * 
2298:             * <p>
2299:             * If <code>revision</code> & <code>pegRevision</code> are valid and not 
2300:             * local, then information will be collected 
2301:             * on remote items (that is taken from a repository). Otherwise information 
2302:             * is gathered on local items not accessing a repository.
2303:             * 
2304:             * @param  path            a WC item on which info should be obtained
2305:             * @param  pegRevision     a revision in which <code>path</code> is first 
2306:             *                         looked up
2307:             * @param  revision        a target revision 
2308:             * @param  recursive       <span class="javakeyword">true</span> to
2309:             *                         descend recursively (relevant for directories)
2310:             * @param  handler         a caller's info handler
2311:             * @throws SVNException    if one of the following is true:
2312:             *                         <ul>
2313:             *                         <li><code>path</code> is not under version control
2314:             *                         <li>can not obtain a URL corresponding to <code>path</code> to 
2315:             *                         get its information from the repository - there's no such entry
2316:             *                         <li>if a remote info: <code>path</code> is an item that does not exist in
2317:             *                         the specified <code>revision</code>
2318:             *                         </ul>
2319:             * @see                    #doInfo(File, SVNRevision)
2320:             * @see                    #doInfo(File, SVNRevision, boolean, ISVNInfoHandler)
2321:             */
2322:            public void doInfo(File path, SVNRevision pegRevision,
2323:                    SVNRevision revision, boolean recursive,
2324:                    ISVNInfoHandler handler) throws SVNException {
2325:                if (handler == null) {
2326:                    return;
2327:                }
2328:                boolean local = (revision == null || !revision.isValid() || revision
2329:                        .isLocal())
2330:                        && (pegRevision == null || !pegRevision.isValid() || pegRevision
2331:                                .isLocal());
2332:
2333:                if (!local) {
2334:                    SVNWCAccess wcAccess = createWCAccess();
2335:                    SVNRevision wcRevision = null;
2336:                    SVNURL url = null;
2337:                    try {
2338:                        wcAccess.probeOpen(path, false, 0);
2339:                        SVNEntry entry = wcAccess.getEntry(path, false);
2340:                        if (entry == null) {
2341:                            SVNErrorMessage err = SVNErrorMessage.create(
2342:                                    SVNErrorCode.UNVERSIONED_RESOURCE,
2343:                                    "''{0}'' is not under version control",
2344:                                    path);
2345:                            SVNErrorManager.error(err);
2346:                        }
2347:                        url = entry.getSVNURL();
2348:                        if (url == null) {
2349:                            SVNErrorMessage err = SVNErrorMessage.create(
2350:                                    SVNErrorCode.ENTRY_MISSING_URL,
2351:                                    "''{0}'' has no URL", path);
2352:                            SVNErrorManager.error(err);
2353:                        }
2354:                        wcRevision = SVNRevision.create(entry.getRevision());
2355:                    } finally {
2356:                        wcAccess.close();
2357:                    }
2358:                    doInfo(url,
2359:                            pegRevision == null || !pegRevision.isValid()
2360:                                    || pegRevision.isLocal() ? wcRevision
2361:                                    : pegRevision, revision, recursive, handler);
2362:                    return;
2363:                }
2364:                SVNWCAccess wcAccess = createWCAccess();
2365:                try {
2366:                    wcAccess.probeOpen(path, false,
2367:                            recursive ? SVNWCAccess.INFINITE_DEPTH : 0);
2368:                    SVNEntry entry = wcAccess.getEntry(path, false);
2369:                    if (entry == null) {
2370:                        SVNErrorMessage err = SVNErrorMessage.create(
2371:                                SVNErrorCode.UNVERSIONED_RESOURCE,
2372:                                "Cannot read entry for ''{0}''", path);
2373:                        SVNErrorManager.error(err);
2374:                    }
2375:                    if (entry.isFile()) {
2376:                        reportEntry(path, entry, handler);
2377:                    } else if (entry.isDirectory()) {
2378:                        if (recursive) {
2379:                            reportAllEntries(wcAccess, path, handler);
2380:                        } else {
2381:                            reportEntry(path, entry, handler);
2382:                        }
2383:                    }
2384:                } finally {
2385:                    wcAccess.close();
2386:                }
2387:            }
2388:
2389:            private void reportEntry(File path, SVNEntry entry,
2390:                    ISVNInfoHandler handler) throws SVNException {
2391:                if (entry.isDirectory() && !"".equals(entry.getName())) {
2392:                    return;
2393:                }
2394:                handler.handleInfo(SVNInfo.createInfo(path, entry));
2395:            }
2396:
2397:            private void reportAllEntries(SVNWCAccess wcAccess, File path,
2398:                    ISVNInfoHandler handler) throws SVNException {
2399:                SVNEntry entry = wcAccess.getEntry(path, false);
2400:                reportEntry(path, entry, handler);
2401:                if (entry.isDirectory()) {
2402:                    SVNAdminArea dir = wcAccess.retrieve(path);
2403:                    for (Iterator entries = dir.entries(false); entries
2404:                            .hasNext();) {
2405:                        SVNEntry childEntry = (SVNEntry) entries.next();
2406:                        if (dir.getThisDirName().equals(childEntry.getName())) {
2407:                            continue;
2408:                        }
2409:                        File childPath = dir.getFile(childEntry.getName());
2410:                        if (childEntry.isDirectory()) {
2411:                            reportAllEntries(wcAccess, childPath, handler);
2412:                        }
2413:                        reportEntry(childPath, childEntry, handler);
2414:                    }
2415:                }
2416:            }
2417:
2418:            /**
2419:             * Collects information about item(s) in a repository and passes it to 
2420:             * an info handler. 
2421:             * 
2422:             * 
2423:             * @param  url              a URL of an item which information is to be
2424:             *                          obtained and processed 
2425:             * @param  pegRevision      a revision in which the item is first looked up
2426:             * @param  revision         a target revision
2427:             * @param  recursive        <span class="javakeyword">true</span> to
2428:             *                          descend recursively (relevant for directories)
2429:             * @param  handler          a caller's info handler
2430:             * @throws SVNException     if <code>url</code> is an item that does not exist in
2431:             *                          the specified <code>revision</code>
2432:             * @see                     #doInfo(SVNURL, SVNRevision, SVNRevision)
2433:             * @see                     #doInfo(File, SVNRevision, boolean, ISVNInfoHandler)
2434:             */
2435:            public void doInfo(SVNURL url, SVNRevision pegRevision,
2436:                    SVNRevision revision, boolean recursive,
2437:                    ISVNInfoHandler handler) throws SVNException {
2438:                if (revision == null || !revision.isValid()) {
2439:                    revision = SVNRevision.HEAD;
2440:                }
2441:                if (pegRevision == null || !pegRevision.isValid()) {
2442:                    pegRevision = revision;
2443:                }
2444:
2445:                SVNRepository repos = createRepository(url, null, pegRevision,
2446:                        revision);
2447:                ;
2448:                url = repos.getLocation();
2449:                long revNum = getRevisionNumber(revision, repos, null);
2450:                SVNDirEntry rootEntry = null;
2451:                try {
2452:                    rootEntry = repos.info("", revNum);
2453:                } catch (SVNException e) {
2454:                    if (e.getErrorMessage() != null
2455:                            && e.getErrorMessage().getErrorCode() == SVNErrorCode.RA_NOT_IMPLEMENTED) {
2456:                        // for svnserve older then 1.2.0
2457:                        if (repos.getLocation().equals(
2458:                                repos.getRepositoryRoot(true))) {
2459:                            rootEntry = new SVNDirEntry(url, "",
2460:                                    SVNNodeKind.DIR, -1, false, -1, null, null);
2461:                        } else {
2462:                            String name = SVNPathUtil.tail(url.getPath());
2463:                            SVNURL location = repos.getLocation();
2464:                            repos.setLocation(location.removePathTail(), false);
2465:                            Collection dirEntries = repos.getDir("", revNum,
2466:                                    null, (Collection) null);
2467:                            for (Iterator ents = dirEntries.iterator(); ents
2468:                                    .hasNext();) {
2469:                                SVNDirEntry dirEntry = (SVNDirEntry) ents
2470:                                        .next();
2471:                                // dir entry name may differ from 'name', due to renames...
2472:                                if (name.equals(dirEntry.getName())) {
2473:                                    rootEntry = dirEntry;
2474:                                    break;
2475:                                }
2476:                            }
2477:                            repos.setLocation(location, false);
2478:                        }
2479:                    } else {
2480:                        throw e;
2481:                    }
2482:                }
2483:                if (rootEntry == null
2484:                        || rootEntry.getKind() == SVNNodeKind.NONE) {
2485:                    SVNErrorMessage err = SVNErrorMessage.create(
2486:                            SVNErrorCode.RA_ILLEGAL_URL,
2487:                            "URL ''{0}'' non-existent in revision ''{1}''",
2488:                            new Object[] { url, new Long(revNum) });
2489:                    SVNErrorManager.error(err);
2490:                }
2491:                SVNURL reposRoot = repos.getRepositoryRoot(true);
2492:                String reposUUID = repos.getRepositoryUUID(true);
2493:                // 1. get locks for this dir and below (only for dir).
2494:                // and only when pegRev is HEAD.
2495:                SVNLock[] locks = null;
2496:                if (pegRevision == SVNRevision.HEAD
2497:                        && rootEntry.getKind() == SVNNodeKind.DIR) {
2498:                    try {
2499:                        locks = repos.getLocks("");
2500:                    } catch (SVNException e) {
2501:                        // may be not supported.
2502:                        if (e.getErrorMessage() != null
2503:                                && e.getErrorMessage().getErrorCode() == SVNErrorCode.RA_NOT_IMPLEMENTED) {
2504:                            locks = new SVNLock[0];
2505:                        } else {
2506:                            throw e;
2507:                        }
2508:                    }
2509:                }
2510:                locks = locks == null ? new SVNLock[0] : locks;
2511:                Map locksMap = new HashMap();
2512:                for (int i = 0; i < locks.length; i++) {
2513:                    SVNLock lock = locks[i];
2514:                    locksMap.put(lock.getPath(), lock);
2515:                }
2516:                // 2. add lock for this entry, only when it is 'related' to head (and is a file).
2517:                if (rootEntry.getKind() == SVNNodeKind.FILE) {
2518:                    try {
2519:                        SVNRepositoryLocation[] locations = getLocations(url,
2520:                                null, null, revision, SVNRevision.HEAD,
2521:                                SVNRevision.UNDEFINED);
2522:                        if (locations != null && locations.length > 0) {
2523:                            SVNURL headURL = locations[0].getURL();
2524:                            if (headURL.equals(url)) {
2525:                                // get lock for this item (@headURL).
2526:                                try {
2527:                                    SVNLock lock = repos.getLock("");
2528:                                    if (lock != null) {
2529:                                        locksMap.put(lock.getPath(), lock);
2530:                                    }
2531:                                } catch (SVNException e) {
2532:                                    if (!(e.getErrorMessage() != null && e
2533:                                            .getErrorMessage().getErrorCode() == SVNErrorCode.RA_NOT_IMPLEMENTED)) {
2534:                                        throw e;
2535:                                    }
2536:                                }
2537:                            }
2538:                        }
2539:                    } catch (SVNException e) {
2540:                        SVNErrorCode code = e.getErrorMessage().getErrorCode();
2541:                        if (code != SVNErrorCode.FS_NOT_FOUND
2542:                                && code != SVNErrorCode.CLIENT_UNRELATED_RESOURCES) {
2543:                            throw e;
2544:                        }
2545:                    }
2546:                }
2547:
2548:                String fullPath = url.getPath();
2549:                String rootPath = fullPath.substring(reposRoot.getPath()
2550:                        .length());
2551:                if (!rootPath.startsWith("/")) {
2552:                    rootPath = "/" + rootPath;
2553:                }
2554:                collectInfo(repos, rootEntry, SVNRevision.create(revNum),
2555:                        rootPath, reposRoot, reposUUID, url, locksMap,
2556:                        recursive, handler);
2557:            }
2558:
2559:            /**
2560:             * Returns the current Working Copy min- and max- revisions as well as
2561:             * changes and switch status within a single string.
2562:             * 
2563:             * <p>
2564:             * A return string has a form of <code>"minR[:maxR][M][S]"</code> where:
2565:             * <ul>
2566:             * <li><code>minR</code> - is the smallest revision number met in the
2567:             * Working Copy
2568:             * <li><code>maxR</code> - is the biggest revision number met in the
2569:             * Working Copy; appears only if there are different revision in the
2570:             * Working Copy
2571:             * <li><code>M</code> - appears only if there're local edits to the 
2572:             * Working Copy - that means 'Modified'
2573:             * <li><code>S</code> - appears only if the Working Copy is switched
2574:             * against a different URL
2575:             * </ul>
2576:             * If <code>path</code> is a directory - this method recursively descends
2577:             * into the Working Copy, collects and processes local information. 
2578:             * 
2579:             * @param  path            a local path
2580:             * @param  trailURL        optional: if not <span class="javakeyword">null</span>
2581:             *                         specifies the name of the item that should be met 
2582:             *                         in the URL corresponding to the repository location
2583:             *                         of the <code>path</code>; if that URL ends with something
2584:             *                         different than this optional parameter - the Working
2585:             *                         Copy will be considered "switched"   
2586:             * @return                 brief info on the Working Copy or the string 
2587:             *                         "exported" if <code>path</code> is a clean directory  
2588:             * @throws SVNException    if <code>path</code> is neither versioned nor
2589:             *                         even exported
2590:             */
2591:            public String doGetWorkingCopyID(final File path, String trailURL)
2592:                    throws SVNException {
2593:                return doGetWorkingCopyID(path, trailURL, false);
2594:            }
2595:
2596:            public String doGetWorkingCopyID(final File path, String trailURL,
2597:                    final boolean committed) throws SVNException {
2598:                SVNWCAccess wcAccess = createWCAccess();
2599:                try {
2600:                    wcAccess.open(path, false, 0);
2601:                } catch (SVNException e) {
2602:                    SVNFileType pathType = SVNFileType.getType(path);
2603:                    if (pathType == SVNFileType.DIRECTORY) {
2604:                        return "exported";
2605:                    } else if (pathType == SVNFileType.NONE) {
2606:                        return null;
2607:                    }
2608:                    return "'" + path + "' is not versioned and not exported";
2609:                } finally {
2610:                    wcAccess.close();
2611:                }
2612:                SVNStatusClient statusClient = new SVNStatusClient(
2613:                        (ISVNAuthenticationManager) null, getOptions());
2614:                statusClient.setIgnoreExternals(true);
2615:                final long[] maxRevision = new long[1];
2616:                final long[] minRevision = new long[] { -1 };
2617:                final boolean[] switched = new boolean[2];
2618:                final String[] wcURL = new String[1];
2619:                statusClient.doStatus(path, true, false, true, false, false,
2620:                        new ISVNStatusHandler() {
2621:                            public void handleStatus(SVNStatus status) {
2622:                                if (status.getEntryProperties() == null
2623:                                        || status.getEntryProperties()
2624:                                                .isEmpty()) {
2625:                                    return;
2626:                                }
2627:                                if (status.getContentsStatus() != SVNStatusType.STATUS_ADDED) {
2628:                                    SVNRevision revision = committed ? status
2629:                                            .getCommittedRevision() : status
2630:                                            .getRevision();
2631:                                    if (revision != null) {
2632:                                        if (minRevision[0] < 0
2633:                                                || minRevision[0] > revision
2634:                                                        .getNumber()) {
2635:                                            minRevision[0] = revision
2636:                                                    .getNumber();
2637:                                        }
2638:                                        maxRevision[0] = Math.max(
2639:                                                maxRevision[0], revision
2640:                                                        .getNumber());
2641:                                    }
2642:                                }
2643:                                switched[0] |= status.isSwitched();
2644:                                switched[1] |= status.getContentsStatus() != SVNStatusType.STATUS_NORMAL;
2645:                                switched[1] |= status.getPropertiesStatus() != SVNStatusType.STATUS_NORMAL
2646:                                        && status.getPropertiesStatus() != SVNStatusType.STATUS_NONE;
2647:                                if (wcURL[0] == null
2648:                                        && status.getFile() != null
2649:                                        && status.getFile().equals(path)
2650:                                        && status.getURL() != null) {
2651:                                    wcURL[0] = status.getURL().toString();
2652:                                }
2653:                            }
2654:                        });
2655:                if (!switched[0] && trailURL != null) {
2656:                    if (wcURL[0] == null) {
2657:                        switched[0] = true;
2658:                    } else {
2659:                        switched[0] = !wcURL[0].endsWith(trailURL);
2660:                    }
2661:                }
2662:                StringBuffer id = new StringBuffer();
2663:                id.append(minRevision[0]);
2664:                if (minRevision[0] != maxRevision[0]) {
2665:                    id.append(":").append(maxRevision[0]);
2666:                }
2667:                if (switched[1]) {
2668:                    id.append("M");
2669:                }
2670:                if (switched[0]) {
2671:                    id.append("S");
2672:                }
2673:                return id.toString();
2674:            }
2675:
2676:            /**
2677:             * Collects and returns information on a single Working Copy item.
2678:             * 
2679:             * <p>
2680:             * If <code>revision</code> is valid and not {@link SVNRevision#WORKING WORKING} 
2681:             * then information will be collected on remote items (that is taken from
2682:             * a repository). Otherwise information is gathered on local items not
2683:             * accessing a repository.
2684:             * 
2685:             * @param  path            a WC item on which info should be obtained
2686:             * @param  revision        a target revision
2687:             * @return                 collected info
2688:             * @throws SVNException    if one of the following is true:
2689:             *                         <ul>
2690:             *                         <li><code>path</code> is not under version control
2691:             *                         <li>can not obtain a URL corresponding to <code>path</code> to 
2692:             *                         get its information from the repository - there's no such entry 
2693:             *                         <li>if a remote info: <code>path</code> is an item that does not exist in
2694:             *                         the specified <code>revision</code>
2695:             *                         </ul>
2696:             * @see                    #doInfo(File, SVNRevision, boolean, ISVNInfoHandler)
2697:             * @see                    #doInfo(SVNURL, SVNRevision, SVNRevision)                        
2698:             */
2699:            public SVNInfo doInfo(File path, SVNRevision revision)
2700:                    throws SVNException {
2701:                final SVNInfo[] result = new SVNInfo[1];
2702:                doInfo(path, revision, false, new ISVNInfoHandler() {
2703:                    public void handleInfo(SVNInfo info) {
2704:                        if (result[0] == null) {
2705:                            result[0] = info;
2706:                        }
2707:                    }
2708:                });
2709:                return result[0];
2710:            }
2711:
2712:            /**
2713:             * Collects and returns information on a single item in a repository. 
2714:             * 
2715:             * @param  url             a URL of an item which information is to be
2716:             *                         obtained       
2717:             * @param  pegRevision     a revision in which the item is first looked up
2718:             * @param  revision        a target revision
2719:             * @return                 collected info
2720:             * @throws SVNException    if <code>url</code> is an item that does not exist in
2721:             *                         the specified <code>revision</code>
2722:             * @see                    #doInfo(SVNURL, SVNRevision, SVNRevision, boolean, ISVNInfoHandler)
2723:             * @see                    #doInfo(File, SVNRevision)
2724:             */
2725:            public SVNInfo doInfo(SVNURL url, SVNRevision pegRevision,
2726:                    SVNRevision revision) throws SVNException {
2727:                final SVNInfo[] result = new SVNInfo[1];
2728:                doInfo(url, pegRevision, revision, false,
2729:                        new ISVNInfoHandler() {
2730:                            public void handleInfo(SVNInfo info) {
2731:                                if (result[0] == null) {
2732:                                    result[0] = info;
2733:                                }
2734:                            }
2735:                        });
2736:                return result[0];
2737:            }
2738:
2739:            public void doCleanupWCProperties(File directory)
2740:                    throws SVNException {
2741:                SVNWCAccess wcAccess = SVNWCAccess.newInstance(this );
2742:                try {
2743:                    SVNAdminArea dir = wcAccess.open(directory, true, true, -1);
2744:                    if (dir != null) {
2745:                        SVNPropertiesManager
2746:                                .deleteWCProperties(dir, null, true);
2747:                    }
2748:                } finally {
2749:                    wcAccess.close();
2750:                }
2751:            }
2752:
2753:            private void collectInfo(SVNRepository repos, SVNDirEntry entry,
2754:                    SVNRevision rev, String path, SVNURL root, String uuid,
2755:                    SVNURL url, Map locks, boolean recursive,
2756:                    ISVNInfoHandler handler) throws SVNException {
2757:                checkCancelled();
2758:                String displayPath = repos.getFullPath(path);
2759:                displayPath = displayPath.substring(repos.getLocation()
2760:                        .getPath().length());
2761:                if ("".equals(displayPath) || "/".equals(displayPath)) {
2762:                    displayPath = path;
2763:                }
2764:                handler.handleInfo(SVNInfo.createInfo(displayPath, root, uuid,
2765:                        url, rev, entry, (SVNLock) locks.get(path)));
2766:                if (entry.getKind() == SVNNodeKind.DIR && recursive) {
2767:                    Collection children = repos.getDir(path, rev.getNumber(),
2768:                            null, new ArrayList());
2769:                    for (Iterator ents = children.iterator(); ents.hasNext();) {
2770:                        SVNDirEntry child = (SVNDirEntry) ents.next();
2771:                        SVNURL childURL = url
2772:                                .appendPath(child.getName(), false);
2773:                        collectInfo(repos, child, rev, SVNPathUtil.append(path,
2774:                                child.getName()), root, uuid, childURL, locks,
2775:                                recursive, handler);
2776:                    }
2777:                }
2778:            }
2779:
2780:            private void doGetRemoteProperty(SVNURL url, String path,
2781:                    SVNRepository repos, String propName, SVNRevision rev,
2782:                    boolean recursive, ISVNPropertyHandler handler)
2783:                    throws SVNException {
2784:                checkCancelled();
2785:                long revNumber = getRevisionNumber(rev, repos, null);
2786:                SVNNodeKind kind = repos.checkPath(path, revNumber);
2787:                Map props = new HashMap();
2788:                if (kind == SVNNodeKind.DIR) {
2789:                    Collection children = repos.getDir(path, revNumber, props,
2790:                            recursive ? new ArrayList() : null);
2791:                    if (propName != null) {
2792:                        String value = (String) props.get(propName);
2793:                        if (value != null) {
2794:                            handler.handleProperty(url, new SVNPropertyData(
2795:                                    propName, value));
2796:                        }
2797:                    } else {
2798:                        for (Iterator names = props.keySet().iterator(); names
2799:                                .hasNext();) {
2800:                            String name = (String) names.next();
2801:                            if (name.startsWith(SVNProperty.SVN_ENTRY_PREFIX)
2802:                                    || name
2803:                                            .startsWith(SVNProperty.SVN_WC_PREFIX)) {
2804:                                continue;
2805:                            }
2806:                            String value = (String) props.get(name);
2807:                            handler.handleProperty(url, new SVNPropertyData(
2808:                                    name, value));
2809:                        }
2810:                    }
2811:                    if (recursive) {
2812:                        checkCancelled();
2813:                        for (Iterator entries = children.iterator(); entries
2814:                                .hasNext();) {
2815:                            SVNDirEntry child = (SVNDirEntry) entries.next();
2816:                            SVNURL childURL = url.appendPath(child.getName(),
2817:                                    false);
2818:                            String childPath = "".equals(path) ? child
2819:                                    .getName() : SVNPathUtil.append(path, child
2820:                                    .getName());
2821:                            doGetRemoteProperty(childURL, childPath, repos,
2822:                                    propName, rev, recursive, handler);
2823:                        }
2824:                    }
2825:                } else if (kind == SVNNodeKind.FILE) {
2826:                    repos.getFile(path, revNumber, props, null);
2827:                    if (propName != null) {
2828:                        String value = (String) props.get(propName);
2829:                        if (value != null) {
2830:                            handler.handleProperty(url, new SVNPropertyData(
2831:                                    propName, value));
2832:                        }
2833:                    } else {
2834:                        for (Iterator names = props.keySet().iterator(); names
2835:                                .hasNext();) {
2836:                            String name = (String) names.next();
2837:                            if (name.startsWith(SVNProperty.SVN_ENTRY_PREFIX)
2838:                                    || name
2839:                                            .startsWith(SVNProperty.SVN_WC_PREFIX)) {
2840:                                continue;
2841:                            }
2842:                            String value = (String) props.get(name);
2843:                            handler.handleProperty(url, new SVNPropertyData(
2844:                                    name, value));
2845:                        }
2846:                    }
2847:                }
2848:            }
2849:
2850:            private void doGetLocalProperty(SVNAdminArea area, String propName,
2851:                    boolean base, ISVNPropertyHandler handler)
2852:                    throws SVNException {
2853:                checkCancelled();
2854:                for (Iterator entries = area.entries(false); entries.hasNext();) {
2855:                    SVNEntry entry = (SVNEntry) entries.next();
2856:                    if (entry.getKind() == SVNNodeKind.DIR
2857:                            && !"".equals(entry.getName())) {
2858:                        continue;
2859:                    }
2860:                    if ((base && entry.isScheduledForAddition())
2861:                            || (!base && entry.isScheduledForDeletion())) {
2862:                        continue;
2863:                    }
2864:                    SVNVersionedProperties properties = base ? area
2865:                            .getBaseProperties(entry.getName()) : area
2866:                            .getProperties(entry.getName());
2867:                    if (propName != null) {
2868:                        String propVal = properties.getPropertyValue(propName);
2869:                        if (propVal != null) {
2870:                            handler.handleProperty(area
2871:                                    .getFile(entry.getName()),
2872:                                    new SVNPropertyData(propName, propVal));
2873:                        }
2874:                    } else {
2875:                        Map allProps = properties.asMap();
2876:                        for (Iterator names = allProps.keySet().iterator(); names
2877:                                .hasNext();) {
2878:                            String name = (String) names.next();
2879:                            String val = (String) allProps.get(name);
2880:                            handler.handleProperty(area
2881:                                    .getFile(entry.getName()),
2882:                                    new SVNPropertyData(name, val));
2883:                        }
2884:                    }
2885:                }
2886:
2887:                for (Iterator entries = area.entries(false); entries.hasNext();) {
2888:                    SVNEntry entry = (SVNEntry) entries.next();
2889:                    if (entry.getKind() == SVNNodeKind.DIR
2890:                            && !"".equals(entry.getName())) {
2891:                        SVNAdminArea childArea = null;
2892:                        try {
2893:                            childArea = area.getWCAccess().retrieve(
2894:                                    area.getFile(entry.getName()));
2895:                        } catch (SVNException e) {
2896:                            if (e.getErrorMessage().getErrorCode() == SVNErrorCode.WC_NOT_LOCKED) {
2897:                                continue;
2898:                            }
2899:                            throw e;
2900:                        }
2901:                        if (childArea != null) {
2902:                            doGetLocalProperty(childArea, propName, base,
2903:                                    handler);
2904:                        }
2905:                    }
2906:                }
2907:            }
2908:
2909:            private void doSetLocalProperty(SVNAdminArea anchor, String name,
2910:                    String propName, String propValue, boolean force,
2911:                    boolean recursive, boolean cancel,
2912:                    ISVNPropertyHandler handler) throws SVNException {
2913:                if (cancel) {
2914:                    checkCancelled();
2915:                }
2916:                if (!"".equals(name)) {
2917:                    SVNEntry entry = anchor.getEntry(name, true);
2918:                    if (entry == null || (recursive && entry.isDeleted())) {
2919:                        return;
2920:                    }
2921:                    if (entry.getKind() == SVNNodeKind.DIR) {
2922:                        File path = anchor.getFile(name);
2923:                        SVNAdminArea dir = anchor.getWCAccess().retrieve(path);
2924:                        if (dir != null) {
2925:                            doSetLocalProperty(dir, "", propName, propValue,
2926:                                    force, recursive, cancel, handler);
2927:                        }
2928:                    } else if (entry.getKind() == SVNNodeKind.FILE) {
2929:                        File wcFile = anchor.getFile(name);
2930:                        if ((SVNProperty.IGNORE.equals(propName) || SVNProperty.EXTERNALS
2931:                                .equals(propName))
2932:                                && propValue != null) {
2933:                            if (!recursive) {
2934:                                SVNErrorMessage err = SVNErrorMessage
2935:                                        .create(
2936:                                                SVNErrorCode.ILLEGAL_TARGET,
2937:                                                "Cannot set ''{0}'' on a file (''{1}'')",
2938:                                                new Object[] { propName, wcFile });
2939:                                SVNErrorManager.error(err);
2940:                            }
2941:                            return;
2942:                        }
2943:                        SVNVersionedProperties props = anchor
2944:                                .getProperties(name);
2945:                        if (SVNProperty.EXECUTABLE.equals(propName)) {
2946:                            SVNFileUtil
2947:                                    .setExecutable(wcFile, propValue != null);
2948:                        }
2949:                        if (!force && SVNProperty.EOL_STYLE.equals(propName)
2950:                                && propValue != null) {
2951:                            if (SVNProperty.isBinaryMimeType(props
2952:                                    .getPropertyValue(SVNProperty.MIME_TYPE))) {
2953:                                if (!recursive) {
2954:                                    SVNErrorMessage err = SVNErrorMessage
2955:                                            .create(
2956:                                                    SVNErrorCode.ILLEGAL_TARGET,
2957:                                                    "File ''{0}'' has binary mime type property",
2958:                                                    wcFile);
2959:                                    SVNErrorManager.error(err);
2960:                                }
2961:                                return;
2962:                            }
2963:                            if (!SVNTranslator.checkNewLines(wcFile)) {
2964:                                SVNErrorMessage err = SVNErrorMessage
2965:                                        .create(
2966:                                                SVNErrorCode.ILLEGAL_TARGET,
2967:                                                "File ''{0}'' has incosistent newlines",
2968:                                                wcFile);
2969:                                SVNErrorManager.error(err);
2970:                            }
2971:                        }
2972:                        String oldValue = props.getPropertyValue(propName);
2973:                        boolean modified = oldValue == null ? propValue != null
2974:                                : !oldValue.equals(propValue);
2975:                        props.setPropertyValue(propName, propValue);
2976:
2977:                        if (SVNProperty.EOL_STYLE.equals(propName)
2978:                                || SVNProperty.KEYWORDS.equals(propName)) {
2979:                            entry.setTextTime(null);
2980:                        } else if (SVNProperty.NEEDS_LOCK.equals(propName)
2981:                                && propValue == null) {
2982:                            SVNFileUtil.setReadonly(wcFile, false);
2983:                        }
2984:                        if (modified && handler != null) {
2985:                            handler.handleProperty(anchor.getFile(name),
2986:                                    new SVNPropertyData(propName, propValue));
2987:                        }
2988:                    }
2989:                    SVNLog log = anchor.getLog();
2990:                    anchor.saveVersionedProperties(log, true);
2991:                    anchor.saveEntries(false);
2992:                    log.save();
2993:                    anchor.runLogs();
2994:                    return;
2995:                }
2996:                SVNVersionedProperties props = anchor.getProperties(name);
2997:                if ((SVNProperty.KEYWORDS.equals(propName)
2998:                        || SVNProperty.EOL_STYLE.equals(propName)
2999:                        || SVNProperty.MIME_TYPE.equals(propName) || SVNProperty.EXECUTABLE
3000:                        .equals(propName))
3001:                        && propValue != null) {
3002:                    if (!recursive) {
3003:                        SVNErrorMessage err = SVNErrorMessage.create(
3004:                                SVNErrorCode.ILLEGAL_TARGET,
3005:                                "Cannot set ''{0}'' on a directory (''{1}'')",
3006:                                new Object[] { propName, anchor.getRoot() });
3007:                        SVNErrorManager.error(err);
3008:                    }
3009:                } else {
3010:                    String oldValue = props.getPropertyValue(propName);
3011:                    boolean modified = oldValue == null ? propValue != null
3012:                            : !oldValue.equals(propValue);
3013:                    props.setPropertyValue(propName, propValue);
3014:                    SVNLog log = anchor.getLog();
3015:                    anchor.saveVersionedProperties(log, true);
3016:                    log.save();
3017:                    anchor.runLogs();
3018:                    if (modified && handler != null) {
3019:                        handler.handleProperty(anchor.getFile(name),
3020:                                new SVNPropertyData(propName, propValue));
3021:                    }
3022:                }
3023:                if (!recursive) {
3024:                    return;
3025:                }
3026:                for (Iterator ents = anchor.entries(true); ents.hasNext();) {
3027:                    SVNEntry entry = (SVNEntry) ents.next();
3028:                    if ("".equals(entry.getName())) {
3029:                        continue;
3030:                    }
3031:                    doSetLocalProperty(anchor, entry.getName(), propName,
3032:                            propValue, force, recursive, cancel, handler);
3033:                }
3034:            }
3035:
3036:            private static String validatePropertyName(String name)
3037:                    throws SVNException {
3038:                if (name == null || name.trim().length() == 0) {
3039:                    SVNErrorMessage err = SVNErrorMessage.create(
3040:                            SVNErrorCode.CLIENT_PROPERTY_NAME,
3041:                            "Property name is empty");
3042:                    SVNErrorManager.error(err);
3043:                    return name;
3044:                }
3045:                name = name.trim();
3046:                if (!(Character.isLetter(name.charAt(0))
3047:                        || name.charAt(0) == ':' || name.charAt(0) == '_')) {
3048:                    SVNErrorMessage err = SVNErrorMessage.create(
3049:                            SVNErrorCode.CLIENT_PROPERTY_NAME,
3050:                            "Bad property name ''{0}''", name);
3051:                    SVNErrorManager.error(err);
3052:                }
3053:                for (int i = 1; i < name.length(); i++) {
3054:                    if (!(Character.isLetterOrDigit(name.charAt(i))
3055:                            || name.charAt(i) == '-' || name.charAt(i) == '.'
3056:                            || name.charAt(i) == ':' || name.charAt(i) == '_')) {
3057:                        SVNErrorMessage err = SVNErrorMessage.create(
3058:                                SVNErrorCode.CLIENT_PROPERTY_NAME,
3059:                                "Bad property name ''{0}''", name);
3060:                        SVNErrorManager.error(err);
3061:                    }
3062:                }
3063:                return name;
3064:            }
3065:
3066:            private static String validatePropertyValue(String name,
3067:                    String value, boolean force) throws SVNException {
3068:                if (value == null) {
3069:                    return value;
3070:                }
3071:                if (SVNProperty.isSVNProperty(name)) {
3072:                    value = value.replaceAll("\r\n", "\n");
3073:                    value = value.replace('\r', '\n');
3074:                }
3075:                if (!force && SVNProperty.EOL_STYLE.equals(name)) {
3076:                    value = value.trim();
3077:                    if (SVNTranslator.getEOL(value) == null) {
3078:                        SVNErrorMessage err = SVNErrorMessage
3079:                                .create(
3080:                                        SVNErrorCode.IO_UNKNOWN_EOL,
3081:                                        "Unrecognized line ending style ''{0}''",
3082:                                        value);
3083:                        SVNErrorManager.error(err);
3084:                    }
3085:                } else if (!force && SVNProperty.MIME_TYPE.equals(name)) {
3086:                    value = value.trim();
3087:                } else if (SVNProperty.IGNORE.equals(name)
3088:                        || SVNProperty.EXTERNALS.equals(name)) {
3089:                    if (!value.endsWith("\n")) {
3090:                        value += "\n";
3091:                    }
3092:                    if (SVNProperty.EXTERNALS.equals(name)) {
3093:                        SVNExternalInfo[] externalInfos = SVNWCAccess
3094:                                .parseExternals("", value);
3095:                        for (int i = 0; externalInfos != null
3096:                                && i < externalInfos.length; i++) {
3097:                            String path = externalInfos[i].getPath();
3098:                            SVNExternalInfo.checkPath(path);
3099:                        }
3100:                    }
3101:                } else if (SVNProperty.KEYWORDS.equals(name)) {
3102:                    value = value.trim();
3103:                } else if (SVNProperty.EXECUTABLE.equals(name)
3104:                        || SVNProperty.SPECIAL.equals(name)
3105:                        || SVNProperty.NEEDS_LOCK.equals(name)) {
3106:                    value = "*";
3107:                }
3108:                return value;
3109:            }
3110:
3111:            private Map fetchLockTokens(SVNRepository repository,
3112:                    Map pathsTokensMap) throws SVNException {
3113:                Map tokens = new HashMap();
3114:                for (Iterator paths = pathsTokensMap.keySet().iterator(); paths
3115:                        .hasNext();) {
3116:                    String path = (String) paths.next();
3117:                    SVNLock lock = repository.getLock(path);
3118:                    if (lock == null || lock.getID() == null) {
3119:                        SVNErrorMessage err = SVNErrorMessage.create(
3120:                                SVNErrorCode.CLIENT_MISSING_LOCK_TOKEN,
3121:                                "''{0}'' is not locked", path);
3122:                        SVNErrorManager.error(err);
3123:                        continue;
3124:                    }
3125:                    tokens.put(path, lock.getID());
3126:                }
3127:                return tokens;
3128:            }
3129:
3130:            private void doGetLocalFileContents(File path, OutputStream dst,
3131:                    SVNRevision revision, boolean expandKeywords)
3132:                    throws SVNException {
3133:                SVNWCAccess wcAccess = createWCAccess();
3134:                InputStream input = null;
3135:                boolean hasMods = false;
3136:                SVNVersionedProperties properties = null;
3137:
3138:                try {
3139:                    SVNAdminArea area = wcAccess.open(path.getParentFile(),
3140:                            false, 0);
3141:                    SVNEntry entry = wcAccess.getEntry(path, false);
3142:                    if (entry == null) {
3143:                        SVNErrorMessage err = SVNErrorMessage
3144:                                .create(
3145:                                        SVNErrorCode.UNVERSIONED_RESOURCE,
3146:                                        "''{0}'' is not under version control or doesn''t exist",
3147:                                        path, SVNErrorMessage.TYPE_WARNING);
3148:                        SVNErrorManager.error(err);
3149:                    } else if (entry.getKind() != SVNNodeKind.FILE) {
3150:                        SVNErrorMessage err = SVNErrorMessage.create(
3151:                                SVNErrorCode.UNVERSIONED_RESOURCE,
3152:                                "''{0}'' refers to a directory", path,
3153:                                SVNErrorMessage.TYPE_WARNING);
3154:                        SVNErrorManager.error(err);
3155:                    }
3156:                    String name = path.getName();
3157:                    if (revision != SVNRevision.WORKING) {
3158:                        // get base version and base props.
3159:                        input = area.getBaseFileForReading(name, false);
3160:                        properties = area.getBaseProperties(name);
3161:                    } else {
3162:                        // get working version and working props.
3163:                        input = SVNFileUtil.openFileForReading(area
3164:                                .getFile(path.getName()));
3165:                        hasMods = area.hasPropModifications(name)
3166:                                || area.hasTextModifications(name, true);
3167:                        properties = area.getProperties(name);
3168:                    }
3169:                    String eolStyle = properties
3170:                            .getPropertyValue(SVNProperty.EOL_STYLE);
3171:                    String keywords = properties
3172:                            .getPropertyValue(SVNProperty.KEYWORDS);
3173:                    boolean special = properties
3174:                            .getPropertyValue(SVNProperty.SPECIAL) != null;
3175:                    byte[] eols = null;
3176:                    Map keywordsMap = null;
3177:                    String time = null;
3178:
3179:                    if (eolStyle != null) {
3180:                        eols = SVNTranslator.getEOL(eolStyle);
3181:                    }
3182:                    if (hasMods && !special) {
3183:                        time = SVNTimeUtil.formatDate(new Date(path
3184:                                .lastModified()));
3185:                    } else {
3186:                        time = entry.getCommittedDate();
3187:                    }
3188:                    if (keywords != null) {
3189:                        String url = entry.getURL();
3190:                        String author = hasMods ? "(local)" : entry.getAuthor();
3191:                        String rev = hasMods ? entry.getCommittedRevision()
3192:                                + "M" : entry.getCommittedRevision() + "";
3193:                        keywordsMap = SVNTranslator.computeKeywords(keywords,
3194:                                expandKeywords ? url : null, author, time, rev,
3195:                                getOptions());
3196:                    }
3197:                    OutputStream translatingStream = eols != null
3198:                            || keywordsMap != null ? new SVNTranslatorOutputStream(
3199:                            dst, eols, false, keywordsMap, expandKeywords)
3200:                            : dst;
3201:                    try {
3202:                        SVNTranslator
3203:                                .copy(input,
3204:                                        new SVNCancellableOutputStream(
3205:                                                translatingStream,
3206:                                                getEventDispatcher()));
3207:                        if (translatingStream != dst) {
3208:                            SVNFileUtil.closeFile(translatingStream);
3209:                        }
3210:                        dst.flush();
3211:                    } catch (IOException e) {
3212:                        if (e instanceof  SVNCancellableOutputStream.IOCancelException) {
3213:                            SVNErrorManager.cancel(e.getMessage());
3214:                        }
3215:                        SVNErrorManager.error(SVNErrorMessage.create(
3216:                                SVNErrorCode.IO_ERROR, e.getMessage()));
3217:                    }
3218:                } finally {
3219:                    SVNFileUtil.closeFile(input);
3220:                    wcAccess.close();
3221:                }
3222:            }
3223:
3224:            private static class LockInfo {
3225:
3226:                public LockInfo(File file, SVNRevision rev) {
3227:                    myFile = file;
3228:                    myRevision = rev;
3229:                }
3230:
3231:                public LockInfo(File file, String token) {
3232:                    myFile = file;
3233:                    myToken = token;
3234:                }
3235:
3236:                private File myFile;
3237:                private SVNRevision myRevision;
3238:                private String myToken;
3239:            }
3240:
3241:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.