Source Code Cross Referenced for SVNAdminClient.java in  » Source-Control » tmatesoft-SVN » org » tmatesoft » svn » core » wc » admin » 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.admin 
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.admin;
0013:
0014:        import java.io.ByteArrayOutputStream;
0015:        import java.io.File;
0016:        import java.io.IOException;
0017:        import java.io.InputStream;
0018:        import java.io.OutputStream;
0019:        import java.net.InetAddress;
0020:        import java.net.UnknownHostException;
0021:        import java.nio.charset.Charset;
0022:        import java.nio.charset.CharsetDecoder;
0023:        import java.util.HashMap;
0024:        import java.util.Iterator;
0025:        import java.util.Map;
0026:
0027:        import org.tmatesoft.svn.core.ISVNLogEntryHandler;
0028:        import org.tmatesoft.svn.core.SVNErrorCode;
0029:        import org.tmatesoft.svn.core.SVNErrorMessage;
0030:        import org.tmatesoft.svn.core.SVNException;
0031:        import org.tmatesoft.svn.core.SVNLock;
0032:        import org.tmatesoft.svn.core.SVNNodeKind;
0033:        import org.tmatesoft.svn.core.SVNProperty;
0034:        import org.tmatesoft.svn.core.SVNRevisionProperty;
0035:        import org.tmatesoft.svn.core.SVNURL;
0036:        import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
0037:        import org.tmatesoft.svn.core.internal.io.fs.FSCommitter;
0038:        import org.tmatesoft.svn.core.internal.io.fs.FSFS;
0039:        import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryUtil;
0040:        import org.tmatesoft.svn.core.internal.io.fs.FSRevisionRoot;
0041:        import org.tmatesoft.svn.core.internal.util.SVNDate;
0042:        import org.tmatesoft.svn.core.internal.util.SVNUUIDGenerator;
0043:        import org.tmatesoft.svn.core.internal.wc.DefaultLoadHandler;
0044:        import org.tmatesoft.svn.core.internal.wc.ISVNLoadHandler;
0045:        import org.tmatesoft.svn.core.internal.wc.SVNAdminHelper;
0046:        import org.tmatesoft.svn.core.internal.wc.SVNCancellableEditor;
0047:        import org.tmatesoft.svn.core.internal.wc.SVNDumpEditor;
0048:        import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
0049:        import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
0050:        import org.tmatesoft.svn.core.internal.wc.SVNSynchronizeEditor;
0051:        import org.tmatesoft.svn.core.io.ISVNEditor;
0052:        import org.tmatesoft.svn.core.io.ISVNLockHandler;
0053:        import org.tmatesoft.svn.core.io.SVNRepository;
0054:        import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
0055:        import org.tmatesoft.svn.core.replicator.SVNRepositoryReplicator;
0056:        import org.tmatesoft.svn.core.wc.ISVNEventHandler;
0057:        import org.tmatesoft.svn.core.wc.ISVNOptions;
0058:        import org.tmatesoft.svn.core.wc.ISVNRepositoryPool;
0059:        import org.tmatesoft.svn.core.wc.SVNBasicClient;
0060:        import org.tmatesoft.svn.core.wc.SVNRevision;
0061:        import org.tmatesoft.svn.util.SVNDebugLog;
0062:
0063:        /**
0064:         * The <b>SVNAdminClient</b> class provides methods that brings repository-side functionality
0065:         * and repository synchronizing features.
0066:         * 
0067:         * <p>
0068:         * Repository administrative methods are analogues of the corresponding commands of the native 
0069:         * Subversion 'svnadmin' utility, while repository synchronizing methods are the ones for the
0070:         * 'svnsync' utility. 
0071:         * 
0072:         * <p>
0073:         * Here's a list of the <b>SVNAdminClient</b>'s methods 
0074:         * matched against corresponing commands of the Subversion svnsync and svnadmin command-line utilities:
0075:         * 
0076:         * <table cellpadding="3" cellspacing="1" border="0" width="40%" 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>doInitialize()</td><td>'svnsync initialize'</td>
0083:         * </tr>
0084:         * <tr bgcolor="#EAEAEA" align="left">
0085:         * <td>doSynchronize()</td><td>'svnsync synchronize'</td>
0086:         * </tr>
0087:         * <tr bgcolor="#EAEAEA" align="left">
0088:         * <td>doCopyRevisionProperties()</td><td>'svnsync copy-revprops'</td>
0089:         * </tr>
0090:         * <tr bgcolor="#EAEAEA" align="left">
0091:         * <td>doDump()</td><td>'svnadmin dump'</td>
0092:         * </tr>
0093:         * <tr bgcolor="#EAEAEA" align="left">
0094:         * <td>doListTransactions()</td><td>'svnadmin lstxns'</td>
0095:         * </tr>
0096:         * <tr bgcolor="#EAEAEA" align="left">
0097:         * <td>doLoad()</td><td>'svnadmin load'</td>
0098:         * </tr>
0099:         * <tr bgcolor="#EAEAEA" align="left">
0100:         * <td>doRemoveTransactions()</td><td>'svnadmin rmtxns'</td>
0101:         * </tr>
0102:         * <tr bgcolor="#EAEAEA" align="left">
0103:         * <td>doVerify()</td><td>'svnadmin verify'</td>
0104:         * </tr>
0105:         * </table>
0106:         * 
0107:         * @version 1.1.1
0108:         * @author  TMate Software Ltd.
0109:         * @since   1.1.0
0110:         */
0111:        public class SVNAdminClient extends SVNBasicClient {
0112:            private ISVNLogEntryHandler mySyncHandler;
0113:            private ISVNLoadHandler myLoadHandler;
0114:            private ISVNAdminEventHandler myEventHandler;
0115:
0116:            /**
0117:             * Creates a new admin client.
0118:             * 
0119:             * @param authManager   an auth manager
0120:             * @param options       an options driver
0121:             */
0122:            public SVNAdminClient(ISVNAuthenticationManager authManager,
0123:                    ISVNOptions options) {
0124:                super (authManager, options);
0125:            }
0126:
0127:            /**
0128:             * Creates a new admin client.
0129:             * 
0130:             * @param repositoryPool a repository pool 
0131:             * @param options        an options driver
0132:             */
0133:            public SVNAdminClient(ISVNRepositoryPool repositoryPool,
0134:                    ISVNOptions options) {
0135:                super (repositoryPool, options);
0136:            }
0137:
0138:            /**
0139:             * Sets a replication handler that will receive a log entry object 
0140:             * per each replayed revision.
0141:             * 
0142:             * <p>
0143:             * Log entries dispatched to the handler may not contain changed paths and 
0144:             * committed log message until this features are implemented in future releases. 
0145:             * 
0146:             * @param handler a replay handler
0147:             */
0148:            public void setReplayHandler(ISVNLogEntryHandler handler) {
0149:                mySyncHandler = handler;
0150:            }
0151:
0152:            /**
0153:             * Sets an event handler for this object. 
0154:             * {@link ISVNAdminEventHandler} should be provided to <b>SVNAdminClent</b>
0155:             * via this method also.
0156:             * 
0157:             * @param handler an event handler
0158:             */
0159:            public void setEventHandler(ISVNEventHandler handler) {
0160:                super .setEventHandler(handler);
0161:                if (handler instanceof  ISVNAdminEventHandler) {
0162:                    myEventHandler = (ISVNAdminEventHandler) handler;
0163:                }
0164:            }
0165:
0166:            /**
0167:             * Creates an FSFS-type repository.
0168:             * 
0169:             * This implementation uses {@link org.tmatesoft.svn.core.io.SVNRepositoryFactory#createLocalRepository(File, String, boolean, boolean)}}.
0170:             * <p>
0171:             * If <code>uuid</code> is <span class="javakeyword">null</span> a new uuid will be generated, otherwise 
0172:             * the specified will be used.
0173:             * 
0174:             * <p>
0175:             * If <code>enableRevisionProperties</code> is <span class="javakeyword">true</span>, an empty 
0176:             * pre-revprop-change hook will be placed into the repository /hooks subdir. This enables changes to 
0177:             * revision properties of the newly created repository. 
0178:             * 
0179:             * <p>
0180:             * If <code>force</code> is <span class="javakeyword">true</span> and <code>path</code> already 
0181:             * exists, deletes that path and creates a repository in its place.
0182:             *  
0183:             * @param  path                        a repository root dir path
0184:             * @param  uuid                        a repository uuid
0185:             * @param  enableRevisionProperties    enables/disables changes to revision properties
0186:             * @param  force                       forces operation to run
0187:             * @return                             a local URL (file:///) of a newly created repository
0188:             * @throws SVNException
0189:             * @see                                #doCreateRepository(File, String, boolean, boolean, boolean)
0190:             * @since                              1.1.0 
0191:             */
0192:            public SVNURL doCreateRepository(File path, String uuid,
0193:                    boolean enableRevisionProperties, boolean force)
0194:                    throws SVNException {
0195:                return SVNRepositoryFactory.createLocalRepository(path, uuid,
0196:                        enableRevisionProperties, force);
0197:            }
0198:
0199:            /**
0200:             * Creates an FSFS-type repository.
0201:             * 
0202:             * This implementation uses {@link org.tmatesoft.svn.core.io.SVNRepositoryFactory#createLocalRepository(File, String, boolean, boolean)}}.
0203:             * <p>
0204:             * If <code>uuid</code> is <span class="javakeyword">null</span> a new uuid will be generated, otherwise 
0205:             * the specified will be used.
0206:             * 
0207:             * <p>
0208:             * If <code>enableRevisionProperties</code> is <span class="javakeyword">true</span>, an empty 
0209:             * pre-revprop-change hook will be placed into the repository /hooks subdir. This enables changes to 
0210:             * revision properties of the newly created repository. 
0211:             * 
0212:             * <p>
0213:             * If <code>force</code> is <span class="javakeyword">true</span> and <code>path</code> already 
0214:             * exists, deletes that path and creates a repository in its place.
0215:             * 
0216:             * <p>
0217:             * Set <code>pre14Compatible</code> to <span class="javakeyword">true</span> if you want a new repository 
0218:             * to be compatible with pre-1.4 servers.
0219:             * 
0220:             * @param  path                        a repository root dir path
0221:             * @param  uuid                        a repository uuid
0222:             * @param  enableRevisionProperties    enables/disables changes to revision properties
0223:             * @param  force                       forces operation to run
0224:             * @param  pre14Compatible             <span class="javakeyword">true</span> to 
0225:             *                                     create a repository with pre-1.4 format
0226:             * @return                             a local URL (file:///) of a newly created repository
0227:             * @throws SVNException
0228:             * @since                              1.1.1 
0229:             */
0230:            public SVNURL doCreateRepository(File path, String uuid,
0231:                    boolean enableRevisionProperties, boolean force,
0232:                    boolean pre14Compatible) throws SVNException {
0233:                return SVNRepositoryFactory.createLocalRepository(path, uuid,
0234:                        enableRevisionProperties, force, pre14Compatible);
0235:            }
0236:
0237:            /**
0238:             * Copies revision properties from the source repository that the destination one is synchronized with 
0239:             * to the given revision of the destination repository itself.
0240:             * 
0241:             * <p>
0242:             * This method is equivalent to the command 'copy-revprops' of the native Subversion <i>svnsync</i> utility. 
0243:             * Note that the destination repository given as <code>toURL</code> must be synchronized with a source 
0244:             * repository. Please, see {@link #doInitialize(SVNURL, SVNURL)}} how to initialize such a synchronization.  
0245:             * 
0246:             * @param  toURL          a url to the destination repository which must be synchronized
0247:             *                        with another repository 
0248:             * @param  revision       a particular revision of the source repository to copy revision properties
0249:             *                        from 
0250:             * @throws SVNException   
0251:             * @since                 1.1, new in Subversion 1.4
0252:             */
0253:            public void doCopyRevisionProperties(SVNURL toURL, long revision)
0254:                    throws SVNException {
0255:                SVNRepository toRepos = createRepository(toURL, true);
0256:                checkIfRepositoryIsAtRoot(toRepos, toURL);
0257:
0258:                SVNException error = null;
0259:                SVNException error2 = null;
0260:                lock(toRepos);
0261:                try {
0262:                    SessionInfo info = openSourceRepository(toRepos);
0263:                    if (revision > info.myLastMergedRevision) {
0264:                        SVNErrorMessage err = SVNErrorMessage
0265:                                .create(SVNErrorCode.IO_ERROR,
0266:                                        "Cannot copy revprops for a revision that has not been synchronized yet");
0267:                        SVNErrorManager.error(err);
0268:                    }
0269:                    copyRevisionProperties(info.myRepository, toRepos,
0270:                            revision, false);
0271:                } catch (SVNException svne) {
0272:                    error = svne;
0273:                } finally {
0274:                    try {
0275:                        unlock(toRepos);
0276:                    } catch (SVNException svne) {
0277:                        error2 = svne;
0278:                    }
0279:                }
0280:
0281:                if (error != null) {
0282:                    throw error;
0283:                } else if (error2 != null) {
0284:                    throw error2;
0285:                }
0286:            }
0287:
0288:            /**
0289:             * Initializes synchronization between source and target repositories.
0290:             * 
0291:             * <p>
0292:             * This method is equivalent to the command 'initialize' ('init') of the native Subversion <i>svnsync</i> 
0293:             * utility. Initialization places information of a source repository to a destination one (setting special 
0294:             * revision properties in revision 0) as well as copies all revision props from revision 0 of the source 
0295:             * repository to revision 0 of the destination one.   
0296:             * 
0297:             * @param  fromURL         a source repository url
0298:             * @param  toURL           a destination repository url
0299:             * @throws SVNException   
0300:             * @since                  1.1, new in Subversion 1.4
0301:             */
0302:            public void doInitialize(SVNURL fromURL, SVNURL toURL)
0303:                    throws SVNException {
0304:                SVNRepository toRepos = createRepository(toURL, true);
0305:                checkIfRepositoryIsAtRoot(toRepos, toURL);
0306:
0307:                SVNException error = null;
0308:                SVNException error2 = null;
0309:                lock(toRepos);
0310:                try {
0311:                    long latestRevision = toRepos.getLatestRevision();
0312:                    if (latestRevision != 0) {
0313:                        SVNErrorMessage err = SVNErrorMessage
0314:                                .create(SVNErrorCode.IO_ERROR,
0315:                                        "Cannot initialize a repository with content in it");
0316:                        SVNErrorManager.error(err);
0317:                    }
0318:
0319:                    String fromURLProp = toRepos.getRevisionPropertyValue(0,
0320:                            SVNRevisionProperty.FROM_URL);
0321:                    if (fromURLProp != null) {
0322:                        SVNErrorMessage err = SVNErrorMessage
0323:                                .create(
0324:                                        SVNErrorCode.IO_ERROR,
0325:                                        "Destination repository is already synchronizing from ''{0}''",
0326:                                        fromURLProp);
0327:                        SVNErrorManager.error(err);
0328:                    }
0329:
0330:                    // TODO close session.
0331:                    SVNRepository fromRepos = createRepository(fromURL, false);
0332:                    checkIfRepositoryIsAtRoot(fromRepos, fromURL);
0333:
0334:                    toRepos.setRevisionPropertyValue(0,
0335:                            SVNRevisionProperty.FROM_URL, fromURL
0336:                                    .toDecodedString());
0337:                    String uuid = fromRepos.getRepositoryUUID(true);
0338:                    toRepos.setRevisionPropertyValue(0,
0339:                            SVNRevisionProperty.FROM_UUID, uuid);
0340:                    toRepos.setRevisionPropertyValue(0,
0341:                            SVNRevisionProperty.LAST_MERGED_REVISION, "0");
0342:
0343:                    copyRevisionProperties(fromRepos, toRepos, 0, false);
0344:                } catch (SVNException svne) {
0345:                    error = svne;
0346:                } finally {
0347:                    try {
0348:                        unlock(toRepos);
0349:                    } catch (SVNException svne) {
0350:                        error2 = svne;
0351:                    }
0352:                }
0353:
0354:                if (error != null) {
0355:                    throw error;
0356:                } else if (error2 != null) {
0357:                    throw error2;
0358:                }
0359:            }
0360:
0361:            /**
0362:             * Completely synchronizes two repositories.
0363:             * 
0364:             * <p>
0365:             * This method initializes the destination repository and then copies all revision
0366:             * changes (including revision properties) 
0367:             * from the given source repository to the destination one. First it 
0368:             * tries to use synchronization features similar to the native Subversion 
0369:             * 'svnsync' capabilities. But if a server does not support 
0370:             * <code>replay</code> functionality, SVNKit uses its own repository 
0371:             * replication feature (see {@link org.tmatesoft.svn.core.replicator.SVNRepositoryReplicator}})
0372:             * 
0373:             * @param  fromURL        a url of a repository to copy from     
0374:             * @param  toURL          a destination repository url
0375:             * @throws SVNException
0376:             * @since                 1.1
0377:             */
0378:            public void doCompleteSynchronize(SVNURL fromURL, SVNURL toURL)
0379:                    throws SVNException {
0380:                try {
0381:                    doInitialize(fromURL, toURL);
0382:                    doSynchronize(toURL);
0383:                    return;
0384:                } catch (SVNException svne) {
0385:                    if (svne.getErrorMessage().getErrorCode() != SVNErrorCode.RA_NOT_IMPLEMENTED) {
0386:                        throw svne;
0387:                    }
0388:                }
0389:
0390:                SVNRepositoryReplicator replicator = SVNRepositoryReplicator
0391:                        .newInstance();
0392:                SVNRepository fromRepos = createRepository(fromURL, true);
0393:                // TODO close session
0394:                SVNRepository toRepos = createRepository(toURL, false);
0395:                replicator.replicateRepository(fromRepos, toRepos, 1, -1);
0396:            }
0397:
0398:            /**
0399:             * Synchronizes the repository at the given url.
0400:             * 
0401:             * <p>
0402:             * Synchronization means copying revision changes and revision properties from the source 
0403:             * repository (that the destination one is synchronized with) to the destination one starting at 
0404:             * the last merged revision. This method is equivalent to the command 'synchronize' ('sync') of 
0405:             * the native Subversion <i>svnsync</i> utility. 
0406:             * 
0407:             * @param  toURL          a destination repository url
0408:             * @throws SVNException
0409:             * @since                 1.1, new in Subversion 1.4
0410:             */
0411:            public void doSynchronize(SVNURL toURL) throws SVNException {
0412:                SVNRepository toRepos = createRepository(toURL, true);
0413:                checkIfRepositoryIsAtRoot(toRepos, toURL);
0414:
0415:                SVNException error = null;
0416:                SVNException error2 = null;
0417:
0418:                lock(toRepos);
0419:                try {
0420:                    SessionInfo info = openSourceRepository(toRepos);
0421:                    SVNRepository fromRepos = info.myRepository;
0422:                    long lastMergedRevision = info.myLastMergedRevision;
0423:                    String currentlyCopying = toRepos.getRevisionPropertyValue(
0424:                            0, SVNRevisionProperty.CURRENTLY_COPYING);
0425:                    long toLatestRevision = toRepos.getLatestRevision();
0426:
0427:                    if (currentlyCopying != null) {
0428:                        long copyingRev = Long.parseLong(currentlyCopying);
0429:                        if (copyingRev < lastMergedRevision
0430:                                || copyingRev > lastMergedRevision + 1
0431:                                || (toLatestRevision != lastMergedRevision && toLatestRevision != copyingRev)) {
0432:                            SVNErrorMessage err = SVNErrorMessage
0433:                                    .create(
0434:                                            SVNErrorCode.IO_ERROR,
0435:                                            "Revision being currently copied ({0,number,integer}), last merged revision ({1,number,integer}), and destination HEAD ({2,number,integer}) are inconsistent; have you committed to the destination without using svnsync?",
0436:                                            new Long[] {
0437:                                                    new Long(copyingRev),
0438:                                                    new Long(lastMergedRevision),
0439:                                                    new Long(toLatestRevision) });
0440:                            SVNErrorManager.error(err);
0441:                        } else if (copyingRev == toLatestRevision) {
0442:                            if (copyingRev > lastMergedRevision) {
0443:                                copyRevisionProperties(fromRepos, toRepos,
0444:                                        toLatestRevision, true);
0445:                                lastMergedRevision = copyingRev;
0446:                            }
0447:                            toRepos.setRevisionPropertyValue(0,
0448:                                    SVNRevisionProperty.LAST_MERGED_REVISION,
0449:                                    SVNProperty.toString(lastMergedRevision));
0450:                            toRepos
0451:                                    .setRevisionPropertyValue(
0452:                                            0,
0453:                                            SVNRevisionProperty.CURRENTLY_COPYING,
0454:                                            null);
0455:                        }
0456:                    } else {
0457:                        if (toLatestRevision != lastMergedRevision) {
0458:                            SVNErrorMessage err = SVNErrorMessage
0459:                                    .create(
0460:                                            SVNErrorCode.IO_ERROR,
0461:                                            "Destination HEAD ({0,number,integer}) is not the last merged revision ({1,number,integer}); have you committed to the destination without using svnsync?",
0462:                                            new Long[] {
0463:                                                    new Long(toLatestRevision),
0464:                                                    new Long(lastMergedRevision) });
0465:                            SVNErrorManager.error(err);
0466:                        }
0467:                    }
0468:
0469:                    long fromLatestRevision = fromRepos.getLatestRevision();
0470:                    if (fromLatestRevision < lastMergedRevision) {
0471:                        return;
0472:                    }
0473:
0474:                    for (long currentRev = lastMergedRevision + 1; currentRev <= fromLatestRevision; currentRev++) {
0475:                        toRepos.setRevisionPropertyValue(0,
0476:                                SVNRevisionProperty.CURRENTLY_COPYING,
0477:                                SVNProperty.toString(currentRev));
0478:                        SVNSynchronizeEditor syncEditor = new SVNSynchronizeEditor(
0479:                                toRepos, mySyncHandler, currentRev - 1);
0480:                        ISVNEditor cancellableEditor = SVNCancellableEditor
0481:                                .newInstance(syncEditor, this , getDebugLog());
0482:                        try {
0483:                            fromRepos.replay(0, currentRev, true,
0484:                                    cancellableEditor);
0485:                        } catch (SVNException e) {
0486:                            try {
0487:                                cancellableEditor.abortEdit();
0488:                            } catch (SVNException abortError) {
0489:                            }
0490:                            throw e;
0491:                        }
0492:                        cancellableEditor.closeEdit();
0493:                        if (syncEditor.getCommitInfo().getNewRevision() != currentRev) {
0494:                            SVNErrorMessage err = SVNErrorMessage
0495:                                    .create(
0496:                                            SVNErrorCode.IO_ERROR,
0497:                                            "Commit created rev {0,number,integer} but should have created {1,number,integer}",
0498:                                            new Long[] {
0499:                                                    new Long(syncEditor
0500:                                                            .getCommitInfo()
0501:                                                            .getNewRevision()),
0502:                                                    new Long(currentRev) });
0503:                            SVNErrorManager.error(err);
0504:                        }
0505:                        copyRevisionProperties(fromRepos, toRepos, currentRev,
0506:                                true);
0507:                        toRepos.setRevisionPropertyValue(0,
0508:                                SVNRevisionProperty.LAST_MERGED_REVISION,
0509:                                SVNProperty.toString(currentRev));
0510:                        toRepos.setRevisionPropertyValue(0,
0511:                                SVNRevisionProperty.CURRENTLY_COPYING, null);
0512:                    }
0513:                } catch (SVNException svne) {
0514:                    error = svne;
0515:                } finally {
0516:                    try {
0517:                        unlock(toRepos);
0518:                    } catch (SVNException svne) {
0519:                        error2 = svne;
0520:                    }
0521:                }
0522:
0523:                if (error != null) {
0524:                    throw error;
0525:                } else if (error2 != null) {
0526:                    throw error2;
0527:                }
0528:            }
0529:
0530:            public void doListLocks(File repositoryRoot) throws SVNException {
0531:                FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
0532:                File digestFile = fsfs.getDigestFileFromRepositoryPath("/");
0533:                ISVNLockHandler handler = new ISVNLockHandler() {
0534:                    public void handleLock(String path, SVNLock lock,
0535:                            SVNErrorMessage error) throws SVNException {
0536:                        checkCancelled();
0537:                        if (myEventHandler != null) {
0538:                            SVNAdminEvent event = new SVNAdminEvent(
0539:                                    SVNAdminEventAction.LOCK_LISTED, lock,
0540:                                    error, null);
0541:                            myEventHandler.handleAdminEvent(event,
0542:                                    ISVNEventHandler.UNKNOWN);
0543:                        }
0544:
0545:                    }
0546:
0547:                    public void handleUnlock(String path, SVNLock lock,
0548:                            SVNErrorMessage error) throws SVNException {
0549:                    }
0550:                };
0551:                fsfs.walkDigestFiles(digestFile, handler, false);
0552:            }
0553:
0554:            public void doRemoveLocks(File repositoryRoot, String[] paths)
0555:                    throws SVNException {
0556:                if (paths == null) {
0557:                    return;
0558:                }
0559:
0560:                FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
0561:                for (int i = 0; i < paths.length; i++) {
0562:                    String path = paths[i];
0563:                    if (path == null) {
0564:                        continue;
0565:                    }
0566:                    checkCancelled();
0567:
0568:                    SVNLock lock = null;
0569:                    try {
0570:                        lock = fsfs.getLockHelper(path, false);
0571:                        if (lock == null) {
0572:                            if (myEventHandler != null) {
0573:                                SVNAdminEvent event = new SVNAdminEvent(
0574:                                        SVNAdminEventAction.NOT_LOCKED, lock,
0575:                                        null, "Path '" + path
0576:                                                + "' isn't locked.");
0577:                                myEventHandler.handleAdminEvent(event,
0578:                                        ISVNEventHandler.UNKNOWN);
0579:                            }
0580:                            continue;
0581:                        }
0582:
0583:                        fsfs.unlockPath(path, lock.getID(), null, true, false);
0584:                        if (myEventHandler != null) {
0585:                            SVNAdminEvent event = new SVNAdminEvent(
0586:                                    SVNAdminEventAction.UNLOCKED, lock, null,
0587:                                    "Removed lock on '" + path + "'.");
0588:                            myEventHandler.handleAdminEvent(event,
0589:                                    ISVNEventHandler.UNKNOWN);
0590:                        }
0591:                    } catch (SVNException svne) {
0592:                        if (myEventHandler != null) {
0593:                            SVNAdminEvent event = new SVNAdminEvent(
0594:                                    SVNAdminEventAction.UNLOCK_FAILED, lock,
0595:                                    svne.getErrorMessage(), "svnadmin: "
0596:                                            + svne.getErrorMessage()
0597:                                                    .getFullMessage());
0598:                            myEventHandler.handleAdminEvent(event,
0599:                                    ISVNEventHandler.UNKNOWN);
0600:                        }
0601:                    }
0602:                }
0603:            }
0604:
0605:            /**
0606:             * Lists all uncommitted transactions.
0607:             * On each uncommetted transaction found this method fires an {@link SVNAdminEvent} 
0608:             * with action set to {@link SVNAdminEventAction#TRANSACTION_LISTED} to the registered 
0609:             * {@link ISVNAdminEventHandler} (if any). To register your <b>ISVNAdminEventHandler</b> 
0610:             * pass it to {@link #setEventHandler(ISVNEventHandler)}. For this operation the following 
0611:             * information can be retrieved out of {@link SVNAdminEvent}:
0612:             * <ul>
0613:             * <li>transaction name - use {@link SVNAdminEvent#getTxnName() SVNAdminEvent.getTxnName()} to get it</li>
0614:             * <li>transaction directory - use {@link SVNAdminEvent#getTxnDir() SVNAdminEvent.getTxnDir()} to get it</li>
0615:             * </ul>
0616:             * 
0617:             * @param  repositoryRoot   a repository root directory path
0618:             * @throws SVNException
0619:             * @since                   1.1.1
0620:             */
0621:            public void doListTransactions(File repositoryRoot)
0622:                    throws SVNException {
0623:                FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
0624:                Map txns = fsfs.listTransactions();
0625:
0626:                for (Iterator names = txns.keySet().iterator(); names.hasNext();) {
0627:                    String txnName = (String) names.next();
0628:                    File txnDir = (File) txns.get(txnName);
0629:                    SVNDebugLog.getDefaultLog().info(txnName + "\n");
0630:                    if (myEventHandler != null) {
0631:                        SVNAdminEvent event = new SVNAdminEvent(txnName,
0632:                                txnDir, SVNAdminEventAction.TRANSACTION_LISTED);
0633:                        myEventHandler.handleAdminEvent(event,
0634:                                ISVNEventHandler.UNKNOWN);
0635:                    }
0636:                }
0637:            }
0638:
0639:            /**
0640:             * Removes the specified outstanding transactions from a repository.
0641:             * On each transaction removed this method fires an {@link SVNAdminEvent} 
0642:             * with action set to {@link SVNAdminEventAction#TRANSACTION_REMOVED} to the registered 
0643:             * {@link ISVNAdminEventHandler} (if any). To register your <b>ISVNAdminEventHandler</b> 
0644:             * pass it to {@link #setEventHandler(ISVNEventHandler)}. For this operation the following 
0645:             * information can be retrieved out of {@link SVNAdminEvent}:
0646:             * <ul>
0647:             * <li>transaction name - use {@link SVNAdminEvent#getTxnName() SVNAdminEvent.getTxnName()} to get it</li>
0648:             * <li>transaction directory - use {@link SVNAdminEvent#getTxnDir() SVNAdminEvent.getTxnDir()} to get it</li>
0649:             * </ul>
0650:             * 
0651:             * @param  repositoryRoot   a repository root directory path
0652:             * @param  transactions     an array with transaction names
0653:             * @throws SVNException
0654:             * @since                   1.1.1
0655:             */
0656:            public void doRemoveTransactions(File repositoryRoot,
0657:                    String[] transactions) throws SVNException {
0658:                if (transactions == null) {
0659:                    return;
0660:                }
0661:
0662:                FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
0663:                for (int i = 0; i < transactions.length; i++) {
0664:                    String txnName = transactions[i];
0665:                    fsfs.openTxn(txnName);
0666:                    FSCommitter.purgeTxn(fsfs, txnName);
0667:                    SVNDebugLog.getDefaultLog().info(
0668:                            "Transaction '" + txnName + "' removed.\n");
0669:                    if (myEventHandler != null) {
0670:                        SVNAdminEvent event = new SVNAdminEvent(txnName, fsfs
0671:                                .getTransactionDir(txnName),
0672:                                SVNAdminEventAction.TRANSACTION_REMOVED);
0673:                        myEventHandler.handleAdminEvent(event,
0674:                                ISVNEventHandler.UNKNOWN);
0675:                    }
0676:                }
0677:            }
0678:
0679:            /**
0680:             * Verifies the data stored in the repository. This method uses the dump implementation 
0681:             * (non incremental, beginning with revision 0, ending at the latest one) 
0682:             * passing a dummy output stream to it. This allows to check the integrity of the 
0683:             * repository data. 
0684:             * 
0685:             * @param  repositoryRoot   a repository root directory path
0686:             * @throws SVNException     verification failed - a repository may be corrupted
0687:             * @since                   1.1.1
0688:             */
0689:            public void doVerify(File repositoryRoot) throws SVNException {
0690:                doVerify(repositoryRoot, SVNRevision.create(0),
0691:                        SVNRevision.HEAD);
0692:            }
0693:
0694:            public void doVerify(File repositoryRoot,
0695:                    SVNRevision startRevision, SVNRevision endRevision)
0696:                    throws SVNException {
0697:                FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
0698:                long startRev = startRevision.getNumber();
0699:                long endRev = endRevision.getNumber();
0700:                if (startRev < 0) {
0701:                    startRev = 0;
0702:                }
0703:                if (endRev < 0) {
0704:                    endRev = fsfs.getYoungestRevision();
0705:                }
0706:                try {
0707:                    dump(fsfs, SVNFileUtil.DUMMY_OUT, startRev, endRev, false,
0708:                            false);
0709:                } catch (IOException ioe) {
0710:                    SVNErrorMessage err = SVNErrorMessage.create(
0711:                            SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage());
0712:                    SVNErrorManager.error(err, ioe);
0713:                }
0714:            }
0715:
0716:            /**
0717:             * Dumps contents of the repository to the provided output stream in a 
0718:             * 'dumpfile' portable format.
0719:             * 
0720:             * <p>
0721:             * On each revision dumped this method fires an {@link SVNAdminEvent} 
0722:             * with action set to {@link SVNAdminEventAction#REVISION_DUMPED} to the registered 
0723:             * {@link ISVNAdminEventHandler} (if any). To register your <b>ISVNAdminEventHandler</b> 
0724:             * pass it to {@link #setEventHandler(ISVNEventHandler)}. For this operation the following 
0725:             * information can be retrieved out of {@link SVNAdminEvent}:
0726:             * <ul>
0727:             * <li>dumped revision - use {@link SVNAdminEvent#getRevision() SVNAdminEvent.getRevision()} to get it</li>
0728:             * </ul>
0729:             * 
0730:             * @param  repositoryRoot   a repository root directory path
0731:             * @param  dumpStream       an output stream to write dumped contents to
0732:             * @param  startRevision    the first revision to start dumping from
0733:             * @param  endRevision      the last revision to end dumping at
0734:             * @param  isIncremental    if <span class="javakeyword">true</span> 
0735:             *                          then the first revision dumped will be a 
0736:             *                          diff against the previous revision; otherwise 
0737:             *                          the first revision is a fulltext. 
0738:             * @param  useDeltas        if <span class="javakeyword">true</span> 
0739:             *                          deltas will be written instead of fulltexts
0740:             * @throws SVNException
0741:             * @since                   1.1.1
0742:             */
0743:            public void doDump(File repositoryRoot, OutputStream dumpStream,
0744:                    SVNRevision startRevision, SVNRevision endRevision,
0745:                    boolean isIncremental, boolean useDeltas)
0746:                    throws SVNException {
0747:                FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
0748:                long youngestRevision = fsfs.getYoungestRevision();
0749:
0750:                long lowerR = SVNAdminHelper.getRevisionNumber(startRevision,
0751:                        youngestRevision, fsfs);
0752:                long upperR = SVNAdminHelper.getRevisionNumber(endRevision,
0753:                        youngestRevision, fsfs);
0754:
0755:                if (!SVNRevision.isValidRevisionNumber(lowerR)) {
0756:                    lowerR = 0;
0757:                    upperR = youngestRevision;
0758:                } else if (!SVNRevision.isValidRevisionNumber(upperR)) {
0759:                    upperR = lowerR;
0760:                }
0761:
0762:                if (lowerR > upperR) {
0763:                    SVNErrorMessage err = SVNErrorMessage.create(
0764:                            SVNErrorCode.CL_ARG_PARSING_ERROR,
0765:                            "First revision cannot be higher than second");
0766:                    SVNErrorManager.error(err);
0767:                }
0768:
0769:                try {
0770:                    dump(fsfs, dumpStream, lowerR, upperR, isIncremental,
0771:                            useDeltas);
0772:                } catch (IOException ioe) {
0773:                    SVNErrorMessage err = SVNErrorMessage.create(
0774:                            SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage());
0775:                    SVNErrorManager.error(err, ioe);
0776:                }
0777:            }
0778:
0779:            /**
0780:             * Reads the provided dump stream committing new revisions to a repository.
0781:             * 
0782:             * <p>
0783:             * On each revision loaded this method fires an {@link SVNAdminEvent} 
0784:             * with action set to {@link SVNAdminEventAction#REVISION_LOADED} to the registered 
0785:             * {@link ISVNAdminEventHandler} (if any). To register your <b>ISVNAdminEventHandler</b> 
0786:             * pass it to {@link #setEventHandler(ISVNEventHandler)}. For this operation the following 
0787:             * information can be retrieved out of {@link SVNAdminEvent}:
0788:             * <ul>
0789:             * <li>original revision - use {@link SVNAdminEvent#getOriginalRevision() SVNAdminEvent.getOriginalRevision()} to get it</li>
0790:             * <li>new committed revision - use {@link SVNAdminEvent#getRevision() SVNAdminEvent.getRevision()} to get it</li>
0791:             * </ul>
0792:             * 
0793:             * <p>
0794:             * A call to this method is equivalent to 
0795:             * <code>doLoad(repositoryRoot, dumpStream, false, false, SVNUUIDAction.DEFAULT, null)</code>.
0796:             * 
0797:             * @param  repositoryRoot   the root directory path of the repository where 
0798:             *                          new revisions will be committed
0799:             * @param  dumpStream       stream with dumped contents of a repository
0800:             * @throws SVNException
0801:             * @see                     #doLoad(File, InputStream, boolean, boolean, SVNUUIDAction, String)                     
0802:             * @since                   1.1.1
0803:             */
0804:            public void doLoad(File repositoryRoot, InputStream dumpStream)
0805:                    throws SVNException {
0806:                doLoad(repositoryRoot, dumpStream, false, false,
0807:                        SVNUUIDAction.DEFAULT, null);
0808:            }
0809:
0810:            /**
0811:             * Reads the provided dump stream committing new revisions to a repository.
0812:             * 
0813:             * <p>
0814:             * On each revision loaded this method fires an {@link SVNAdminEvent} 
0815:             * with action set to {@link SVNAdminEventAction#REVISION_LOADED} to the registered 
0816:             * {@link ISVNAdminEventHandler} (if any). To register your <b>ISVNAdminEventHandler</b> 
0817:             * pass it to {@link #setEventHandler(ISVNEventHandler)}. For this operation the following 
0818:             * information can be retrieved out of {@link SVNAdminEvent}:
0819:             * <ul>
0820:             * <li>original revision - use {@link SVNAdminEvent#getOriginalRevision() SVNAdminEvent.getOriginalRevision()} to get it</li>
0821:             * <li>new committed revision - use {@link SVNAdminEvent#getRevision() SVNAdminEvent.getRevision()} to get it</li>
0822:             * </ul>
0823:             * 
0824:             * @param  repositoryRoot    the root directory path of the repository where 
0825:             *                           new revisions will be committed
0826:             * @param  dumpStream        stream with dumped contents of a repository
0827:             * @param  usePreCommitHook  if <span class="javakeyword">true</span> 
0828:             *                           then calls a pre-commit hook before committing 
0829:             * @param  usePostCommitHook if <span class="javakeyword">true</span> 
0830:             *                           then calls a post-commit hook after committing
0831:             * @param  uuidAction        one of the three possible ways to treat uuids 
0832:             * @param  parentDir         if not <span class="javakeyword">null</span> 
0833:             *                           then loads at this directory in the repository
0834:             * @throws SVNException
0835:             * @since                       1.1.1
0836:             */
0837:            public void doLoad(File repositoryRoot, InputStream dumpStream,
0838:                    boolean usePreCommitHook, boolean usePostCommitHook,
0839:                    SVNUUIDAction uuidAction, String parentDir)
0840:                    throws SVNException {
0841:                CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
0842:                ISVNLoadHandler handler = getLoadHandler(repositoryRoot,
0843:                        usePreCommitHook, usePostCommitHook, uuidAction,
0844:                        parentDir, decoder);
0845:
0846:                String line = null;
0847:                int version = -1;
0848:                StringBuffer buffer = new StringBuffer();
0849:                try {
0850:                    line = SVNFileUtil.readLineFromStream(dumpStream, buffer,
0851:                            decoder);
0852:                    if (line == null) {
0853:                        SVNAdminHelper.generateIncompleteDataError();
0854:                    }
0855:
0856:                    //parse format
0857:                    if (!line.startsWith(SVNAdminHelper.DUMPFILE_MAGIC_HEADER
0858:                            + ":")) {
0859:                        SVNErrorMessage err = SVNErrorMessage.create(
0860:                                SVNErrorCode.STREAM_MALFORMED_DATA,
0861:                                "Malformed dumpfile header");
0862:                        SVNErrorManager.error(err);
0863:                    }
0864:
0865:                    try {
0866:                        line = line
0867:                                .substring(SVNAdminHelper.DUMPFILE_MAGIC_HEADER
0868:                                        .length() + 1);
0869:                        line = line.trim();
0870:                        version = Integer.parseInt(line);
0871:                        if (version > SVNAdminHelper.DUMPFILE_FORMAT_VERSION) {
0872:                            SVNErrorMessage err = SVNErrorMessage
0873:                                    .create(
0874:                                            SVNErrorCode.STREAM_MALFORMED_DATA,
0875:                                            "Unsupported dumpfile version: {0,number,integer}",
0876:                                            new Integer(version));
0877:                            SVNErrorManager.error(err);
0878:                        }
0879:                    } catch (NumberFormatException nfe) {
0880:                        SVNErrorMessage err = SVNErrorMessage.create(
0881:                                SVNErrorCode.STREAM_MALFORMED_DATA,
0882:                                "Malformed dumpfile header");
0883:                        SVNErrorManager.error(err, nfe);
0884:                    }
0885:
0886:                    while (true) {
0887:                        checkCancelled();
0888:                        boolean foundNode = false;
0889:
0890:                        //skip empty lines
0891:                        buffer.setLength(0);
0892:                        line = SVNFileUtil.readLineFromStream(dumpStream,
0893:                                buffer, decoder);
0894:                        if (line == null) {
0895:                            if (buffer.length() > 0) {
0896:                                SVNAdminHelper.generateIncompleteDataError();
0897:                            } else {
0898:                                break;
0899:                            }
0900:                        }
0901:
0902:                        if (line.length() == 0
0903:                                || Character.isWhitespace(line.charAt(0))) {
0904:                            continue;
0905:                        }
0906:
0907:                        Map headers = readHeaderBlock(dumpStream, line, decoder);
0908:                        if (headers
0909:                                .containsKey(SVNAdminHelper.DUMPFILE_REVISION_NUMBER)) {
0910:                            handler.closeRevision();
0911:                            handler.openRevision(headers);
0912:                        } else if (headers
0913:                                .containsKey(SVNAdminHelper.DUMPFILE_NODE_PATH)) {
0914:                            handler.openNode(headers);
0915:                            foundNode = true;
0916:                        } else if (headers
0917:                                .containsKey(SVNAdminHelper.DUMPFILE_UUID)) {
0918:                            String uuid = (String) headers
0919:                                    .get(SVNAdminHelper.DUMPFILE_UUID);
0920:                            handler.parseUUID(uuid);
0921:                        } else if (headers
0922:                                .containsKey(SVNAdminHelper.DUMPFILE_MAGIC_HEADER)) {
0923:                            try {
0924:                                version = Integer
0925:                                        .parseInt((String) headers
0926:                                                .get(SVNAdminHelper.DUMPFILE_MAGIC_HEADER));
0927:                            } catch (NumberFormatException nfe) {
0928:                                SVNErrorMessage err = SVNErrorMessage.create(
0929:                                        SVNErrorCode.STREAM_MALFORMED_DATA,
0930:                                        "Malformed dumpfile header");
0931:                                SVNErrorManager.error(err, nfe);
0932:                            }
0933:                        } else {
0934:                            SVNErrorMessage err = SVNErrorMessage.create(
0935:                                    SVNErrorCode.STREAM_MALFORMED_DATA,
0936:                                    "Unrecognized record type in stream");
0937:                            SVNErrorManager.error(err);
0938:                        }
0939:
0940:                        String contentLength = (String) headers
0941:                                .get(SVNAdminHelper.DUMPFILE_CONTENT_LENGTH);
0942:                        String propContentLength = (String) headers
0943:                                .get(SVNAdminHelper.DUMPFILE_PROP_CONTENT_LENGTH);
0944:                        String textContentLength = (String) headers
0945:                                .get(SVNAdminHelper.DUMPFILE_TEXT_CONTENT_LENGTH);
0946:
0947:                        boolean isOldVersion = version == 1
0948:                                && contentLength != null
0949:                                && propContentLength == null
0950:                                && textContentLength == null;
0951:                        int actualPropLength = 0;
0952:                        if (propContentLength != null || isOldVersion) {
0953:                            String delta = (String) headers
0954:                                    .get(SVNAdminHelper.DUMPFILE_PROP_DELTA);
0955:                            boolean isDelta = delta != null
0956:                                    && "true".equals(delta);
0957:
0958:                            if (foundNode && !isDelta) {
0959:                                handler.removeNodeProperties();
0960:                            }
0961:
0962:                            int length = 0;
0963:                            try {
0964:                                length = Integer
0965:                                        .parseInt(propContentLength != null ? propContentLength
0966:                                                : contentLength);
0967:                            } catch (NumberFormatException nfe) {
0968:                                SVNErrorMessage err = SVNErrorMessage
0969:                                        .create(
0970:                                                SVNErrorCode.STREAM_MALFORMED_DATA,
0971:                                                "Malformed dumpfile header: can't parse property block length header");
0972:                                SVNErrorManager.error(err, nfe);
0973:                            }
0974:                            actualPropLength += handler.parsePropertyBlock(
0975:                                    dumpStream, length, foundNode);
0976:                        }
0977:
0978:                        if (textContentLength != null) {
0979:                            String delta = (String) headers
0980:                                    .get(SVNAdminHelper.DUMPFILE_TEXT_DELTA);
0981:                            boolean isDelta = delta != null
0982:                                    && "true".equals(delta);
0983:                            int length = 0;
0984:                            try {
0985:                                length = Integer.parseInt(textContentLength);
0986:                            } catch (NumberFormatException nfe) {
0987:                                SVNErrorMessage err = SVNErrorMessage
0988:                                        .create(
0989:                                                SVNErrorCode.STREAM_MALFORMED_DATA,
0990:                                                "Malformed dumpfile header: can't parse text block length header");
0991:                                SVNErrorManager.error(err, nfe);
0992:                            }
0993:                            handler.parseTextBlock(dumpStream, length, isDelta);
0994:                        } else if (isOldVersion) {
0995:                            int length = 0;
0996:                            try {
0997:                                length = Integer.parseInt(contentLength);
0998:                            } catch (NumberFormatException nfe) {
0999:                                SVNErrorMessage err = SVNErrorMessage
1000:                                        .create(
1001:                                                SVNErrorCode.STREAM_MALFORMED_DATA,
1002:                                                "Malformed dumpfile header: can't parse content length header");
1003:                                SVNErrorManager.error(err, nfe);
1004:                            }
1005:
1006:                            length -= actualPropLength;
1007:
1008:                            if (length > 0
1009:                                    || SVNNodeKind
1010:                                            .parseKind((String) headers
1011:                                                    .get(SVNAdminHelper.DUMPFILE_NODE_KIND)) == SVNNodeKind.FILE) {
1012:                                handler.parseTextBlock(dumpStream, length,
1013:                                        false);
1014:                            }
1015:                        }
1016:
1017:                        if (contentLength != null && !isOldVersion) {
1018:                            int remaining = 0;
1019:                            try {
1020:                                remaining = Integer.parseInt(contentLength);
1021:                            } catch (NumberFormatException nfe) {
1022:                                SVNErrorMessage err = SVNErrorMessage
1023:                                        .create(
1024:                                                SVNErrorCode.STREAM_MALFORMED_DATA,
1025:                                                "Malformed dumpfile header: can't parse content length header");
1026:                                SVNErrorManager.error(err, nfe);
1027:                            }
1028:
1029:                            int propertyContentLength = 0;
1030:                            if (propContentLength != null) {
1031:                                try {
1032:                                    propertyContentLength = Integer
1033:                                            .parseInt(propContentLength);
1034:                                } catch (NumberFormatException nfe) {
1035:                                    SVNErrorMessage err = SVNErrorMessage
1036:                                            .create(
1037:                                                    SVNErrorCode.STREAM_MALFORMED_DATA,
1038:                                                    "Malformed dumpfile header: can't parse property block length header");
1039:                                    SVNErrorManager.error(err, nfe);
1040:                                }
1041:                            }
1042:                            remaining -= propertyContentLength;
1043:
1044:                            int txtContentLength = 0;
1045:                            if (textContentLength != null) {
1046:                                try {
1047:                                    txtContentLength = Integer
1048:                                            .parseInt(textContentLength);
1049:                                } catch (NumberFormatException nfe) {
1050:                                    SVNErrorMessage err = SVNErrorMessage
1051:                                            .create(
1052:                                                    SVNErrorCode.STREAM_MALFORMED_DATA,
1053:                                                    "Malformed dumpfile header: can't parse text block length header");
1054:                                    SVNErrorManager.error(err, nfe);
1055:                                }
1056:                            }
1057:                            remaining -= txtContentLength;
1058:
1059:                            if (remaining < 0) {
1060:                                SVNErrorMessage err = SVNErrorMessage
1061:                                        .create(
1062:                                                SVNErrorCode.STREAM_MALFORMED_DATA,
1063:                                                "Sum of subblock sizes larger than total block content length");
1064:                                SVNErrorManager.error(err);
1065:                            }
1066:
1067:                            byte buf[] = new byte[SVNAdminHelper.STREAM_CHUNK_SIZE];
1068:                            while (remaining > 0) {
1069:                                int numToRead = remaining >= SVNAdminHelper.STREAM_CHUNK_SIZE ? SVNAdminHelper.STREAM_CHUNK_SIZE
1070:                                        : remaining;
1071:                                int numRead = dumpStream
1072:                                        .read(buf, 0, numToRead);
1073:
1074:                                remaining -= numRead;
1075:                                if (numRead != numToRead) {
1076:                                    SVNAdminHelper
1077:                                            .generateIncompleteDataError();
1078:                                }
1079:                            }
1080:                        }
1081:
1082:                        if (foundNode) {
1083:                            handler.closeNode();
1084:                            foundNode = false;
1085:                        }
1086:                    }
1087:
1088:                    handler.closeRevision();
1089:
1090:                } catch (IOException ioe) {
1091:                    SVNErrorMessage err = SVNErrorMessage.create(
1092:                            SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage());
1093:                    SVNErrorManager.error(err, ioe);
1094:                }
1095:            }
1096:
1097:            private void dump(FSFS fsfs, OutputStream dumpStream, long start,
1098:                    long end, boolean isIncremental, boolean useDeltas)
1099:                    throws SVNException, IOException {
1100:                boolean isDumping = dumpStream != null;
1101:                long youngestRevision = fsfs.getYoungestRevision();
1102:
1103:                if (!SVNRevision.isValidRevisionNumber(start)) {
1104:                    start = 0;
1105:                }
1106:
1107:                if (!SVNRevision.isValidRevisionNumber(end)) {
1108:                    end = youngestRevision;
1109:                }
1110:
1111:                if (dumpStream == null) {
1112:                    dumpStream = SVNFileUtil.DUMMY_OUT;
1113:                }
1114:
1115:                if (start > end) {
1116:                    SVNErrorMessage err = SVNErrorMessage
1117:                            .create(
1118:                                    SVNErrorCode.REPOS_BAD_ARGS,
1119:                                    "Start revision {0,number,integer} is greater than end revision {1,number,integer}",
1120:                                    new Object[] { new Long(start),
1121:                                            new Long(end) });
1122:                    SVNErrorManager.error(err);
1123:                }
1124:
1125:                if (end > youngestRevision) {
1126:                    SVNErrorMessage err = SVNErrorMessage
1127:                            .create(
1128:                                    SVNErrorCode.REPOS_BAD_ARGS,
1129:                                    "End revision {0,number,integer} is invalid (youngest revision is {1,number,integer})",
1130:                                    new Object[] { new Long(end),
1131:                                            new Long(youngestRevision) });
1132:                    SVNErrorManager.error(err);
1133:                }
1134:
1135:                if (start == 0 && isIncremental) {
1136:                    isIncremental = false;
1137:                }
1138:
1139:                String uuid = fsfs.getUUID();
1140:                int version = SVNAdminHelper.DUMPFILE_FORMAT_VERSION;
1141:
1142:                if (!useDeltas) {
1143:                    //for compatibility with SVN 1.0.x
1144:                    version--;
1145:                }
1146:
1147:                writeDumpData(dumpStream, SVNAdminHelper.DUMPFILE_MAGIC_HEADER
1148:                        + ": " + version + "\n\n");
1149:                writeDumpData(dumpStream, SVNAdminHelper.DUMPFILE_UUID + ": "
1150:                        + uuid + "\n\n");
1151:
1152:                for (long i = start; i <= end; i++) {
1153:                    long fromRev, toRev;
1154:
1155:                    checkCancelled();
1156:
1157:                    if (i == start && !isIncremental) {
1158:                        if (i == 0) {
1159:                            writeRevisionRecord(dumpStream, fsfs, 0);
1160:                            toRev = 0;
1161:                            String message = (isDumping ? "* Dumped"
1162:                                    : "* Verified")
1163:                                    + " revision " + toRev + ".";
1164:                            if (myEventHandler != null) {
1165:                                SVNAdminEvent event = new SVNAdminEvent(toRev,
1166:                                        SVNAdminEventAction.REVISION_DUMPED,
1167:                                        message);
1168:                                myEventHandler.handleAdminEvent(event,
1169:                                        ISVNEventHandler.UNKNOWN);
1170:                            }
1171:                            continue;
1172:                        }
1173:
1174:                        fromRev = 0;
1175:                        toRev = i;
1176:                    } else {
1177:                        fromRev = i - 1;
1178:                        toRev = i;
1179:                    }
1180:
1181:                    writeRevisionRecord(dumpStream, fsfs, toRev);
1182:                    boolean useDeltasForRevision = useDeltas
1183:                            && (isIncremental || i != start);
1184:                    FSRevisionRoot toRoot = fsfs.createRevisionRoot(toRev);
1185:                    ISVNEditor dumpEditor = new SVNDumpEditor(fsfs, toRoot,
1186:                            toRev, start, "/", dumpStream, useDeltasForRevision);
1187:
1188:                    if (i == start && !isIncremental) {
1189:                        FSRevisionRoot fromRoot = fsfs
1190:                                .createRevisionRoot(fromRev);
1191:                        SVNAdminHelper.deltifyDir(fsfs, fromRoot, "/", "",
1192:                                toRoot, "/", dumpEditor);
1193:                    } else {
1194:                        FSRepositoryUtil.replay(fsfs, toRoot, "", -1, false,
1195:                                dumpEditor);
1196:                    }
1197:                    String message = (isDumping ? "* Dumped" : "* Verified")
1198:                            + " revision " + toRev + ".";
1199:                    if (myEventHandler != null) {
1200:                        SVNAdminEvent event = new SVNAdminEvent(toRev,
1201:                                SVNAdminEventAction.REVISION_DUMPED, message);
1202:                        myEventHandler.handleAdminEvent(event,
1203:                                ISVNEventHandler.UNKNOWN);
1204:                    }
1205:                }
1206:            }
1207:
1208:            private void writeRevisionRecord(OutputStream dumpStream,
1209:                    FSFS fsfs, long revision) throws SVNException, IOException {
1210:                Map revProps = fsfs.getRevisionProperties(revision);
1211:
1212:                String revisionDate = (String) revProps
1213:                        .get(SVNRevisionProperty.DATE);
1214:                if (revisionDate != null) {
1215:                    SVNDate date = SVNDate.parseDatestamp(revisionDate);
1216:                    revProps.put(SVNRevisionProperty.DATE, date.format());
1217:                }
1218:
1219:                ByteArrayOutputStream encodedProps = new ByteArrayOutputStream();
1220:                SVNAdminHelper.writeProperties(revProps, null, encodedProps);
1221:
1222:                writeDumpData(dumpStream,
1223:                        SVNAdminHelper.DUMPFILE_REVISION_NUMBER + ": "
1224:                                + revision + "\n");
1225:                String propContents = new String(encodedProps.toByteArray(),
1226:                        "UTF-8");
1227:                writeDumpData(dumpStream,
1228:                        SVNAdminHelper.DUMPFILE_PROP_CONTENT_LENGTH + ": "
1229:                                + propContents.length() + "\n");
1230:                writeDumpData(dumpStream,
1231:                        SVNAdminHelper.DUMPFILE_CONTENT_LENGTH + ": "
1232:                                + propContents.length() + "\n\n");
1233:                writeDumpData(dumpStream, propContents);
1234:                dumpStream.write('\n');
1235:            }
1236:
1237:            private void writeDumpData(OutputStream out, String data)
1238:                    throws IOException {
1239:                out.write(data.getBytes("UTF-8"));
1240:            }
1241:
1242:            private ISVNLoadHandler getLoadHandler(File repositoryRoot,
1243:                    boolean usePreCommitHook, boolean usePostCommitHook,
1244:                    SVNUUIDAction uuidAction, String parentDir,
1245:                    CharsetDecoder decoder) throws SVNException {
1246:                if (myLoadHandler == null) {
1247:                    FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
1248:                    DefaultLoadHandler handler = new DefaultLoadHandler(
1249:                            usePreCommitHook, usePostCommitHook, uuidAction,
1250:                            parentDir, myEventHandler, decoder);
1251:                    handler.setFSFS(fsfs);
1252:                    myLoadHandler = handler;
1253:                } else {
1254:                    myLoadHandler.setUsePreCommitHook(usePreCommitHook);
1255:                    myLoadHandler.setUsePostCommitHook(usePostCommitHook);
1256:                    myLoadHandler.setUUIDAction(uuidAction);
1257:                    myLoadHandler.setParentDir(parentDir);
1258:                }
1259:
1260:                return myLoadHandler;
1261:            }
1262:
1263:            private Map readHeaderBlock(InputStream dumpStream,
1264:                    String firstHeader, CharsetDecoder decoder)
1265:                    throws SVNException, IOException {
1266:                Map headers = new HashMap();
1267:                StringBuffer buffer = new StringBuffer();
1268:
1269:                while (true) {
1270:                    String header = null;
1271:                    buffer.setLength(0);
1272:                    if (firstHeader != null) {
1273:                        header = firstHeader;
1274:                        firstHeader = null;
1275:                    } else {
1276:                        header = SVNFileUtil.readLineFromStream(dumpStream,
1277:                                buffer, decoder);
1278:                        if (header == null && buffer.length() > 0) {
1279:                            SVNAdminHelper.generateIncompleteDataError();
1280:                        } else if (buffer.length() == 0) {
1281:                            break;
1282:                        }
1283:                    }
1284:
1285:                    int colonInd = header.indexOf(':');
1286:                    if (colonInd == -1) {
1287:                        SVNErrorMessage err = SVNErrorMessage
1288:                                .create(
1289:                                        SVNErrorCode.STREAM_MALFORMED_DATA,
1290:                                        "Dump stream contains a malformed header (with no '':'') at ''{0}''",
1291:                                        header.length() > 20 ? header
1292:                                                .substring(0, 19) : header);
1293:                        SVNErrorManager.error(err);
1294:                    }
1295:
1296:                    String name = header.substring(0, colonInd);
1297:                    if (colonInd + 2 > header.length()) {
1298:                        SVNErrorMessage err = SVNErrorMessage
1299:                                .create(
1300:                                        SVNErrorCode.STREAM_MALFORMED_DATA,
1301:                                        "Dump stream contains a malformed header (with no value) at ''{0}''",
1302:                                        header.length() > 20 ? header
1303:                                                .substring(0, 19) : header);
1304:                        SVNErrorManager.error(err);
1305:                    }
1306:                    String value = header.substring(colonInd + 2);
1307:                    headers.put(name, value);
1308:                }
1309:
1310:                return headers;
1311:            }
1312:
1313:            private void copyRevisionProperties(SVNRepository fromRepository,
1314:                    SVNRepository toRepository, long revision, boolean sync)
1315:                    throws SVNException {
1316:                Map existingRevProps = null;
1317:                if (sync) {
1318:                    existingRevProps = toRepository.getRevisionProperties(
1319:                            revision, null);
1320:                }
1321:
1322:                boolean sawSyncProperties = false;
1323:                Map revProps = fromRepository.getRevisionProperties(revision,
1324:                        null);
1325:                for (Iterator propNames = revProps.keySet().iterator(); propNames
1326:                        .hasNext();) {
1327:                    String propName = (String) propNames.next();
1328:                    String propValue = (String) revProps.get(propName);
1329:                    if (propName.startsWith("sync-")) {
1330:                        sawSyncProperties = true;
1331:                    } else {
1332:                        toRepository.setRevisionPropertyValue(revision,
1333:                                propName, propValue);
1334:                    }
1335:
1336:                    if (sync) {
1337:                        existingRevProps.remove(propName);
1338:                    }
1339:                }
1340:
1341:                if (sync) {
1342:                    for (Iterator propNames = existingRevProps.keySet()
1343:                            .iterator(); propNames.hasNext();) {
1344:                        String propName = (String) propNames.next();
1345:                        toRepository.setRevisionPropertyValue(revision,
1346:                                propName, null);
1347:                    }
1348:                }
1349:
1350:                if (sawSyncProperties) {
1351:                    SVNDebugLog.getDefaultLog().info(
1352:                            "Copied properties for revision " + revision
1353:                                    + " (sync-* properties skipped).\n");
1354:                } else {
1355:                    SVNDebugLog.getDefaultLog().info(
1356:                            "Copied properties for revision " + revision
1357:                                    + ".\n");
1358:                }
1359:            }
1360:
1361:            private SessionInfo openSourceRepository(SVNRepository targetRepos)
1362:                    throws SVNException {
1363:                String fromURL = targetRepos.getRevisionPropertyValue(0,
1364:                        SVNRevisionProperty.FROM_URL);
1365:                String fromUUID = targetRepos.getRevisionPropertyValue(0,
1366:                        SVNRevisionProperty.FROM_UUID);
1367:                String lastMergedRev = targetRepos.getRevisionPropertyValue(0,
1368:                        SVNRevisionProperty.LAST_MERGED_REVISION);
1369:
1370:                if (fromURL == null || fromUUID == null
1371:                        || lastMergedRev == null) {
1372:                    SVNErrorMessage err = SVNErrorMessage.create(
1373:                            SVNErrorCode.IO_ERROR,
1374:                            "Destination repository has not been initialized");
1375:                    SVNErrorManager.error(err);
1376:                }
1377:
1378:                SVNURL srcURL = SVNURL.parseURIDecoded(fromURL);
1379:                // TOOD close session.
1380:                SVNRepository srcRepos = createRepository(srcURL, false);
1381:
1382:                checkIfRepositoryIsAtRoot(srcRepos, srcURL);
1383:
1384:                String reposUUID = srcRepos.getRepositoryUUID(true);
1385:                if (!fromUUID.equals(reposUUID)) {
1386:                    SVNErrorMessage err = SVNErrorMessage
1387:                            .create(
1388:                                    SVNErrorCode.IO_ERROR,
1389:                                    "UUID of destination repository ({0}) does not match expected UUID ({1})",
1390:                                    new String[] { reposUUID, fromUUID });
1391:                    SVNErrorManager.error(err);
1392:                }
1393:
1394:                return new SessionInfo(srcRepos, Long.parseLong(lastMergedRev));
1395:            }
1396:
1397:            private void checkIfRepositoryIsAtRoot(SVNRepository repos,
1398:                    SVNURL url) throws SVNException {
1399:                SVNURL reposRoot = repos.getRepositoryRoot(true);
1400:                if (!reposRoot.equals(url)) {
1401:                    SVNErrorMessage err = SVNErrorMessage
1402:                            .create(
1403:                                    SVNErrorCode.IO_ERROR,
1404:                                    "Session is rooted at ''{0}'' but the repos root is ''{1}''",
1405:                                    new SVNURL[] { url, reposRoot });
1406:                    SVNErrorManager.error(err);
1407:                }
1408:            }
1409:
1410:            private void lock(SVNRepository repos) throws SVNException {
1411:                String hostName = null;
1412:                try {
1413:                    hostName = InetAddress.getLocalHost().getHostName();
1414:                } catch (UnknownHostException e) {
1415:                    SVNErrorMessage err = SVNErrorMessage.create(
1416:                            SVNErrorCode.IO_ERROR, "Can't get local hostname");
1417:                    SVNErrorManager.error(err, e);
1418:                }
1419:
1420:                if (hostName.length() > 256) {
1421:                    hostName = hostName.substring(0, 256);
1422:                }
1423:
1424:                String lockToken = hostName
1425:                        + ":"
1426:                        + SVNUUIDGenerator.formatUUID(SVNUUIDGenerator
1427:                                .generateUUID());
1428:                int i = 0;
1429:                for (i = 0; i < 10; i++) {
1430:                    String reposLockToken = repos.getRevisionPropertyValue(0,
1431:                            SVNRevisionProperty.LOCK);
1432:                    if (reposLockToken != null) {
1433:                        if (reposLockToken.equals(lockToken)) {
1434:                            return;
1435:                        }
1436:                        try {
1437:                            Thread.sleep(1000);
1438:                        } catch (InterruptedException e) {
1439:                            //
1440:                        }
1441:                    } else {
1442:                        repos.setRevisionPropertyValue(0,
1443:                                SVNRevisionProperty.LOCK, lockToken);
1444:                    }
1445:                }
1446:
1447:                SVNErrorMessage err = SVNErrorMessage
1448:                        .create(
1449:                                SVNErrorCode.IO_ERROR,
1450:                                "Couldn''t get lock on destination repos after {0,number,integer} attempts\n",
1451:                                new Integer(i));
1452:                SVNErrorManager.error(err);
1453:            }
1454:
1455:            private void unlock(SVNRepository repos) throws SVNException {
1456:                repos.setRevisionPropertyValue(0, SVNRevisionProperty.LOCK,
1457:                        null);
1458:            }
1459:
1460:            private class SessionInfo {
1461:
1462:                SVNRepository myRepository;
1463:                long myLastMergedRevision;
1464:
1465:                public SessionInfo(SVNRepository repos, long lastMergedRev) {
1466:                    myRepository = repos;
1467:                    myLastMergedRevision = lastMergedRev;
1468:                }
1469:            }
1470:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.