Changeset 716


Ignore:
Timestamp:
Jun 2, 2008, 2:29:02 PM (15 years ago)
Author:
Nicklas Nordborg
Message:

References #114: Implement FTP Server

Cleaned up code and documentation. Added lots of debugging/logging. Added license text to source files.

Location:
extensions/net.sf.basedb.ftp/trunk
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • extensions/net.sf.basedb.ftp/trunk/META-INF/extensions.xml

    r714 r716  
    11<?xml version="1.0" encoding="UTF-8" ?>
     2<!--
     3  $Id $
     4
     5  Copyright (C) 2008 Nicklas Nordborg
     6
     7  This file is part of FTP extension for BASE.
     8  Available at http://baseplugins.thep.lu.se/
     9
     10  BASE is free software; you can redistribute it and/or
     11  modify it under the terms of the GNU General Public License
     12  as published by the Free Software Foundation; either version 2
     13  of the License, or (at your option) any later version.
     14
     15  BASE is distributed in the hope that it will be useful,
     16  but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  GNU General Public License for more details.
     19
     20  You should have received a copy of the GNU General Public License
     21  along with this program; if not, write to the Free Software
     22  Foundation, Inc., 59 Temple Place - Suite 330,
     23  Boston, MA  02111-1307, USA.
     24-->
    225<extensions xmlns="http://base.thep.lu.se/extensions.xsd">
    326  <about>
  • extensions/net.sf.basedb.ftp/trunk/build.xml

    r714 r716  
    11<?xml version="1.0" encoding="UTF-8"?>
     2<!--
     3  $Id $
     4
     5  Copyright (C) 2008 Nicklas Nordborg
     6
     7  This file is part of FTP extension for BASE.
     8  Available at http://baseplugins.thep.lu.se/
     9
     10  BASE is free software; you can redistribute it and/or
     11  modify it under the terms of the GNU General Public License
     12  as published by the Free Software Foundation; either version 2
     13  of the License, or (at your option) any later version.
     14
     15  BASE is distributed in the hope that it will be useful,
     16  but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  GNU General Public License for more details.
     19
     20  You should have received a copy of the GNU General Public License
     21  along with this program; if not, write to the Free Software
     22  Foundation, Inc., 59 Temple Place - Suite 330,
     23  Boston, MA  02111-1307, USA.
     24-->
    225<project
    326  name="MevLauncher"
  • extensions/net.sf.basedb.ftp/trunk/ftp.config

    r714 r716  
     1# $Id $
     2#
     3# Copyright (C) 2008 Nicklas Nordborg
     4#
     5# This file is part of FTP extension for BASE.
     6# Available at http://baseplugins.thep.lu.se/
     7#
     8# BASE is free software; you can redistribute it and/or
     9# modify it under the terms of the GNU General Public License
     10# as published by the Free Software Foundation; either version 2
     11# of the License, or (at your option) any later version.
     12#
     13# BASE is distributed in the hope that it will be useful,
     14# but WITHOUT ANY WARRANTY; without even the implied warranty of
     15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16# GNU General Public License for more details.
     17#
     18# You should have received a copy of the GNU General Public License
     19# along with this program; if not, write to the Free Software
     20# Foundation, Inc., 59 Temple Place - Suite 330,
     21# Boston, MA  02111-1307, USA.
     22# -------------------------------------------------------------
    123# Licensed to the Apache Software Foundation (ASF) under one
    224# or more contributor license agreements.  See the NOTICE file
     
    5880
    5981##-----------------------------------------------------------------------------
     82## BASE User manager configuration
     83## Class name is hardcoded into the API and is displayed here just for reference
     84##-----------------------------------------------------------------------------
     85#config.user-manager.class=net.sf.basedb.clients.ftp.BaseUserManager
     86#config.user-manager.max-download-rate=0
     87#config.user-manager.max-upload-rate=0
     88
     89
     90##-----------------------------------------------------------------------------
    6091## Ftp message configuration block
    6192##-----------------------------------------------------------------------------
     
    71102config.connection-manager.max-login=10
    72103config.connection-manager.anonymous-login-enabled=false
    73 #config.connection-manager.max-anonymous-login=10
    74104config.connection-manager.default-idle-time=60
    75105config.connection-manager.timeout-poll-inverval=60
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/BaseFileObject.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    225
     
    1942import net.sf.basedb.core.query.Orders;
    2043
     44import org.apache.ftpserver.filesystem.NativeFileObject;
    2145import org.apache.ftpserver.ftplet.FileObject;
     46import org.slf4j.Logger;
     47import org.slf4j.LoggerFactory;
    2248
    2349/**
     
    2955    a directory (MKDIR) or file (STOR)
    3056  </ol>
     57  @author Nicklas
     58  @version 1.0
    3159*/
    3260public class BaseFileObject
    3361  implements FileObject
    3462{
     63  private static final Logger log = LoggerFactory.getLogger(BaseFileObject.class);
    3564
    3665  private BaseUser user;
     
    77106    this.name = path.substring(path.lastIndexOf('/')+1);
    78107    this.owner = user.getName();
    79    
    80108  }
    81109 
     
    147175
    148176  /**
    149     3 for directories, 1 for files (TODO - I don't understand why!)
     177    3 for directories, 1 for files (TODO - I don't understand why, but this is how
     178    the {@link NativeFileObject} object does it).
    150179  */
    151180  @Override
     
    171200
    172201  /**
    173     If it is a file, get it's last update time, if it is a
    174     directory, return the current time, otherwise, return 0.
     202    If it is a file, get it's last update time.
     203    If it is a directory, return the current time.
     204    Otherwise, return 0.
    175205  */
    176206  @Override
     
    243273  public FileObject[] listFiles()
    244274  {
     275    if (log.isDebugEnabled())
     276    {
     277      log.debug("List files");
     278      log.debug("   dir=" + this);
     279    }
    245280    if (directory == null) return null;
    246281   
     
    253288      dirQuery.order(Orders.asc(Hql.property("name")));
    254289      dirQuery.include(Include.ALL);
    255       dirQuery.exclude(Include.REMOVED);
    256290      for (Directory dir : dirQuery.list(dc))
    257291      {
     
    262296      fileQuery.order(Orders.asc(Hql.property("name")));
    263297      fileQuery.include(Include.ALL);
    264       fileQuery.exclude(Include.REMOVED);
    265298      for (File file : fileQuery.list(dc))
    266299      {
     
    268301      }
    269302    }
     303    catch (RuntimeException ex)
     304    {
     305      log.error("Could not list files in directory: " + this, ex);
     306      throw ex;
     307    }
    270308    finally
    271309    {
    272310      if (dc != null) dc.close();
     311    }
     312    if (log.isDebugEnabled())
     313    {
     314      log.debug("List files ok: size=" + all.size());
    273315    }
    274316    return all.toArray(new FileObject[all.size()]);
     
    282324  public boolean mkdir()
    283325  {
     326    if (log.isDebugEnabled())
     327    {
     328      log.debug("Make directory");
     329      log.debug("   dir=" + this);
     330    }
    284331    if (file != null || directory != null) return false;
    285332    if (!user.sc.hasPermission(Permission.CREATE, Item.DIRECTORY)) return false;
     
    292339      dc.commit();
    293340    }
     341    catch (RuntimeException ex)
     342    {
     343      log.error("Could not create directory: " + this, ex);
     344      throw ex;
     345    }
    294346    finally
    295347    {
    296348      if (dc != null) dc.close();
     349    }
     350    if (log.isDebugEnabled())
     351    {
     352      log.debug("Make directory ok: " + this);
    297353    }
    298354    return true;
     
    306362  public boolean delete()
    307363  {
     364    if (log.isDebugEnabled())
     365    {
     366      log.debug("Delete");
     367      log.debug("   file/dir=" + this);
     368    }
    308369    if (!hasDeletePermission()) return false;
    309370   
     
    322383      }
    323384      dc.commit();
     385      file = null;
     386      directory = null;
     387    }
     388    catch (RuntimeException ex)
     389    {
     390      log.error("Could not delete file/directory: " + this, ex);
     391      throw ex;
    324392    }
    325393    finally
     
    327395      if (dc != null) dc.close();
    328396    }
     397    if (log.isDebugEnabled())
     398    {
     399      log.debug("Delete ok: " + this);
     400    }
    329401    return true;
    330402  }
     
    336408  public boolean move(FileObject dest)
    337409  {
     410    if (log.isDebugEnabled())
     411    {
     412      log.debug("Move");
     413      log.debug("   this=" + this);
     414      log.debug("   dest=" + dest);
     415    }
    338416    if (!doesExist() || dest.doesExist()) return false;
    339417    DbControl dc = user.sc.newDbControl();
     
    341419    {
    342420      Directory newParentDir = null;
     421      // Do we need to change the parent directory?
     422      // If we don't have to we should not call File.setDirectory since it
     423      // may cause a PermissionDeniedException
    343424      if (!hasSameParentDirectory(this, dest))
    344425      {
     
    346427        newParentDir = Directory.getByPath(dc, to.getParent());
    347428      }
    348       System.out.println("new parent=" + newParentDir);
     429      if (log.isDebugEnabled())
     430      {
     431        log.debug("   new parent directory=" + newParentDir);
     432      }
    349433      if (file != null)
    350434      {
     
    361445      dc.commit();
    362446    }
     447    catch (RuntimeException ex)
     448    {
     449      log.error("Could not move: " + this + " --> " + dest, ex);
     450      throw ex;
     451    }
    363452    finally
    364453    {
    365454      if (dc != null) dc.close();
     455    }
     456    if (log.isDebugEnabled())
     457    {
     458      log.debug("Move ok: " + this + " --> " + dest);
    366459    }
    367460    return true;
     
    373466    throws IOException
    374467  {
     468    if (log.isDebugEnabled())
     469    {
     470      log.debug("Reading from file " + this + "[offset="+offset + "]");
     471    }
    375472    if (file == null)
    376473    {
     
    390487    throws IOException
    391488  {
     489    if (log.isDebugEnabled())
     490    {
     491      log.debug("Writing to file " + this + "[offset="+offset + "]");
     492    }
    392493    if (directory != null) return null;
    393494   
    394     System.out.println("Create output stream. offset="+offset);
    395495    OutputStream upload = null;
    396496    DbControl dc = user.sc.newDbControl();
     
    409509        offset = 0;
    410510      }
     511     
     512      if (log.isDebugEnabled())
     513      {
     514        log.debug("Uploading to BASE file: " + file);
     515      }
     516     
    411517      file.setMimeTypeAuto(null, null);
    412518      InputStream in = offset > 0 ? file.getDownloadStream(0) : null;
    413519     
    414520      // The TransactionOutputStream will make sure DbControl is committed
    415       upload = new TransactionalOutputStream(dc, file.getUploadStream(false));
     521      upload = new TransactionalOutputStream(dc, file.getUploadStream(false), toString());
    416522      if (in != null)
    417523      {
    418         while (offset > 0)
     524        long remain = offset;
     525        while (remain > 0)
    419526        {
    420527          int b = in.read();
    421           if (b != -1) upload.write(b);
    422           offset--;
     528          if (b == -1) break;
     529          upload.write(b);
     530          remain--;
    423531        }
    424532        in.close();
     533        log.debug((offset - remain) + " bytes copied from existing file");
    425534      }
    426535      dc.disconnect();
     
    428537    catch (RuntimeException ex)
    429538    {
     539      log.error("Could not create upload stream to " + this, ex);
    430540      if (dc != null) dc.close();
    431541      throw ex;
     
    434544  }
    435545  // -------------------------------------------
     546 
     547  /*
     548    From the Object class
     549    ---------------------
     550  */
     551  @Override
     552  public String toString()
     553  {
     554    String type = "path";
     555    if (file != null)
     556    {
     557      type = "file";
     558    }
     559    else if (directory != null)
     560    {
     561      type = "dir";
     562    }
     563    return "BaseFileObject[" + type + "=" + path + "]";
     564  }
     565  // -------------------------------------------
     566 
    436567 
    437568  private String getOwner(OwnedItem item)
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/BaseFileSystem.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    225
     
    831/**
    932  Implements the file system manager for BASE.
     33  @author Nicklas
     34  @version 1.0
    1035*/
    1136public class BaseFileSystem
     
    1338{
    1439
     40  /**
     41    Creates the file system manager.
     42  */
     43  public BaseFileSystem()
     44  {}
     45 
     46  /*
     47    From the FileSystemManager interface
     48    ------------------------------------
     49  */
    1550  @Override
    1651  public FileSystemView createFileSystemView(User user)
     
    1954    return new BaseFileSystemView((BaseUser)user);
    2055  }
     56  // ---------------------------------------
    2157
    2258}
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/BaseFileSystemView.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    225
     
    932import org.apache.ftpserver.ftplet.FileSystemView;
    1033import org.apache.ftpserver.ftplet.FtpException;
     34import org.slf4j.Logger;
     35import org.slf4j.LoggerFactory;
    1136
    1237/**
     
    1439  Users will start out in their home directory if they have one, otherwise in
    1540  the root.
     41 
     42  @author Nicklas
     43  @version 1.0
    1644*/
    1745public class BaseFileSystemView
     
    1947{
    2048
     49  private static final Logger log = LoggerFactory.getLogger(BaseFileSystemView.class);
     50
    2151  private BaseUser user;
    22  
    2352  private BaseFileObject currentDir;
    2453 
     54  /**
     55    Create a new file system view for the specified user.
     56  */
    2557  public BaseFileSystemView(BaseUser user)
    2658  {
     
    3870    throws FtpException
    3971  {
    40     System.out.println("gcd: current=" + currentDir.getFullName());
     72    if (log.isDebugEnabled()) log.debug("Current directory: " + currentDir);
    4173    return currentDir;
    4274  }
     
    5688    throws FtpException
    5789  {
    58     System.out.println("cd: " + path);
     90    if (log.isDebugEnabled())
     91    {
     92      log.debug("Change directory");
     93      log.debug("   path=" + path);
     94      log.debug("   current="+currentDir);
     95      log.debug("   user=" + user);
     96    }
    5997    Path changeTo = null;
    6098    if (path.startsWith("/"))
     
    73111      changeTo = new Path(append(currentDir.getFullName(), path), Path.Type.DIRECTORY);
    74112    }
     113    if (log.isDebugEnabled())
     114    {
     115      log.debug("   to="+changeTo);
     116    }
    75117    DbControl dc = user.sc.newDbControl();
    76118    try
    77119    {
    78120      currentDir = new BaseFileObject(user, Directory.getByPath(dc, changeTo));
     121      log.debug("Directory changed to: " + currentDir);
    79122      return true;
    80123    }
    81124    catch (RuntimeException ex)
    82125    {
    83       ex.printStackTrace();
     126      log.error("Could not change to directory: " + path, ex);
    84127      return false;
    85128    }
     
    126169    throws FtpException
    127170  {
    128     System.out.println("gfo: " + fileName);
     171    if (log.isDebugEnabled())
     172    {
     173      log.debug("Get file object");
     174      log.debug("   name=" + fileName);
     175      log.debug("   current="+currentDir);
     176      log.debug("   user=" + user);
     177    }
    129178    if (fileName.startsWith("./"))
    130179    {
     
    137186   
    138187    BaseFileObject fo = null;
    139    
    140188    DbControl dc = user.sc.newDbControl();
    141189    try
    142190    {
    143       // Try to get a file
     191      if (log.isDebugEnabled())
     192      {
     193        log.debug("   full path=" + fileName);
     194      }
     195     
     196      // Check if the path represents a file
    144197      try
    145198      {
     
    149202      }
    150203      catch (Exception ex)
    151       {}
     204      {
     205        if (log.isDebugEnabled())
     206        {
     207          log.debug("Not a file: " + fileName, ex);
     208        }
     209      }
    152210
    153211      if (fo == null)
    154212      {
    155         // Try to get a directory
     213        // Check if the path represents a directory
    156214        try
    157215        {
     
    161219        }
    162220        catch (Exception ex)
    163         {}
     221        {
     222          if (log.isDebugEnabled())
     223          {
     224            log.debug("Not a directory: " + fileName, ex);
     225          }
     226        }
    164227      }
    165228    }
     
    169232    }
    170233    if (fo == null) fo = new BaseFileObject(user, fileName);
     234    if (log.isDebugEnabled())
     235    {
     236      log.debug("Get file object: " + fo);
     237    }
    171238    return fo;
    172239  }
     240
     241  @Override
     242  public FileObject getHomeDirectory()
     243    throws FtpException
     244  {
     245    return user.getHome();
     246  }
    173247  // ----------------------------------------
    174 
    175   @Override
    176   public FileObject getHomeDirectory()
    177     throws FtpException
    178   {
    179     return user.getHome();
    180   }
    181248
    182249  /**
     
    187254  private String append(String path1, String path2)
    188255  {
    189     System.out.println("append: p1=" + path1 + "; p2=" + path2);
    190256    boolean atEnd = path1.endsWith("/");
    191257    boolean atStart = path2.startsWith("/");
     
    209275      result = result.substring(0, result.length() - 1);
    210276    }
    211     System.out.println("append: " + result);
     277    if (log.isDebugEnabled())
     278    {
     279      log.debug("append: path1=" + path1 + "; path2=" + path2 + "; result=" + result);
     280    }
    212281    return result;
    213282  }
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/BaseFtpServer.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    225
    326import java.util.EnumSet;
     27import java.util.Iterator;
    428import java.util.Properties;
    529
     
    832import org.apache.ftpserver.config.PropertiesConfiguration;
    933import org.apache.ftpserver.ftplet.Configuration;
     34import org.apache.ftpserver.ftplet.FtpException;
    1035import org.apache.ftpserver.ftplet.Ftplet;
    1136import org.apache.ftpserver.interfaces.FtpServerContext;
     37import org.slf4j.Logger;
     38import org.slf4j.LoggerFactory;
    1239
    1340import net.sf.basedb.core.Application;
     
    2249import net.sf.basedb.core.SystemItems;
    2350
     51/**
     52  The main FTP Server class for BASE. It encapsulates the
     53  {@link FtpServer} from Apache, and forces some BASE-specific
     54  configuration settings. Eg.
     55
     56  <ul>
     57  <li>User manager: {@link BaseUserManager}
     58  <li>File system manager: {@link BaseFileSystem}
     59  <li>Ftplet: {@link BaseFtplet}
     60  <li>Anonymous login is disabled
     61  </ul>
     62 
     63  This class also has some utility method for checking if the
     64  <code>net.sf.basedb.clients.ftp</code> {@link Client} has been
     65  registered in BASE. If not, only the root user is allowed to connect,
     66  but once the root user does that, the ftp client is automatically
     67  registereded and made available to everyone.
     68 
     69  @author Nicklas
     70  @version 1.0
     71*/
    2472public class BaseFtpServer
    2573{
    2674
     75  private static final Logger log = LoggerFactory.getLogger(BaseFtpServer.class);
     76 
     77  /**
     78    The {@link Client#getExternalId()} for FTP server.
     79  */
    2780  public static final String CLIENT_ID = "net.sf.basedb.clients.ftp";
    28  
    29   public static BaseFtpServer DEFAULT;
    3081 
    3182  /**
     
    3485    @return TRUE if the FTP server is registered, FALSE otherwise
    3586  */
    36   public static boolean isClientInstalled()
     87  public static boolean isRegisteredAsClient()
    3788  {
    3889    boolean installed = false;
     
    4495    }
    4596    catch (ItemNotFoundException ex)
    46     {}
     97    {
     98      log.info("FTP Server is not registered as BASE client application", ex);
     99    }
    47100    return installed;
    48101  }
    49102 
    50   public static void installClient(SessionControl sc)
     103  /**
     104    Register the FTP server as a client application in BASE. The
     105    application will be shared to {@link Group#EVERYONE}.
     106    @param sc The session control of a logged in user which must have
     107      permissions to create a {@link Client} item
     108  */
     109  public static void registerAsClient(SessionControl sc)
    51110  {
    52111    Client client = null;
     
    55114    {
    56115      client = Client.getByExternalId(dc, CLIENT_ID);
     116      log.info("FTP Server is already registered as BASE client application");
    57117    }
    58118    catch (ItemNotFoundException ex)
    59119    {
     120      log.info("Registering FTP Server as BASE client application with ID:" + CLIENT_ID);
    60121      Group everyone = Group.getById(dc, SystemItems.getId(Group.EVERYONE));
    61122      GroupPermissions gp = new GroupPermissions();
     
    69130      dc.saveItem(client);
    70131      dc.commit();
     132      log.info("FTP Server successfully registered as BASE client application");
    71133    }
    72134    finally
     
    79141  private FtpServer server;
    80142 
     143  /**
     144    Create a new FTP Server. The configuration properties will be copied and
     145    BASE-specific settings as described in the class documentation will be
     146    added. To start the FTP server call {@link #start()}.
     147   
     148    @param config The configuration settings
     149    @throws Exception If there is any problem
     150  */
    81151  public BaseFtpServer(Properties config)
    82152    throws Exception
    83153  {
    84154    this.config = setPropertiesRequiredByBase(config);
    85     start();
    86   }
    87  
    88   private Configuration setPropertiesRequiredByBase(Properties config)
    89   {
    90     Properties cfg = (Properties)config.clone();
    91     cfg.setProperty("config.create-default-user", "false");
    92     cfg.setProperty("config.user-manager.class", "net.sf.basedb.clients.ftp.BaseUserManager");
    93     cfg.setProperty("config.file-system-manager.class", "net.sf.basedb.clients.ftp.BaseFileSystem");
    94     return new PropertiesConfiguration(cfg);
    95   }
    96  
     155  }
     156
     157  /**
     158    Checks if the FTP Server is running.
     159  */
    97160  public boolean isRunning()
    98161  {
    99162    return server != null && !server.isStopped() && !server.isSuspended();
    100163  }
    101  
     164
     165  /**
     166    Starts the FTP server if it is not already running.
     167  */
    102168  public void start()
    103169  {
    104170    if (isRunning()) return;
     171    log.info("Starting BASE FTP Server");
     172    if (log.isDebugEnabled())
     173    {
     174      Iterator<String> keys = config.getKeys();
     175      while (keys.hasNext())
     176      {
     177        String key = keys.next();
     178        try
     179        {
     180          log.debug(key + "=" + config.getString(key));
     181        }
     182        catch (FtpException ex)
     183        {} // Should never happen
     184      }
     185    }
    105186    try
    106187    {
     
    114195    catch (Exception ex)
    115196    {
     197      log.error("Could not start FTP Server", ex);
    116198      throw new RuntimeException(ex);
    117199    }
    118   }
    119  
     200    log.info("BASE FTP Server has been started");
     201  }
     202 
     203  /**
     204    Stop the FTP server.
     205  */
    120206  public void stop()
    121207  {
    122     if (!isRunning()) return;
    123     server.stop();
    124     server = null;
    125   }
     208    log.info("Stopping BASE FTP Server");
     209    if (server != null)
     210    {
     211      server.stop();
     212      server = null;
     213    }
     214    log.info("BASE FTP Server has been stopped");
     215  }
     216
     217  /**
     218    Makes a copy of the properties and set BASE-specific ones. Returned
     219    as a {@link Configuration} object.
     220  */
     221  private Configuration setPropertiesRequiredByBase(Properties config)
     222  {
     223    Properties cfg = (Properties)config.clone();
     224    cfg.setProperty("config.create-default-user", "false");
     225    cfg.setProperty("config.connection-manager.anonymous-login-enabled", "false");
     226    cfg.setProperty("config.user-manager.class", "net.sf.basedb.clients.ftp.BaseUserManager");
     227    cfg.setProperty("config.file-system-manager.class", "net.sf.basedb.clients.ftp.BaseFileSystem");
     228    if (log.isDebugEnabled())
     229    {
     230      log.debug("Creating new FTP Server configuration");
     231      for (Object key : cfg.keySet())
     232      {
     233        log.debug(key + "=" + cfg.getProperty(key.toString()));
     234      }
     235    }
     236    return new PropertiesConfiguration(cfg);
     237  }
     238 
    126239 
    127240}
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/BaseFtplet.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    225
     
    629import org.apache.ftpserver.ftplet.FtpException;
    730import org.apache.ftpserver.ftplet.FtpSession;
     31import org.apache.ftpserver.ftplet.Ftplet;
    832import org.apache.ftpserver.ftplet.FtpletEnum;
    933import org.apache.ftpserver.ftplet.User;
    10 
     34import org.slf4j.Logger;
     35import org.slf4j.LoggerFactory;
    1136
    1237/**
    1338  We need this ftplet to catch disconnection events and logout the
    14   logged in user from BASE.
    15   @see {@link #onDisconnect(FtpSession)}
     39  logged in user from BASE. We extend the {@link DefaultFtplet}
     40  which is just an empty implementation so we don't have to implement
     41  all methods in the {@link Ftplet} interface.
     42 
     43  @author Nicklas
     44  @version 1.0
    1645*/
    1746public class BaseFtplet
     
    1948{
    2049
     50  private static final Logger log = LoggerFactory.getLogger(BaseFtplet.class);
     51
    2152  public BaseFtplet()
    2253  {}
    2354
     55  /*
     56    From the Ftplet interface
     57    -------------------------
     58  */
    2459  /**
    2560    If a BASE user is currently logged in, log out.
     
    2964    throws FtpException, IOException
    3065  {
    31     System.out.println("onDisconnect: " + session);
     66    log.debug("Disconnecting: ip=" + session.getClientAddress());
    3267    User user = session.getUser();
    33     System.out.println("onDisconnect: " + user);
     68    log.debug("Disconnecting: user=" + user);
    3469    if (user instanceof BaseUser)
    3570    {
     
    3873    return super.onDisconnect(session);
    3974  }
     75
     76  /**
     77    We just log connections at DEBUG level.
     78  */
     79  @Override
     80  public FtpletEnum onConnect(FtpSession session)
     81    throws FtpException, IOException
     82  {
     83    if (log.isDebugEnabled())
     84    {
     85      log.debug("New connection from: " + session.getClientAddress());
     86      log.debug("Server address: " + session.getServerAddress() + ":" + session.getServerPort());
     87    }
     88    return super.onConnect(session);
     89  }
     90  // -------------------------------------
     91 
    4092 
    4193}
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/BaseUser.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    225
     
    629import org.apache.ftpserver.ftplet.Authority;
    730import org.apache.ftpserver.ftplet.AuthorizationRequest;
     31import org.slf4j.Logger;
     32import org.slf4j.LoggerFactory;
    833
    934import net.sf.basedb.core.Application;
     
    1944  a user that has not yet logged in, so we don't
    2045  know if the user exists or not.
     46  @author Nicklas
     47  @version 1.0
    2148*/
    2249public class BaseUser
     
    2451{
    2552
     53  private static final Logger log = LoggerFactory.getLogger(BaseUser.class);
     54
    2655  private final String login;
    2756  private final Authority[] authorities;
     
    3160  private BaseFileObject home;
    3261 
     62  /**
     63    Creates a new, not yet logged in, user object.
     64   
     65    @param login The login of the user
     66    @param authorities The permissions of the user
     67  */
    3368  public BaseUser(String login, Authority[] authorities)
    3469  {
     
    85120  }
    86121 
     122  /**
     123    Checks if the permissions for a user contains the requested
     124    permission. This method returns the <code>request</code>
     125    parameter if there is at least one permission that can
     126    authorize the request ({@link Authority#canAuthorize(AuthorizationRequest)}
     127    and all that can must accept it ({@link Authority#authorize(AuthorizationRequest)}).
     128    <p>
     129    If there is no permission that accepts the request, null is
     130    returned.
     131  */
    87132  @Override
    88133  public AuthorizationRequest authorize(AuthorizationRequest request)
    89134  {
    90     System.out.println("authorize(): login=" +login + "; request=" + request);
     135    boolean debug = log.isDebugEnabled();
     136    if (debug)
     137    {
     138      log.debug("Trying to authorize: login=" + login + "; request="+request);
     139    }
    91140    boolean authorized = false;
    92141    /*
     
    100149      if (auth.canAuthorize(request))
    101150      {
    102         if (auth.authorize(request) == null) return null;
     151        if (debug) log.debug("Can authorize: auth=" + auth);
     152        if (auth.authorize(request) == null)
     153        {
     154          if (debug) log.debug("Permission denied: auth=" + auth + "; request=" + request);
     155          return null;
     156        }
     157        if (debug) log.debug("Accepted: auth=" + auth + "; request=" + request);
    103158        authorized = true;
    104159      }
     160      else
     161      {
     162        if (debug) log.debug("Can't authorize: auth=" + auth);
     163      }
     164    }
     165    if (debug)
     166    {
     167      log.debug(authorized ? "Accepted: " + request : "Permission denied: " + request);
    105168    }
    106169    return authorized ? request : null;
     
    113176  }
    114177
    115   /**
    116     For now, return an empty array. It seems like this method is never
    117     called from the FTP server core.
    118   */
    119178  @Override
    120179  public Authority[] getAuthorities(Class<Authority> clazz)
     
    132191  // ------------------------
    133192 
     193  /*
     194    From the Object class
     195    ---------------------
     196  */
     197  @Override
     198  public String toString()
     199  {
     200    return "BaseUser[login=" + login + "]";
     201  }
     202  // ------------------------
     203 
     204 
    134205  /**
    135206    Check if this object represents a logged in user
     
    149220  {
    150221    if (isLoggedIn()) return;
    151     System.out.println("login: " + login);
     222    log.info("Trying to login: " + login + "; ip="+remoteId);
     223    log.debug("Password:" + password);
    152224    SessionControl sc = Application.newSessionControl(clientId, remoteId, null);
    153225    sc.login(login, password, null, false);
    154     System.out.println("login: ID=" + sc.getId());
     226    log.debug("Login ok, loading user info and home directory. SessionID=" + sc.getId());
    155227   
    156228    // Login was ok
     
    158230    if (clientId == null && sc.getLoggedInUserId() != SystemItems.getId(User.ROOT))
    159231    {
     232      log.warn("FTP Server not registered, only ROOT is allowed to login");
    160233      throw new PermissionDeniedException("Only root is allowed to login");
    161234    }
     
    174247      this.home = new BaseFileObject(this, homeDir);
    175248    }
     249    catch (RuntimeException ex)
     250    {
     251      log.error("Failed to load user info and home directory: login=" + login, ex);
     252      throw ex;
     253    }
    176254    finally
    177255    {
    178256      if (dc != null) dc.close();
    179257    }
    180   }
    181  
    182   /**
    183     Logout and close the
    184    */
     258    log.debug("Login complete: login="+login);
     259  }
     260 
     261  /**
     262    Logout and close the session.
     263  */
    185264  public void logout()
    186265  {
    187266    if (sc != null)
    188267    {
    189       System.out.println("logout: ID=" + sc.getId());
     268      log.info("Logging out: login=" + login + "; SessionID=" + sc.getId());
    190269      sc.logout();
    191270      sc.close();
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/BaseUserManager.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    2 
    325
    426import org.apache.ftpserver.ftplet.Authentication;
     
    1335import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication;
    1436import org.apache.ftpserver.usermanager.WritePermission;
    15 
     37import org.slf4j.Logger;
     38import org.slf4j.LoggerFactory;
     39
     40/**
     41  A user manager implementation for hooking into BASE. This is a read-only
     42  user manager, and all methods that makes modifications will throw an
     43  {@link UnsupportedOperationException}. A lot of the other methods are
     44  also hampered, eg {@link #doesExist(String), {@link #getAllUserNames()}, etc.,
     45  since before we can get information out from BASE a user must be logged in.
     46  <p>
     47 
     48  The only method that really does what it is intended to is the
     49  {@link #authenticate(Authentication)} method. This is probably no harm
     50  since this is the only method are really interested in.
     51  <p>
     52 
     53  As long as the BASE FTP Server hasn't been registered as a client
     54  application with BASE, only the root user is allowed to login. Once
     55  the root user does that, the
     56  {@link BaseFtpServer#registerAsClient(net.sf.basedb.core.SessionControl)}
     57  is called to register the FTP Server. After that everybody can use the FTP
     58  Server.
     59 
     60  @author Nicklas
     61  @version 1.0
     62*/
    1663public class BaseUserManager
    1764  implements UserManager
    1865{
     66  private static final Logger log = LoggerFactory.getLogger(BaseUserManager.class);
    1967
    2068  private boolean ftpClientIsInstalled;
    21 
     69 
     70  private int maxUploadRate = 0;
     71  private int maxDownloadRate = 0;
     72
     73  /**
     74    Creates a new user manager for BASE.
     75  */
    2276  public BaseUserManager()
    2377  {
    24     this.ftpClientIsInstalled = BaseFtpServer.isClientInstalled();
     78    this.ftpClientIsInstalled = BaseFtpServer.isRegisteredAsClient();
    2579  }
    2680 
     
    119173        String ip = auth.getUserMetadata().getInetAddress().getHostAddress();
    120174       
     175        log.info("Trying to authenticate: login=" + login);
     176        log.debug("password=" + pwd);
     177        log.debug("ip=" + ip);
     178       
    121179        user = getBaseUser(login);
    122180        try
    123181        {
    124182          user.login(pwd, ip, ftpClientIsInstalled ? BaseFtpServer.CLIENT_ID : null);
    125           if (!ftpClientIsInstalled)
    126           {
    127             BaseFtpServer.installClient(user.sc);
    128             ftpClientIsInstalled = true;
    129           }
     183          log.info("Login successful: login=" + login);
    130184        }
    131185        catch (Exception ex)
    132186        {
    133           ex.printStackTrace();
     187          log.warn("Login failed: login="+login, ex);
    134188          throw new AuthenticationFailedException(ex.getMessage(), ex);
    135189        }
     190      if (!ftpClientIsInstalled)
     191      {
     192        log.info("Registering BASE FTP Server");
     193        try
     194        {
     195          BaseFtpServer.registerAsClient(user.sc);
     196          ftpClientIsInstalled = true;
     197        }
     198        catch (Exception ex)
     199        {
     200          log.warn("Could not register FTP Server", ex);
     201        }
     202      }
    136203        }
    137204        else if (authentication instanceof AnonymousAuthentication)
    138205        {
    139           throw new AuthenticationFailedException("Anonymous login is not allowed.");
     206          String msg = "Anonymous login is not allowed.";
     207          log.warn(msg);
     208          throw new AuthenticationFailedException(msg);
    140209        }
    141210        else
    142211        {
    143             throw new IllegalArgumentException("Unsupported authentication method: " + authentication);
     212          String msg = "Unsupported authentication method: " + authentication;
     213          log.warn(msg);
     214            throw new IllegalArgumentException(msg);
    144215        }
    145216    return user;
     
    147218  // -------------------------------
    148219 
     220  /**
     221    Get the current maximum transfer rate for uploads.
     222    @return The transfer rate in bytes/second, or 0 if unlimited
     223  */
     224  public int getMaxUploadRate()
     225  {
     226    return maxUploadRate;
     227  }
     228 
     229  /**
     230    Set the maximum transfer rate for uploads. This will only affect
     231    new users.
     232    @param uploadRate The transfer rate in bytes/second, or 0 if unlimited
     233  */
     234  public void setMaxUploadRate(int uploadRate)
     235  {
     236    this.maxUploadRate = uploadRate;
     237  }
     238 
     239  /**
     240    Get the current maximum transfer rate for downloads.
     241    @return The transfer rate in bytes/second, or 0 if unlimited
     242  */
     243  public int getMaxDownloadRate()
     244  {
     245    return maxDownloadRate;
     246  }
     247 
     248  /**
     249    Set the maximum transfer rate for downloads. This will only affect
     250    new users.
     251    @param downloadRate The transfer rate in bytes/second, or 0 if unlimited
     252  */
     253  public void setMaxDownloadRate(int downloadRate)
     254  {
     255    this.maxDownloadRate = downloadRate;
     256  }
     257 
     258  /**
     259    Set the maximum transfer rate for uploads and downloads.
     260    This will only affect new users.
     261    @param transferRate The transfer rate in bytes/second, or 0 if unlimited
     262  */
     263  public void setTransferRate(int transferRate)
     264  {
     265    this.maxDownloadRate = transferRate;
     266    this.maxUploadRate = transferRate;
     267  }
     268
    149269  private BaseUser getBaseUser(String login)
    150270  {
     271    if (log.isDebugEnabled())
     272    {
     273      log.debug("Creating new user: login=" + login);
     274      log.debug("Transfer rate: upload=" + maxUploadRate + "; download=" + maxDownloadRate);
     275    }
    151276    Authority[] auth = new Authority[3];
    152277    auth[0] = new ConcurrentLoginPermission(0, 0);
    153278    auth[1] = new WritePermission();
    154     auth[2] = new TransferRatePermission(0, 0);
     279    auth[2] = new TransferRatePermission(maxDownloadRate, maxUploadRate);
    155280    BaseUser u = new BaseUser(login, auth);   
    156281    return u;
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/FtpServiceController.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    225
    326import net.sf.basedb.clients.web.extensions.service.ServiceControllerAction;
    427
     28/**
     29  Action for hooking into the BASE extensions system. This action
     30  is used to control a single {@link BaseFtpServer} instance, which
     31  should already exist. Actions are created by
     32  {@link FtpServiceControllerFactory}.
     33 
     34  @author Nicklas
     35  @version 1.0
     36  @see FtpServiceControllerFactory
     37*/
    538public class FtpServiceController
    639  implements ServiceControllerAction
     
    942  private final BaseFtpServer server;
    1043 
     44  /**
     45    Creates a new service controller action for controlling
     46    a single ftp server service
     47    @param server The server to control with this action
     48  */
    1149  public FtpServiceController(BaseFtpServer server)
    1250  {
     
    1452  }
    1553 
     54  /*
     55    From the ServiceControllerAction interface
     56    -------------------------------------------
     57  */
    1658  @Override
    1759  public boolean isRunning()
     
    3173    server.stop();
    3274  }
     75  // ----------------------------------------------
     76
     77  /*
     78    From the Object class
     79    ---------------------
     80  */
     81  @Override
     82  public String toString()
     83  {
     84    return "BASE FTP Server";
     85  }
     86  // ----------------------------------------------
     87 
     88 
    3389
    3490}
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/FtpServiceControllerFactory.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    225
     
    528import java.util.Properties;
    629
     30import org.slf4j.Logger;
     31import org.slf4j.LoggerFactory;
     32
    733import net.sf.basedb.clients.web.extensions.service.ServiceControllerAction;
    8 import net.sf.basedb.core.Config;
    934import net.sf.basedb.core.ConfigurationException;
    1035import net.sf.basedb.util.extensions.ActionFactory;
    1136import net.sf.basedb.util.extensions.InvokationContext;
    1237
     38/**
     39  An action factory for creating {@link FtpServiceController} actions.
     40  A single factory is tied to a single {@link BaseFtpServer}, which is
     41  created lazily when it is first needed. This usually happens when
     42  the {@link #getActions(InvokationContext)} method is called.
     43  <p>
     44  The action factory accepts the following parameters:
     45  <ul>
     46  <li>{@link #setConfig(String)}: The path to the configuration file. The
     47    default is: <code>/ftp.config</code>
     48  </ul>
     49 
     50  @author Nicklas
     51  @version 1.0
     52*/
    1353public class FtpServiceControllerFactory
    1454  implements ActionFactory<ServiceControllerAction>
    1555{
     56  private static final Logger log = LoggerFactory.getLogger(FtpServiceControllerFactory.class);
    1657
    17   private FtpServiceController controller;
     58  private FtpServiceController[] controller;
    1859  private BaseFtpServer server;
     60  private String config;
    1961 
     62  /**
     63    Creates a new factory instance.
     64  */
    2065  public FtpServiceControllerFactory()
    2166  {}
    2267 
     68  /*
     69    From the ActionFactory interface
     70    -------------------------------------------
     71  */
    2372  @Override
    2473  public ServiceControllerAction[] getActions(InvokationContext context)
    2574  {
    26     return new ServiceControllerAction[] { getController() };
     75    return getController();
    2776  }
    2877
     78  /**
     79    Always TRUE.
     80  */
    2981  @Override
    3082  public boolean prepareContext(InvokationContext context)
     
    3284    return true;
    3385  }
     86  // -----------------------------------------------
    3487
    35   private FtpServiceController getController()
     88  /**
     89    Set the path to the configuration file to use. The path
     90    should be a path on the CLASSPATH.
     91    @param config The path, or null to use the default path (/ftp.config)
     92  */
     93  public void setConfig(String config)
     94  {
     95    this.config = config;
     96  }
     97
     98  private FtpServiceController[] getController()
    3699  {
    37100    if (controller == null)
    38101    {
    39       controller = new FtpServiceController(getServer());
     102      controller = new FtpServiceController[1];
     103      controller[0] = new FtpServiceController(getServer());
    40104    }
    41105    return controller;
    42106  }
    43107 
     108  /**
     109    Get or create the {@link BaseFtpServer}. A factory can only be associated
     110    with a single ftp server.
     111  */
    44112  private BaseFtpServer getServer()
    45113  {
    46114    if (server == null)
    47115    {
     116      log.info("Creating BASE FTP Server");
    48117      try
    49118      {
    50         URL configUrl = Config.class.getResource("/ftp.config");
     119        if (config == null) config = "/ftp.config";
     120        log.debug("config=" + config);
     121        URL configUrl = BaseFtpServer.class.getResource(config);
    51122        InputStream is = configUrl == null ? null : configUrl.openStream();
    52123        if (is == null)
    53124        {
    54           throw new ConfigurationException("Can't find the properties file. Make sure '/ftp.config' is in the CLASSPATH.");
     125          throw new ConfigurationException("Can't find the properties file. " +
     126              "Make sure '" + config + "' is in the CLASSPATH.");
    55127        }
    56128        Properties config = new Properties();
     
    58130        is.close();
    59131        server = new BaseFtpServer(config);
     132        log.info("BASE FTP Server created successfully");
    60133      }
    61134      catch (RuntimeException ex)
    62135      {
     136        log.error("Could not create BASE FTP Server", ex);
    63137        throw ex;
    64138      }
    65139      catch (Exception ex)
    66140      {
     141        log.error("Could not create BASE FTP Server", ex);
    67142        throw new RuntimeException(ex);
    68143      }
     
    71146  }
    72147 
     148
    73149}
  • extensions/net.sf.basedb.ftp/trunk/src/net/sf/basedb/clients/ftp/TransactionalOutputStream.java

    r714 r716  
     1/**
     2  $Id $
     3
     4  Copyright (C) 2008 Nicklas Nordborg
     5
     6  This file is part of FTP extension for BASE.
     7  Available at http://baseplugins.thep.lu.se/
     8
     9  BASE is free software; you can redistribute it and/or
     10  modify it under the terms of the GNU General Public License
     11  as published by the Free Software Foundation; either version 2
     12  of the License, or (at your option) any later version.
     13
     14  BASE is distributed in the hope that it will be useful,
     15  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  GNU General Public License for more details.
     18
     19  You should have received a copy of the GNU General Public License
     20  along with this program; if not, write to the Free Software
     21  Foundation, Inc., 59 Temple Place - Suite 330,
     22  Boston, MA  02111-1307, USA.
     23*/
    124package net.sf.basedb.clients.ftp;
    225
     
    528import java.io.OutputStream;
    629
     30import org.slf4j.Logger;
     31import org.slf4j.LoggerFactory;
     32
    733import net.sf.basedb.core.DbControl;
    834
     35/**
     36  An output stream implementation that has a {@link DbControl} attached
     37  to it. When the stream is {@link #close()}:ed the DbControl will be
     38  {@link DbControl#commit()}:ed. If the stream is never closed, the finalize
     39  method will rollback the transaction.
     40 
     41  @author Nicklas
     42  @version 1.0
     43*/
    944public class TransactionalOutputStream
    1045  extends FilterOutputStream
    1146{
    1247
    13   private final DbControl dc;
     48  private static final Logger log = LoggerFactory.getLogger(TransactionalOutputStream.class);
     49  private DbControl dc;
     50  private final String filename;
    1451 
    15   public TransactionalOutputStream(DbControl dc, OutputStream out)
     52  /**
     53    Create a new stream.
     54    @param dc The DbControl which should be committed when
     55      the stream is closed
     56    @param out The stream to write to
     57  */
     58  public TransactionalOutputStream(DbControl dc, OutputStream out, String filename)
    1659  {
    1760    super(out);
    1861    this.dc = dc;
     62    this.filename = filename;
    1963  }
    2064 
     65  /*
     66    From the OutputStream class
     67    ---------------------------
     68  */
    2169  @Override
    2270  public void close()
    2371    throws IOException
    2472  {
     73    log.debug("Closing upload to: " + filename);
    2574    super.close();
    26     dc.reconnect();
     75    if (!dc.isConnected()) dc.reconnect();
    2776    dc.commit();
     77    dc = null;
    2878  }
     79  // ------------------------------
     80
     81  /*
     82    From the Object class
     83    ---------------------------
     84  */
     85  /**
     86    Make sure the DbControl is closed.
     87  */
     88  @Override
     89  protected void finalize()
     90    throws Throwable
     91  {
     92    if (dc != null) dc.close();
     93    super.finalize();
     94  }
     95  // ------------------------------
    2996 
    3097}
Note: See TracChangeset for help on using the changeset viewer.