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