Changeset 4096


Ignore:
Timestamp:
Jan 22, 2008, 2:22:03 PM (14 years ago)
Author:
Nicklas Nordborg
Message:

Fixes #902: Support for multiple configuration files for raw data types and extended properties

Location:
trunk
Files:
4 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/build.xml

    r4095 r4096  
    133133  <!-- pattern for configuration files use by copy.config -->
    134134  <patternset id="config.files">
    135     <include name="*.*" />
     135    <include name="**/*.*" />
    136136    <exclude name="web.xml" />
    137137    <exclude name="readme.txt" />
  • trunk/doc/src/docbook/appendix/extended_properties.xml

    r3996 r4096  
    123123  </itemizedlist>
    124124
     125  <bridgehead>Multiple configuration files</bridgehead>
     126  <para>
     127    Starting with BASE 2.6 it is possible to use multiple configuration
     128    files for extended properties. This is useful only if you want to add
     129    new columns. To remove or change existing columns you still have
     130    to modify the original extended properties file. It is rather simple
     131    to use this feature. Create a new subdirectory with the name
     132    <filename>extended-properties</filename> in the same directory as
     133    the <filename>extended-properties.xml</filename>. In this directory
     134    you can put additional extended property files. They should have the
     135    same format as the default file.
     136  </para>
     137 
     138  <tip>
     139    We recommend that you don't modify the default <filename>extended-properties.xml</filename>
     140    file at all (unless you want to remove some of the columns). This will make it
     141    easier when upgrading BASE since you don't have to worry about losing
     142    your own changes.
     143  </tip>
    125144
    126145  <bridgehead>Format of the extended-properties.xml file</bridgehead>
  • trunk/src/core/net/sf/basedb/core/Application.java

    r4078 r4096  
    2929import net.sf.basedb.core.data.SchemaVersionData;
    3030import net.sf.basedb.core.authentication.Authenticator;
     31import net.sf.basedb.util.FileUtil;
     32import net.sf.basedb.util.RegexpFileFilter;
    3133import net.sf.basedb.util.timer.Scheduler;
    3234
     35import java.util.ArrayList;
    3336import java.util.Calendar;
    3437import java.util.GregorianCalendar;
    3538import java.util.HashSet;
     39import java.util.List;
    3640import java.util.Map;
    3741import java.util.HashMap;
     
    394398      log.info("db.queries = " + queryFile);
    395399     
    396       extendedPropertiesFile = Config.getString("db.extended-properties");
     400      extendedPropertiesFile = Config.getString("db.extended-properties", "/extended-properties.xml");
    397401      log.info("db.extended-properties = " + extendedPropertiesFile);
    398402     
    399       rawDataTypesFile = Config.getString("db.raw-data-types");
     403      rawDataTypesFile = Config.getString("db.raw-data-types", "/raw-data-types.xml");
    400404      log.info("db.raw-data-types = " + rawDataTypesFile);
    401405     
     
    707711    @see ExtendedProperties
    708712  */
    709   static String getExtendedPropertiesFile()
    710   {
    711     return extendedPropertiesFile;
     713  static List<String> getExtendedPropertyFiles()
     714  {
     715    List<String> files = new ArrayList<String>();
     716    // Main extended properties file
     717    files.add(extendedPropertiesFile); 
     718    // Scan extended-properties directory
     719    String configDir = Config.getConfigDirectory().getAbsolutePath();
     720    java.io.File propConfigDir = new java.io.File(configDir, "extended-properties");
     721    if (propConfigDir.exists())
     722    {
     723      // Find all XML files
     724      List<java.io.File> xmlFiles = FileUtil.findFiles(propConfigDir,
     725        new RegexpFileFilter(Pattern.compile(".*\\.xml"), null));
     726      if (xmlFiles != null)
     727      {
     728        for (java.io.File xmlFile : xmlFiles)
     729        {
     730          String path = xmlFile.getAbsolutePath().replace(configDir, "");
     731          files.add(path);
     732        }
     733      }
     734    }
     735    return files;
    712736  }
    713737
     
    716740    @see RawDataTypes
    717741  */
    718   static String getRawDataTypesFile()
    719   {
    720     return rawDataTypesFile;
     742  static List<String> getRawDataTypeFiles()
     743  {
     744    List<String> files = new ArrayList<String>();
     745    // Main raw data types file
     746    files.add(rawDataTypesFile); 
     747    // Scan raw-data-types directory
     748    String configDir = Config.getConfigDirectory().getAbsolutePath();
     749    java.io.File rawConfigDir = new java.io.File(configDir, "raw-data-types");
     750    if (rawConfigDir.exists())
     751    {
     752      // Find all XML files
     753      List<java.io.File> xmlFiles = FileUtil.findFiles(rawConfigDir, new RegexpFileFilter(Pattern.compile(".*\\.xml"), null));
     754      if (xmlFiles != null)
     755      {
     756        for (java.io.File xmlFile : xmlFiles)
     757        {
     758          String path = xmlFile.getAbsolutePath().replace(configDir, "");
     759          files.add(path);
     760        }
     761      }
     762    }
     763    return files;
    721764  }
    722765
  • trunk/src/core/net/sf/basedb/core/Config.java

    r4030 r4096  
    2727import java.util.Properties;
    2828import java.io.InputStream;
    29 import java.io.IOException;
    3029import java.net.URL;
    3130
     
    5049  private static boolean isInitialised = false;
    5150 
     51  private static java.io.File configDir = null;
     52 
    5253  /**
    5354    Loads the settings from the configuration file.
     
    6263    {
    6364      URL baseConfig = Config.class.getResource("/base.config");
     65      configDir = new java.io.File(baseConfig.toURI()).getParentFile();
    6466      InputStream is = baseConfig == null ? null : baseConfig.openStream();
    6567      if (is == null)
     
    7173      is.close();
    7274    }
    73     catch (IOException ex)
     75    catch (Exception ex)
    7476    {
    7577      config = null;
     
    8688    isInitialised = false;
    8789    config = null;
     90    configDir = null;
     91  }
     92 
     93  /**
     94    Get the directory where the BASE configuration files are located.
     95    @return The directory as a <code>java.io.File</code> object
     96    @since 2.6
     97  */
     98  public static java.io.File getConfigDirectory()
     99  {
     100    return configDir;
    88101  }
    89102 
  • trunk/src/core/net/sf/basedb/core/ExtendedProperties.java

    r3679 r4096  
    4444/**
    4545  This class is used for reading XML files with information
    46   about extended properties. The file should be located at the path
    47   returned by {@link Application#getExtendedPropertiesFile()
    48   Application.getExtendedPropertiesFile}.
     46  about extended properties. All files returned by {@link Application#getExtendedPropertyFiles()}
     47  are parsed.
    4948
    5049  @see net.sf.basedb.core.data.ExtendableData
     
    7372    that class. The list holds {@link ExtendedProperty} objects.
    7473  */
    75   private static Map<String, List<ExtendedProperty>> properties = null;
     74  private static Map<String, List<ExtendedProperty>> allProperties = null;
    7675
    7776  /**
     
    9190    if (isInitialised) return;
    9291    classes = new ArrayList<String>();
    93     properties = new HashMap<String, List<ExtendedProperty>>();
     92    allProperties = new HashMap<String, List<ExtendedProperty>>();
    9493    loadExtendedPropertiesFile();
    9594    isInitialised = true;
     
    103102    if (classes != null) classes.clear();
    104103    classes = null;
    105     if (properties != null) properties.clear();
    106     properties = null;
     104    if (allProperties != null) allProperties.clear();
     105    allProperties = null;
    107106    isInitialised = false;
    108107  }
     
    111110    Load and parse the file with predefined queries.
    112111    This method will populate the {@link #classes} and
    113     {@link #properties} variables.
     112    {@link #allProperties} variables.
    114113  */
    115114  private static synchronized void loadExtendedPropertiesFile()
    116115    throws BaseException
    117116  {
    118     String propertiesFile = Application.getExtendedPropertiesFile();
    119     if (propertiesFile == null) return;
     117    List<String> files = Application.getExtendedPropertyFiles();
    120118    try
    121119    {
    122       Document dom = XMLUtil.getValidatedXml(ExtendedProperties.class.getResource(propertiesFile), dtdFile);
    123       loadClasses(dom);
    124       log.info("Loaded extended properties from file: " + propertiesFile);
     120      Set<String> usedNames = new HashSet<String>();
     121      for (String xmlFile : files)
     122      {
     123        Document dom = XMLUtil.getValidatedXml(ExtendedProperties.class.getResource(xmlFile), dtdFile);
     124        loadClasses(usedNames, dom, xmlFile);
     125        log.info("Loaded extended properties from file: " + xmlFile);
     126      }
    125127    }
    126128    catch (Exception ex)
     
    154156      className = className.substring(index+1);
    155157    }
    156     return properties.containsKey(className);
     158    return allProperties.containsKey(className);
    157159  }
    158160
     
    172174      className = className.substring(index+1);
    173175    }
    174     List<ExtendedProperty> l = (List<ExtendedProperty>)properties.get(className);
     176    List<ExtendedProperty> l = (List<ExtendedProperty>)allProperties.get(className);
    175177    return l;
    176178  }
     
    181183  */
    182184  @SuppressWarnings("unchecked")
    183   private static void loadClasses(Document dom)
     185  private static void loadClasses(Set<String> usedNames, Document dom, String xmlFile)
    184186  {
    185187    List<Element> classTags = (List<Element>)dom.getRootElement().getChildren("class");
     
    187189    {
    188190      String className = el.getAttributeValue("name");
    189       classes.add(className);
    190       properties.put(className, loadProperties(el));
     191      if (!classes.contains(className))
     192      {
     193        classes.add(className);
     194        allProperties.put(className, new ArrayList<ExtendedProperty>());
     195      }
     196      loadProperties(usedNames, el, xmlFile);
    191197    }
    192198  }
     
    194200  /**
    195201    Load the properties for the specified class node and
    196     put the list in the {@link #properties} variable.
     202    put the list in the {@link #allProperties} variable.
    197203  */
    198204  @SuppressWarnings("unchecked")
    199   private static List<ExtendedProperty> loadProperties(Element classElement)
    200   {
    201     List<ExtendedProperty> properties = new ArrayList<ExtendedProperty>();
     205  private static void loadProperties(Set<String> usedNames, Element classElement, String xmlFile)
     206  {
     207    String className = classElement.getAttributeValue("name");
     208    List<ExtendedProperty> properties = allProperties.get(className);
    202209    List<Element> children = (List<Element>)classElement.getChildren("property");
    203210    DbEngine engine = HibernateUtil.getDbEngine();
    204     String className = classElement.getAttributeValue("name");
    205     Set<String> usedNames = new HashSet<String>();
    206211    for (Element property : children)
    207212    {
     
    209214      if (!ExtendedProperty.isValidName(name))
    210215      {
    211         throw new InvalidDataException("Invalid property for class " +
    212           className + ": name=" + name);
     216        throw new InvalidDataException("Invalid property for class '" +
     217          className + "' in file '" + xmlFile + "': name=" + name);
    213218      }
    214219      if (usedNames.contains("name:" + name))
    215220      {
    216         throw new InvalidDataException("Duplicate property for class " +
    217           className + ": name=" + name);
     221        throw new InvalidDataException("Duplicate property for class '" +
     222          className + "' in file '" + xmlFile + "': name=" + name);
    218223      }
    219224      usedNames.add("name:" + name);
     
    223228      if (!engine.isValidColumnName(column))
    224229      {
    225         throw new InvalidDataException("Invalid column for property " +
    226           className + "[" + name + "]: column=" + column);
     230        throw new InvalidDataException("Invalid column for property '" +
     231          className + "[" + name + "]' in file '" + xmlFile + "': column=" + column);
    227232      }
    228233      if (usedNames.contains("column:" + column))
    229234      {
    230         throw new InvalidDataException("Duplicate column for property " +
    231           className + "[" + name + "]: column=" + column);
     235        throw new InvalidDataException("Duplicate column for property '" +
     236          className + "[" + name + "]' in file '" + xmlFile + "': column=" + column);
    232237      }
    233238      usedNames.add("column:" + column);
     
    266271          if (url == null)
    267272          {
    268             throw new InvalidDataException("Missing url for property link " +
    269               className + "[" + name + "]: regexp=" + regexp);
     273            throw new InvalidDataException("Missing url for property link '" +
     274              className + "[" + name + "]' in file '" + xmlFile + "': regexp=" + regexp);
    270275          }
    271276          try
     
    275280          catch (PatternSyntaxException ex)
    276281          {
    277             throw new InvalidDataException("Invalid regexp for property link " +
    278               className + "[" + name + "]: regexp=" + regexp, ex);
     282            throw new InvalidDataException("Invalid regexp for property link '" +
     283              className + "[" + name + "]' in file '" + xmlFile + "': regexp=" + regexp, ex);
    279284          }
    280285        }
     
    282287      properties.add(new ExtendedProperty(name, title, description, column, type, length, nullable, insertable, updateable, averageMethod, epLinks));
    283288    }
    284     return properties;
    285289  }
    286290}
  • trunk/src/core/net/sf/basedb/core/RawDataTypes.java

    r3867 r4096  
    4949/**
    5050  This class is used for reading the XML configuration file with
    51   information about raw data types. The file should be located at the path
    52   returned by {@link Application#getRawDataTypesFile()}.
     51  information about raw data types. All files returned by {@link
     52  Application#getRawDataTypeFiles()} are parsed.
    5353
    5454  @author Nicklas
     
    6363  */
    6464  private static final org.apache.log4j.Logger log =
    65     org.apache.log4j.LogManager.getLogger("net.sf.basedb.core");
     65    org.apache.log4j.LogManager.getLogger("net.sf.basedb.core.RawDataTypes");
    6666
    6767  /**
     
    7979    The DTD which is used to validate the XML file.
    8080  */
    81   private static final URL dtdFile = RawDataTypes.class.getResource("/net/sf/basedb/core/dtd/raw-data-types.dtd");
     81  private static final URL dtdFile =
     82    RawDataTypes.class.getResource("/net/sf/basedb/core/dtd/raw-data-types.dtd");
    8283 
    8384  private static boolean isInitialised = false;
     
    164165    throws BaseException
    165166  {
    166     String xmlFile = Application.getRawDataTypesFile();
    167     if (xmlFile == null) xmlFile = "/raw-data-types.xml";
     167    List<String> files = Application.getRawDataTypeFiles();
    168168    try
    169169    {
    170       Document dom = XMLUtil.getValidatedXml(RawDataTypes.class.getResource(xmlFile), dtdFile);
    171       loadRawDataTypes(dom);
    172       log.info("Loaded raw data types from file: " + xmlFile);
     170      for (String xmlFile : files)
     171      {
     172        Document dom = XMLUtil.getValidatedXml(RawDataTypes.class.getResource(xmlFile), dtdFile);
     173        loadRawDataTypes(dom, xmlFile);
     174        log.info("Loaded raw data types from file: " + xmlFile);
     175      }
    173176    }
    174177    catch (Exception ex)
     
    287290  */
    288291  @SuppressWarnings({"unchecked"})
    289   private static void loadRawDataTypes(Document dom)
     292  private static void loadRawDataTypes(Document dom, String xmlFile)
    290293  {
    291294    List<Element> rawDataTypeTags = dom.getRootElement().getChildren("raw-data-type");
     
    303306      if (!ExtendedProperty.isValidName(id))
    304307      {
    305         throw new InvalidDataException("Invalid id for raw data type: " + id);
     308        throw new InvalidDataException("Invalid id for raw data type '" +
     309          id + "' in file '" + xmlFile + "'");
     310      }
     311      if (usedNames.contains("id:" + id))
     312      {
     313        throw new InvalidDataException("Duplicate id for raw data type '" +
     314            id +"' in file '" + xmlFile);
    306315      }
    307316      if (usedNames.contains("name:" + name))
    308317      {
    309         throw new InvalidDataException("Duplicate name for raw data type " +
    310           id +": name=" + name);
    311       }
     318        throw new InvalidDataException("Duplicate name for raw data type '" +
     319            id +"' in file '" + xmlFile + "': name=" + name);
     320      }
     321      usedNames.add("id:" + id);
    312322      usedNames.add("name:" + name);
    313323      if ("database".equals(storage))
     
    315325        if (!engine.isValidTableName(table))
    316326        {
    317           throw new InvalidDataException("Invalid table for raw data type " +
    318               id +": table=" + table);
     327          throw new InvalidDataException("Invalid table for raw data type '" +
     328              id +"' in file '" + xmlFile + "': table=" + table);
    319329        }
    320330        if (usedNames.contains("table:" + table))
    321331        {
    322           throw new InvalidDataException("Duplicate table for raw data type " +
    323             id +": table=" + table);
     332          throw new InvalidDataException("Duplicate table for raw data type '" +
     333              id +"' in file '" + xmlFile + "': table=" + table);
    324334        }
    325335        usedNames.add("table:" + table);
     
    329339        throw new ConfigurationException("Attribute storage='" + storage +
    330340          "' is no longer supported. Please remove declaration for <rawdatatype id='" + id +
    331           "'> from " + Application.getRawDataTypesFile());
     341          "'> from file '" + xmlFile + "'");
    332342      }
    333343      if (channels <= 0)
    334344      {
    335         throw new InvalidDataException("Number of channels must be > 0 for raw data type "+
    336             id + ": channels=" + channels);
    337       }
    338       List<RawDataProperty> properties = loadProperties(el, channels);
    339       List<IntensityFormula> formulas = loadIntensityFormulas(el, channels);
     345        throw new InvalidDataException("Number of channels must be > 0 for raw data type '"+
     346            id +"' in file '" + xmlFile + "': channels=" + channels);
     347      }
     348      List<RawDataProperty> properties = loadProperties(el, channels, xmlFile);
     349      List<IntensityFormula> formulas = loadIntensityFormulas(el, channels, xmlFile);
    340350      RawDataType rdt = new RawDataType(id, name, description, channels,
    341351          table, properties, formulas);
     
    350360  */
    351361  @SuppressWarnings({"unchecked"})
    352   private static List<RawDataProperty> loadProperties(Element rawDataTypeElement, int channels)
     362  private static List<RawDataProperty> loadProperties(Element rawDataTypeElement, int channels, String xmlFile)
    353363  {
    354364    List<RawDataProperty> properties = new ArrayList<RawDataProperty>();
     
    362372      if (!ExtendedProperty.isValidName(name))
    363373      {
    364         throw new InvalidDataException("Invalid property for raw data type " +
    365           rawDataType + ": name=" + name);
     374        throw new InvalidDataException("Invalid property for raw data type '" +
     375          rawDataType + "' in file '" + xmlFile + "': name=" + name);
    366376      }
    367377      if (usedNames.contains("name:" + name))
    368378      {
    369         throw new InvalidDataException("Duplicate property for raw data type " +
    370           rawDataType + ": name=" + name);
     379        throw new InvalidDataException("Duplicate property for raw data type '" +
     380          rawDataType + "' in file '" + xmlFile + "': name=" + name);
    371381      }
    372382      usedNames.add("name:" + name);
     
    376386      if (!engine.isValidColumnName(column))
    377387      {
    378         throw new InvalidDataException("Invalid column for property " +
    379           rawDataType + "[" + name + "]: column=" + column);
     388        throw new InvalidDataException("Invalid column for raw data property '" +
     389          rawDataType + "[" + name + "]' in file '" + xmlFile + "': column=" + column);
    380390      }
    381391      if (usedNames.contains("column:" + column))
    382392      {
    383         throw new InvalidDataException("Duplicate column for property " +
    384           rawDataType + "[" + name + "]: column=" + column);
     393        throw new InvalidDataException("Duplicate column for raw data property '" +
     394          rawDataType + "[" + name + "]' in file '" + xmlFile + "': column=" + column);
    385395      }
    386396      usedNames.add("column:" + column);
     
    408418      if (channel < 0 || channel > channels)
    409419      {
    410         throw new InvalidDataException("Channel for property " + rawDataType+ "[" + name + "]"
    411             +  " must be >= 0 and < " + channels + ": channel=" + channel);
     420        throw new InvalidDataException("Channel for raw data property '" +
     421            rawDataType+ "[" + name + "]' in file '" + xmlFile + "'" +
     422            " must be >= 0 and < " + channels + ": channel=" + channel);
    412423      }
    413424      properties.add(new RawDataProperty(name, title, description, column, type, length, nullable, averageMethod, channel));
     
    421432  */
    422433  @SuppressWarnings({"unchecked"})
    423   private static List<IntensityFormula> loadIntensityFormulas(Element rawDataTypeElement, int channels)
     434  private static List<IntensityFormula> loadIntensityFormulas(Element rawDataTypeElement, int channels, String xmlFile)
    424435  {
    425436    List<IntensityFormula> formulas = new ArrayList<IntensityFormula>();
     
    432443      if (!ExtendedProperty.isValidName(name))
    433444      {
    434         throw new InvalidDataException("Invalid intensity formula for raw data type " +
    435           rawDataType + ": name=" + name);
     445        throw new InvalidDataException("Invalid intensity formula for raw data type '" +
     446          rawDataType + "' in file '" + xmlFile + "': name=" + name);
    436447      }
    437448      if (usedNames.contains("name:" + name))
    438449      {
    439         throw new InvalidDataException("Duplicate intensity formula for raw data type " +
    440           rawDataType + ": name=" + name);
     450        throw new InvalidDataException("Duplicate intensity formula for raw data type '" +
     451          rawDataType + "' in file '" + xmlFile + "': name=" + name);
    441452      }
    442453      usedNames.add("name:" + name);
     
    451462        if (channel <= 0 || channel > channels)
    452463        {
    453           throw new InvalidDataException("Channel for intensity formula " +
    454               rawDataType+ "[" + name + "]"
    455               " must be > 0 and < " + channels + ": channel=" + channel);
     464          throw new InvalidDataException("Channel for intensity formula '" +
     465              rawDataType+ "[" + name + "]' in file '" + xmlFile + "'"  +
     466              " must be > 0 and < " + channels + ": channel=" + channel);
    456467        }
    457468        if (expressions[channel-1] != null)
    458469        {
    459           throw new InvalidDataException("Duplicate expression for intensity formula " +
    460             rawDataType + "[" + name + "]: channel=" + channel);
     470          throw new InvalidDataException("Duplicate expression for intensity formula '" +
     471            rawDataType + "[" + name + "]' in file '" + xmlFile + "': channel=" + channel);
    461472        }
    462473        if (exp == null)
    463474        {
    464           throw new InvalidDataException("Missing expression for formula " +
    465             rawDataType + "[" + name + "]: channel=" + channel);
     475          throw new InvalidDataException("Missing expression for formula '" +
     476            rawDataType + "[" + name + "]' in file '" + xmlFile + "': channel=" + channel);
    466477        }
    467478        expressions[channel-1] = exp;
Note: See TracChangeset for help on using the changeset viewer.