001 /* 002 // $Id: //open/mondrian/src/main/mondrian/rolap/aggmatcher/DefaultRecognizer.java#14 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2005-2008 Julian Hyde and others 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 011 package mondrian.rolap.aggmatcher; 012 013 import mondrian.olap.Hierarchy; 014 import mondrian.resource.MondrianResource; 015 import mondrian.recorder.MessageRecorder; 016 import mondrian.rolap.RolapStar; 017 import mondrian.rolap.RolapLevel; 018 import mondrian.rolap.HierarchyUsage; 019 020 import java.util.Iterator; 021 022 /** 023 * This is the default Recognizer. It uses the rules found in the file 024 * DefaultRules.xml to find aggregate tables and there columns. 025 * 026 * @author Richard M. Emberson 027 * @version $Id: //open/mondrian/src/main/mondrian/rolap/aggmatcher/DefaultRecognizer.java#14 $ 028 */ 029 class DefaultRecognizer extends Recognizer { 030 031 private static final MondrianResource mres = MondrianResource.instance(); 032 033 private final DefaultRules aggDefault; 034 035 DefaultRecognizer(final DefaultRules aggDefault, 036 final RolapStar star, 037 final JdbcSchema.Table dbFactTable, 038 final JdbcSchema.Table aggTable, 039 final MessageRecorder msgRecorder) { 040 super(star, dbFactTable, aggTable, msgRecorder); 041 this.aggDefault = aggDefault; 042 } 043 044 /** 045 * Get the DefaultRules instance associated with this object. 046 */ 047 DefaultRules getRules() { 048 return aggDefault; 049 } 050 051 /** 052 * Get the Matcher to be used to match columns to be ignored. 053 */ 054 protected Recognizer.Matcher getIgnoreMatcher() { 055 return getRules().getIgnoreMatcher(); 056 } 057 058 /** 059 * Get the Matcher to be used to match the column which is the fact count 060 * column. 061 */ 062 protected Recognizer.Matcher getFactCountMatcher() { 063 return getRules().getFactCountMatcher(); 064 } 065 066 /** 067 * Get the Match used to identify columns that are measures. 068 */ 069 protected Recognizer.Matcher getMeasureMatcher( 070 JdbcSchema.Table.Column.Usage factUsage) { 071 072 String measureName = factUsage.getSymbolicName(); 073 String measureColumnName = factUsage.getColumn().getName(); 074 String aggregateName = factUsage.getAggregator().getName(); 075 076 return getRules().getMeasureMatcher( 077 measureName, 078 measureColumnName, 079 aggregateName); 080 } 081 082 /** 083 * Create measures for an aggregate table. 084 * <p> 085 * First, iterator through all fact table measure usages. 086 * Create a Matcher for each such usage. 087 * Iterate through all aggregate table columns. 088 * For each column that matches create a measure usage. 089 * <p> 090 * Per fact table measure usage, at most only one aggregate measure should 091 * be created. 092 * 093 * @return number of measures created. 094 */ 095 protected int checkMeasures() { 096 msgRecorder.pushContextName("DefaultRecognizer.checkMeasures"); 097 098 try { 099 int measureCountCount = 0; 100 101 for (Iterator<JdbcSchema.Table.Column.Usage> it = 102 dbFactTable.getColumnUsages(JdbcSchema.UsageType.MEASURE); 103 it.hasNext();) { 104 JdbcSchema.Table.Column.Usage factUsage = it.next(); 105 106 Matcher matcher = getMeasureMatcher(factUsage); 107 108 int matchCount = 0; 109 for (JdbcSchema.Table.Column aggColumn : aggTable.getColumns()) { 110 // if marked as ignore, then do not consider 111 if (aggColumn.hasUsage(JdbcSchema.UsageType.IGNORE)) { 112 continue; 113 } 114 115 if (matcher.matches(aggColumn.getName())) { 116 makeMeasure(factUsage, aggColumn); 117 118 measureCountCount++; 119 matchCount++; 120 } 121 } 122 123 if (matchCount > 1) { 124 String msg = mres.AggMultipleMatchingMeasure.str( 125 msgRecorder.getContext(), 126 aggTable.getName(), 127 dbFactTable.getName(), 128 matchCount, 129 factUsage.getSymbolicName(), 130 factUsage.getColumn().getName(), 131 factUsage.getAggregator().getName()); 132 msgRecorder.reportError(msg); 133 134 returnValue = false; 135 } 136 } 137 return measureCountCount; 138 139 } finally { 140 msgRecorder.popContextName(); 141 } 142 } 143 144 /** 145 * This creates a foreign key usage. 146 * 147 * <p>Using the foreign key Matcher with the fact usage's column name the 148 * aggregate table's columns are searched for one that matches. For each 149 * that matches a foreign key usage is created (thought if more than one is 150 * created its is an error which is handled in the calling code. 151 */ 152 protected int matchForeignKey(JdbcSchema.Table.Column.Usage factUsage) { 153 JdbcSchema.Table.Column factColumn = factUsage.getColumn(); 154 155 // search to see if any of the aggTable's columns match 156 Recognizer.Matcher matcher = 157 getRules().getForeignKeyMatcher(factColumn.getName()); 158 159 int matchCount = 0; 160 for (JdbcSchema.Table.Column aggColumn : aggTable.getColumns()) { 161 // if marked as ignore, then do not consider 162 if (aggColumn.hasUsage(JdbcSchema.UsageType.IGNORE)) { 163 continue; 164 } 165 166 if (matcher.matches(aggColumn.getName())) { 167 makeForeignKey(factUsage, aggColumn, null); 168 matchCount++; 169 } 170 } 171 return matchCount; 172 } 173 174 /** 175 * Create level usages. 176 * 177 * <p> A Matcher is created using the Hierarchy's name, the RolapLevel 178 * name, and the column name associated with the RolapLevel's key 179 * expression. The aggregate table columns are search for the first match 180 * and, if found, a level usage is created for that column and true is 181 * returned. 182 */ 183 protected boolean matchLevel( 184 final Hierarchy hierarchy, 185 final HierarchyUsage hierarchyUsage, 186 final RolapLevel level) { 187 188 msgRecorder.pushContextName("DefaultRecognizer.matchLevel"); 189 try { 190 191 String usagePrefix = hierarchyUsage.getUsagePrefix(); 192 String hierName = hierarchy.getName(); 193 String levelName = level.getName(); 194 String levelColumnName = getColumnName(level.getKeyExp()); 195 196 Recognizer.Matcher matcher = getRules().getLevelMatcher( 197 usagePrefix, hierName, levelName, levelColumnName); 198 199 for (JdbcSchema.Table.Column aggColumn : aggTable.getColumns()) { 200 if (matcher.matches(aggColumn.getName())) { 201 makeLevel( 202 aggColumn, 203 hierarchy, 204 hierarchyUsage, 205 getColumnName(level.getKeyExp()), 206 getColumnName(level.getKeyExp()), 207 level.getName()); 208 return true; 209 } 210 } 211 return false; 212 213 } finally { 214 msgRecorder.popContextName(); 215 } 216 } 217 } 218 219 // End DefaultRecognizer.java