extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/BaseFileSystemView.java

Code
Comments
Other
Rev Date Author Line
716 02 Jun 08 nicklas 1 /**
716 02 Jun 08 nicklas 2   $Id $
716 02 Jun 08 nicklas 3
716 02 Jun 08 nicklas 4   Copyright (C) 2008 Nicklas Nordborg
716 02 Jun 08 nicklas 5
1381 15 Aug 11 martin 6   This file is part of the FTP Server extension for BASE.
716 02 Jun 08 nicklas 7   Available at http://baseplugins.thep.lu.se/
1381 15 Aug 11 martin 8   BASE main site: http://base.thep.lu.se/
1381 15 Aug 11 martin 9   -----------------------------------------------------------
1381 15 Aug 11 martin 10   
1381 15 Aug 11 martin 11   This is free software; you can redistribute it and/or
716 02 Jun 08 nicklas 12   modify it under the terms of the GNU General Public License
1381 15 Aug 11 martin 13   as published by the Free Software Foundation; either version 3
716 02 Jun 08 nicklas 14   of the License, or (at your option) any later version.
1381 15 Aug 11 martin 15   
1381 15 Aug 11 martin 16   The software is distributed in the hope that it will be useful,
716 02 Jun 08 nicklas 17   but WITHOUT ANY WARRANTY; without even the implied warranty of
716 02 Jun 08 nicklas 18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
716 02 Jun 08 nicklas 19   GNU General Public License for more details.
1381 15 Aug 11 martin 20   
1381 15 Aug 11 martin 21   You should have received a copy of the GNU General Public License
1381 15 Aug 11 martin 22   along with BASE. If not, see <http://www.gnu.org/licenses/>.
716 02 Jun 08 nicklas 23
716 02 Jun 08 nicklas 24 */
714 30 May 08 nicklas 25 package net.sf.basedb.clients.ftp;
714 30 May 08 nicklas 26
714 30 May 08 nicklas 27 import net.sf.basedb.core.DbControl;
714 30 May 08 nicklas 28 import net.sf.basedb.core.Directory;
714 30 May 08 nicklas 29 import net.sf.basedb.core.File;
714 30 May 08 nicklas 30 import net.sf.basedb.core.Path;
714 30 May 08 nicklas 31
915 11 Dec 08 nicklas 32 import org.apache.ftpserver.ftplet.FtpFile;
714 30 May 08 nicklas 33 import org.apache.ftpserver.ftplet.FileSystemView;
714 30 May 08 nicklas 34 import org.apache.ftpserver.ftplet.FtpException;
716 02 Jun 08 nicklas 35 import org.slf4j.Logger;
716 02 Jun 08 nicklas 36 import org.slf4j.LoggerFactory;
714 30 May 08 nicklas 37
714 30 May 08 nicklas 38 /**
714 30 May 08 nicklas 39   The view of the BASE file system as seen from the currently logged in user.
714 30 May 08 nicklas 40   Users will start out in their home directory if they have one, otherwise in
714 30 May 08 nicklas 41   the root.
716 02 Jun 08 nicklas 42   
716 02 Jun 08 nicklas 43   @author Nicklas
716 02 Jun 08 nicklas 44   @version 1.0
714 30 May 08 nicklas 45 */
714 30 May 08 nicklas 46 public class BaseFileSystemView 
714 30 May 08 nicklas 47   implements FileSystemView 
714 30 May 08 nicklas 48 {
714 30 May 08 nicklas 49
716 02 Jun 08 nicklas 50   private static final Logger log = LoggerFactory.getLogger(BaseFileSystemView.class);
716 02 Jun 08 nicklas 51
714 30 May 08 nicklas 52   private BaseUser user;
915 11 Dec 08 nicklas 53   private BaseFtpFile currentDir;
714 30 May 08 nicklas 54   
716 02 Jun 08 nicklas 55   /**
716 02 Jun 08 nicklas 56     Create a new file system view for the specified user.
716 02 Jun 08 nicklas 57   */
714 30 May 08 nicklas 58   public BaseFileSystemView(BaseUser user)
714 30 May 08 nicklas 59   {
714 30 May 08 nicklas 60     this.user = user;
714 30 May 08 nicklas 61     this.currentDir = user.getHome();
714 30 May 08 nicklas 62   }
714 30 May 08 nicklas 63   
714 30 May 08 nicklas 64   /*
714 30 May 08 nicklas 65     From the FileSystemView interface
714 30 May 08 nicklas 66     ---------------------------------------
714 30 May 08 nicklas 67   */
714 30 May 08 nicklas 68   
714 30 May 08 nicklas 69   @Override
915 11 Dec 08 nicklas 70   public FtpFile getWorkingDirectory() 
714 30 May 08 nicklas 71     throws FtpException 
714 30 May 08 nicklas 72   {
716 02 Jun 08 nicklas 73     if (log.isDebugEnabled()) log.debug("Current directory: " + currentDir);
714 30 May 08 nicklas 74     return currentDir;
714 30 May 08 nicklas 75   }
714 30 May 08 nicklas 76   
714 30 May 08 nicklas 77   /**
714 30 May 08 nicklas 78     Change to another current directory. There are three cases:
714 30 May 08 nicklas 79     <ol>
714 30 May 08 nicklas 80     <li>The path is '..', meaning that we have to go up one
714 30 May 08 nicklas 81       directory, unless we are at the root directory.
714 30 May 08 nicklas 82     <li>The path starts with a '/', meaning that it is an absolute
714 30 May 08 nicklas 83       path
1229 19 Aug 10 nicklas 84     <li>The path is '.', meaning that we stay in the current
1229 19 Aug 10 nicklas 85       directory (this is used by some clients to keep the
1229 19 Aug 10 nicklas 86       connection alive)
714 30 May 08 nicklas 87     <li>All other paths are relative to the current directory.
714 30 May 08 nicklas 88     </ol>
714 30 May 08 nicklas 89   */
714 30 May 08 nicklas 90   @Override
915 11 Dec 08 nicklas 91   public boolean changeWorkingDirectory(String path) 
714 30 May 08 nicklas 92     throws FtpException 
714 30 May 08 nicklas 93   {
716 02 Jun 08 nicklas 94     if (log.isDebugEnabled()) 
716 02 Jun 08 nicklas 95     {
716 02 Jun 08 nicklas 96       log.debug("Change directory");
716 02 Jun 08 nicklas 97       log.debug("   path=" + path);
716 02 Jun 08 nicklas 98       log.debug("   current="+currentDir);
716 02 Jun 08 nicklas 99       log.debug("   user=" + user);
716 02 Jun 08 nicklas 100     }
714 30 May 08 nicklas 101     Path changeTo = null;
714 30 May 08 nicklas 102     if (path.startsWith("/"))
714 30 May 08 nicklas 103     {
714 30 May 08 nicklas 104       // Absolute path
714 30 May 08 nicklas 105       changeTo = new Path(append(path, ""), Path.Type.DIRECTORY);
714 30 May 08 nicklas 106     }
714 30 May 08 nicklas 107     else if (path.startsWith(".."))
714 30 May 08 nicklas 108     {
714 30 May 08 nicklas 109       // Move to parent directory
915 11 Dec 08 nicklas 110       changeTo = new Path(currentDir.getAbsolutePath(), Path.Type.DIRECTORY).getParent();
714 30 May 08 nicklas 111     }
1229 19 Aug 10 nicklas 112     else if (path.equals("."))
1229 19 Aug 10 nicklas 113     {
1229 19 Aug 10 nicklas 114       // Keep changeTo == null
1229 19 Aug 10 nicklas 115     }
714 30 May 08 nicklas 116     else
714 30 May 08 nicklas 117     {
714 30 May 08 nicklas 118       // Move to subdir within current directory
915 11 Dec 08 nicklas 119       changeTo = new Path(append(currentDir.getAbsolutePath(), path), Path.Type.DIRECTORY);
714 30 May 08 nicklas 120     }
716 02 Jun 08 nicklas 121     if (log.isDebugEnabled()) 
716 02 Jun 08 nicklas 122     {
716 02 Jun 08 nicklas 123       log.debug("   to="+changeTo);
716 02 Jun 08 nicklas 124     }
714 30 May 08 nicklas 125     DbControl dc = user.sc.newDbControl();
714 30 May 08 nicklas 126     try
714 30 May 08 nicklas 127     {
1229 19 Aug 10 nicklas 128       if (changeTo != null)
1229 19 Aug 10 nicklas 129       {
1229 19 Aug 10 nicklas 130         currentDir = new BaseFtpFile(user, Directory.getByPath(dc, changeTo));
1229 19 Aug 10 nicklas 131       }
716 02 Jun 08 nicklas 132       log.debug("Directory changed to: " + currentDir);
714 30 May 08 nicklas 133       return true;
714 30 May 08 nicklas 134     }
714 30 May 08 nicklas 135     catch (RuntimeException ex)
714 30 May 08 nicklas 136     {
716 02 Jun 08 nicklas 137       log.error("Could not change to directory: " + path, ex);
714 30 May 08 nicklas 138       return false;
714 30 May 08 nicklas 139     }
714 30 May 08 nicklas 140     finally
714 30 May 08 nicklas 141     {
714 30 May 08 nicklas 142       if (dc != null) dc.close();
714 30 May 08 nicklas 143     }
714 30 May 08 nicklas 144   }
714 30 May 08 nicklas 145   
714 30 May 08 nicklas 146   /**
714 30 May 08 nicklas 147     Do nothing.
714 30 May 08 nicklas 148   */
714 30 May 08 nicklas 149   @Override
714 30 May 08 nicklas 150   public void dispose() 
714 30 May 08 nicklas 151   {}
714 30 May 08 nicklas 152   
714 30 May 08 nicklas 153   /**
714 30 May 08 nicklas 154     Always true.
714 30 May 08 nicklas 155   */
714 30 May 08 nicklas 156   @Override
714 30 May 08 nicklas 157   public boolean isRandomAccessible() 
714 30 May 08 nicklas 158     throws FtpException 
714 30 May 08 nicklas 159   {
714 30 May 08 nicklas 160     return true;
714 30 May 08 nicklas 161   }
714 30 May 08 nicklas 162   
714 30 May 08 nicklas 163   /**
714 30 May 08 nicklas 164     Get a file object. There are three cases regarding the file name:
714 30 May 08 nicklas 165     <ul>
714 30 May 08 nicklas 166     <li>It starts with './'. The path is relative the current directory
714 30 May 08 nicklas 167       but we have to remove the './'.
714 30 May 08 nicklas 168     <li>It starts with '/'. It is an absolute path.
714 30 May 08 nicklas 169     <li>Otherwise it is relative to the current directory.
714 30 May 08 nicklas 170     </ul>
714 30 May 08 nicklas 171     
714 30 May 08 nicklas 172     Once we have the full path, we first check BASE if there is an existing
714 30 May 08 nicklas 173     file with the name. If so, we create a file object representing that file.
714 30 May 08 nicklas 174     Otherwise we check if there is a directory with the name and create a file
714 30 May 08 nicklas 175     object representing that directory. As a last resort we create a file object
714 30 May 08 nicklas 176     representing a non-existing file or directory.
714 30 May 08 nicklas 177   */
714 30 May 08 nicklas 178   @Override
915 11 Dec 08 nicklas 179   public FtpFile getFile(String fileName) 
714 30 May 08 nicklas 180     throws FtpException 
714 30 May 08 nicklas 181   {
716 02 Jun 08 nicklas 182     if (log.isDebugEnabled()) 
716 02 Jun 08 nicklas 183     {
716 02 Jun 08 nicklas 184       log.debug("Get file object");
716 02 Jun 08 nicklas 185       log.debug("   name=" + fileName);
716 02 Jun 08 nicklas 186       log.debug("   current="+currentDir);
716 02 Jun 08 nicklas 187       log.debug("   user=" + user);
716 02 Jun 08 nicklas 188     }
717 03 Jun 08 nicklas 189     boolean preferDirectory = fileName.endsWith("/");
714 30 May 08 nicklas 190     if (fileName.startsWith("./"))
714 30 May 08 nicklas 191     {
915 11 Dec 08 nicklas 192       fileName = append(currentDir.getAbsolutePath(), fileName.substring(2));
714 30 May 08 nicklas 193     }
714 30 May 08 nicklas 194     else if (!fileName.startsWith("/"))
714 30 May 08 nicklas 195     {
915 11 Dec 08 nicklas 196       fileName = append(currentDir.getAbsolutePath(), fileName);
714 30 May 08 nicklas 197     }
714 30 May 08 nicklas 198     
915 11 Dec 08 nicklas 199     BaseFtpFile fo = null;
714 30 May 08 nicklas 200     DbControl dc = user.sc.newDbControl();
714 30 May 08 nicklas 201     try
714 30 May 08 nicklas 202     {
716 02 Jun 08 nicklas 203       if (log.isDebugEnabled()) 
716 02 Jun 08 nicklas 204       {
716 02 Jun 08 nicklas 205         log.debug("   full path=" + fileName);
716 02 Jun 08 nicklas 206       }
716 02 Jun 08 nicklas 207       
716 02 Jun 08 nicklas 208       // Check if the path represents a file
717 03 Jun 08 nicklas 209       if (preferDirectory) fo = getDirectory(dc, fileName);
717 03 Jun 08 nicklas 210       if (fo == null) fo = getFile(dc, fileName);
717 03 Jun 08 nicklas 211       if (fo == null && !preferDirectory) fo = getDirectory(dc, fileName);
714 30 May 08 nicklas 212     }
714 30 May 08 nicklas 213     finally
714 30 May 08 nicklas 214     {
714 30 May 08 nicklas 215       if (dc != null) dc.close();
714 30 May 08 nicklas 216     }
915 11 Dec 08 nicklas 217     if (fo == null) fo = new BaseFtpFile(user, fileName);
716 02 Jun 08 nicklas 218     if (log.isDebugEnabled())
716 02 Jun 08 nicklas 219     {
716 02 Jun 08 nicklas 220       log.debug("Get file object: " + fo);
716 02 Jun 08 nicklas 221     }
714 30 May 08 nicklas 222     return fo;
714 30 May 08 nicklas 223   }
714 30 May 08 nicklas 224
714 30 May 08 nicklas 225   @Override
915 11 Dec 08 nicklas 226   public FtpFile getHomeDirectory() 
714 30 May 08 nicklas 227     throws FtpException 
714 30 May 08 nicklas 228   {
714 30 May 08 nicklas 229     return user.getHome();
714 30 May 08 nicklas 230   }
716 02 Jun 08 nicklas 231   // ----------------------------------------
714 30 May 08 nicklas 232
714 30 May 08 nicklas 233   /**
717 03 Jun 08 nicklas 234     Try to load the given path as a BASE File object.
717 03 Jun 08 nicklas 235   */
915 11 Dec 08 nicklas 236   private BaseFtpFile getFile(DbControl dc, String path)
717 03 Jun 08 nicklas 237   {
915 11 Dec 08 nicklas 238     BaseFtpFile fo = null;
717 03 Jun 08 nicklas 239     try
717 03 Jun 08 nicklas 240     {
717 03 Jun 08 nicklas 241       Path filePath = new Path(path, Path.Type.FILE);
717 03 Jun 08 nicklas 242       File file = File.getByPath(dc, filePath, false);
915 11 Dec 08 nicklas 243       fo = new BaseFtpFile(user, file);
717 03 Jun 08 nicklas 244     }
717 03 Jun 08 nicklas 245     catch (Exception ex)
717 03 Jun 08 nicklas 246     {
717 03 Jun 08 nicklas 247       if (log.isDebugEnabled())
717 03 Jun 08 nicklas 248       {
717 03 Jun 08 nicklas 249         log.debug("Not a file: " + path, ex);
717 03 Jun 08 nicklas 250       }
717 03 Jun 08 nicklas 251     }
717 03 Jun 08 nicklas 252     return fo;
717 03 Jun 08 nicklas 253   }
717 03 Jun 08 nicklas 254   
717 03 Jun 08 nicklas 255   /**
717 03 Jun 08 nicklas 256     Try to load the given path as a BASE Directory object.
717 03 Jun 08 nicklas 257   */
915 11 Dec 08 nicklas 258   private BaseFtpFile getDirectory(DbControl dc, String path)
717 03 Jun 08 nicklas 259   {
915 11 Dec 08 nicklas 260     BaseFtpFile fo = null;
717 03 Jun 08 nicklas 261     try
717 03 Jun 08 nicklas 262     {
717 03 Jun 08 nicklas 263       Path dirPath = new Path(path, Path.Type.DIRECTORY);
717 03 Jun 08 nicklas 264       Directory dir = Directory.getByPath(dc, dirPath);
915 11 Dec 08 nicklas 265       fo = new BaseFtpFile(user, dir);
717 03 Jun 08 nicklas 266     }
717 03 Jun 08 nicklas 267     catch (Exception ex)
717 03 Jun 08 nicklas 268     {
717 03 Jun 08 nicklas 269       if (log.isDebugEnabled())
717 03 Jun 08 nicklas 270       {
717 03 Jun 08 nicklas 271         log.debug("Not a directory: " + path, ex);
717 03 Jun 08 nicklas 272       }
717 03 Jun 08 nicklas 273     }
717 03 Jun 08 nicklas 274     return fo;
717 03 Jun 08 nicklas 275   }
717 03 Jun 08 nicklas 276
717 03 Jun 08 nicklas 277   
717 03 Jun 08 nicklas 278   /**
714 30 May 08 nicklas 279     Concatenate two paths to create a full path. The concatenation makes
714 30 May 08 nicklas 280     sure that no '/' is missing or doubled. The path never ends with '/'
714 30 May 08 nicklas 281     unless it is the root directory.
714 30 May 08 nicklas 282   */
714 30 May 08 nicklas 283   private String append(String path1, String path2)
714 30 May 08 nicklas 284   {
714 30 May 08 nicklas 285     boolean atEnd = path1.endsWith("/");
714 30 May 08 nicklas 286     boolean atStart = path2.startsWith("/");
714 30 May 08 nicklas 287
714 30 May 08 nicklas 288     String result = null;
714 30 May 08 nicklas 289     if (atEnd && atStart)
714 30 May 08 nicklas 290     {
714 30 May 08 nicklas 291       result = path1 + path2.substring(1);
714 30 May 08 nicklas 292     }
714 30 May 08 nicklas 293     else if (atEnd || atStart)
714 30 May 08 nicklas 294     {
714 30 May 08 nicklas 295       result = path1 + path2;
714 30 May 08 nicklas 296     }
714 30 May 08 nicklas 297     else
714 30 May 08 nicklas 298     {
714 30 May 08 nicklas 299       result = path1 + "/" + path2;
714 30 May 08 nicklas 300     }
714 30 May 08 nicklas 301     
714 30 May 08 nicklas 302     if (result.endsWith("/") && result.length() > 1)
714 30 May 08 nicklas 303     {
714 30 May 08 nicklas 304       result = result.substring(0, result.length() - 1);
714 30 May 08 nicklas 305     }
716 02 Jun 08 nicklas 306     if (log.isDebugEnabled())
716 02 Jun 08 nicklas 307     {
716 02 Jun 08 nicklas 308       log.debug("append: path1=" + path1 + "; path2=" + path2 + "; result=" + result);
716 02 Jun 08 nicklas 309     }
714 30 May 08 nicklas 310     return result;
714 30 May 08 nicklas 311   }
714 30 May 08 nicklas 312   
714 30 May 08 nicklas 313 }