001 /* 002 // $Id: //open/mondrian/src/main/mondrian/rolap/RolapCubeMember.java#8 $ 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 // wgorman, 19 October 2007 012 */ 013 014 package mondrian.rolap; 015 016 import java.util.ArrayList; 017 import java.util.List; 018 019 import mondrian.mdx.HierarchyExpr; 020 import mondrian.mdx.ResolvedFunCall; 021 import mondrian.olap.Exp; 022 import mondrian.olap.Id; 023 import mondrian.olap.MatchType; 024 import mondrian.olap.Member; 025 import mondrian.olap.OlapElement; 026 import mondrian.olap.Property; 027 import mondrian.olap.SchemaReader; 028 029 /** 030 * RolapCubeMember wraps RolapMembers and binds them to a specific cube. 031 * RolapCubeMember wraps or overrides RolapMember methods that directly 032 * reference the wrapped Member. Methods that only contain calls to other 033 * methods do not need wrapped. 034 * 035 * @author Will Gorman (wgorman@pentaho.org) 036 * @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapCubeMember.java#8 $ 037 */ 038 public class RolapCubeMember extends RolapMember { 039 040 protected final String rolapAllMemberCubeName; 041 042 protected final RolapMember rolapMember; 043 044 protected final RolapCubeLevel rolapLevel; 045 046 protected final RolapCube rolapCube; 047 048 public RolapCubeMember(RolapCubeMember parent, RolapMember member, 049 RolapCubeLevel level, RolapCube cube) { 050 super(); 051 052 this.parentMember = parent; 053 this.rolapMember = member; 054 this.rolapLevel = level; 055 this.rolapCube = cube; 056 if (parent != null) { 057 this.parentUniqueName = parent.getUniqueName(); 058 } 059 if (member.isAll()) { 060 // this is a special case ... 061 // replace hierarchy name portion of all member with new name 062 if (member.getLevel().getHierarchy().getName().equals( 063 level.getHierarchy().getName())) { 064 rolapAllMemberCubeName = member.getName(); 065 } else { 066 // special case if we're dealing with a closure 067 String replacement = 068 level.getHierarchy().getName().replaceAll("\\$", "\\\\\\$"); 069 070 // convert string to regular expression 071 String memberLevelName = member.getLevel().getHierarchy().getName().replaceAll("\\.", "\\\\."); 072 073 rolapAllMemberCubeName = member.getName().replaceAll( 074 memberLevelName, 075 replacement); 076 } 077 setUniqueName(rolapAllMemberCubeName); 078 } else { 079 rolapAllMemberCubeName = null; 080 Object name = rolapMember.getPropertyValue(Property.NAME.name); 081 if (name != null 082 && !(rolapMember.getKey() != null && name.equals(rolapMember 083 .getKey()))) { 084 // Save memory by only saving the name as a property if it's 085 // different from the key. 086 setUniqueName(name); 087 } else if (rolapMember.getKey() != null) { 088 setUniqueName(rolapMember.getKey()); 089 } 090 } 091 } 092 093 public int getDepth() { 094 return rolapMember.getDepth(); 095 } 096 097 public boolean isNull() { 098 return rolapMember.isNull(); 099 } 100 101 public boolean isMeasure() { 102 return rolapMember.isMeasure(); 103 } 104 105 public boolean isAll() { 106 return rolapMember.isAll(); 107 } 108 109 public RolapMember getRolapMember() { 110 return rolapMember; 111 } 112 113 /** 114 * Returns the cube this cube member belongs to. 115 * 116 * <p>This method is not in the {@link Member} interface, because regular 117 * members may be shared, and therefore do not belong to a specific cube. 118 * 119 * @return Cube this cube member belongs to 120 */ 121 public RolapCube getCube() { 122 return rolapCube; 123 } 124 125 public Member getDataMember() { 126 127 RolapMember member = (RolapMember) rolapMember.getDataMember(); 128 if (member != null) { 129 RolapCubeMember cubeDataMember = 130 new RolapCubeMember( 131 getParentMember(), member, 132 getLevel(), this.rolapCube); 133 return cubeDataMember; 134 } else { 135 return null; 136 } 137 } 138 139 public int compareTo(Object o) { 140 // light wrapper around rolap member compareTo 141 RolapCubeMember other = (RolapCubeMember) o; 142 return rolapMember.compareTo(other.rolapMember); 143 } 144 145 public boolean equals(Object o) { 146 return (o == this) 147 || ((o instanceof RolapCubeMember) 148 && equals((RolapCubeMember) o)); 149 } 150 151 public boolean equals(OlapElement o) { 152 return o.getClass() == RolapCubeMember.class 153 && equals((RolapCubeMember) o); 154 } 155 156 private boolean equals(RolapCubeMember that) { 157 assert that != null; // public method should have checked 158 // Do not use equalsIgnoreCase; unique names should be identical, and 159 // hashCode assumes this. 160 return this.rolapLevel.equals(that.rolapLevel) 161 && this.rolapMember.equals(that.rolapMember); 162 } 163 164 public Object getKey() { 165 return rolapMember.getKey(); 166 } 167 168 // override with stricter return type 169 public RolapCubeHierarchy getHierarchy() { 170 return (RolapCubeHierarchy) super.getHierarchy(); 171 } 172 173 /** 174 * {@inheritDoc} 175 * 176 * <p>This method is central to how RolapCubeMember works. It allows 177 * a member from the cache to be used within different usages of the same 178 * shared dimension. The cache member is the same, but the RolapCubeMembers 179 * wrapping the cache member report that they belong to different levels, 180 * and hence different hierarchies, dimensions, and cubes. 181 */ 182 // this is cube dependent 183 public RolapCubeLevel getLevel() { 184 return rolapLevel; 185 } 186 187 public String getName() { 188 if (rolapMember.isAll()) { 189 return rolapAllMemberCubeName; 190 } 191 return rolapMember.getName(); 192 } 193 194 public Comparable getOrderKey() { 195 return rolapMember.getOrderKey(); 196 } 197 198 void setOrderKey(Comparable orderKey) { 199 // this should never be called 200 throw new UnsupportedOperationException(); 201 } 202 203 public int getOrdinal() { 204 return rolapMember.getOrdinal(); 205 } 206 207 void setOrdinal(int ordinal) { 208 rolapMember.setOrdinal(ordinal); 209 } 210 211 public synchronized void setProperty(String name, Object value) { 212 rolapMember.setProperty(name, value); 213 } 214 215 public Object getPropertyValue(String propertyName, boolean matchCase) { 216 217 // we need to wrap these children as rolap cube members 218 Property property = Property.lookup(propertyName, matchCase); 219 if (property != null) { 220 Member parentMember; 221 switch (property.ordinal) { 222 case Property.CONTRIBUTING_CHILDREN_ORDINAL: 223 List<RolapMember> list = new ArrayList<RolapMember>(); 224 List<RolapMember> origList = 225 (List) rolapMember.getPropertyValue( 226 propertyName, matchCase); 227 for (RolapMember member : origList) { 228 list.add( 229 new RolapCubeMember( 230 this, member, this.getLevel(), this.rolapCube)); 231 } 232 return list; 233 234 case Property.DIMENSION_UNIQUE_NAME_ORDINAL: 235 return getHierarchy().getDimension().getUniqueName(); 236 237 case Property.HIERARCHY_UNIQUE_NAME_ORDINAL: 238 return getHierarchy().getUniqueName(); 239 240 case Property.LEVEL_UNIQUE_NAME_ORDINAL: 241 return getLevel().getUniqueName(); 242 243 case Property.MEMBER_UNIQUE_NAME_ORDINAL: 244 return getUniqueName(); 245 246 case Property.MEMBER_NAME_ORDINAL: 247 return getName(); 248 249 case Property.MEMBER_CAPTION_ORDINAL: 250 return getCaption(); 251 252 case Property.PARENT_UNIQUE_NAME_ORDINAL: 253 parentMember = getParentMember(); 254 return parentMember == null ? null : parentMember 255 .getUniqueName(); 256 case Property.CHILDREN_CARDINALITY_ORDINAL: 257 // because rolapcalculated member overrides this property, 258 // we need to make sure it gets called 259 if (rolapMember instanceof RolapCalculatedMember) { 260 return 261 rolapMember.getPropertyValue(propertyName, matchCase); 262 } else { 263 return super.getPropertyValue(propertyName, matchCase); 264 } 265 266 case Property.MEMBER_KEY_ORDINAL: 267 case Property.KEY_ORDINAL: 268 return this == this.getHierarchy().getAllMember() ? 0 269 : getKey(); 270 271 } 272 } 273 // fall through to rolap member 274 return rolapMember.getPropertyValue(propertyName, matchCase); 275 } 276 277 public int getSolveOrder() { 278 return rolapMember.getSolveOrder(); 279 } 280 281 protected Object getPropertyFromMap(String propertyName, 282 boolean matchCase) { 283 return rolapMember.getPropertyFromMap(propertyName, matchCase); 284 } 285 286 public final MemberType getMemberType() { 287 return rolapMember.getMemberType(); 288 } 289 290 public RolapCubeMember getParentMember() { 291 return (RolapCubeMember) super.getParentMember(); 292 } 293 294 public String getCaption() { 295 return rolapMember.getCaption(); 296 } 297 298 public boolean isCalculated() { 299 return rolapMember.isCalculated(); 300 } 301 302 public boolean isCalculatedInQuery() { 303 return rolapMember.isCalculatedInQuery(); 304 } 305 306 // this method is overridden to make sure that any HierarchyExpr returns 307 // the cube hierarchy vs. shared hierarchy. this is the case for 308 // SqlMemberSource.RolapParentChildMemberNoClosure 309 public Exp getExpression() { 310 Exp exp = rolapMember.getExpression(); 311 if (exp instanceof ResolvedFunCall) { 312 // convert any args to RolapCubeHierarchies 313 ResolvedFunCall fcall = (ResolvedFunCall)exp; 314 for (int i = 0; i < fcall.getArgCount(); i++) { 315 if (fcall.getArg(i) instanceof HierarchyExpr) { 316 HierarchyExpr expr = (HierarchyExpr)fcall.getArg(i); 317 if (expr.getHierarchy().equals(rolapMember.getHierarchy())) { 318 fcall.getArgs()[i] = new HierarchyExpr(this.getHierarchy()); 319 } 320 } 321 } 322 323 } 324 return exp; 325 } 326 327 public OlapElement lookupChild(SchemaReader schemaReader, 328 Id.Segment childName, MatchType matchType) { 329 return 330 schemaReader.lookupMemberChildByName(this, childName, matchType); 331 } 332 333 } 334 335 // End RolapCubeMember.java