Changeset 5607


Ignore:
Timestamp:
Apr 15, 2011, 9:52:28 AM (12 years ago)
Author:
Nicklas Nordborg
Message:

References #1593: Extension system for the core API

References #1592: Unified installation procedure for plug-ins, extensions and more...

Added tags for min/max BASE version that an extension is working with. Switched to use numbers instead of strings in version information and added an extra suffix "-dev" used for development versions.

Also fixes problems with error handling in the startup of the extensions system and problems with re-scanning updated extensions that had an error before or got an error after the update.

Location:
trunk
Files:
1 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/build.xml

    r5591 r5607  
    6060  <!-- set BASE version
    6161    Use numerical versions for bugfix (maintenance) releases starting
    62     with "1". Use "0" for the first release of a new trunk version.  Add
    63     "pre" to unreleased versions.  Examples: 2.1.1pre, 2.1.1,
    64     2.1.2pre, 2.2.2, 2.2.0pre, 2.2.0, 2.2.1pre, 2.2.1
     62    with "1". Use "0" for the first release of a new trunk version.  Set
     63    "base.versionsuffix" to "-dev" for unreleased versions. Examples: 2.1.1-dev, 2.1.1,
     64    2.1.2-dev, 2.2.2, 2.2.0-dev, 2.2.0, 2.2.1-dev, 2.2.1
    6565  -->
    6666  <property name="base.majorversion" value="3" />
    6767  <property name="base.minorversion" value="0" />
    68   <property name="base.maintenanceversion" value="0pre" />
     68  <property name="base.maintenanceversion" value="0" />
     69  <property name="base.versionsuffix" value="-dev" />
    6970  <property name="base.version"
    7071    value="${base.majorversion}.${base.minorversion}.${base.maintenanceversion}" />
     
    493494        token="@BUILD@"
    494495        value="${base.build}"
     496      />
     497      <replacefilter
     498        token="@SUFFIX@"
     499        value="${base.versionsuffix}"
    495500      />
    496501    </replace>
     
    11641169      use="false"
    11651170      private="true"
    1166       windowtitle="BASE ${base.version} API documentation"
     1171      windowtitle="BASE ${base.version}${base.versionsuffix} API documentation"
    11671172      stylesheetfile="${javadoc.src}/javadoc.css"
    11681173      classpathref="javadoc.classpath"
     
    12051210      </group>
    12061211     
    1207       <header><![CDATA[${base.version}: ${TODAY}]]></header>
     1212      <header><![CDATA[${base.version}${base.versionsuffix}: ${TODAY}]]></header>
    12081213      <link href="http://download.oracle.com/javase/6/docs/api"/>
    12091214      <link href="http://docs.jboss.org/hibernate/stable/core/api/"/>
     
    13151320      <property name="distribution.dir" location="${docbook.html.out}" />
    13161321      <property name="build.dir" location="${build}/docbook/html" />
    1317       <property name="base.version" value="${base.version}"/>
     1322      <property name="base.version" value="${base.version}${base.versionsuffix}"/>
    13181323    </ant>
    13191324     <copy todir="${docbook.html.out}">
     
    13691374      <property name="build.dir" location="${build}/docbook/pdf" />
    13701375      <property name="pdf.name" value="base.pdf" />
    1371       <property name="base.version" value="${base.version}"/>
     1376      <property name="base.version" value="${base.version}${base.versionsuffix}"/>
    13721377    </ant>
    13731378  </target>
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ExtensionsControl.java

    r5606 r5607  
    184184  private static ProcessResults scan(boolean initialScan, boolean forceUpdate)
    185185  {
     186    log.info("Starting scan: intial=" + initialScan + "; forceUpdate="+forceUpdate);
    186187    String rootPath = servletContext.getContextPath();
    187188    File resourceDir = new File(servletContext.getRealPath(RESOURCES_URL));
     
    203204      if (!initialScan)
    204205      {
     206        log.debug("Checking for deleted files");
    205207        // 1. Process files that has been deleted
    206208        DeletedFilter deleted = new DeletedFilter();
     
    214216        manager.processFiles(unregister, deleted);
    215217        numUnregistered = unregister.getNumUnregistered();
     218       
     219        log.debug("Processed " + unregister.getNumFiles() + " deleted files");
    216220      }
    217221     
     222      log.debug("Checking for new and updated files");
    218223      // 2. Update the manager with new and modified files
    219224      manager.scanForNewAndUpdated();
     
    221226      numModifiedFiles = manager.getNumModified();
    222227      numDeletedFiles = manager.getNumDeleted();
     228      log.debug("Found " + numNewFiles + " new and " + numModifiedFiles + " modified files");
    223229     
    224230      if (initialScan || numNewFiles > 0 || numModifiedFiles > 0 || forceUpdate)
    225231      {
    226         // Process files that are valid and new/updated (unless forceUpdate=true)
     232        // 3. Process files that are valid and new/updated (unless forceUpdate=true)
    227233        ValidAndNewOrModifiedFilter valid = new ValidAndNewOrModifiedFilter(initialScan || forceUpdate);
    228234       
    229         // 3. Load extension definitions
     235        // 3a. Load extension definitions
    230236        WebClientRegisterExtensionsProcessor registerExtensions =
    231237          new WebClientRegisterExtensionsProcessor(rootPath, rootPath + RESOURCES_URL, rootPath + SERVLET_URL, results);
     
    238244        manager.processFiles(registerExtensions, valid);
    239245
    240         // 4. Extract web resources
     246        // 3b. Extract web resources
    241247        ExtractResourcesProcessor extractResources = new ExtractResourcesProcessor(resourceDir, Pattern.compile("resources/(.*)"), "$1", results);
    242248        extractResources.setForceOverwrite(forceUpdate);
    243249        manager.processFiles(extractResources, valid);
    244250
    245         // 5. Servlets
     251        // 3c. Servlets
    246252        LoadServletsProcessor loadServlets = new LoadServletsProcessor(servletContext, results);
    247253        manager.processFiles(loadServlets, valid);
    248254       
    249         // 6. Actual registration of all extensions
     255        // 3d. Actual registration of all extensions
    250256        registerExtensions.finalizeRegistration(manager);
    251257        numRegistered = registerExtensions.getNumRegistered();
    252258      }
    253259     
    254       // Reset the 'last modifed' status of all files and generated summary per file
     260      // 4. Reset the 'last modifed' status of all files and generated summary per file
    255261      manager.processFiles(new SetFileStatusProcessor(results));
    256262      results.setEnded();
     
    468474    @throws PermissionDeniedException If the logged in user doesn't
    469475      have WRITE permission
     476    @since 3.0
    470477  */
    471478  public ProcessResults installAndUpdateExtensions(boolean forceUpdate)
     
    479486    @return A {@link ProcessResults} object, or null if no scan
    480487      has taken place
     488    @since 3.0
    481489  */
    482490  public ProcessResults getLastScanResults()
     
    495503 
    496504  /**
    497     Get an iterator returning all registered extension points.
     505    Get an list returning all registered extension points.
    498506    @see Registry#getExtensionPoints()
     507    @since 3.0 (Returned an Iterator in BASE 2.x)
    499508  */
    500509  public List<ExtensionPoint<?>> getExtensionPoints()
     
    560569 
    561570  /**
    562     Get an iterator returning all registered extensions.
     571    Get a list returning all registered extensions.
    563572    @see Registry#getExtensions()
     573    @since 3.0 (Returned an Iterator in BASE 2.x)
    564574  */
    565575  public List<Extension<?>> getExtensions()
     
    569579 
    570580  /**
    571     Get an iterator returning all registered extensions for a
     581    Get a list returning all registered extensions for a
    572582    specific extension point.
    573583    @param id The ID of the extension point
    574584    @see Registry#getExtensions(String)
     585    @since 3.0 (Returned an Iterator in BASE 2.x)
    575586  */
    576587  public List<Extension<?>> getExtensions(String id)
  • trunk/src/clients/web/net/sf/basedb/clients/web/taglib/Page.java

    r5384 r5607  
    2525import net.sf.basedb.core.Application;
    2626import net.sf.basedb.core.SessionControl;
     27import net.sf.basedb.core.Version;
    2728import net.sf.basedb.clients.web.Base;
    2829import net.sf.basedb.util.Values;
     
    183184    MAX_URL_LENGTH = maxUrlLength > 0 ? String.valueOf(maxUrlLength) : null;
    184185    ROOT = ((HttpServletRequest)pageContext.getRequest()).getContextPath()+"/";
    185     BASE_VERSION = "BASE " + Application.getMajorVersion() + "." +
    186       Application.getMinorVersion() + "." +
    187       Application.getMaintenanceVersion();
     186    BASE_VERSION = "BASE " + Version.getMajor() + "." +
     187      Version.getMinor() + "." + Version.getMaintenance() + Version.getSuffix();
    188188    SERVER_NAME = Application.getHostName();
    189189    initialized = true;
  • trunk/src/core/base.version

    r2960 r5607  
    33maintenance: @MAINTENANCE@
    44build: @BUILD@
     5suffix: @SUFFIX@
  • trunk/src/core/net/sf/basedb/core/Application.java

    r5606 r5607  
    3737import net.sf.basedb.util.extensions.manager.ExtensionsManager;
    3838import net.sf.basedb.util.extensions.manager.ProcessResults;
     39import net.sf.basedb.util.extensions.manager.filter.ValidAndNewOrModifiedFilter;
    3940import net.sf.basedb.util.extensions.manager.filter.WasProcessedFilter;
    4041import net.sf.basedb.util.extensions.manager.processor.MarkAsProcessedProcessor;
     
    208209  /**
    209210    Get the major version.
    210   */
    211   public static String getMajorVersion()
     211    @since 3.0 (was returning a String in 2.x)
     212  */
     213  public static int getMajorVersion()
    212214  {
    213215    return Version.getMajor();
     
    216218  /**
    217219    Get the minor version.
    218   */
    219   public static String getMinorVersion()
     220    @since 3.0 (was returning a String in 2.x)
     221  */
     222  public static int getMinorVersion()
    220223  {
    221224    return Version.getMinor();
     
    225228  /**
    226229    Get the maintenance version.
    227   */
    228   public static String getMaintenanceVersion()
     230    @since 3.0 (was returning a String in 2.x)
     231  */
     232  public static int getMaintenanceVersion()
    229233  {
    230234    return Version.getMaintenance();
     
    239243  }
    240244
     245  /**
     246    Get the version suffix (eg. "-dev").
     247    @since 3.0
     248  */
     249  public String getVersionSuffix()
     250  {
     251    return Version.getSuffix();
     252  }
     253 
    241254  /**
    242255    Get the BASE version string. It is created by combining
     
    245258  public static String getVersionString()
    246259  {
    247     return "BASE " + getMajorVersion() + "." + getMinorVersion() +
    248       "." + getMaintenanceVersion() + " (build #" + getBuild() +
     260    return "BASE " + Version.getMajor() + "." + Version.getMinor() +
     261      "." + Version.getMaintenance() + Version.getSuffix() + " (build #" + Version.getBuild() +
    249262      "; schema #" + Application.getSchemaVersion()+")";
    250263  }
    251264 
     265  private static int schemaVersion = -2;
    252266  /**
    253267    Get the current database schema version number.
     
    259273    org.hibernate.Session session = null;
    260274    org.hibernate.Transaction tx = null;
    261     int schemaVersion = -2;
    262     try
    263     {
    264       session = HibernateUtil.newSession();
    265       schemaVersion++;
    266       tx = HibernateUtil.newTransaction(session);
    267       org.hibernate.Query query = HibernateUtil.getPredefinedQuery(session, "GET_SCHEMA_VERSION");
    268       schemaVersion = HibernateUtil.loadData(SchemaVersionData.class, query).getSchemaVersion();
    269       HibernateUtil.commit(tx);
    270     }
    271     catch (Throwable t)
    272     {
    273       if (tx != null) HibernateUtil.rollback(tx);
    274       log.error("getSchemaVersion", t);
    275     }
    276     finally
    277     {
    278       if (session != null) HibernateUtil.close(session);
     275    if (schemaVersion > 0) return schemaVersion;
     276   
     277    synchronized (Application.class)
     278    {
     279      schemaVersion = -2;
     280      try
     281      {
     282        session = HibernateUtil.newSession();
     283        schemaVersion++;
     284        tx = HibernateUtil.newTransaction(session);
     285        org.hibernate.Query query = HibernateUtil.getPredefinedQuery(session, "GET_SCHEMA_VERSION");
     286        schemaVersion = HibernateUtil.loadData(SchemaVersionData.class, query).getSchemaVersion();
     287        HibernateUtil.commit(tx);
     288      }
     289      catch (Throwable t)
     290      {
     291        if (tx != null) HibernateUtil.rollback(tx);
     292        log.error("getSchemaVersion", t);
     293      }
     294      finally
     295      {
     296        if (session != null) HibernateUtil.close(session);
     297      }     
    279298    }
    280299    return schemaVersion;
     
    550569        // Filter that only load core extension points
    551570        loader.setFilter(new ExtensionPointFilter("net\\.sf\\.basedb\\.core\\..*"));
    552         xtManager.processFiles(new RegisterExtensionsProcessor(loader, results));
     571        xtManager.processFiles(new RegisterExtensionsProcessor(loader, results), new ValidAndNewOrModifiedFilter(false));
    553572        xtManager.processFiles(new MarkAsProcessedProcessor(), new WasProcessedFilter(results));
    554573       
  • trunk/src/core/net/sf/basedb/core/Version.java

    r5384 r5607  
    3131
    3232import net.sf.basedb.util.FileUtil;
     33import net.sf.basedb.util.Values;
    3334
    3435/**
     
    4344public class Version
    4445{
    45   private static String major;
    46   private static String minor;
    47   private static String maintenance;
     46  private static int major;
     47  private static int minor;
     48  private static int maintenance;
    4849  private static int build;
     50  private static String suffix;
    4951 
    5052  static
     
    7274      Properties config = new Properties();
    7375      config.load(is);
    74       major = config.getProperty("major");
    75       minor = config.getProperty("minor");
    76       maintenance = config.getProperty("maintenance");
     76      major = Values.getInt(config.getProperty("major"));
     77      minor = Values.getInt(config.getProperty("minor"));
     78      maintenance = Values.getInt(config.getProperty("maintenance"));
    7779      build = parseBuildNumber(config.getProperty("build"));
     80      suffix = config.getProperty("suffix", "");
    7881    }
    7982    catch (IOException ex)
     
    8992  /**
    9093    Get the major version.
     94    @since 3.0 (was returning a String in 2.x)
    9195  */
    92   public static String getMajor()
     96  public static int getMajor()
    9397  {
    9498    return major;
     
    97101  /**
    98102    Get the minor version.
     103    @since 3.0 (was returning a String in 2.x)
    99104  */
    100   public static String getMinor()
     105  public static int getMinor()
    101106  {
    102107    return minor;
     
    104109  /**
    105110    Get the maintentance version.
     111    @since 3.0 (was returning a String in 2.x)
    106112  */
    107   public static String getMaintenance()
     113  public static int getMaintenance()
    108114  {
    109115    return maintenance;
     
    118124  }
    119125 
     126  /**
     127    Get the version suffix string (eg "-dev" for development versions)
     128    @since 3.0
     129  */
     130  public static String getSuffix()
     131  {
     132    return suffix;
     133  }
     134 
    120135  public static String getVersion()
    121136  {
    122     return major+"."+minor+"."+maintenance + "(build " + build + ")";
     137    return major+"."+minor+"."+maintenance + suffix + "(build " + build + ")";
    123138  }
    124139
     140  /**
     141    Compare the given version string, which should be of the
     142    form a.b or a.b.c, with the current BASE version.
     143    If they are exactly equal 0 is returned.
     144    If the given string is less than the current version
     145    -1 is returned, if the given string is greater than
     146    the current version +1 is returned.
     147   
     148    @param version
     149    @return 0, -1 or +1
     150    @since 3.0
     151    @throws InvalidDataException If the given string isn't correctly formatted
     152  */
     153  public static int compareWith(String version)
     154  {
     155    if (version == null) throw new NullPointerException("version");
     156    Pattern p = Pattern.compile("(\\d+)\\.(\\d+)\\.?(\\d*)");
     157    Matcher m = p.matcher(version);
     158    if (!m.matches())
     159    {
     160      throw new InvalidDataException("Version is not correctly formatted: " + version);
     161    }
     162   
     163    // Major and minor as a first step
     164    int vMajor = Values.getInt(m.group(1));
     165    int vMinor = Values.getInt(m.group(2));
     166    if (vMajor != major) return vMajor < major ? -1 : 1;
     167    if (vMinor != minor) return vMinor < minor ? -1 : 1;
     168   
     169    // Need to check maintenance as well (if given)
     170    if (m.groupCount() > 2)
     171    {
     172      int vMaintenance = Values.getInt(m.group(3));
     173      if (vMaintenance != maintenance) return vMaintenance < maintenance ? -1 : 1;
     174    }
     175    return 0;
     176  }
     177 
    125178  /**
    126179    Find the first digits in a string and return those as the build number.
  • trunk/src/core/net/sf/basedb/core/plugin/About.java

    r4889 r5607  
    5151
    5252  /**
     53    Get the minimum BASE version that the plug-in requires.
     54    The returned value should be 2 or 3 numbers separated by
     55    a dot (eg. 3.0, 3.1.2, etc). A null return value indicates
     56    that the plug-in works with all BASE versions.
     57    @return A string or null
     58    @since 3.0
     59  */
     60  public String getMinBaseVersion();
     61 
     62  /**
     63    Get the maximum BASE version were to plug-in no longer is
     64    expected to work. The returned value should be 2 or 3 numbers separated
     65    by a dot (eg. 3.0, 3.1.2, etc). A null return value indicates
     66    that the plug-in works with all BASE versions.
     67    @return A string or null
     68    @since 3.0
     69  */
     70  public String getMaxBaseVersion();
     71
     72 
     73  /**
    5374    A description of the plugin and what it does. May return null.
    5475  */
  • trunk/src/core/net/sf/basedb/core/plugin/AboutImpl.java

    r4889 r5607  
    3535  private final String description;
    3636  private final String version;
     37  private final String minBaseVersion;
     38  private final String maxBaseVersion;
    3739  private final String copyright;
    3840  private final String contact;
    3941  private final String email;
    4042  private final String url;
     43 
     44 
     45  /**
     46    Create a new about object without any min or max BASE version requirement.
     47  */
     48  public AboutImpl(String name, String description, String version, String copyright, String contact, String email, String url)
     49  {
     50    this(name, description, version, null, null, copyright, contact, email, url);
     51  }
     52
    4153 
    4254  /**
     
    4658    @param description A description of the plugin
    4759    @param version The version of the plugin
     60    @param minBaseVersion The minium version of BASE that is required by the plugin
     61    @param maxBaseVersion The maxium version of BASE that the plugin is expected to work with
    4862    @param copyright A copyright notice
    4963    @param contact Contact information for the plugin
     
    5165    @param url An URL to get more inforamtion about the plugin
    5266    @throws NullPointerException If the name is null
     67    @since 3.0
    5368  */
    54   public AboutImpl(String name, String description, String version, String copyright, String contact, String email, String url)
     69  public AboutImpl(String name, String description, String version, String minBaseVersion, String maxBaseVersion, String copyright, String contact, String email, String url)
    5570  {
    5671    if (name == null) throw new NullPointerException("The 'name' parameter mustn't be null.");
     
    6277    this.url = url;
    6378    this.version = version;
     79    this.minBaseVersion = minBaseVersion;
     80    this.maxBaseVersion = maxBaseVersion;
    6481  }
    6582
     
    6885    -------------------------------------------
    6986  */
     87  @Override
    7088  public String getContact()
    7189  {
     
    7391  }
    7492
     93  @Override
    7594  public String getCopyright()
    7695  {
     
    7897  }
    7998
     99  @Override
    80100  public String getDescription()
    81101  {
     
    83103  }
    84104
     105  @Override
    85106  public String getEmail()
    86107  {
     
    88109  }
    89110
     111  @Override
    90112  public String getName()
    91113  {
     
    93115  }
    94116
     117  @Override
    95118  public String getUrl()
    96119  {
     
    98121  }
    99122
     123  @Override
    100124  public String getVersion()
    101125  {
    102126    return version;
    103127  }
     128 
     129  @Override
     130  public String getMinBaseVersion()
     131  {
     132    return minBaseVersion;
     133  }
     134 
     135  @Override
     136  public String getMaxBaseVersion()
     137  {
     138    return maxBaseVersion;
     139  }
    104140  // -------------------------------------------
    105141}
  • trunk/src/core/net/sf/basedb/core/xsd/extensions.xsd

    r5519 r5607  
    3030    <xsd:complexType>
    3131      <xsd:sequence>
     32        <!-- global 'about' element -->
    3233        <xsd:element name="about" type="aboutType" minOccurs="0" />
     34       
     35        <!-- 'extension-point' element -->
    3336        <xsd:element name="extension-point" minOccurs="0" maxOccurs="unbounded">
    3437          <xsd:complexType>
     
    5255        </xsd:element>
    5356       
     57        <!-- 'extension' element -->
    5458        <xsd:element name="extension" minOccurs="0" maxOccurs="unbounded">
    5559          <xsd:complexType>
     
    97101      <xsd:element name="description" type="xsd:string" minOccurs="0" maxOccurs="1" />
    98102      <xsd:element name="version" type="xsd:string" minOccurs="0" maxOccurs="1" />
     103      <xsd:element name="min-base-version" type="baseVersionType" minOccurs="0" maxOccurs="1" />
     104      <xsd:element name="max-base-version" type="baseVersionType" minOccurs="0" maxOccurs="1" />
    99105      <xsd:element name="copyright" type="xsd:string" minOccurs="0" maxOccurs="1" />
    100106      <xsd:element name="contact" type="xsd:string" minOccurs="0" maxOccurs="1" />
     
    103109    </xsd:all>
    104110  </xsd:complexType>
     111 
     112  <!-- A string matching BASE version number with or without patch number -->
     113  <xsd:simpleType name="baseVersionType" >
     114    <xsd:restriction base="xsd:string">
     115      <xsd:pattern value="\d\.\d+\.?\d*"></xsd:pattern>
     116    </xsd:restriction>
     117  </xsd:simpleType>
    105118 
    106119  <!--
     
    121134    </xsd:sequence>
    122135  </xsd:complexType>
    123  
    124   <xsd:group name="extends">
    125     <xsd:sequence>
    126       <xsd:element name="extends" minOccurs="0" maxOccurs="unbounded">
    127         <xsd:complexType>
    128           <xsd:simpleContent>
    129             <xsd:extension base="xsd:string">
    130               <xsd:attribute name="index" type="xsd:float" />
    131             </xsd:extension>
    132           </xsd:simpleContent>
    133         </xsd:complexType>
    134       </xsd:element>
    135     </xsd:sequence>
    136   </xsd:group>
    137  
     136
    138137</xsd:schema>
  • trunk/src/core/net/sf/basedb/util/extensions/AboutBean.java

    r4515 r5607  
    3939  private String description;
    4040  private String version;
     41  private String minBaseVersion;
     42  private String maxBaseVersion;
    4143  private String copyright;
    4244  private String contact;
     
    119121  }
    120122
     123  @Override
     124  public String getMinBaseVersion()
     125  {
     126    return minBaseVersion;
     127  }
     128  public void setMinBaseVersion(String version)
     129  {
     130    this.minBaseVersion = version;
     131  }
     132
     133  @Override
     134  public String getMaxBaseVersion()
     135  {
     136    return maxBaseVersion;
     137  }
     138  public void setMaxBaseVersion(String version)
     139  {
     140    this.maxBaseVersion = version;
     141  }
     142
     143 
    121144  /**
    122145    Copy information from antoher <code>About</code> object
     
    132155    description = overwrite || description == null ? from.getDescription() : description;
    133156    version = overwrite || version == null ? from.getVersion() : version;
     157    minBaseVersion = overwrite || minBaseVersion == null ? from.getMinBaseVersion() : minBaseVersion;
     158    maxBaseVersion = overwrite || maxBaseVersion == null ? from.getMaxBaseVersion() : maxBaseVersion;
    134159    copyright = overwrite || copyright == null ? from.getCopyright() : copyright;
    135160    contact = overwrite || contact == null ? from.getContact() : contact;
  • trunk/src/core/net/sf/basedb/util/extensions/Registry.java

    r5606 r5607  
    287287    {
    288288      handleEvent(EventType.BEFORE_UNREGISTRATION, rep, null);
     289      for (RegisteredExtension<?> rext : rep.getExtensions())
     290      {
     291        handleEvent(EventType.BEFORE_UNREGISTRATION, rep, rext);
     292        extensions.remove(rext.getId());
     293      }
    289294      extensionPoints.remove(id);
    290295    }
     
    894899    private String description;
    895900    private String version;
     901    private String minBaseVersion;
     902    private String maxBaseVersion;
    896903    private String copyright;
    897904    private String contact;
     
    953960      return version;
    954961    }
     962   
     963    @Override
     964    public String getMinBaseVersion()
     965    {
     966      return minBaseVersion;
     967    }
     968
     969    @Override
     970    public String getMaxBaseVersion()
     971    {
     972      return maxBaseVersion;
     973    }
    955974    // ---------------------------------
    956975
     
    963982      this.description = about.getDescription();
    964983      this.version = about.getVersion();
     984      this.minBaseVersion = about.getMinBaseVersion();
     985      this.maxBaseVersion = about.getMaxBaseVersion();
    965986      this.contact = about.getContact();
    966987      this.copyright = about.getCopyright();
  • trunk/src/core/net/sf/basedb/util/extensions/manager/ExtensionsFile.java

    r5606 r5607  
    8282  private boolean hasError;
    8383
    84   private volatile boolean hasValidated;
    8584  private volatile boolean isValid;
    8685  private Throwable validationError;
     
    380379    Validate the XML file with the extension definitions.
    381380  */
    382   synchronized void validate()
    383   {
    384     if (hasValidated) return;
    385    
     381  synchronized boolean validate()
     382  {
    386383    log.info("Validating extensions in file: " + this);
    387     hasValidated = false;
    388384    isValid = false;
     385    hasError = false;
    389386    validationError = null;
    390 
     387    jarLoader = null;
     388   
    391389    InputStream in = null;
    392390    try
     
    394392      in = getXmlStream();
    395393      about = new XmlLoader().validateXmlFile(in, getName());
    396     }
    397     catch (RuntimeException ex)
    398     {
    399       log.error("Error validating extensions in file: " + this, ex);
    400       validationError = ex;
    401       throw ex;
     394      log.info("Successfully validated extensions in file: " + this);
     395      isValid = true;
    402396    }
    403397    catch (Throwable t)
     
    405399      log.error("Error validating extensions in file: " + this, t);
    406400      validationError = t;
    407       throw new RuntimeException(t);
    408401    }
    409402    finally
    410403    {
    411404      FileUtil.close(in);
    412       hasValidated = true;
    413     }
    414     log.info("Successfully validated extensions in file: " + this);
    415     isValid = true;
     405    }
     406    return isValid;
    416407  }
    417408
     
    427418  public boolean hasError()
    428419  {
    429     return hasError;
     420    return hasError || !isValid;
    430421  }
    431422 
     
    541532  }
    542533 
     534  /**
     535    Get the class loader used to load classes for the extension. Only JAR
     536    files have class loaders so this method may return null.
     537  */
    543538  public ClassLoader getClassLoader()
    544539    throws IOException
     
    546541    if (jarLoader == null && isJar())
    547542    {
    548       jarLoader = (JarClassLoader)JarClassLoader.getInstance(getFile().getAbsolutePath());
     543      jarLoader = (JarClassLoader)JarClassLoader.getInstance(getFile().getAbsolutePath(), true);
    549544    }
    550545    return jarLoader;
    551546  }
    552  
    553 
    554547
    555548  /**
     
    669662        xtFile.lastLength = xtFile.file.length();
    670663      }
     664      if (!xtFile.isValid)
     665      {
     666        // Cleanup to avoid leaking memory
     667        xtFile.allObjects.clear();
     668        xtFile.jarLoader = null;
     669        xtFile.objectMetadata.clear();
     670      }
    671671    }
    672672   
  • trunk/src/core/net/sf/basedb/util/extensions/manager/ExtensionsManager.java

    r5606 r5607  
    220220      if (!xtFile.exists())
    221221      {
    222         log.info("File '" + xtFile + "' has been deleted.");
     222        log.debug("File '" + xtFile + "' has been deleted.");
    223223        unregisterAllObjects(xtFile);
    224224        it.remove();
     
    227227      else if (xtFile.isNew())
    228228      {
     229        numNew++;
     230      }
     231      else if (xtFile.checkModified())
     232      {
     233        log.debug("File '" + xtFile + "' is modified. Validating...");
    229234        xtFile.validate();
    230         numNew++;
    231       }
    232       else if (xtFile.checkModified())
    233       {
    234         xtFile.validate();
     235        log.debug("File '" + xtFile + "' is " + (xtFile.isValid() ? "valid" : "invalid"));
    235236        numModified++;
    236237      }
     
    305306    if (files != null && files.length > 0)
    306307    {
    307       log.info("Found " + files.length + " file(s)");
     308      log.debug("Found " + files.length + " files");
    308309      for (File file : files)
    309310      {
    310311        if (ignore.contains(file))
    311312        {
    312           log.info("File '" + file + "' is ignored.");
     313          log.debug("File '" + file + "' is ignored.");
    313314          continue; // with the next file
    314315        }
     
    318319        if (xtFile != null)
    319320        {
    320           log.info("File '" + xtFile + "' is a known file.");
     321          log.debug("File '" + xtFile + "' is a known file.");
    321322        }
    322323        else
     
    327328        }
    328329      }
     330      log.info("Found " + numNew + " files");
    329331    }
    330332    else
     
    389391      installedObjects.put(key, xtFile);
    390392    }
    391     else
     393    else if (!xtFile.equals(xtOther))
    392394    {
    393395      throw new ItemAlreadyExistsException(key.toDescription() + " is defined in '" + xtOther.getName() + "'");
     
    442444  {
    443445    if (processor == null) throw new NullPointerException("processor");
     446    log.info("Processing files with processor: " + processor);
    444447
    445448    // 1. Filter files with the given filter
     
    448451    {
    449452      filtered = new ArrayList<ExtensionsFile>(xtFiles.size());
    450       log.debug("Filtering files with filter: " + filter);
     453      log.info("Filtering files with filter: " + filter);
    451454      for (ExtensionsFile xtFile : xtFiles.values())
    452455      {
     
    481484      }
    482485      processor.done(this);
    483       log.debug("All files processed successfully with processor: " + processor);
     486      log.debug("All files processed with processor: " + processor);
    484487    }
    485488    catch (Throwable t)
    486489    {
    487       log.warn("Error when processing extensions with " + processor, t);
     490      log.error("Error when processing extensions with " + processor, t);
    488491      processor.done(null, t);
    489492    }
  • trunk/src/core/net/sf/basedb/util/extensions/manager/filter/ValidAndNewOrModifiedFilter.java

    r5605 r5607  
    6262  public boolean evaluate(ExtensionsFile xtFile)
    6363  {
    64     if (!xtFile.isValid() || xtFile.hasError())
     64    if (!xtFile.isValid() || (xtFile.hasError() && !allowUnmodified))
    6565    {
    6666      log.info("File has errors (skipping): " + xtFile);
  • trunk/src/core/net/sf/basedb/util/extensions/manager/processor/RegisterExtensionsProcessor.java

    r5606 r5607  
    2424import java.io.InputStream;
    2525import java.util.ArrayList;
     26import java.util.Collections;
    2627import java.util.List;
    2728
     
    117118    {
    118119      log.info("Loading extensions from file: " + xtFile);
     120      FileData data = new FileData();
     121      data.writeableFile = wFile;
     122      allData.add(data);
    119123      in = xtFile.getXmlStream();
    120124      loader.loadXmlFile(in, xtFile.getName(), xtFile.getClassLoader(), true);
    121       FileData data = new FileData();
    122       data.writeableFile = wFile;
    123125      data.extensionPoints = new ArrayList<ExtensionPoint<?>>(loader.getExtensionPoints());
    124126      data.extensions = new ArrayList<Extension<?>>(loader.getExtensions());
     
    126128      log.info("Loaded " + data.extensionPoints.size() + "/" + data.extensions.size() +
    127129          " extensions from file: " + xtFile);
    128       allData.add(data);
    129130    }
    130131    catch (Exception ex)
     
    134135      if (results != null)
    135136      {
    136         results.addErrorMessage(xtFile, "Failed to load extensions:" + ex.getMessage());
     137        results.addErrorMessage(xtFile, "Failed to load extension(s): " + ex.getMessage());
    137138      }
    138139      log.error("Failed to load extensions from file: " + xtFile, ex);
     
    218219      ExtensionsFile xtFile = wFile.getExtensionsFile();
    219220
    220       // NOTE! Do not register files with an error
    221       if (xtFile.hasError())
    222       {
    223         log.debug("Skipping file with error: " + xtFile);
    224         continue; // with the next file
    225       }
    226      
    227221      if (!forceUpdate && (!xtFile.wasModified() || xtFile.isNew()))
    228222      {
    229223        log.debug("Skipping new or unmodified file: " + xtFile);
    230224        continue;
     225      }
     226
     227      // Unregister all extensions if the file has an error
     228      if (xtFile.hasError())
     229      {
     230        data.extensions = Collections.emptyList();
     231        data.extensionPoints = Collections.emptyList();
    231232      }
    232233     
     
    405406      if (forceUpdate || !registry.extensionPointIsRegistered(ep.getId()))
    406407      {
     408        log.debug("Registering extension point: " + ep);
    407409        ExtensionPointKey key = new ExtensionPointKey(ep);
    408410        data.writeableFile.registerObject(key, ep);
     
    425427  private boolean unregisterExtensionPoint(FileData data, ExtensionPoint ep, Registry registry)
    426428  {
     429    log.debug("Unregistering extension point: " + ep);
    427430    unregisterFactory(data, ep.getRendererFactory());
    428431    unregisterFactory(data, ep.getErrorHandlerFactory());
     
    444447      if (forceUpdate || !registry.extensionIsRegistered(ext.getId()))
    445448      {
     449        log.debug("Registering extension: " + ext);
    446450        ExtensionKey key = new ExtensionKey(ext);
    447451        data.writeableFile.registerObject(key, ext);
     
    464468  private boolean unregisterExtension(FileData data, Extension ext, Registry registry)
    465469  {
     470    log.debug("Unregistering extension: " + ext);
    466471    unregisterFactory(data, ext.getRendererFactory());
    467472    unregisterFactory(data, ext.getActionFactory());
  • trunk/src/core/net/sf/basedb/util/extensions/manager/processor/UnregisterExtensionsProcessor.java

    r5603 r5607  
    2525import net.sf.basedb.util.extensions.ExtensionPoint;
    2626import net.sf.basedb.util.extensions.Registry;
     27import net.sf.basedb.util.extensions.manager.ExtensionKey;
     28import net.sf.basedb.util.extensions.manager.ExtensionPointKey;
    2729import net.sf.basedb.util.extensions.manager.ExtensionsFile;
    2830import net.sf.basedb.util.extensions.manager.ExtensionsFileProcessor;
    2931import net.sf.basedb.util.extensions.manager.ExtensionsManager;
     32import net.sf.basedb.util.extensions.manager.FactoryParametersKey;
    3033import net.sf.basedb.util.extensions.manager.ProcessResults;
    3134import net.sf.basedb.util.extensions.manager.ExtensionsFile.WriteableExtensionsFile;
     
    8588    try
    8689    {
     90      wFile.open();
    8791      int num = 0;
    8892      Registry registry = manager.getRegistry();
    8993      for (ExtensionPoint ep : xtFile.getObjectsOfClass(ExtensionPoint.class))
    9094      {
    91         registry.unregisterExtensionPoint(ep.getId());
     95        unregisterExtensionPoint(wFile, ep, registry);
    9296        num++;
    9397      }
    9498      for (Extension ext : xtFile.getObjectsOfClass(Extension.class))
    9599      {
    96         registry.unregisterExtension(ext.getId());
     100        unregisterExtension(wFile, ext, registry);
    97101        num++;
    98102      }
     
    101105      if (results != null)
    102106      {
    103         results.setStatus(xtFile, "Deleted");
    104         results.addMessage(xtFile, num + " extensions unregisterered.");
     107        if (!xtFile.exists()) results.setStatus(xtFile, "Deleted");
     108        if (num > 0) results.addMessage(xtFile, num + " extension(s) unregisterered.");
    105109      }
    106110      log.info("Unregistered  " + num + " extensions from file: " + xtFile);
     
    115119      }
    116120      log.error("Could not unregister extensions in file: " + xtFile, ex);
     121    }
     122    finally
     123    {
     124      wFile.close();
    117125    }
    118126  }
     
    132140  {}
    133141  // ----------------------------------------------------
     142 
     143  /**
     144    Unregister the given extension including factory metadata etc.
     145  */
     146  private void unregisterExtension(WriteableExtensionsFile wFile, Extension ext, Registry registry)
     147  {
     148    unregisterFactory(wFile, ext.getRendererFactory());
     149    unregisterFactory(wFile, ext.getActionFactory());
     150    ExtensionKey key = new ExtensionKey(ext);
     151    wFile.unregisterObject(key);
     152    registry.unregisterExtension(ext.getId());
     153  }
     154
     155  /**
     156    Unregister the given extension point including factory metadata etc.
     157  */
     158  private void unregisterExtensionPoint(WriteableExtensionsFile wFile, ExtensionPoint ep, Registry registry)
     159  {
     160    unregisterFactory(wFile, ep.getRendererFactory());
     161    unregisterFactory(wFile, ep.getErrorHandlerFactory());
     162    ExtensionPointKey key = new ExtensionPointKey(ep);
     163    wFile.unregisterObject(key);
     164    registry.unregisterExtensionPoint(ep.getId());
     165  }
     166 
     167  private void unregisterFactory(WriteableExtensionsFile wFile, Object factory)
     168  {
     169    if (factory == null) return;
     170    wFile.unregisterMetadata(new FactoryParametersKey(factory));
     171  }
     172
    134173 
    135174  /**
  • trunk/src/core/net/sf/basedb/util/extensions/xml/XmlLoader.java

    r5598 r5607  
    4141import org.jdom.output.XMLOutputter;
    4242
     43import net.sf.basedb.core.BaseException;
    4344import net.sf.basedb.core.InvalidUseOfNullException;
    4445import net.sf.basedb.core.StringUtil;
     46import net.sf.basedb.core.Version;
    4547import net.sf.basedb.core.plugin.About;
    4648import net.sf.basedb.util.ClassUtil;
     
    273275    lastName = filename;
    274276    About globalAbout = loadGlobalAbout(validatedDom);
     277    verifyBaseVersion(globalAbout, true);
    275278    return globalAbout;
    276279  }
     
    444447  {
    445448    log.debug("Validating file: " + filename);
    446     return XMLUtil.getSchemaValidatedXML(xmlFile, filename, namespace, schemaFileURL);
     449    Document dom = XMLUtil.getSchemaValidatedXML(xmlFile, filename, namespace, schemaFileURL);
     450    return dom;
     451  }
     452 
     453  protected boolean verifyBaseVersion(About about, boolean throwException)
     454  {
     455    if (about == null) return true;
     456    String minVersion = about.getMinBaseVersion();
     457    String maxVersion = about.getMaxBaseVersion();
     458    if (minVersion != null && Version.compareWith(minVersion) > 0)
     459    {
     460      if (throwException)
     461      {
     462        throw new BaseException("BASE version "+ minVersion + " or higher is required");
     463      }
     464      return false;
     465    }
     466    if (maxVersion != null && Version.compareWith(maxVersion) <= 0)
     467    {
     468      if (throwException)
     469      {
     470        throw new BaseException("BASE version "+ maxVersion + " or higher is not supported");
     471      }
     472      return false;
     473    }
     474    return true;
    447475  }
    448476 
     
    472500      about.setDescription(Values.getStringOrNull(aboutTag.getChildText("description", ns)));
    473501      about.setVersion(Values.getStringOrNull(aboutTag.getChildText("version", ns)));
     502      about.setMinBaseVersion(Values.getStringOrNull(aboutTag.getChildText("min-base-version", ns)));
     503      about.setMaxBaseVersion(Values.getStringOrNull(aboutTag.getChildText("max-base-version", ns)));
    474504      about.setContact(Values.getStringOrNull(aboutTag.getChildText("contact", ns)));
    475505      about.setCopyright(Values.getStringOrNull(aboutTag.getChildText("copyright", ns)));
     
    672702          about.copy(globalAbout, false);
    673703        }
    674  
    675         // <action-factory>
    676         Element afTag = epTag.getChild("action-factory", ns);
    677         ActionFactory af = null;
    678         if (afTag != null)
     704       
     705        if (!verifyBaseVersion(about, false))
    679706        {
    680           af = createFactory(afTag, classLoader, ActionFactory.class);
     707          String min = about.getMinBaseVersion();
     708          String max = about.getMaxBaseVersion();
     709          log.info("Extension '" + id + "' require BASE version between " +
     710            (min == null ? "*" : min) + " and " + (max == null ? "*" : max)
     711          );
    681712        }
    682      
    683         // <renderer-factory>
    684         Element rfTag = epTag.getChild("renderer-factory", ns);
    685         RendererFactory rf = null;
    686         if (rfTag != null)
     713        else
    687714        {
    688           rf = createFactory(rfTag, classLoader, RendererFactory.class);
    689         }
     715          // <action-factory>
     716          Element afTag = epTag.getChild("action-factory", ns);
     717          ActionFactory af = null;
     718          if (afTag != null)
     719          {
     720            af = createFactory(afTag, classLoader, ActionFactory.class);
     721          }
    690722       
    691         String commonIdPrefix = null;
    692         if (extensionPoints.size() > 1)
    693         {
    694           // We need to calculate the common id prefix for the extension points
    695           // so that we can create unique extension id:s
    696           commonIdPrefix = StringUtil.getCommonPrefix(extensionPoints);
    697         }
    698        
    699         for (int i = 0; i < extensionPoints.size(); ++i)
    700         {
    701           epId = extensionPoints.get(i);
    702           float index = indexes.get(i);
    703           ExtensionBean<Action> ext = new ExtensionBean<Action>();
    704           temp.add(ext);
    705           numLoaded++;
    706          
    707           String thisId = id;
    708           if (commonIdPrefix != null)
     723          // <renderer-factory>
     724          Element rfTag = epTag.getChild("renderer-factory", ns);
     725          RendererFactory rf = null;
     726          if (rfTag != null)
    709727          {
    710             thisId += ":" + epId.substring(commonIdPrefix.length());
     728            rf = createFactory(rfTag, classLoader, RendererFactory.class);
    711729          }
    712730         
    713           ext.setId(thisId);
    714           ext.setExtends(epId);
    715           ext.setIndex(index);
    716           ext.setAbout(about);
    717           ext.setActionFactory(af);
    718           ext.setRendererFactory(rf);
     731          String commonIdPrefix = null;
     732          if (extensionPoints.size() > 1)
     733          {
     734            // We need to calculate the common id prefix for the extension points
     735            // so that we can create unique extension id:s
     736            commonIdPrefix = StringUtil.getCommonPrefix(extensionPoints);
     737          }
     738         
     739          for (int i = 0; i < extensionPoints.size(); ++i)
     740          {
     741            epId = extensionPoints.get(i);
     742            float index = indexes.get(i);
     743            ExtensionBean<Action> ext = new ExtensionBean<Action>();
     744            temp.add(ext);
     745            numLoaded++;
     746           
     747            String thisId = id;
     748            if (commonIdPrefix != null)
     749            {
     750              thisId += ":" + epId.substring(commonIdPrefix.length());
     751            }
     752           
     753            ext.setId(thisId);
     754            ext.setExtends(epId);
     755            ext.setIndex(index);
     756            ext.setAbout(about);
     757            ext.setActionFactory(af);
     758            ext.setRendererFactory(rf);
     759          }
    719760        }
    720761      }
  • trunk/src/info/net/sf/basedb/info/VersionInfo.java

    r4512 r5607  
    3535  private static final long serialVersionUID = 9189853948028180946L;
    3636
    37   private String major;
    38   private String minor;
    39   private String maintenance;
     37  private int major;
     38  private int minor;
     39  private int maintenance;
    4040  private int build;
    4141  private int schema;
     
    6464    @return Returns the maintenance version
    6565    @see net.sf.basedb.core.Application#getMaintenanceVersion()
     66    @since 3.0 (was returning a String in 2.x)
    6667  */
    67   public String getMaintenance()
     68  public int getMaintenance()
    6869  {
    6970    return maintenance;
    7071  }
    7172
    72   public void setMaintenance(String maintenance)
     73  public void setMaintenance(int maintenance)
    7374  {
    7475    this.maintenance = maintenance;
     
    7879    @return Returns the major version
    7980    @see net.sf.basedb.core.Application#getMajorVersion()
     81    @since 3.0 (was returning a String in 2.x)
    8082  */
    81   public String getMajor()
     83  public int getMajor()
    8284  {
    8385    return major;
    8486  }
    8587
    86   public void setMajor(String major)
     88  public void setMajor(int major)
    8789  {
    8890    this.major = major;
     
    9294    @return Returns the minor version
    9395    @see net.sf.basedb.core.Application#getMinorVersion()
     96    @since 3.0 (was returning a String in 2.x)
    9497  */
    95   public String getMinor()
     98  public int getMinor()
    9699  {
    97100    return minor;
    98101  }
    99102
    100   public void setMinor(String minor)
     103  public void setMinor(int minor)
    101104  {
    102105    this.minor = minor;
  • trunk/www/admin/extensions/details.jsp

    r5606 r5607  
    463463              List<String> messages = fileResults.getMessages();
    464464              Throwable validationError = file.getValidationError();
     465              %>
     466              <ul style="padding-left: 20px; margin: 0px; text-align: left;" class="error">
     467              <%
     468              if (validationError != null)
     469              {
     470                %>
     471                <li><%=validationError.getClass().getSimpleName()%>: <%=HTML.niceFormat(validationError.getMessage())%>
     472                <%
     473              }
    465474              for (String msg : messages)
    466475              {
     
    469478                <%
    470479              }
    471               if (validationError != null)
    472               {
    473                 %>
    474                 <li><%=HTML.niceFormat(validationError.getMessage())%>
    475                 <%
    476               }
     480              %>
     481              </ul>
     482              <%
    477483            }
    478484            else
  • trunk/www/admin/extensions/index.jsp

    r5606 r5607  
    3434  import="net.sf.basedb.util.extensions.Extension"
    3535  import="net.sf.basedb.clients.web.extensions.ExtensionsControl"
    36   import="net.sf.basedb.clients.web.extensions.ExtensionsFile"
    3736  import="java.util.List"
    3837%>
  • trunk/www/admin/extensions/scan_results.jsp

    r5602 r5607  
    109109    {
    110110      ExtensionsFile extFile = fileResults.getExtensionsFile();
    111       boolean isError = fileResults.hasError();
    112111      String detailsId = Integer.toString(extFile.hashCode());
    113112      List<String> messages = fileResults.getMessages();
    114       boolean hasMessages = messages != null && messages.size() > 0;
    115113      Throwable validationError = extFile.getValidationError();
     114      boolean hasMessages = (messages != null && messages.size() > 0) || validationError != null;
    116115      %>
    117116      <tr>
    118117        <td class="prompt"><%=extFile.getName() %></td>
    119         <td><%=isError ? "Error" : fileResults.getStatus() %>
     118        <td><%=fileResults.getStatus() %>
    120119        <base:icon
    121120          id="<%="icon." + detailsId %>"
     
    123122          onclick="<%="showDetails('" + detailsId + "')" %>"
    124123          visible="<%=hasMessages%>"
    125           />
     124        />
    126125        </td>
    127126      </tr>
    128127      <%
    129       if (hasMessages || validationError != null)
     128      if (hasMessages)
    130129      {
    131130        %>
    132131        <tr id="details.<%=detailsId %>" style="display:none;">
    133132          <td></td><td>
     133          <ul style="padding-left: 20px; margin: 0px; text-align: left;">
    134134          <%
    135135          for (String msg : messages)
     
    142142          {
    143143            %>
    144             <li><%=HTML.niceFormat(validationError.getMessage())%>
     144            <li><%=validationError.getClass().getSimpleName()%>: <%=HTML.niceFormat(validationError.getMessage())%>
    145145            <%
    146146          }
    147147          %>
     148          </ul>
    148149          </td>
    149150        </tr>
Note: See TracChangeset for help on using the changeset viewer.