001 /* 002 // $Id: //open/mondrian/src/main/mondrian/rolap/RolapDimension.java#32 $ 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) 2001-2002 Kana Software, Inc. 007 // Copyright (C) 2001-2008 Julian Hyde and others 008 // All Rights Reserved. 009 // You must accept the terms of that agreement to use this software. 010 // 011 // jhyde, 10 August, 2001 012 */ 013 014 package mondrian.rolap; 015 016 import org.apache.log4j.Logger; 017 import mondrian.olap.*; 018 import mondrian.resource.MondrianResource; 019 020 /** 021 * <code>RolapDimension</code> implements {@link Dimension}for a ROLAP 022 * database. 023 * 024 * <h2><a name="topic_ordinals">Topic: Dimension ordinals </a></h2> 025 * 026 * {@link RolapEvaluator} needs each dimension to have an ordinal, so that it 027 * can store the evaluation context as an array of members. 028 * 029 * <p> 030 * The ordinal of a dimension <em>within a particular cube</em> is found by 031 * calling {@link #getOrdinal(Cube)}. Ordinals 032 * are contiguous and zero-based. Zero is always the <code>[Measures]</code> 033 * dimension. 034 * 035 * <p> 036 * A dimension may be either shared or private to a particular cube. The 037 * dimension object doesn't actually know which; {@link Schema} has a list of 038 * shared hierarchies ({@link Schema#getSharedHierarchies}), and {@link Cube} 039 * has a list of dimensions ({@link Cube#getDimensions}). 040 * 041 * <p> 042 * If a dimension is shared between several cubes, the {@link Dimension}objects 043 * which represent them may (or may not be) the same. (That's why there's no 044 * <code>getCube()</code> method.) 045 * 046 * <p> 047 * Furthermore, since members are created by a {@link MemberReader}which 048 * belongs to the {@link RolapHierarchy}, you will the members will be the same 049 * too. For example, if you query <code>[Product].[Beer]</code> from the 050 * <code>Sales</code> and <code>Warehouse</code> cubes, you will get the 051 * same {@link RolapMember}object. 052 * ({@link RolapSchema#mapSharedHierarchyToReader} holds the mapping. I don't 053 * know whether it's still necessary.) 054 * 055 * @author jhyde 056 * @since 10 August, 2001 057 * @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapDimension.java#32 $ 058 */ 059 class RolapDimension extends DimensionBase { 060 061 private static final Logger LOGGER = Logger.getLogger(RolapDimension.class); 062 063 private final Schema schema; 064 065 RolapDimension( 066 Schema schema, 067 String name, 068 DimensionType dimensionType, 069 final boolean highCardinality) 070 { 071 // todo: recognition of a time dimension should be improved 072 // allow multiple time dimensions 073 super(name, dimensionType, highCardinality); 074 this.schema = schema; 075 this.hierarchies = new RolapHierarchy[0]; 076 } 077 078 /** 079 * Creates a dimension from an XML definition. 080 * 081 * @pre schema != null 082 */ 083 RolapDimension( 084 RolapSchema schema, 085 RolapCube cube, 086 MondrianDef.Dimension xmlDimension, 087 MondrianDef.CubeDimension xmlCubeDimension) 088 { 089 this( 090 schema, 091 xmlDimension.name, 092 xmlDimension.getDimensionType(), 093 xmlDimension.highCardinality); 094 095 Util.assertPrecondition(schema != null); 096 097 if (cube != null) { 098 Util.assertTrue(cube.getSchema() == schema); 099 } 100 101 if (!Util.isEmpty(xmlDimension.caption)) { 102 setCaption(xmlDimension.caption); 103 } 104 this.hierarchies = new RolapHierarchy[xmlDimension.hierarchies.length]; 105 for (int i = 0; i < xmlDimension.hierarchies.length; i++) { 106 107 // remaps the xml hierarchy relation to the fact table. 108 // moved out of RolapHierarchy constructor 109 // this should eventually be phased out completely 110 if (xmlDimension.hierarchies[i].relation == null && 111 xmlDimension.hierarchies[i].memberReaderClass == null && 112 cube != null) { 113 xmlDimension.hierarchies[i].relation = cube.fact; 114 } 115 116 RolapHierarchy hierarchy = new RolapHierarchy( 117 this, xmlDimension.hierarchies[i], xmlCubeDimension); 118 hierarchies[i] = hierarchy; 119 } 120 121 // if there was no dimension type assigned, determine now. 122 if (dimensionType == null) { 123 for (int i = 0; i < hierarchies.length; i++) { 124 Level[] levels = hierarchies[i].getLevels(); 125 LevLoop: 126 for (int j = 0; j < levels.length; j++) { 127 Level lev = levels[j]; 128 if (lev.isAll()) { 129 continue LevLoop; 130 } 131 if (dimensionType == null) { 132 // not set yet - set it according to current level 133 dimensionType = (lev.getLevelType().isTime()) 134 ? DimensionType.TimeDimension 135 : isMeasures() 136 ? DimensionType.MeasuresDimension 137 : DimensionType.StandardDimension; 138 139 } else { 140 // Dimension type was set according to first level. 141 // Make sure that other levels fit to definition. 142 if (dimensionType == DimensionType.TimeDimension && 143 !lev.getLevelType().isTime() && 144 !lev.isAll()) { 145 throw MondrianResource.instance().NonTimeLevelInTimeHierarchy.ex( 146 getUniqueName()); 147 } 148 if (dimensionType != DimensionType.TimeDimension && 149 lev.getLevelType().isTime()) { 150 throw MondrianResource.instance().TimeLevelInNonTimeHierarchy.ex( 151 getUniqueName()); 152 } 153 } 154 } 155 } 156 } 157 } 158 159 protected Logger getLogger() { 160 return LOGGER; 161 } 162 163 /** 164 * Initializes a dimension within the context of a cube. 165 */ 166 void init(MondrianDef.CubeDimension xmlDimension) { 167 for (int i = 0; i < hierarchies.length; i++) { 168 if (hierarchies[i] != null) { 169 ((RolapHierarchy) hierarchies[i]).init(xmlDimension); 170 } 171 } 172 } 173 174 RolapHierarchy newHierarchy(String subName, boolean hasAll) { 175 RolapHierarchy hierarchy = new RolapHierarchy(this, subName, hasAll); 176 this.hierarchies = (RolapHierarchy[]) 177 RolapUtil.addElement(this.hierarchies, hierarchy); 178 return hierarchy; 179 } 180 181 /** 182 * Returns the hierarchy of an expression. 183 * 184 * <p>In this case, the expression is a dimension, so the hierarchy is the 185 * dimension's default hierarchy (its first). 186 */ 187 public Hierarchy getHierarchy() { 188 return hierarchies[0]; 189 } 190 191 public int getOrdinal(Cube cube) { 192 // this is temporary to verify that all calls to this method are for 193 // the measures dimension 194 assert isMeasures(); 195 return 0; 196 } 197 198 public Schema getSchema() { 199 return schema; 200 } 201 } 202 203 // End RolapDimension.java