Changeset 5605


Ignore:
Timestamp:
Apr 12, 2011, 2:46:47 PM (10 years ago)
Author:
Nicklas Nordborg
Message:

References #1593: Extension system for the core API

Better support for handling updated extensions. New and missing extensions are now registered/unregistered properly.

Fixed some startup problems that left BASE in "isRunning" mode when it actually failed to cleanup due to an error in the start() method.

Location:
trunk/src
Files:
1 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ExtensionsControl.java

    r5603 r5605  
    264264      manager.processFiles(unregister, deleted);
    265265      numUnregistered = unregister.getNumUnregistered();
    266      
    267       // 2. Update the manager with new and modified files
    268       manager.scanForNewAndUpdated();
    269       numNewFiles = manager.getNumNew();
    270       numModifiedFiles = manager.getNumModified();
    271       numDeletedFiles = manager.getNumDeleted();
    272     }
     266    }
     267   
     268    // 2. Update the manager with new and modified files
     269    manager.scanForNewAndUpdated();
     270    numNewFiles = manager.getNumNew();
     271    numModifiedFiles = manager.getNumModified();
     272    numDeletedFiles = manager.getNumDeleted();
    273273   
    274274    if (initialScan || numNewFiles > 0 || numModifiedFiles > 0 || forceUpdate)
    275275    {
    276276      // Process files that are valid and new/updated (unless forceUpdate=true)
    277       ValidAndNewOrModifiedFilter valid = new ValidAndNewOrModifiedFilter(forceUpdate);
     277      ValidAndNewOrModifiedFilter valid = new ValidAndNewOrModifiedFilter(initialScan || forceUpdate);
    278278     
    279279      // 3. Load extension definitions
    280280      WebClientRegisterExtensionsProcessor registerExtensions =
    281281        new WebClientRegisterExtensionsProcessor(rootPath, rootPath + RESOURCES_URL, rootPath + SERVLET_URL, results);
     282      registerExtensions.setForceUpdate(forceUpdate);
    282283      manager.processFiles(registerExtensions, valid);
    283284
    284285      // 4. Extract web resources
    285       ExtractResourcesProcessor extractResources = new ExtractResourcesProcessor(resourceDir, forceUpdate, Pattern.compile("resources/(.*)"), "$1", results);
     286      ExtractResourcesProcessor extractResources = new ExtractResourcesProcessor(resourceDir, Pattern.compile("resources/(.*)"), "$1", results);
     287      extractResources.setForceOverwrite(forceUpdate);
    286288      manager.processFiles(extractResources, valid);
    287289
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/SetFileStatusProcessor.java

    r5603 r5605  
    2626import net.sf.basedb.util.extensions.manager.ProcessResults;
    2727import net.sf.basedb.util.extensions.manager.ExtensionsFile.WriteableExtensionsFile;
     28import net.sf.basedb.util.extensions.manager.ProcessResults.FileResults;
    2829import net.sf.basedb.util.extensions.manager.processor.MarkAsProcessedProcessor;
    2930
     
    5657  {
    5758    ExtensionsFile xtFile = wFile.getExtensionsFile();
     59    FileResults fileResults = results.getResults(xtFile);
    5860    if (!xtFile.isValid())
    5961    {
     
    6870      results.setStatus(xtFile, "Installed");
    6971    }
    70     else if (xtFile.wasModified())
     72    else if (xtFile.wasModified() || fileResults != null)
    7173    {
    7274      results.setStatus(xtFile, "Updated");
  • trunk/src/core/net/sf/basedb/core/Application.java

    r5603 r5605  
    3535import net.sf.basedb.util.StaticCache;
    3636import net.sf.basedb.util.extensions.Registry;
    37 import net.sf.basedb.util.extensions.manager.ExtensionsFile;
    3837import net.sf.basedb.util.extensions.manager.ExtensionsManager;
    3938import net.sf.basedb.util.extensions.manager.ProcessResults;
     39import net.sf.basedb.util.extensions.manager.filter.WasProcessedFilter;
    4040import net.sf.basedb.util.extensions.manager.processor.MarkAsProcessedProcessor;
    4141import net.sf.basedb.util.extensions.manager.processor.RegisterExtensionsProcessor;
     
    436436      if (!userFilesDirectory.exists() || !userFilesDirectory.isDirectory())
    437437      {
    438         throw new ConfigurationException("Userfiles directory '" + userFilesDirectory + "' doesn't exists or is not a directory.");
     438        throw new ConfigurationException("Directory 'userfiles' in base.config doesn't exists or is not a directory: " + userFilesDirectory);
    439439      }
    440440
     
    550550        loader.setFilter(new ExtensionPointFilter("net\\.sf\\.basedb\\.core\\..*"));
    551551        xtManager.processFiles(new RegisterExtensionsProcessor(loader, results));
    552         //xtManager.processFiles(new MarkAsProcessedProcessor());
     552        xtManager.processFiles(new MarkAsProcessedProcessor(), new WasProcessedFilter(results));
    553553       
    554554        // Initialise log manager factory
     
    10391039  private static void cleanSessionControlCache(boolean force)
    10401040  {
     1041    if (sessionCache == null) return;
    10411042    if (!force)
    10421043    {
  • trunk/src/core/net/sf/basedb/core/QueryExecutor.java

    r5358 r5605  
    7676  static void unload()
    7777  {
    78     service.shutdown();
     78    if (service != null) service.shutdown();
    7979    service = null;
    8080  }
  • trunk/src/core/net/sf/basedb/util/extensions/manager/ExtensionsFile.java

    r5603 r5605  
    510510  }
    511511
     512  /**
     513    Get a list of all metadata defined in this extensions
     514    file that are keyed with the specified class or interface.
     515    Note! The returned list may be empty if another
     516    thread is currently processing this file.
     517   
     518    @param ofClass The class/interface the metadata keys must be
     519      an instance of
     520    @return A list with the objects, if no objects are found
     521      the list is empty
     522  */
     523  public <T> List<T> getMetadataKeysOfClass(Class<T> ofClass)
     524  {
     525    List<T> matching = new ArrayList<T>();
     526    try
     527    {
     528      if (readLock())
     529      {
     530        for (ObjectKey key : objectMetadata.keySet())
     531        {
     532          if (ofClass.isInstance(key)) matching.add(ofClass.cast(key));
     533        }
     534      }
     535    }
     536    finally
     537    {
     538      rwLock.readLock().unlock();
     539    }
     540    return matching;
     541  }
     542 
    512543  public ClassLoader getClassLoader()
    513544    throws IOException
     
    600631    public void close()
    601632    {
    602       System.out.println("close(): " + isClosed);
    603633      if (isClosed) return;
    604634      isClosed = true;
     
    608638    public boolean open()
    609639    {
    610       System.out.println("open(): " + isClosed);
    611640      if (isClosed)
    612641      {
    613642        isClosed = !xtFile.writeLock();
    614643      }
    615       System.out.println("open2(): " + isClosed);
    616644      return !isClosed;
    617645    }
     
    666694   
    667695    /**
     696      Unregister an object that was "defined" by this extensions
     697      file.
     698      @param key The object key used to identify the object
     699      @throws IllegalStateException If the file has been closed
     700    */
     701    public <O> void unregisterObject(ObjectKey<O> key)
     702    {
     703      checkClosed();
     704      xtFile.allObjects.remove(key);
     705      xtFile.manager.unregisterObject(key);
     706    }
     707   
     708    /**
    668709      Register metadata about an object. The difference
    669710      between this method and the {@link #registerObject(ObjectKey, Object)}
     
    681722   
    682723   
     724    /**
     725      Unregister metadata about an object.
     726      @param key The object key used to identify the metadata
     727    */
     728    public <M> void unregisterMetadata(ObjectKey<M> key)
     729    {
     730      checkClosed();
     731      xtFile.objectMetadata.remove(key);
     732    }
     733   
    683734  }
    684735}
  • trunk/src/core/net/sf/basedb/util/extensions/manager/ExtensionsManager.java

    r5603 r5605  
    2727import java.util.ArrayList;
    2828import java.util.Collection;
     29import java.util.Comparator;
    2930import java.util.HashMap;
    3031import java.util.HashSet;
     
    8283    this.ignore = new HashSet<File>();
    8384    this.directories = new HashSet<File>();
    84     this.xtFiles = new TreeMap<URI, ExtensionsFile>();
     85    this.xtFiles = new TreeMap<URI, ExtensionsFile>(new JarFirstURIComparator());
    8586    this.installedObjects = new HashMap<ObjectKey, ExtensionsFile>();
    8687  }
     
    220221      {
    221222        log.info("File '" + xtFile + "' has been deleted.");
     223        unregisterAllObjects(xtFile);
    222224        it.remove();
    223225        numDeleted++;
     226      }
     227      else if (xtFile.isNew())
     228      {
     229        xtFile.validate();
     230        numNew++;
    224231      }
    225232      else if (xtFile.checkModified())
     
    389396  }
    390397 
     398  /**
     399    Unregister all objects know in the file.
     400  */
     401  void unregisterAllObjects(ExtensionsFile xtFile)
     402  {
     403    Iterator<ExtensionsFile> it = installedObjects.values().iterator();
     404    while (it.hasNext())
     405    {
     406      if (it.next().equals(xtFile)) it.remove();
     407    }
     408  }
     409 
    391410  public void processFiles(ExtensionsFileProcessor processor)
    392411  {
     
    460479  }
    461480 
     481  public static class JarFirstURIComparator
     482    implements Comparator<URI>
     483  {
     484    public JarFirstURIComparator()
     485    {}
     486
     487    @Override
     488    public int compare(URI u1, URI u2)
     489    {
     490      String s1 = u1.getScheme();
     491      String s2 = u2.getScheme();
     492      if (!s1.equals(s2))
     493      {
     494        if (s1.equals("jar")) return -1;
     495        if (s2.equals("jar")) return 1;
     496      }
     497      return u1.compareTo(u2);
     498    }
     499  }
     500 
    462501}
  • trunk/src/core/net/sf/basedb/util/extensions/manager/filter/ValidAndNewOrModifiedFilter.java

    r5603 r5605  
    2828  Filter implementation for extension files that
    2929  allow valid and new or modified files to pass.
    30   The forceUpdate parameter can be set to also
     30  The allowUnmodified parameter can be set to also
    3131  allow unmodified files to pass.
    3232 
  • trunk/src/core/net/sf/basedb/util/extensions/manager/processor/ExtractResourcesProcessor.java

    r5603 r5605  
    7070 
    7171  private final File mainDir;
    72   private final boolean forceOverwrite;
     72  private boolean forceOverwrite;
    7373  private final Pattern filter;
    7474  private final String replacement;
     
    8383   
    8484    @param mainDir The main directory to where the resources should be extracted
    85     @param forceOverwrite TRUE to force overwriting existing files, FALSE to
    86       only overwrite files if they are different from the files in the JAR
    87   */
    88   public ExtractResourcesProcessor(File mainDir, boolean forceOverwrite, ProcessResults results)
    89   {
    90     this(mainDir, forceOverwrite, null, null, results);
     85  */
     86  public ExtractResourcesProcessor(File mainDir, ProcessResults results)
     87  {
     88    this(mainDir, null, null, results);
    9189  }
    9290
     
    9593   
    9694    @param mainDir The main directory to where the resources should be extracted
    97     @param forceOverwrite TRUE to force overwriting existing files, FALSE to
    98       only overwrite files if they are different from the files in the JAR
    9995    @param filter A regular expression filter that must match the file name
    10096      in the JAR file
     
    10298      using {@link Matcher#replaceAll(String)}.
    10399  */
    104   public ExtractResourcesProcessor(File mainDir, boolean forceOverwrite, Pattern filter, String replacement, ProcessResults results)
     100  public ExtractResourcesProcessor(File mainDir, Pattern filter, String replacement, ProcessResults results)
    105101  {
    106102    this.mainDir = mainDir;
    107     this.forceOverwrite = forceOverwrite;
    108103    this.filter = filter;
    109104    this.replacement = replacement;
     
    257252 
    258253  /**
     254    Set a flag indicating if already existing files should
     255    always be updated or not.
     256   
     257    @param forceOverwrite TRUE to force overwriting existing files,
     258      FALSE to only overwrite files if they are different from
     259      the files in the JAR
     260  */
     261  public void setForceOverwrite(boolean forceOverwrite)
     262  {
     263    this.forceOverwrite = forceOverwrite;
     264  }
     265 
     266  /**
    259267    Get the number of files that was successfully processed.
    260268  */
  • trunk/src/core/net/sf/basedb/util/extensions/manager/processor/RegisterExtensionsProcessor.java

    r5603 r5605  
    7676  private final ProcessResults results;
    7777  private boolean delayRegistration;
     78  private boolean forceUpdate;
    7879  private List<FileData> allData;
    7980
     
    8182  private int numError;
    8283  private int numRegistered;
     84  private int numUnregistered;
    8385
    8486  /**
     
    104106    this.numError = 0;
    105107    this.numRegistered = 0;
     108    this.numUnregistered = 0;
    106109  }
    107110
     
    151154  public void done(ExtensionsManager manager, Throwable t)
    152155  {
    153     if (allData != null)  allData.clear();
     156    if (allData != null) allData.clear();
    154157    allData = null;
    155158  }
     
    179182 
    180183  /**
     184    Set a flag to indicate if already registered extensions should
     185    be re-registered or not.
     186    @param forceUpdate TRUE to always re-register extensions,
     187      FALSE to only register new or updated extensions
     188  */
     189  public void setForceUpdate(boolean forceUpdate)
     190  {
     191    this.forceUpdate = forceUpdate;
     192  }
     193 
     194  /**
    181195    Get the loader the processor is using for parsing xml files with
    182196    extension definitions.
     
    198212    Registry registry = manager.getRegistry();
    199213
    200     // First loop -- register extension points
     214    // First loop -- unregister extensions and extension points that are missing
     215    log.info("Unregistering all missing extension points and extensions");
     216    for (FileData data : allData)
     217    {
     218      WriteableExtensionsFile wFile = data.writeableFile;
     219      ExtensionsFile xtFile = wFile.getExtensionsFile();
     220
     221      // NOTE! Do not register files with an error
     222      if (xtFile.hasError())
     223      {
     224        log.debug("Skipping file with error: " + xtFile);
     225        continue; // with the next file
     226      }
     227     
     228      if (!forceUpdate && (!xtFile.wasModified() || xtFile.isNew()))
     229      {
     230        log.debug("Skipping new or unmodified file: " + xtFile);
     231        continue;
     232      }
     233     
     234      try
     235      {
     236        wFile.open();
     237        int num = 0;
     238        // Extension points
     239        for (ExtensionPoint ep : xtFile.getObjectsOfClass(ExtensionPoint.class))
     240        {
     241          if (unregisterExtensionPoint(data, ep, registry))
     242          {
     243            num++;
     244          }
     245        }
     246        if (num > 0 && results != null)
     247        {
     248          numUnregistered += num;
     249          results.addMessage(xtFile, num + " extension point(s) unregistered.");
     250        }
     251        log.info("Unregistered " + num + " extension point(s) from file: " + xtFile);
     252       
     253        // Extensions
     254        num = 0;
     255        for (Extension ext : xtFile.getObjectsOfClass(Extension.class))
     256        {
     257          if (unregisterExtension(data, ext, registry))
     258          {
     259            num++;
     260          }
     261        }
     262        if (num > 0 && results != null)
     263        {
     264          numUnregistered += num;
     265          results.addMessage(xtFile, num + " extension(s) unregistered.");
     266        }
     267        log.info("Unregistered " + num + " extension(s) from file: " + xtFile);
     268      }
     269      catch (Throwable ex)
     270      {
     271        log.error("Could not unregister extensions from file: " + xtFile, ex);
     272      }
     273      finally
     274      {
     275        wFile.close(); // Important! release the write lock
     276      }
     277    }
     278   
     279   
     280    // Second loop -- register extension points
    201281    log.info("Registering all loaded extension points");
    202282    for (FileData data : allData)
     
    215295      {
    216296        wFile.open();
    217         int num = registerExtensionPoints(data, registry);
     297        int num = registerExtensionPoints(data, registry, forceUpdate || xtFile.wasModified());
    218298        if (num > 0 && results != null)
    219299        {
     
    239319    }
    240320   
    241     // Second loop -- register extensions
     321    // Third loop -- register extensions
    242322    log.info("Registering all loaded extensions");
    243323    for (FileData data : allData)
     
    256336      {
    257337        wFile.open();
    258         int num = registerExtensions(data, registry);
     338        int num = registerExtensions(data, registry, forceUpdate || xtFile.wasModified());
    259339        if (num > 0 && results != null)
    260340        {
     
    308388    return numRegistered;
    309389  }
    310 
    311  
    312   private int registerExtensionPoints(FileData data, Registry registry)
     390 
     391  /**
     392    Get the number of extensions + extension points that
     393    was unregistered.
     394  */
     395  public int getNumUnregistered()
     396  {
     397    return numUnregistered;
     398  }
     399
     400 
     401  private int registerExtensionPoints(FileData data, Registry registry, boolean forceUpdate)
    313402  {
    314403    int numRegistered = 0;
    315404    for (ExtensionPoint<Action> ep : data.extensionPoints)
    316405    {
    317       //if (!registry.extensionPointIsRegistered(ep.getId()))
     406      if (forceUpdate || !registry.extensionPointIsRegistered(ep.getId()))
    318407      {
    319408        ExtensionPointKey key = new ExtensionPointKey(ep);
     
    328417  }
    329418 
    330   private int registerExtensions(FileData data, Registry registry)
     419  /**
     420    Unregister the given extension point if it is not included in the new
     421    file data information. In all cases, factory metadata must be removed,
     422    since we leak memory otherwise (new factory instances are always created
     423    when scanning a modified file).
     424    @return TRUE if the extension point is not going to be registered again
     425  */
     426  private boolean unregisterExtensionPoint(FileData data, ExtensionPoint ep, Registry registry)
     427  {
     428    unregisterFactory(data, ep.getRendererFactory());
     429    unregisterFactory(data, ep.getErrorHandlerFactory());
     430    ExtensionPointKey key = new ExtensionPointKey(ep);
     431    data.writeableFile.unregisterObject(key);
     432    if (!data.extensionPoints.contains(ep))
     433    {
     434      registry.unregisterExtensionPoint(ep.getId());
     435      return true;
     436    }
     437    return false;
     438  }
     439 
     440  private int registerExtensions(FileData data, Registry registry, boolean forceUpdate)
    331441  {
    332442    int numRegistered = 0;
    333443    for (Extension<Action> ext : data.extensions)
    334444    {
    335       //if (!registry.extensionIsRegistered(ext.getId()))
     445      if (forceUpdate || !registry.extensionIsRegistered(ext.getId()))
    336446      {
    337447        ExtensionKey key = new ExtensionKey(ext);
     
    345455    return numRegistered;
    346456  }
     457
     458  /**
     459    Unregister the given extension if it is not included in the new
     460    file data information. In all cases, factory metadata must be removed,
     461    since we leak memory otherwise (new factory instances are always created
     462    when scanning a modified file).
     463    @return TRUE if the extension point is not going to be registered again
     464  */
     465  private boolean unregisterExtension(FileData data, Extension ext, Registry registry)
     466  {
     467    unregisterFactory(data, ext.getRendererFactory());
     468    unregisterFactory(data, ext.getActionFactory());
     469    ExtensionKey key = new ExtensionKey(ext);
     470    data.writeableFile.unregisterObject(key);
     471    if (!data.extensions.contains(ext))
     472    {
     473      registry.unregisterExtension(ext.getId());
     474      return true;
     475    }
     476    return false;
     477  }
    347478 
    348479  /**
     
    360491  }
    361492
     493  private void unregisterFactory(FileData data, Object factory)
     494  {
     495    if (factory == null) return;
     496    data.writeableFile.unregisterMetadata(new FactoryParametersKey(factory));
     497  }
     498 
    362499  /**
    363500    Keep track of the extension points and extensions found in a file.
Note: See TracChangeset for help on using the changeset viewer.