1 package org
.argeo
.slc
.web
.ajaxplorer
.svn
;
5 import org
.argeo
.slc
.web
.ajaxplorer
.AjxpDriverException
;
6 import org
.argeo
.slc
.web
.ajaxplorer
.file
.FileDriver
;
7 import org
.springframework
.beans
.factory
.BeanNameAware
;
8 import org
.tmatesoft
.svn
.core
.SVNException
;
9 import org
.tmatesoft
.svn
.core
.SVNURL
;
10 import org
.tmatesoft
.svn
.core
.internal
.io
.fs
.FSRepositoryFactory
;
11 import org
.tmatesoft
.svn
.core
.io
.SVNRepository
;
12 import org
.tmatesoft
.svn
.core
.wc
.SVNClientManager
;
13 import org
.tmatesoft
.svn
.core
.wc
.SVNInfo
;
14 import org
.tmatesoft
.svn
.core
.wc
.SVNRevision
;
15 import org
.tmatesoft
.svn
.core
.wc
.admin
.SVNAdminClient
;
17 public class SvnDriver
extends FileDriver
implements BeanNameAware
{
18 private final static String DEFAULT_DATA_PATH
= System
19 .getProperty("user.home")
20 + File
.separator
+ "AjaXplorerArchiver" + File
.separator
+ "data";
22 private final static long WRITE_ACTION_TIMEOUT
= 10 * 60 * 1000;
24 private SVNURL baseUrl
;
25 private SVNClientManager manager
;
27 private String beanName
;
29 private boolean isInWriteAction
= false;
32 FSRepositoryFactory
.setup();
33 manager
= SVNClientManager
.newInstance();
35 String basePath
= getBasePath();
36 if (basePath
!= null) {
37 File baseDir
= new File(basePath
);
38 if (baseDir
.exists()) {// base dir exists
39 boolean shouldCheckOut
= baseDirChecks(baseDir
);
47 String defaultBasePath
= DEFAULT_DATA_PATH
+ File
.separator
48 + "svnwc" + File
.separator
+ beanName
;
49 log
.warn("No base path provided, use " + defaultBasePath
);
50 setBasePath(defaultBasePath
);
52 File baseDir
= new File(getBasePath());
53 if (!baseDir
.exists()) {
57 if (baseDirChecks(baseDir
)) {
58 if (getBaseUrl() == null) {
59 String defaultRepoPath
= DEFAULT_DATA_PATH
+ File
.separator
60 + "svnrepos" + File
.separator
+ beanName
;
61 log
.warn("No base URL found, create repository at "
63 baseUrl
= createRepository(new File(defaultRepoPath
));
65 checkOut(new File(getBasePath()));
68 log
.info("SVN driver initialized with base url " + getBaseUrl()
69 + " and base path " + getBasePath());
72 /** Builds a SVN URL. */
73 public SVNURL
getSVNURL(String relativePath
) {
75 return baseUrl
.appendPath(relativePath
, false);
76 } catch (SVNException e
) {
77 throw new AjxpDriverException(
78 "Cannot build URL from relative path " + relativePath
79 + " and base url " + baseUrl
);
83 public SVNRepository
getRepository() {
85 return manager
.createRepository(baseUrl
, true);
86 } catch (SVNException e
) {
87 throw new AjxpDriverException("Cannot create repository for "
93 * Verifies that the provided existing base dir is ok and whether one should
94 * check out. Set the base url from the working copy.
96 * @return whether one should check out.
98 protected boolean baseDirChecks(File baseDir
) {
99 if (!baseDir
.isDirectory()) {
100 throw new AjxpDriverException("Base path " + baseDir
101 + " is not a directory.");
104 try {// retrieves SVN infos
105 SVNInfo info
= manager
.getWCClient().doInfo(baseDir
,
106 SVNRevision
.WORKING
);
107 SVNURL baseUrlTemp
= info
.getURL();
108 if (baseUrl
!= null) {
109 if (!baseUrl
.equals(baseUrlTemp
)) {
110 throw new AjxpDriverException(
111 "SVN URL of the working copy "
113 + " is not compatible with provided baseUrl "
117 this.baseUrl
= baseUrlTemp
;
120 } catch (SVNException e
) {// no info retrieved
122 .warn("Could not retrieve SVN info from "
126 + "). Guess that it is and empty dir and try to check out from provided URL.");
127 if (baseDir
.listFiles().length
!= 0) {
128 throw new AjxpDriverException("Base dir " + baseDir
129 + " is not a working copy and not an empty dir.");
135 protected void checkOut(File baseDir
) {
136 if (getBaseUrl() == null) {
137 throw new AjxpDriverException(
138 "No SVN URL provided, cannot check out.");
141 // Make sure directory exists
145 long revision
= manager
.getUpdateClient().doCheckout(getBaseUrl(),
146 baseDir
, SVNRevision
.UNDEFINED
, SVNRevision
.HEAD
, true);
147 log
.info("Checked out from " + baseUrl
+ " to " + baseDir
148 + " at revision " + revision
);
149 } catch (SVNException e
) {
150 throw new AjxpDriverException("Cannot check out from " + baseUrl
151 + " to " + baseDir
, e
);
155 protected SVNURL
createRepository(File repoDir
) {
157 SVNAdminClient adminClient
= manager
.getAdminClient();
158 return adminClient
.doCreateRepository(repoDir
, null, true, false);
159 } catch (SVNException e
) {
160 throw new AjxpDriverException("Cannot create repository at "
165 private void updateIfRequired(File dir
) {
167 SVNInfo wcInfo
= manager
.getWCClient().doInfo(getBaseDir(),
168 SVNRevision
.WORKING
);
169 SVNRevision wcRev
= wcInfo
.getRevision();
170 SVNInfo repoInfo
= manager
.getWCClient().doInfo(getBaseUrl(),
171 null, SVNRevision
.HEAD
);
172 SVNRevision repoRev
= repoInfo
.getRevision();
174 if (log
.isTraceEnabled())
176 .trace("WC Revision=" + wcRev
+ ", Repo Revision="
179 if (!wcRev
.equals(repoRev
)) {
180 log
.debug("Update working copy from revision " + wcRev
181 + " to revision " + repoRev
);
182 manager
.getUpdateClient().doUpdate(getBaseDir(),
183 SVNRevision
.HEAD
, true);
185 } catch (SVNException e
) {
186 throw new AjxpDriverException("Cannot update working copy "
191 public synchronized void beginWriteAction(File dir
) {
192 if (isInWriteAction
) {
194 wait(WRITE_ACTION_TIMEOUT
);
195 } catch (InterruptedException e
) {
198 if (isInWriteAction
) {
199 throw new AjxpDriverException(
200 "Still in write action after timeout "
201 + WRITE_ACTION_TIMEOUT
+ " ms.");
205 isInWriteAction
= true;
206 updateIfRequired(dir
);
209 public synchronized void completeWriteAction(File dir
) {
210 isInWriteAction
= false;
214 public synchronized void rollbackWriteAction(File dir
) {
216 isInWriteAction
= false;
220 public void commitAll(String message
) throws SVNException
{
221 if(log
.isTraceEnabled())
222 log
.trace("SVN Commit: " + getBaseDir());
223 manager
.getCommitClient().doCommit(new File
[] { getBaseDir() }, true,
224 message
, true, true);
228 /** Spring bean name, set at initialization. */
229 public void setBeanName(String beanName
) {
230 this.beanName
= beanName
;
233 public void setBaseUrl(String baseUrl
) {
235 this.baseUrl
= SVNURL
.parseURIDecoded(baseUrl
);
236 } catch (SVNException e
) {
237 throw new AjxpDriverException("Cannot parse SVN URL " + baseUrl
, e
);
241 public SVNURL
getBaseUrl() {
245 public SVNClientManager
getManager() {