001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2008-2010 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.gui.validate; 011 012import mondrian.gui.MondrianGuiDef; 013import mondrian.gui.SchemaExplorer; 014 015import org.apache.log4j.Logger; 016 017import java.lang.reflect.Field; 018import java.util.TreeSet; 019 020/** 021 * Validates a <code>MondrianGuiDef</code>. Class contains <code>invalid</code> 022 * method formerly from <code>mondrian.gui.SchemaTreeCellRenderer</code>. 023 * 024 * @author mlowery 025 */ 026public class ValidationUtils { 027 028 private static final Logger LOGGER = 029 Logger.getLogger(ValidationUtils.class); 030 031 static String[] DEF_LEVEL = { 032 "column", "nameColumn", "parentColumn", "ordinalColumn", "captionColumn" 033 }; 034 035 /** 036 * Validate a schema model and returns the first error message if it is 037 * invalid. 038 * 039 * @param messages Message provider 040 * @param jdbcValidator Validator 041 * @param treeModel Tree model 042 * @param tpath Path 043 * @param value Value 044 * @param cube Cube 045 * @param parentDimension Parent dimension 046 * @param parentHierarchy Parent hierarchy 047 * @param parentLevel Parent level 048 * @param isSchemaRequired Whether schema is required 049 * @return Error message if element is invalid, null if it is valid 050 */ 051 public static String invalid( 052 Messages messages, 053 JdbcValidator jdbcValidator, 054 TreeModel treeModel, 055 TreeModelPath tpath, 056 Object value, 057 MondrianGuiDef.Cube cube, 058 MondrianGuiDef.Dimension parentDimension, 059 MondrianGuiDef.Hierarchy parentHierarchy, 060 MondrianGuiDef.Level parentLevel, 061 boolean isSchemaRequired) 062 { 063 String nameMustBeSet = messages.getString( 064 "schemaTreeCellRenderer.nameMustBeSet.alert", "Name must be set"); 065 066 if (!tpath.isEmpty()) { 067 int pathcount = tpath.getPathCount(); 068 for (int i = 0; 069 i < pathcount 070 && (cube == null 071 || parentDimension == null 072 || parentHierarchy == null 073 || parentLevel == null); 074 i++) 075 { 076 final Object p = tpath.getPathComponent(i); 077 if (p instanceof MondrianGuiDef.Cube 078 && cube == null) 079 { 080 cube = (MondrianGuiDef.Cube) p; 081 } 082 if (p instanceof MondrianGuiDef.Dimension 083 && parentDimension == null) 084 { 085 parentDimension = (MondrianGuiDef.Dimension) p; 086 } 087 if (p instanceof MondrianGuiDef.Hierarchy 088 && parentHierarchy == null) 089 { 090 parentHierarchy = (MondrianGuiDef.Hierarchy) p; 091 } 092 if (p instanceof MondrianGuiDef.Level 093 && parentLevel == null) 094 { 095 parentLevel = (MondrianGuiDef.Level) p; 096 } 097 } 098 } 099 100 //Step 1: check validity of this value object 101 if (value instanceof MondrianGuiDef.Schema) { 102 if (isEmpty(((MondrianGuiDef.Schema) value).name)) { 103 return nameMustBeSet; 104 } 105 } else if (value instanceof MondrianGuiDef.VirtualCube) { 106 MondrianGuiDef.VirtualCube virtCube = 107 (MondrianGuiDef.VirtualCube)value; 108 if (isEmpty(virtCube.name)) { 109 return nameMustBeSet; 110 } 111 if (isEmpty(virtCube.dimensions)) { 112 return messages.getString( 113 "schemaTreeCellRenderer.cubeMustHaveDimensions.alert", 114 "Cube must contain dimensions"); 115 } 116 if (isEmpty(virtCube.measures)) { 117 return messages.getString( 118 "schemaTreeCellRenderer.cubeMustHaveMeasures.alert", 119 "Cube must contain measures"); 120 } 121 } else if (value instanceof MondrianGuiDef.VirtualCubeDimension) { 122 if (isEmpty(((MondrianGuiDef.VirtualCubeDimension) value).name)) { 123 return nameMustBeSet; 124 } 125 } else if (value instanceof MondrianGuiDef.VirtualCubeMeasure) { 126 if (isEmpty(((MondrianGuiDef.VirtualCubeMeasure) value).name)) { 127 return nameMustBeSet; 128 } 129 } else if (value instanceof MondrianGuiDef.Cube) { 130 MondrianGuiDef.Cube cubeVal = (MondrianGuiDef.Cube) value; 131 if (isEmpty(cubeVal.name)) { 132 return nameMustBeSet; 133 } 134 if (cubeVal.fact == null 135 || ((cubeVal.fact instanceof MondrianGuiDef.Table) 136 && isEmpty(((MondrianGuiDef.Table) cubeVal.fact).name)) 137 || ((cubeVal.fact instanceof MondrianGuiDef.View) 138 && isEmpty(((MondrianGuiDef.View) cubeVal.fact).alias))) 139 { 140 return messages.getString( 141 "schemaTreeCellRenderer.factNameMustBeSet.alert", 142 "Fact name must be set"); 143 } 144 if (isEmpty(cubeVal.dimensions)) { 145 return messages.getString( 146 "schemaTreeCellRenderer.cubeMustHaveDimensions.alert", 147 "Cube must contain dimensions"); 148 } 149 if (isEmpty(cubeVal.measures)) { 150 return messages.getString( 151 "schemaTreeCellRenderer.cubeMustHaveMeasures.alert", 152 "Cube must contain measures"); 153 } 154 // database validity check, if database connection is successful 155 if (jdbcValidator.isInitialized()) { 156 if (((MondrianGuiDef.Cube) value).fact 157 instanceof MondrianGuiDef.Table) 158 { 159 final MondrianGuiDef.Table table = 160 (MondrianGuiDef.Table) cubeVal.fact; 161 String schemaName = table.schema; 162 String factTable = table.name; 163 if (!jdbcValidator.isTableExists(schemaName, factTable)) { 164 return messages.getFormattedString( 165 "schemaTreeCellRenderer.factTableDoesNotExist.alert", 166 "Fact table {0} does not exist in database {1}", 167 factTable, 168 ((schemaName == null || schemaName.equals("")) 169 ? "." 170 : "schema " + schemaName)); 171 } 172 } 173 } 174 } else { 175 if (value instanceof MondrianGuiDef.CubeDimension) { 176 if (isEmpty(((MondrianGuiDef.CubeDimension) value).name)) { 177 return nameMustBeSet; 178 } 179 if (value instanceof MondrianGuiDef.DimensionUsage) { 180 if (isEmpty( 181 ((MondrianGuiDef.DimensionUsage) value).source)) 182 { 183 return messages.getString( 184 "schemaTreeCellRenderer.sourceMustBeSet.alert", 185 "Source must be set"); 186 } 187 // Check source is name of one of dimensions of schema 188 // (shared dimensions) 189 MondrianGuiDef.Schema s = 190 (MondrianGuiDef.Schema) treeModel.getRoot(); 191 MondrianGuiDef.Dimension ds[] = s.dimensions; 192 String sourcename = 193 ((MondrianGuiDef.DimensionUsage) value).source; 194 boolean notfound = true; 195 for (int j = 0; j < ds.length; j++) { 196 if (ds[j].name.equalsIgnoreCase(sourcename)) { 197 notfound = false; 198 break; 199 } 200 } 201 if (notfound) { 202 return messages.getFormattedString( 203 "schemaTreeCellRenderer.sourceInSharedDimensionDoesNotExist.alert", 204 "Source {0} does not exist as Shared Dimension of Schema", 205 sourcename); 206 } 207 } 208 if (value instanceof MondrianGuiDef.Dimension && cube != null) { 209 if (!isEmpty( 210 ((MondrianGuiDef.Dimension) value).foreignKey)) 211 { 212 // database validity check, if database connection is 213 // successful 214 if (jdbcValidator.isInitialized()) { 215 // TODO: Need to add validation for Views 216 if (cube.fact instanceof MondrianGuiDef.Table) { 217 final MondrianGuiDef.Table factTable = 218 (MondrianGuiDef.Table) cube.fact; 219 String foreignKey = 220 ((MondrianGuiDef.Dimension) value) 221 .foreignKey; 222 if (!jdbcValidator.isColExists( 223 factTable.schema, 224 factTable.name, 225 foreignKey)) 226 { 227 return messages.getFormattedString( 228 "schemaTreeCellRenderer.foreignKeyDoesNotExist.alert", 229 "foreignKey {0} does not exist in fact table", 230 foreignKey); 231 } 232 } 233 } 234 } 235 } 236 } else if (value instanceof MondrianGuiDef.Level) { 237 // Check 'column' exists in 'table' if table is specified 238 // otherwise :: case of join. 239 240 // It should exist in relation table if it is specified 241 // otherwise :: case of table. 242 243 // It should exist in fact table :: case of degenerate dimension 244 // where dimension columns exist in fact table and there is no 245 // separate table. 246 MondrianGuiDef.Level level = (MondrianGuiDef.Level) value; 247 if (!isEmpty(level.levelType)) { 248 // Empty leveltype is treated as default value of "Regular"" 249 // which is ok with standard/time dimension. 250 if (parentDimension != null) { 251 if ((isEmpty(parentDimension.type) 252 || parentDimension.type.equals( 253 "StandardDimension")) 254 && !isEmpty(level.levelType) 255 && (!level.levelType.equals( 256 MondrianGuiDef.Level._levelType_values[0]))) 257 { 258 // If dimension type is 'standard' then leveltype 259 // should be 'regular' 260 return messages.getFormattedString( 261 "schemaTreeCellRenderer.levelUsedOnlyInTimeDimension.alert", 262 "levelType {0} can only be used with a TimeDimension", 263 level.levelType); 264 } else if (!isEmpty(parentDimension.type) 265 && (parentDimension.type.equals( 266 "TimeDimension")) 267 && !isEmpty(level.levelType) 268 && (level.levelType.equals( 269 MondrianGuiDef.Level 270 ._levelType_values[0]))) 271 { 272 // If dimension type is 'time' then leveltype value 273 // could be 'timeyears', 'timedays' etc' 274 return messages.getFormattedString( 275 "schemaTreeCellRenderer.levelUsedOnlyInStandardDimension.alert", 276 "levelType {0} can only be used with a StandardDimension", 277 level.levelType); 278 } 279 } 280 } 281 // verify level's name is set 282 if (isEmpty(level.name)) { 283 return messages.getString( 284 "schemaTreeCellRenderer.nameMustBeSet.alert", 285 "Level name must be set" 286 ); 287 } 288 289 // check level's column is in fact table 290 String column = level.column; 291 if (isEmpty(column)) { 292 if (level.properties == null 293 || level.properties.length == 0) 294 { 295 return messages.getString( 296 "schemaTreeCellRenderer.columnMustBeSet.alert", 297 "Column must be set"); 298 } 299 } else { 300 // Enforces validation for all column types against invalid 301 // value. 302 String theMessage = null; 303 try { 304 for (int i = 0; i < DEF_LEVEL.length; i++) { 305 Field theField = 306 level.getClass().getDeclaredField(DEF_LEVEL[i]); 307 column = (String) theField.get(level); 308 theMessage = validateColumn( 309 column, 310 DEF_LEVEL[i], 311 messages, 312 level, 313 jdbcValidator, 314 cube, 315 parentHierarchy); 316 if (theMessage != null) { 317 break; 318 } 319 } 320 } catch (Exception ex) { 321 LOGGER.error("ValidationUtils", ex); 322 } 323 return theMessage; 324 } 325 } else if (value instanceof MondrianGuiDef.Property) { 326 // Check 'column' exists in 'table' if [level table] is 327 // specified otherwise :: case of join. 328 329 // It should exist in [hierarchy relation table] if it is 330 // specified otherwise :: case of table. 331 332 // It should exist in [fact table] :: case of degenerate 333 // dimension where dimension columns exist in fact table and 334 // there is no separate table. 335 MondrianGuiDef.Property p = (MondrianGuiDef.Property) value; 336 // check property's column is in table 337 String column = p.column; 338 if (isEmpty(column)) { 339 return messages.getString( 340 "schemaTreeCellRenderer.columnMustBeSet.alert", 341 "Column must be set"); 342 } 343 // Database validity check, if database connection is successful 344 if (jdbcValidator.isInitialized()) { 345 String table = null; 346 if (parentLevel != null) { 347 // specified table for level's column' 348 table = parentLevel.table; 349 } 350 if (isEmpty(table)) { 351 if (parentHierarchy != null) { 352 if (parentHierarchy.relation == null 353 && cube != null) 354 { 355 // Case of degenerate dimension within cube, 356 // hierarchy table not specified 357 final MondrianGuiDef.Table factTable = 358 (MondrianGuiDef.Table) cube.fact; 359 if (!jdbcValidator.isColExists( 360 factTable.schema, 361 factTable.name, 362 column)) 363 { 364 return messages.getFormattedString( 365 "schemaTreeCellRenderer.degenDimensionColumnDoesNotExist.alert", 366 "Degenerate dimension validation check - Column {0} does not exist in fact table", 367 column); 368 } 369 } else if (parentHierarchy.relation 370 instanceof MondrianGuiDef.Table) 371 { 372 final MondrianGuiDef.Table parentTable = 373 (MondrianGuiDef.Table) 374 parentHierarchy.relation; 375 if (!jdbcValidator.isColExists( 376 parentTable.schema, 377 parentTable.name, 378 column)) 379 { 380 return messages.getFormattedString( 381 "schemaTreeCellRenderer.columnInDimensionDoesNotExist.alert", 382 "Column {0} does not exist in Dimension table", 383 parentTable.name); 384 } 385 } 386 } 387 } else { 388 if (!jdbcValidator.isColExists(null, table, column)) { 389 return messages.getFormattedString( 390 "schemaTreeCellRenderer.columnInDimensionDoesNotExist.alert", 391 "Column {0} does not exist in Level table {1}", 392 column, 393 table); 394 } 395 } 396 } 397 } else if (value instanceof MondrianGuiDef.Measure) { 398 final MondrianGuiDef.Measure measure = 399 (MondrianGuiDef.Measure) value; 400 if (isEmpty(measure.name)) { 401 return nameMustBeSet; 402 } 403 if (isEmpty(measure.aggregator)) { 404 return messages.getString( 405 "schemaTreeCellRenderer.aggregatorMustBeSet.alert", 406 "Aggregator must be set"); 407 } 408 if (measure.measureExp != null) { 409 // Measure expressions are OK 410 } else if (isEmpty(measure.column)) { 411 return messages.getString( 412 "schemaTreeCellRenderer.columnMustBeSet.alert", 413 "Column must be set"); 414 } else if (cube != null && cube.fact != null) { 415 // Database validity check, if database connection is 416 // successful 417 if (cube.fact instanceof MondrianGuiDef.Table) { 418 final MondrianGuiDef.Table factTable = 419 (MondrianGuiDef.Table) cube.fact; 420 if (jdbcValidator.isInitialized()) { 421 String column = measure.column; 422 if (jdbcValidator.isColExists( 423 factTable.schema, 424 factTable.name, 425 column)) 426 { 427 // Check for aggregator type only if column 428 // exists in table. 429 430 // Check if aggregator selected is valid on 431 // the data type of the column selected. 432 int colType = 433 jdbcValidator.getColumnDataType( 434 factTable.schema, 435 factTable.name, 436 measure.column); 437 // Coltype of 2, 4,5, 7, 8, -5 is numeric types 438 // whereas 1, 12 are char varchar string 439 // and 91 is date type. 440 // Types are enumerated in java.sql.Types. 441 int agIndex = -1; 442 if ("sum".equals( 443 measure.aggregator) 444 || "avg".equals( 445 measure.aggregator)) 446 { 447 // aggregator = sum or avg, column should 448 // be numeric 449 agIndex = 0; 450 } 451 if (!(agIndex == -1 452 || (colType >= 2 && colType <= 8) 453 || colType == -5 || colType == -6)) 454 { 455 return messages.getFormattedString( 456 "schemaTreeCellRenderer.aggregatorNotValidForColumn.alert", 457 "Aggregator {0} is not valid for the data type of the column {1}", 458 measure.aggregator, 459 measure.column); 460 } 461 } 462 } 463 } 464 } 465 } else if (value instanceof MondrianGuiDef.Hierarchy) { 466 final MondrianGuiDef.Hierarchy hierarchy = 467 (MondrianGuiDef.Hierarchy) value; 468 if (hierarchy.relation instanceof MondrianGuiDef.Join) { 469 if (isEmpty(hierarchy.primaryKeyTable)) { 470 if (isEmpty(hierarchy.primaryKey)) { 471 return messages.getString( 472 "schemaTreeCellRenderer.primaryKeyTableAndPrimaryKeyMustBeSet.alert", 473 "PrimaryKeyTable and PrimaryKey must be set for Join"); 474 } else { 475 return messages.getString( 476 "schemaTreeCellRenderer.primaryKeyTableMustBeSet.alert", 477 "PrimaryKeyTable must be set for Join"); 478 } 479 } 480 if (isEmpty(hierarchy.primaryKey)) { 481 return messages.getString( 482 "schemaTreeCellRenderer.primaryKeyMustBeSet.alert", 483 "PrimaryKey must be set for Join"); 484 } 485 } 486 487 MondrianGuiDef.Level[] levels = hierarchy.levels; 488 if (levels == null || levels.length == 0) { 489 return messages.getString( 490 "schemaTreeCellRenderer.atLeastOneLevelForHierarchy.alert", 491 "At least one Level must be set for Hierarchy"); 492 } 493 494 // Validates that value in primaryKey exists in Table. 495 String schema = null; 496 String pkTable = null; 497 if (hierarchy.relation instanceof MondrianGuiDef.Join) { 498 String[] schemaAndTable = 499 SchemaExplorer.getTableNameForAlias( 500 hierarchy.relation, 501 hierarchy.primaryKeyTable); 502 schema = schemaAndTable[0]; 503 pkTable = schemaAndTable[1]; 504 } else if (hierarchy.relation instanceof MondrianGuiDef.Table) { 505 final MondrianGuiDef.Table table = 506 (MondrianGuiDef.Table) hierarchy.relation; 507 pkTable = table.name; 508 schema = table.schema; 509 } 510 511 if (pkTable != null 512 && !jdbcValidator.isColExists( 513 schema, pkTable, hierarchy.primaryKey)) 514 { 515 return messages.getFormattedString( 516 "schemaTreeCellRenderer.columnInTableDoesNotExist.alert", 517 "Column {0} defined in field {1} does not exist in table {2}", 518 isEmpty(hierarchy.primaryKey.trim()) 519 ? "' '" 520 : hierarchy.primaryKey, "primaryKey", 521 pkTable); 522 } 523 524 // Validates against primaryKeyTable name on field when using 525 // Table. 526 if (hierarchy.relation instanceof MondrianGuiDef.Table) { 527 if (!isEmpty(hierarchy.primaryKeyTable)) { 528 return messages.getString( 529 "schemaTreeCellRenderer.fieldMustBeEmpty", 530 "Table field must be empty"); 531 } 532 } 533 534 // Validates that the value at primaryKeyTable corresponds to 535 // tables in joins. 536 String primaryKeyTable = hierarchy.primaryKeyTable; 537 if (!isEmpty(primaryKeyTable) 538 && (hierarchy.relation instanceof MondrianGuiDef.Join)) 539 { 540 TreeSet<String> joinTables = new TreeSet<String>(); 541 SchemaExplorer.getTableNamesForJoin( 542 hierarchy.relation, joinTables); 543 if (!joinTables.contains(primaryKeyTable)) { 544 return messages.getString( 545 "schemaTreeCellRenderer.wrongTableValue", 546 "Table value does not correspond to any join"); 547 } 548 } 549 550 if (!isEmpty(primaryKeyTable) 551 && (hierarchy.relation instanceof MondrianGuiDef.Table)) 552 { 553 MondrianGuiDef.Table theTable = 554 (MondrianGuiDef.Table) hierarchy.relation; 555 String compareTo = 556 (theTable.alias != null 557 && theTable.alias.trim().length() > 0) 558 ? theTable.alias 559 : theTable.name; 560 if (!primaryKeyTable.equals(compareTo)) { 561 return messages.getString( 562 "schemaTreeCellRenderer.tableDoesNotMatch", 563 "Table value does not correspond to Hierarchy Relation"); 564 } 565 } 566 567 } else if (value instanceof MondrianGuiDef.NamedSet) { 568 final MondrianGuiDef.NamedSet namedSet = 569 (MondrianGuiDef.NamedSet) value; 570 if (isEmpty(namedSet.name)) { 571 return nameMustBeSet; 572 } 573 if (isEmpty(namedSet.formula) 574 && namedSet.formulaElement == null) 575 { 576 return messages.getString( 577 "schemaTreeCellRenderer.formulaMustBeSet.alert", 578 "Formula must be set"); 579 } 580 } else if (value instanceof MondrianGuiDef.Formula) { 581 final MondrianGuiDef.Formula formula = 582 (MondrianGuiDef.Formula) value; 583 if (isEmpty(formula.cdata)) { 584 return messages.getString( 585 "schemaTreeCellRenderer.formulaMustBeSet.alert", 586 "Formula must be set"); 587 } 588 } else if (value instanceof MondrianGuiDef.UserDefinedFunction) { 589 final MondrianGuiDef.UserDefinedFunction udf = 590 (MondrianGuiDef.UserDefinedFunction) value; 591 if (isEmpty(udf.name)) { 592 return nameMustBeSet; 593 } 594 if (isEmpty(udf.className) 595 && udf.script == null) 596 { 597 return messages.getString( 598 "Either a Class Name or a Script are required", 599 "Class name must be set"); 600 } 601 } else if (value instanceof MondrianGuiDef.MemberFormatter) { 602 final MondrianGuiDef.MemberFormatter f = 603 (MondrianGuiDef.MemberFormatter) value; 604 if (isEmpty(f.className) 605 && f.script == null) 606 { 607 return messages.getString( 608 "schemaTreeCellRenderer.classNameOrScriptRequired.alert", 609 "Either a Class Name or a Script are required"); 610 } 611 } else if (value instanceof MondrianGuiDef.CellFormatter) { 612 final MondrianGuiDef.CellFormatter f = 613 (MondrianGuiDef.CellFormatter) value; 614 if (isEmpty(f.className) 615 && f.script == null) 616 { 617 return messages.getString( 618 "schemaTreeCellRenderer.classNameOrScriptRequired.alert", 619 "Either a Class Name or a Script are required"); 620 } 621 } else if (value instanceof MondrianGuiDef.PropertyFormatter) { 622 final MondrianGuiDef.PropertyFormatter f = 623 (MondrianGuiDef.PropertyFormatter) value; 624 if (isEmpty(f.className) 625 && f.script == null) 626 { 627 return messages.getString( 628 "schemaTreeCellRenderer.classNameOrScriptRequired.alert", 629 "Either a Class Name or a Script are required"); 630 } 631 } else if (value instanceof MondrianGuiDef.CalculatedMember) { 632 final MondrianGuiDef.CalculatedMember calculatedMember = 633 (MondrianGuiDef.CalculatedMember) value; 634 if (isEmpty(calculatedMember.name)) { 635 return nameMustBeSet; 636 } 637 if (isEmpty(calculatedMember.dimension)) { 638 return messages.getString( 639 "schemaTreeCellRenderer.dimensionMustBeSet.alert", 640 "Dimension must be set"); 641 } 642 if (isEmpty(calculatedMember.formula) 643 && calculatedMember.formulaElement == null) 644 { 645 return messages.getString( 646 "schemaTreeCellRenderer.formulaMustBeSet.alert", 647 "Formula must be set"); 648 } 649 } else if (value instanceof MondrianGuiDef.Join) { 650 final MondrianGuiDef.Join join = (MondrianGuiDef.Join) value; 651 if (isEmpty(join.leftKey)) { 652 return messages.getString( 653 "schemaTreeCellRenderer.leftKeyMustBeSet.alert", 654 "Left key must be set"); 655 } 656 if (isEmpty(join.rightKey)) { 657 return messages.getString( 658 "schemaTreeCellRenderer.rightKeyMustBeSet.alert", 659 "Right key must be set"); 660 } 661 } else if (value instanceof MondrianGuiDef.Table) { 662 final MondrianGuiDef.Table table = (MondrianGuiDef.Table) value; 663 String tableName = table.name; 664 if (!jdbcValidator.isTableExists(null, tableName)) { 665 return messages.getFormattedString( 666 "schemaTreeCellRenderer.tableDoesNotExist.alert", 667 "Table {0} does not exist in database", 668 tableName); 669 } 670 671 String theSchema = table.schema; 672 if (!isEmpty(theSchema) 673 && !jdbcValidator.isSchemaExists(theSchema)) 674 { 675 return messages.getFormattedString( 676 "schemaTreeCellRenderer.schemaDoesNotExist.alert", 677 "Schema {0} does not exist", 678 theSchema); 679 } 680 if (isEmpty(theSchema) && isSchemaRequired) { 681 return messages.getString( 682 "schemaTreeCellRenderer.schemaMustBeSet.alert", 683 "Schema must be set"); 684 } 685 } 686 } 687 688 // Step 2: check validity of all child objects for this value object. 689 int childCnt = treeModel.getChildCount(value); 690 for (int i = 0; i < childCnt; i++) { 691 Object child = treeModel.getChild(value, i); 692 String childErrMsg; 693 if (child instanceof MondrianGuiDef.Cube) { 694 // check current cube child and its children 695 childErrMsg = invalid( 696 messages, 697 jdbcValidator, 698 treeModel, 699 tpath, 700 child, 701 (MondrianGuiDef.Cube) child, 702 parentDimension, 703 parentHierarchy, 704 parentLevel, 705 isSchemaRequired); 706 } else if (child instanceof MondrianGuiDef.Dimension) { 707 // check the current hierarchy and its children 708 childErrMsg = invalid( 709 messages, 710 jdbcValidator, 711 treeModel, 712 tpath, 713 child, 714 cube, 715 (MondrianGuiDef.Dimension) child, 716 parentHierarchy, 717 parentLevel, 718 isSchemaRequired); 719 } else if (child instanceof MondrianGuiDef.Hierarchy) { 720 // special check for cube dimension where foreign key is blank : 721 // allowed/not allowed 722 if (value instanceof MondrianGuiDef.Dimension 723 && cube != null 724 && ((MondrianGuiDef.Hierarchy) child).relation != null) 725 { 726 if (isEmpty( 727 ((MondrianGuiDef.Dimension) value).foreignKey)) 728 { 729 // check foreignkey is not blank; 730 // if relation is null, foreignkey must be specified 731 return messages.getString( 732 "schemaTreeCellRenderer.foreignKeyMustBeSet.alert", 733 "Foreign key must be set"); 734 } 735 } 736 // check the current hierarchy and its children 737 childErrMsg = invalid( 738 messages, 739 jdbcValidator, 740 treeModel, 741 tpath, 742 child, 743 cube, 744 parentDimension, 745 (MondrianGuiDef.Hierarchy) child, 746 parentLevel, 747 isSchemaRequired); 748 } else if (child instanceof MondrianGuiDef.Level) { 749 // check the current hierarchy and its children 750 childErrMsg = invalid( 751 messages, 752 jdbcValidator, 753 treeModel, 754 tpath, 755 child, 756 cube, 757 parentDimension, 758 parentHierarchy, 759 (MondrianGuiDef.Level) child, 760 isSchemaRequired); 761 } else { 762 // check this child and all its children objects with incoming 763 // cube and hierarchy 764 childErrMsg = invalid( 765 messages, 766 jdbcValidator, 767 treeModel, 768 tpath, 769 child, 770 cube, 771 parentDimension, 772 parentHierarchy, 773 parentLevel, 774 isSchemaRequired); 775 } 776 777 // If all children are valid then do a special check. 778 // Special check for cubes to see if their child dimensions have 779 // foreign key set and set the childErrMsg with error msg 780 /* === Begin : disabled 781 if (childErrMsg == null) { // all children are valid 782 if (child instanceof MondrianGuiDef.Cube) { 783 MondrianGuiDef.Cube c = (MondrianGuiDef.Cube) child; 784 MondrianGuiDef.CubeDimension [] ds = c.dimensions; 785 for (int j=0; j<ds.length; j++) { 786 MondrianGuiDef.CubeDimension d = 787 (MondrianGuiDef.CubeDimension) ds[j]; 788 if (d instanceof MondrianGuiDef.DimensionUsage) { 789 continue; // check the next dimension. 790 } 791 792 // check foreignkey is not blank 793 if(isEmpty(d.foreignKey)) { 794 childErrMsg = "ForeignKey" + emptyMsg; 795 break; 796 } 797 798 // database validity check, if database connection is 799 // successful 800 if (jdbcMetaData.getErrMsg() == null) { 801 String foreignKey = d.foreignKey; 802 if (! jdbcMetaData.isColExists( 803 ((MondrianGuiDef.Table) c.fact).schema, 804 ((MondrianGuiDef.Table) c.fact).name, 805 foreignKey)) 806 { 807 childErrMsg = 808 "ForeignKey '" + foreignKey + 809 "' does not exist in fact table."; 810 break; 811 } 812 // check foreignKey is a fact table column 813 if (! allcols.contains(foreignKey)) { 814 childErrMsg = 815 "ForeignKey '" + foreignKey 816 + "' does not exist in fact table."; 817 break; 818 } 819 * / 820 } 821 } 822 } 823 } 824 * === End : disabled 825 */ 826 // Now set the final errormsg 827 if (childErrMsg != null) { 828 String childClassName = child.getClass().getName(); 829 String simpleName[] = childClassName.split("[$.]", 0); 830 String childName; 831 try { 832 Field f = child.getClass().getField("name"); 833 childName = (String) f.get(child); 834 if (childName == null) { 835 childName = ""; 836 } 837 childErrMsg = messages.getFormattedString( 838 "schemaTreeCellRenderer.childErrorMessageWithName.alert", 839 "{0} {1} is invalid", 840 simpleName[simpleName.length - 1], 841 childName); 842 } catch (Exception ex) { 843 childErrMsg = messages.getFormattedString( 844 "schemaTreeCellRenderer.childErrorExceptionMessage.alert", 845 "{0} is invalid", 846 simpleName[simpleName.length - 1]); 847 } 848 return childErrMsg; 849 } 850 } 851 852 return null; 853 } 854 855 /** 856 * Returns whether an object is null or the empty string. 857 * 858 * @param v Object 859 * @return Whether object is null or the empty string 860 */ 861 public static boolean isEmpty(String v) { 862 return (v == null) || v.equals(""); 863 } 864 865 /** 866 * Returns whether an array is null or empty 867 * 868 * @param arr array 869 * @return whether the array is null or empty 870 */ 871 public static boolean isEmpty(Object[] arr) { 872 return arr == null || arr.length == 0; 873 } 874 875 /** 876 * Validates a column, and returns an error message if it is invalid. 877 * 878 * @param column Column 879 * @param fieldName Field name 880 * @param messages Message provider 881 * @param level Level 882 * @param jdbcValidator JDBC validator 883 * @param cube Cube 884 * @param parentHierarchy Hierarchy 885 * @return Error message if invalid, null if valid 886 */ 887 private static String validateColumn( 888 String column, 889 String fieldName, 890 Messages messages, 891 MondrianGuiDef.Level level, 892 JdbcValidator jdbcValidator, 893 MondrianGuiDef.Cube cube, 894 MondrianGuiDef.Hierarchy parentHierarchy) 895 { 896 if (!isEmpty(column)) { 897 // database validity check, if database connection is successful 898 if (jdbcValidator.isInitialized()) { 899 // specified table for level's column 900 String table = level.table; 901 // If table has been changed in join then sets the table value 902 // to null to cause "tableMustBeSet" validation fail. 903 if (!isEmpty(table) 904 && parentHierarchy != null 905 && parentHierarchy.relation instanceof MondrianGuiDef.Join) 906 { 907 TreeSet<String> joinTables = new TreeSet<String>(); 908 SchemaExplorer.getTableNamesForJoin( 909 parentHierarchy.relation, joinTables); 910 if (!joinTables.contains(table)) { 911 return messages.getString( 912 "schemaTreeCellRenderer.wrongTableValue", 913 "Table value does not correspond to any join"); 914 } 915 } 916 917 if (!isEmpty(table) 918 && parentHierarchy != null 919 && parentHierarchy.relation instanceof MondrianGuiDef.Table) 920 { 921 final MondrianGuiDef.Table parentTable = 922 (MondrianGuiDef.Table) parentHierarchy.relation; 923 MondrianGuiDef.Table theTable = parentTable; 924 String compareTo = 925 (theTable.alias != null 926 && theTable.alias.trim().length() > 0) 927 ? theTable.alias 928 : theTable.name; 929 if (!table.equals(compareTo)) { 930 return messages.getString( 931 "schemaTreeCellRenderer.tableDoesNotMatch", 932 "Table value does not correspond to Hierarchy Relation"); 933 } 934 } 935 936 if (!isEmpty(table) 937 && parentHierarchy != null 938 && parentHierarchy.relation instanceof MondrianGuiDef.View) 939 { 940 return messages.getString( 941 "schemaTreeCellRenderer.noTableForView", 942 "Table for column cannot be set in View"); 943 } 944 945 if (isEmpty(table)) { 946 if (parentHierarchy != null) { 947 if (parentHierarchy.relation == null 948 && cube != null) 949 { 950 // case of degenerate dimension within cube, 951 // hierarchy table not specified 952 if (!jdbcValidator.isColExists( 953 ((MondrianGuiDef.Table) cube.fact).schema, 954 ((MondrianGuiDef.Table) cube.fact).name, 955 column)) 956 { 957 return messages.getFormattedString( 958 "schemaTreeCellRenderer.degenDimensionColumnDoesNotExist.alert", 959 "Degenerate dimension validation check - Column {0} does not exist in fact table", 960 column); 961 } 962 } else if (parentHierarchy.relation 963 instanceof MondrianGuiDef.Table) 964 { 965 final MondrianGuiDef.Table parentTable = 966 (MondrianGuiDef.Table) parentHierarchy.relation; 967 if (!jdbcValidator.isColExists( 968 parentTable.schema, 969 parentTable.name, 970 column)) 971 { 972 return messages.getFormattedString( 973 "schemaTreeCellRenderer.columnInTableDoesNotExist.alert", 974 "Column {0} defined in field {1} does not exist in table {2}", 975 isEmpty(column.trim()) 976 ? "' '" 977 : column, 978 fieldName, 979 parentTable.name); 980 } 981 } else if (parentHierarchy.relation 982 instanceof MondrianGuiDef.Join) 983 { 984 // relation is join, table should be specified 985 return messages.getString( 986 "schemaTreeCellRenderer.tableMustBeSet.alert", 987 "Table must be set"); 988 } 989 } 990 } else { 991 String schema = null; 992 // if using Joins then gets the table name for isColExists 993 // validation. 994 if (parentHierarchy != null 995 && parentHierarchy.relation 996 instanceof MondrianGuiDef.Join) 997 { 998 String[] schemaAndTable = 999 SchemaExplorer.getTableNameForAlias( 1000 parentHierarchy.relation, 1001 table); 1002 schema = schemaAndTable[0]; 1003 table = schemaAndTable[1]; 1004 } 1005 if (!jdbcValidator.isColExists(schema, table, column)) { 1006 return messages.getFormattedString( 1007 "schemaTreeCellRenderer.columnInTableDoesNotExist.alert", 1008 "Column {0} defined in field {1} does not exist in table {2}", 1009 isEmpty(column.trim()) 1010 ? "' '" 1011 : column, 1012 fieldName, 1013 table); 1014 } 1015 } 1016 } 1017 } 1018 return null; 1019 } 1020 1021} 1022 1023// End ValidationUtils.java