001 /*
002 * SandboxManager.java
003 * Copyright (c) 1998-2008, The University of Sheffield.
004 *
005 * This code is from the GATE project (http://gate.ac.uk/) and is free
006 * software licenced under the GNU General Public License version 3. It is
007 * distributed without any warranty. For more details see COPYING.txt in the
008 * top level directory (or at http://gatewiki.sf.net/COPYING.txt).
009 *
010 * Hamish Cunningham 8th January 2007
011 */
012 package gate.versioning.svnkit;
013
014 import gate.util.GateException;
015 import gate.util.GateRuntimeException;
016
017 import java.io.File;
018 import java.io.IOException;
019 import java.util.Collection;
020 import java.util.Collections;
021 import java.util.List;
022 import java.util.Map;
023 import java.util.concurrent.ConcurrentHashMap;
024 import java.util.concurrent.ConcurrentMap;
025
026 import org.apache.log4j.Logger;
027 import org.tmatesoft.svn.core.SVNCommitInfo;
028 import org.tmatesoft.svn.core.SVNException;
029 import org.tmatesoft.svn.core.SVNURL;
030 import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
031 import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
032
033 /**
034 * This class manages a set of {@link Sandbox}es. This is a Spring Bean and it
035 * is assumed that this will be a singleton. It ensures that there is never more
036 * than one {@link Sandbox} object for any given SVN-managed file tree, and it
037 * linearises operations on these objects. It is intended to be thread-safe.
038 *
039 * <b>NOTE</b>: this API assumes that its clients are friendly enough not to add
040 * a sandbox that is a subdirectory of another sandbox also being managed. If
041 * this rule is not followed then the results will be unpredictable!
042 */
043 public class SandboxManager {
044
045 private static final Logger log = Logger.getLogger(SandboxManager.class);
046
047 /**
048 * A map of sandboxes to their ids.
049 */
050 ConcurrentMap<String, Sandbox> sandboxMap =
051 new ConcurrentHashMap<String, Sandbox>();
052
053 /**
054 * A directory holding subversion config info, if null then the users default
055 * .subversion directory will be used
056 */
057 private File configDir = null;
058
059 public void setConfigDir(File dir) {
060 System.out.println("SVN config will be read from " + dir.getAbsolutePath());
061 configDir = dir;
062 }
063
064 public File getConfigDir() {
065 return configDir;
066 }
067
068 /**
069 * Add a new Sandbox. This will be identified by the canonical form of the
070 * path to the directory tree. If a sandbox that is already recorded is added
071 * nothing is done and the method returns false.
072 *
073 * @param location
074 * a file pointing to the top-level directory of the sandbox on disk.
075 * @param username
076 * - for svn authentication
077 * @param password
078 * - for svn authentication
079 *
080 * @return boolean indicates if the new sandbox was added.
081 *
082 * @throws GateException
083 * when the location doesn't exist or isn't under version control.
084 */
085 public boolean addSandbox(File location, String username, String password)
086 throws GateException {
087 // is it valid?
088 if(!isSandboxDir(location))
089 throw new GateException(location.getPath()
090 + " is not a valid SVN sandbox directory");
091 // do we know it already?
092 String id = getSandboxId(location);
093 if(sandboxMap.get(id) != null) return false; // already managed
094 // add it
095 Sandbox sandbox = new Sandbox(username, password, configDir);
096 sandboxMap.put(id, sandbox);
097 return true;
098 } // addSandbox(File)
099
100 /**
101 * Add a new Sandbox. This will be identified by the canonical form of the
102 * path to the directory tree. If a sandbox that is already recorded is added
103 * nothing is done and the method returns false.
104 *
105 * @param location
106 * a file pointing to the top-level directory of the sandbox on disk.
107 * @param authManager
108 * - custom authentication manager for svn authentication
109 *
110 * @return boolean indicates if the new sandbox was added.
111 *
112 * @throws GateException
113 * when the location doesn't exist or isn't under version control.
114 */
115 public boolean addSandbox(File location, ISVNAuthenticationManager authManager)
116 throws GateException {
117 // is it valid?
118 if(!isSandboxDir(location))
119 throw new GateException(location.getPath()
120 + " is not a valid SVN sandbox directory (2)");
121 // do we know it already?
122 String id = getSandboxId(location);
123 if(sandboxMap.get(id) != null) return false; // already managed
124 // add it
125 Sandbox sandbox = new Sandbox(authManager, configDir);
126 sandboxMap.put(id, sandbox);
127 return true;
128 } // addSandbox(File,ISVNAuthenticationManager)
129
130 /**
131 * Generate an ID for a File that points to a sandbox tree on disk. This ID is
132 * the directory's canonical path.
133 *
134 * @throws GateRuntimeException
135 * when the location won't resolve to a canonical path.
136 */
137 public String getSandboxId(File sbDir) throws GateRuntimeException {
138 String id;
139 try {
140 id = sbDir.getCanonicalPath();
141 }
142 catch(IOException e) {
143 throw new GateRuntimeException("couldn't get canonical path for "
144 + sbDir.getName() + "; error was: " + e);
145 }
146 return id;
147 } // getSandboxId(FSR)
148
149 /**
150 * Check that a File points to a valid sandbox on disk.
151 *
152 * @param sbDir
153 * a file pointing to the top-level directory of the sandbox on disk.
154 *
155 * @return boolean indicates if the sandbox is valid.
156 */
157 public boolean isSandboxDir(File sbDir) {
158 // is it a dir?
159 if(!sbDir.isDirectory()) return false;
160 // is it under svn control?
161 File sbSVNDir = new File(sbDir, ".svn");
162 if(!sbSVNDir.isDirectory()) return false;
163 return true;
164 } // isSandboxDir(FSR)
165
166 /**
167 * Forget a sandbox.
168 *
169 * @param sbDir
170 * a file pointing to the top-level directory of the sandbox on disk
171 * (it is assumed to be a File).
172 */
173 public void forgetSandbox(File sbDir) {
174 Sandbox sb = sandboxMap.remove(getSandboxId(sbDir));
175 if(sb != null) {
176 sb.close();
177 }
178 } // forgetSandbox(File)
179
180 /**
181 * Get a sandbox from its ID (canonical path to the directory tree).
182 *
183 * @param id
184 * the ID of the Sandbox (if you only have the location of the
185 * sandbox on disk, use {@link getSandboxId(File)} and pass the
186 * result to this method.
187 */
188 public Sandbox getSandbox(String id) {
189 return sandboxMap.get(id);
190 } // getSandbox(FSR)
191
192 /**
193 * Get an (immutable) list of all known sandboxes.
194 */
195 public List<Sandbox> getSandboxList() {
196 Collection<Sandbox> sbColl = sandboxMap.values();
197 List<Sandbox> sbList = Collections.list(Collections.enumeration(sbColl));
198 return Collections.unmodifiableList(sbList);
199 } // getSandboxList()
200
201 /**
202 * Get an (immutable) map of all known sandboxes indexed by id.
203 */
204 public Map<String, Sandbox> getSandboxMap() {
205 return Collections.unmodifiableMap(sandboxMap);
206 } // getSandboxMap()
207
208 /**
209 * Create a new local SVN repository. This includes three directories "trunk",
210 * "tags" and "branches" as per normal convention.
211 *
212 * @return SVNURL the URL of the new repository.
213 */
214 public SVNURL createLocalRepository(File location) throws SVNException {
215 SVNURL repositoryURL =
216 SVNRepositoryFactory.createLocalRepository(location, null, false, true);
217 SVNURL trunk = repositoryURL.appendPath("trunk", false);
218 SVNURL tags = repositoryURL.appendPath("tags", false);
219 SVNURL branches = repositoryURL.appendPath("branches", false);
220 String commitMessage =
221 "Created by gate.versioning.svnkit.SandboxManager.createLocalRepository";
222 Sandbox tmpSandbox = new Sandbox("", "", configDir);
223 SVNCommitInfo commitInfo;
224 commitInfo = tmpSandbox.makeDirectory(trunk, commitMessage);
225 commitInfo = tmpSandbox.makeDirectory(tags, commitMessage);
226 commitInfo = tmpSandbox.makeDirectory(branches, commitMessage);
227 return repositoryURL;
228 } // createLocalRepository(File)
229
230 /**
231 * This method adds a list of sandboxes to the sandboxMap. In case of any
232 * exception, the runtime exception is thrown and since the method is called
233 * when starting the application, the process of starting the application will
234 * be terminated. // TODO why does this throw runtime exception?!
235 *
236 * We assume that all sandboxes are for users with same username/password on
237 * svn.
238 *
239 * @param folderIds
240 * the list of full paths of the sandboxes to be added.
241 * @param username
242 * - for svn authentication
243 * @param password
244 * - for svn authentication
245 *
246 */
247 public void addSandboxes(List folderIds, String username, String password) {
248 try {
249 for(int i = 0; i < folderIds.size(); i++) {
250 addSandbox(new File((String)folderIds.get(i)), username, password);
251 }
252 }
253 catch(GateException e) {
254 throw new GateRuntimeException(e);
255 }
256 }
257
258 /**
259 * Close all managed sandboxes.
260 */
261 public void shutdown() {
262 log.info("SandboxManager shutting down");
263 for(Map.Entry<String, Sandbox> sb : sandboxMap.entrySet()) {
264 log.info("Shutting down sandbox " + sb.getKey());
265 sb.getValue().close();
266 }
267 log.info("Shutdown complete");
268 }
269 } // SandboxManager
|