SandboxManager.java
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!= nullreturn 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!= nullreturn 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 sbDirthrows 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 locationthrows 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