| 
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
 |