]> git.argeo.org Git - gpl/argeo-slc.git/blob - legacy/runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/web/ajaxplorer/svn/SvnDriver.java
Restructure SLC
[gpl/argeo-slc.git] / legacy / runtime / org.argeo.slc.server / src / main / java / org / argeo / slc / web / ajaxplorer / svn / SvnDriver.java
1 /*
2 * Copyright (C) 2007-2012 Mathieu Baudier
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.slc.web.ajaxplorer.svn;
17
18 import java.io.File;
19
20 import org.argeo.slc.web.ajaxplorer.AjxpDriverException;
21 import org.argeo.slc.web.ajaxplorer.file.FileDriver;
22 import org.springframework.beans.factory.BeanNameAware;
23 import org.tmatesoft.svn.core.SVNException;
24 import org.tmatesoft.svn.core.SVNURL;
25 import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
26 import org.tmatesoft.svn.core.io.SVNRepository;
27 import org.tmatesoft.svn.core.wc.SVNClientManager;
28 import org.tmatesoft.svn.core.wc.SVNInfo;
29 import org.tmatesoft.svn.core.wc.SVNRevision;
30 import org.tmatesoft.svn.core.wc.admin.SVNAdminClient;
31
32 public class SvnDriver extends FileDriver implements BeanNameAware {
33 private final static String DEFAULT_DATA_PATH = System
34 .getProperty("user.home")
35 + File.separator + "AjaXplorerArchiver" + File.separator + "data";
36
37 private final static long WRITE_ACTION_TIMEOUT = 10 * 60 * 1000;
38
39 private SVNURL baseUrl;
40 private SVNClientManager manager;
41
42 private String beanName;
43
44 private boolean isInWriteAction = false;
45
46 public void init() {
47 FSRepositoryFactory.setup();
48 manager = SVNClientManager.newInstance();
49
50 String basePath = getBasePath();
51 if (basePath != null) {
52 File baseDir = new File(basePath);
53 if (baseDir.exists()) {// base dir exists
54 boolean shouldCheckOut = baseDirChecks(baseDir);
55 if (shouldCheckOut) {
56 checkOut(baseDir);
57 }
58 } else {
59 checkOut(baseDir);
60 }
61 } else {
62 String defaultBasePath = DEFAULT_DATA_PATH + File.separator
63 + "svnwc" + File.separator + beanName;
64 log.warn("No base path provided, use " + defaultBasePath);
65 setBasePath(defaultBasePath);
66
67 File baseDir = new File(getBasePath());
68 if (!baseDir.exists()) {
69 baseDir.mkdirs();
70 }
71
72 if (baseDirChecks(baseDir)) {
73 if (getBaseUrl() == null) {
74 String defaultRepoPath = DEFAULT_DATA_PATH + File.separator
75 + "svnrepos" + File.separator + beanName;
76 log.warn("No base URL found, create repository at "
77 + defaultRepoPath);
78 baseUrl = createRepository(new File(defaultRepoPath));
79 }
80 checkOut(new File(getBasePath()));
81 }
82 }
83 log.info("SVN driver initialized with base url " + getBaseUrl()
84 + " and base path " + getBasePath());
85 }
86
87 /** Builds a SVN URL. */
88 public SVNURL getSVNURL(String relativePath) {
89 try {
90 return baseUrl.appendPath(relativePath, false);
91 } catch (SVNException e) {
92 throw new AjxpDriverException(
93 "Cannot build URL from relative path " + relativePath
94 + " and base url " + baseUrl);
95 }
96 }
97
98 public SVNRepository getRepository() {
99 try {
100 return manager.createRepository(baseUrl, true);
101 } catch (SVNException e) {
102 throw new AjxpDriverException("Cannot create repository for "
103 + baseUrl, e);
104 }
105 }
106
107 /**
108 * Verifies that the provided existing base dir is ok and whether one should
109 * check out. Set the base url from the working copy.
110 *
111 * @return whether one should check out.
112 */
113 protected boolean baseDirChecks(File baseDir) {
114 if (!baseDir.isDirectory()) {
115 throw new AjxpDriverException("Base path " + baseDir
116 + " is not a directory.");
117 }
118
119 try {// retrieves SVN infos
120 SVNInfo info = manager.getWCClient().doInfo(baseDir,
121 SVNRevision.WORKING);
122 SVNURL baseUrlTemp = info.getURL();
123 if (baseUrl != null) {
124 if (!baseUrl.equals(baseUrlTemp)) {
125 throw new AjxpDriverException(
126 "SVN URL of the working copy "
127 + baseUrlTemp
128 + " is not compatible with provided baseUrl "
129 + baseUrl);
130 }
131 } else {
132 this.baseUrl = baseUrlTemp;
133 }
134 return false;
135 } catch (SVNException e) {// no info retrieved
136 log
137 .warn("Could not retrieve SVN info from "
138 + baseDir
139 + "("
140 + e.getMessage()
141 + "). Guess that it is and empty dir and try to check out from provided URL.");
142 if (baseDir.listFiles().length != 0) {
143 throw new AjxpDriverException("Base dir " + baseDir
144 + " is not a working copy and not an empty dir.");
145 }
146 return true;
147 }
148 }
149
150 protected void checkOut(File baseDir) {
151 if (getBaseUrl() == null) {
152 throw new AjxpDriverException(
153 "No SVN URL provided, cannot check out.");
154 }
155
156 // Make sure directory exists
157 baseDir.mkdirs();
158
159 try {
160 long revision = manager.getUpdateClient().doCheckout(getBaseUrl(),
161 baseDir, SVNRevision.UNDEFINED, SVNRevision.HEAD, true);
162 log.info("Checked out from " + baseUrl + " to " + baseDir
163 + " at revision " + revision);
164 } catch (SVNException e) {
165 throw new AjxpDriverException("Cannot check out from " + baseUrl
166 + " to " + baseDir, e);
167 }
168 }
169
170 protected SVNURL createRepository(File repoDir) {
171 try {
172 SVNAdminClient adminClient = manager.getAdminClient();
173 return adminClient.doCreateRepository(repoDir, null, true, false);
174 } catch (SVNException e) {
175 throw new AjxpDriverException("Cannot create repository at "
176 + repoDir, e);
177 }
178 }
179
180 private void updateIfRequired(File dir) {
181 try {
182 SVNInfo wcInfo = manager.getWCClient().doInfo(getBaseDir(),
183 SVNRevision.WORKING);
184 SVNRevision wcRev = wcInfo.getRevision();
185 SVNInfo repoInfo = manager.getWCClient().doInfo(getBaseUrl(),
186 null, SVNRevision.HEAD);
187 SVNRevision repoRev = repoInfo.getRevision();
188
189 if (log.isTraceEnabled())
190 log
191 .trace("WC Revision=" + wcRev + ", Repo Revision="
192 + repoRev);
193
194 if (!wcRev.equals(repoRev)) {
195 log.debug("Update working copy from revision " + wcRev
196 + " to revision " + repoRev);
197 manager.getUpdateClient().doUpdate(getBaseDir(),
198 SVNRevision.HEAD, true);
199 }
200 } catch (SVNException e) {
201 throw new AjxpDriverException("Cannot update working copy "
202 + getBaseDir(),e);
203 }
204 }
205
206 public synchronized void beginWriteAction(File dir) {
207 if (isInWriteAction) {
208 try {
209 wait(WRITE_ACTION_TIMEOUT);
210 } catch (InterruptedException e) {
211 // silent
212 }
213 if (isInWriteAction) {
214 throw new AjxpDriverException(
215 "Still in write action after timeout "
216 + WRITE_ACTION_TIMEOUT + " ms.");
217 }
218 }
219
220 isInWriteAction = true;
221 updateIfRequired(dir);
222 }
223
224 public synchronized void completeWriteAction(File dir) {
225 isInWriteAction = false;
226 notifyAll();
227 }
228
229 public synchronized void rollbackWriteAction(File dir) {
230 // TODO: revert?
231 isInWriteAction = false;
232 notifyAll();
233 }
234
235 public void commitAll(String message) throws SVNException{
236 if(log.isTraceEnabled())
237 log.trace("SVN Commit: " + getBaseDir());
238 manager.getCommitClient().doCommit(new File[] { getBaseDir() }, true,
239 message, true, true);
240
241 }
242
243 /** Spring bean name, set at initialization. */
244 public void setBeanName(String beanName) {
245 this.beanName = beanName;
246 }
247
248 public void setBaseUrl(String baseUrl) {
249 try {
250 this.baseUrl = SVNURL.parseURIDecoded(baseUrl);
251 } catch (SVNException e) {
252 throw new AjxpDriverException("Cannot parse SVN URL " + baseUrl, e);
253 }
254 }
255
256 public SVNURL getBaseUrl() {
257 return baseUrl;
258 }
259
260 public SVNClientManager getManager() {
261 return manager;
262 }
263
264 }