Changeset 3600
- Timestamp:
- Jul 25, 2007, 1:14:48 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/doc/src/docbook/appendix/incompatible.xml
r3518 r3600 79 79 old behaviour use <code>ch(1) == 'NULL'</code>. 80 80 </para> 81 82 <bridgehead>Extended properties and raw data types</bridgehead> 83 <para> 84 We have added validation code to check for invalid values. If you 85 have modified the <filename>extended-properties.xml</filename> 86 or the <filename>raw-data-types.xml</filename> file and they 87 contain invalid values, you may not be able to start BASE until 88 they are fixed. The validation is rather strict and things that may 89 have worked before (because you were lucky or the because the database 90 has been forgiving) may no longer work. Here is an overview of the most 91 important validation rules: 92 </para> 93 94 <itemizedlist> 95 <listitem> 96 <para> 97 Names and identifiers for extended properties and raw data type 98 can only contain letters, digits and underscores. They must not 99 start with a digit. 100 </para> 101 </listitem> 102 <listitem> 103 <para> 104 Names of database tables and columns can only contain letters, 105 digits and underscores. They must not start with a digit. 106 </para> 107 </listitem> 108 <listitem> 109 <para> 110 There mustn't be any duplicate tables, columns, properties, etc. 111 for a given context. For example, no duplicate tables in the 112 database, no duplicate columns in a table, and no duplicate 113 properties for a raw data type. 114 </para> 115 </listitem> 116 </itemizedlist> 117 81 118 </sect1> 82 119 -
trunk/src/core/net/sf/basedb/core/Application.java
r3502 r3600 392 392 393 393 // Initialise other utility classes 394 HibernateUtil.init1(); 394 395 ExtendedProperties.init(); 395 396 RawDataTypes.init(); 396 397 RawDataUtil.init(); 397 HibernateUtil.init ();398 HibernateUtil.init2(); 398 399 QueryRuntimeFilterFactory.init(); 399 400 PredefinedQuery.init(); -
trunk/src/core/net/sf/basedb/core/ExtendedProperties.java
r3562 r3600 24 24 package net.sf.basedb.core; 25 25 26 import net.sf.basedb.core.dbengine.DbEngine; 27 import net.sf.basedb.util.Values; 26 28 import net.sf.basedb.util.XMLUtil; 27 29 30 import java.util.HashSet; 28 31 import java.util.List; 29 32 import java.util.ArrayList; 30 33 import java.util.Map; 31 34 import java.util.HashMap; 35 import java.util.Set; 36 import java.util.regex.PatternSyntaxException; 32 37 import java.net.URL; 33 38 … … 194 199 List<ExtendedProperty> properties = new ArrayList<ExtendedProperty>(); 195 200 List<Element> children = (List<Element>)classElement.getChildren("property"); 201 DbEngine engine = HibernateUtil.getDbEngine(); 202 String className = classElement.getAttributeValue("name"); 203 Set<String> usedNames = new HashSet<String>(); 196 204 for (Element property : children) 197 205 { 198 String name = property.getAttributeValue("name"); 199 String title = property.getAttributeValue("title"); 206 String name = Values.getStringOrNull(property.getAttributeValue("name")); 207 if (!ExtendedProperty.isValidName(name)) 208 { 209 throw new InvalidDataException("Invalid property for class " + 210 className + ": name=" + name); 211 } 212 if (usedNames.contains("name:" + name)) 213 { 214 throw new InvalidDataException("Duplicate property for class " + 215 className + ": name=" + name); 216 } 217 usedNames.add("name:" + name); 218 String title = Values.getStringOrNull(property.getAttributeValue("title")); 200 219 if (title == null) title = name; 220 String column = Values.getStringOrNull(property.getAttributeValue("column")); 221 if (!engine.isValidColumnName(column)) 222 { 223 throw new InvalidDataException("Invalid column for property " + 224 className + "[" + name + "]: column=" + column); 225 } 226 if (usedNames.contains("column:" + column)) 227 { 228 throw new InvalidDataException("Duplicate column for property " + 229 className + "[" + name + "]: column=" + column); 230 } 231 usedNames.add("column:" + column); 232 String description = Values.getStringOrNull(property.getAttributeValue("description")); 233 int length = XMLUtil.getIntAttribute(property, "length", 255); 201 234 Type type = Type.fromValue(property.getAttributeValue("type")); 202 String column = property.getAttributeValue("column");203 String description = property.getAttributeValue("description");204 int length = XMLUtil.getIntAttribute(property, "length", 255);205 235 if (type == Type.STRING && length > 255) type = Type.TEXT; 206 236 boolean nullable = XMLUtil.getBooleanAttribute(property, "null", true); … … 230 260 for (Element link : links) 231 261 { 232 String regexp = link.getAttributeValue("regexp"); 233 String url = link.getAttributeValue("url"); 234 epLinks.add(new ExtendedPropertyLinker(regexp, url)); 262 String regexp = Values.getStringOrNull(link.getAttributeValue("regexp")); 263 String url = Values.getStringOrNull(link.getAttributeValue("url")); 264 if (url == null) 265 { 266 throw new InvalidDataException("Missing url for property link " + 267 className + "[" + name + "]: regexp=" + regexp); 268 } 269 try 270 { 271 epLinks.add(new ExtendedPropertyLinker(regexp, url)); 272 } 273 catch (PatternSyntaxException ex) 274 { 275 throw new InvalidDataException("Invalid regexp for property link " + 276 className + "[" + name + "]: regexp=" + regexp, ex); 277 } 235 278 } 236 279 } -
trunk/src/core/net/sf/basedb/core/ExtendedProperty.java
r3590 r3600 26 26 import java.text.NumberFormat; 27 27 import java.util.List; 28 import java.util.regex.Pattern; 29 28 30 29 31 /** … … 37 39 public class ExtendedProperty 38 40 { 41 42 /** 43 A regexp checking for invalid characters. 44 */ 45 private static final Pattern valid = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*"); 46 47 /** 48 Check that the name only contains a-zA-Z0-9_ and starts with 49 a letter or underscore. 50 @since 2.4 51 */ 52 public static boolean isValidName(String name) 53 { 54 return name == null ? false : valid.matcher(name).matches(); 55 } 56 39 57 private final String name; 40 58 private final Type type; -
trunk/src/core/net/sf/basedb/core/HibernateUtil.java
r3597 r3600 138 138 139 139 /** 140 Initialise this class. This is done at startup time by the 141 {@link Application#start()} method. Initialising means that we 140 First step of initialising this class. This is done at startup time by the 141 {@link Application#start()} method. In this step we load configuration 142 settings from the 'base.config' and 'hibernate.cfg.xml' files and 143 create the Dialect and DbEngine objects. 144 145 Initialising means that we 142 146 load the configuration from the properties and the xml file, 143 147 read all mapping files, generate additional mappings for the … … 145 149 used by {@link Query} implementation. 146 150 */ 147 static synchronized void init ()151 static synchronized void init1() 148 152 throws BaseException 149 153 { … … 155 159 cfg = new Configuration(); 156 160 setConfigurationProperties(cfg); 161 dialect = Dialect.getDialect(cfg.getProperties()); 162 dbEngine = EngineFactory.createEngine(dialect); 163 } 164 catch (HibernateException ex) 165 { 166 throw new BaseException(ex); 167 } 168 } 169 170 /** 171 Second step of initialising this class. This is done at startup time by the 172 {@link Application#start()} method. In this step we read all mapping files, 173 generate additional mappings for the {@link ExtendableData} items and raw data, 174 and generate filters used by {@link Query} implementation. 175 */ 176 static synchronized void init2() 177 throws BaseException 178 { 179 // Return if we have already been initialised 180 if (isInitialised) return; 181 182 try 183 { 157 184 addStaticMappings(cfg); 158 185 addExtendedPropertiesMappings(cfg); … … 161 188 cfg.configure(); 162 189 sf = cfg.buildSessionFactory(); 163 dialect = Dialect.getDialect(cfg.getProperties());164 dbEngine = EngineFactory.createEngine(dialect);165 190 } 166 191 catch (HibernateException ex) … … 170 195 isInitialised = true; 171 196 } 172 197 173 198 /** 174 199 Unload all settings. -
trunk/src/core/net/sf/basedb/core/RawDataTypes.java
r3562 r3600 24 24 package net.sf.basedb.core; 25 25 26 import net.sf.basedb.core.dbengine.DbEngine; 27 import net.sf.basedb.util.Values; 26 28 import net.sf.basedb.util.XMLUtil; 27 29 30 import java.util.HashSet; 28 31 import java.util.List; 29 32 import java.util.ArrayList; 30 33 import java.util.Map; 34 import java.util.Set; 31 35 import java.util.TreeMap; 32 36 import java.net.URL; … … 141 145 { 142 146 List<Element> rawDataTypeTags = dom.getRootElement().getChildren("raw-data-type"); 147 DbEngine engine = HibernateUtil.getDbEngine(); 148 Set<String> usedNames = new HashSet<String>(); 143 149 for (Element el : rawDataTypeTags) 144 150 { 145 String id = el.getAttributeValue("id");146 String name = el.getAttributeValue("name");147 String description = el.getAttributeValue("description");151 String id = Values.getStringOrNull(el.getAttributeValue("id")); 152 String name = Values.getStringOrNull(el.getAttributeValue("name")); 153 String description = Values.getStringOrNull(el.getAttributeValue("description")); 148 154 String storage = el.getAttributeValue("storage"); 149 String table = el.getAttributeValue("table");155 String table = Values.getStringOrNull(el.getAttributeValue("table")); 150 156 int channels = XMLUtil.getIntAttribute(el, "channels", 2); 151 List<RawDataProperty> properties = loadProperties(el); 157 158 if (!ExtendedProperty.isValidName(id)) 159 { 160 throw new InvalidDataException("Invalid id for raw data type: " + id); 161 } 162 if (usedNames.contains("name:" + name)) 163 { 164 throw new InvalidDataException("Duplicate name for raw data type " + 165 id +": name=" + name); 166 } 167 usedNames.add("name:" + name); 168 if ("database".equals(storage)) 169 { 170 if (!engine.isValidTableName(table)) 171 { 172 throw new InvalidDataException("Invalid table for raw data type " + 173 id +": table=" + table); 174 } 175 if (usedNames.contains("table:" + table)) 176 { 177 throw new InvalidDataException("Duplicate table for raw data type " + 178 id +": table=" + table); 179 } 180 usedNames.add("table:" + table); 181 } 182 if (channels <= 0) 183 { 184 throw new InvalidDataException("Number of channels must be > 0 for raw data type "+ 185 id + ": channels=" + channels); 186 } 187 List<RawDataProperty> properties = loadProperties(el, channels); 152 188 List<IntensityFormula> formulas = loadIntensityFormulas(el, channels); 153 189 RawDataType rdt = new RawDataType(id, name, description, channels, storage, table, properties, formulas); … … 161 197 */ 162 198 @SuppressWarnings({"unchecked"}) 163 private static List<RawDataProperty> loadProperties(Element rawDataTypeElement )199 private static List<RawDataProperty> loadProperties(Element rawDataTypeElement, int channels) 164 200 { 165 201 List<RawDataProperty> properties = new ArrayList<RawDataProperty>(); 166 202 List<Element> children = rawDataTypeElement.getChildren("property"); 203 String rawDataType = rawDataTypeElement.getAttributeValue("id"); 204 DbEngine engine = HibernateUtil.getDbEngine(); 205 Set<String> usedNames = new HashSet<String>(); 167 206 for (Element property : children) 168 207 { 169 String name = property.getAttributeValue("name"); 170 String title = property.getAttributeValue("title"); 208 String name = Values.getStringOrNull(property.getAttributeValue("name")); 209 if (!ExtendedProperty.isValidName(name)) 210 { 211 throw new InvalidDataException("Invalid property for raw data type " + 212 rawDataType + ": name=" + name); 213 } 214 if (usedNames.contains("name:" + name)) 215 { 216 throw new InvalidDataException("Duplicate property for raw data type " + 217 rawDataType + ": name=" + name); 218 } 219 usedNames.add("name:" + name); 220 String title = Values.getStringOrNull(property.getAttributeValue("title")); 171 221 if (title == null) title = name; 172 String column = property.getAttributeValue("column"); 173 String description = property.getAttributeValue("description"); 222 String column = Values.getStringOrNull(property.getAttributeValue("column")); 223 if (!engine.isValidColumnName(column)) 224 { 225 throw new InvalidDataException("Invalid column for property " + 226 rawDataType + "[" + name + "]: column=" + column); 227 } 228 if (usedNames.contains("column:" + column)) 229 { 230 throw new InvalidDataException("Duplicate column for property " + 231 rawDataType + "[" + name + "]: column=" + column); 232 } 233 usedNames.add("column:" + column); 234 String description = Values.getStringOrNull(property.getAttributeValue("description")); 174 235 Type type = Type.fromValue(property.getAttributeValue("type")); 175 236 int length = XMLUtil.getIntAttribute(property, "length", 255); … … 192 253 } 193 254 int channel = XMLUtil.getIntAttribute(property, "channel", 0); 255 if (channel < 0 || channel > channels) 256 { 257 throw new InvalidDataException("Channel for property " + rawDataType+ "[" + name + "]" 258 + " must be >= 0 and < " + channels + ": channel=" + channel); 259 } 194 260 properties.add(new RawDataProperty(name, title, description, column, type, length, nullable, averageMethod, channel)); 195 261 } … … 206 272 List<IntensityFormula> formulas = new ArrayList<IntensityFormula>(); 207 273 List<Element> children = rawDataTypeElement.getChildren("intensity-formula"); 274 String rawDataType = rawDataTypeElement.getAttributeValue("id"); 275 Set<String> usedNames = new HashSet<String>(); 208 276 for (Element formula : children) 209 277 { 210 String name = formula.getAttributeValue("name"); 211 String title = formula.getAttributeValue("title"); 278 String name = Values.getStringOrNull(formula.getAttributeValue("name")); 279 if (!ExtendedProperty.isValidName(name)) 280 { 281 throw new InvalidDataException("Invalid intensity formula for raw data type " + 282 rawDataType + ": name=" + name); 283 } 284 if (usedNames.contains("name:" + name)) 285 { 286 throw new InvalidDataException("Duplicate intensity formula for raw data type " + 287 rawDataType + ": name=" + name); 288 } 289 usedNames.add("name:" + name); 290 String title = Values.getStringOrNull(formula.getAttributeValue("title")); 212 291 if (title == null) title = name; 213 String description = formula.getAttributeValue("description");292 String description = Values.getStringOrNull(formula.getAttributeValue("description")); 214 293 String[] expressions = new String[channels]; 215 294 for (Element expression : (List<Element>)formula.getChildren("formula")) 216 295 { 217 296 int channel = XMLUtil.getIntAttribute(expression, "channel", 0); 297 String exp = Values.getStringOrNull(expression.getAttributeValue("expression")); 218 298 if (channel <= 0 || channel > channels) 219 299 { 220 throw new BaseException("Invalid channel number for expression: "+expression); 300 throw new InvalidDataException("Channel for intensity formula " + 301 rawDataType+ "[" + name + "]" 302 + " must be > 0 and < " + channels + ": channel=" + channel); 221 303 } 222 304 if (expressions[channel-1] != null) 223 305 { 224 throw new BaseException("Expression for channel "+channel+" has already been defined: " +expression); 225 } 226 expressions[channel-1] = expression.getAttributeValue("expression"); 306 throw new InvalidDataException("Duplicate expression for intensity formula " + 307 rawDataType + "[" + name + "]: channel=" + channel); 308 } 309 if (exp == null) 310 { 311 throw new InvalidDataException("Missing expression for formula " + 312 rawDataType + "[" + name + "]: channel=" + channel); 313 } 314 expressions[channel-1] = exp; 227 315 } 228 316 formulas.add(new IntensityFormula(name, title, description, expressions)); -
trunk/src/core/net/sf/basedb/core/data/ExtendableData.java
r3562 r3600 68 68 <td> 69 69 The property name of the extended property. 70 See {@link net.sf.basedb.core.ExtendedProperty#getName()}. 70 See {@link net.sf.basedb.core.ExtendedProperty#getName()}. The name 71 must only contain letters, numbers and underscores but the first character 72 can't be a number. The name must be unique within the class. 71 73 </td> 72 74 </tr> … … 89 91 <td> 90 92 The database column name of the extended property. This value 91 must of course be unique for each class. 92 See {@link net.sf.basedb.core.ExtendedProperty#getColumn()}. 93 must be unique for each class. The value is validated by the 94 {@link net.sf.basedb.core.dbengine.DbEngine#isValidColumnName(String)} 95 which normally means it must follow the same rules as the <code>name</code> 96 attribute. See {@link net.sf.basedb.core.ExtendedProperty#getColumn()}. 93 97 </td> 94 98 </tr> -
trunk/src/core/net/sf/basedb/core/dbengine/AbstractDbEngine.java
r2812 r3600 24 24 package net.sf.basedb.core.dbengine; 25 25 26 import java.util.regex.Pattern; 27 26 28 /** 27 29 An abstract superclass with default implementations for most {@link DbEngine} … … 36 38 { 37 39 40 /** 41 A regexp checking for invalid characters. 42 */ 43 private static final Pattern valid = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*"); 44 38 45 /** 39 46 Create AbstractDbEngine. … … 121 128 return "EXP("+ value + ")"; 122 129 } 130 /** 131 Checks that the name only contains the following characters: a-zA-Z0-9_ 132 It must also start with a letter or underscore. 133 @since 2.4 134 */ 135 public boolean isValidTableName(String tableName) 136 { 137 return isValidName(tableName); 138 } 139 140 /** 141 Checks that the name only contains the following characters: a-zA-Z0-9_ 142 It must also start with a letter or underscore. 143 */ 144 public boolean isValidColumnName(String columnName) 145 { 146 return isValidName(columnName); 147 } 123 148 // ------------------------------------------- 124 149 150 /** 151 Check that the name only contains a-zA-Z0-9_ and starts with 152 a letter or underscore. 153 @since 2.4 154 */ 155 protected boolean isValidName(String name) 156 { 157 return name == null ? false : valid.matcher(name).matches(); 158 } 159 160 125 161 } -
trunk/src/core/net/sf/basedb/core/dbengine/DbEngine.java
r3468 r3600 239 239 public String exp(String value); 240 240 241 /** 242 Check if a given string is valid to be used as a table name in the 243 current database. 244 @param tableName The string to check 245 @return TRUE if the name is valid, FALSE if not 246 @since 2.4 247 */ 248 public boolean isValidTableName(String tableName); 249 250 /** 251 Check if a given string is valid to be used as a column name in the 252 current database. 253 @param columnName The string to check 254 @return TRUE if the name is valid, FALSE if not 255 @since 2.4 256 */ 257 public boolean isValidColumnName(String columnName); 241 258 }
Note: See TracChangeset
for help on using the changeset viewer.