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) 2001-2005 Julian Hyde 008// Copyright (C) 2005-2012 Pentaho and others 009// All Rights Reserved. 010*/ 011package mondrian.olap; 012 013import mondrian.resource.MondrianResource; 014 015/** 016 * Skeleton implementation for {@link Hierarchy}. 017 * 018 * @author jhyde 019 * @since 6 August, 2001 020 */ 021public abstract class HierarchyBase 022 extends OlapElementBase 023 implements Hierarchy 024{ 025 026 protected final Dimension dimension; 027 /** 028 * <code>name</code> and <code>subName</code> are the name of the 029 * hierarchy, respectively containing and not containing dimension 030 * name. For example: 031 * <table> 032 * <tr> <th>uniqueName</th> <th>name</th> <th>subName</th></tr> 033 * <tr> <td>[Time.Weekly]</td> <td>Time.Weekly</td> <td>Weekly</td></tr> 034 * <tr> <td>[Customers]</td> <td>Customers</td> <td>null</td></tr> 035 * </table> 036 * 037 * <p>If {@link mondrian.olap.MondrianProperties#SsasCompatibleNaming} is 038 * true, name and subName have the same value. 039 */ 040 protected final String subName; 041 protected final String name; 042 protected final String uniqueName; 043 protected String description; 044 protected Level[] levels; 045 protected final boolean hasAll; 046 protected String allMemberName; 047 protected String allLevelName; 048 049 protected HierarchyBase( 050 Dimension dimension, 051 String subName, 052 String caption, 053 boolean visible, 054 String description, 055 boolean hasAll) 056 { 057 this.dimension = dimension; 058 this.hasAll = hasAll; 059 if (caption != null) { 060 this.caption = caption; 061 } else if (subName == null) { 062 this.caption = dimension.getCaption(); 063 } else { 064 this.caption = subName; 065 } 066 this.description = description; 067 this.visible = visible; 068 069 String name = dimension.getName(); 070 if (MondrianProperties.instance().SsasCompatibleNaming.get()) { 071 if (subName == null) { 072 // e.g. "Time" 073 subName = name; 074 } 075 this.subName = subName; 076 this.name = subName; 077 // e.g. "[Time].[Weekly]" for dimension "Time", hierarchy "Weekly"; 078 // "[Time]" for dimension "Time", hierarchy "Time". 079 this.uniqueName = 080 subName.equals(name) 081 ? dimension.getUniqueName() 082 : Util.makeFqName(dimension, this.name); 083 } else { 084 this.subName = subName; 085 if (this.subName != null) { 086 // e.g. "Time.Weekly" 087 this.name = name + "." + subName; 088 if (this.subName.equals(name)) { 089 this.uniqueName = dimension.getUniqueName(); 090 } else { 091 // e.g. "[Time.Weekly]" 092 this.uniqueName = Util.makeFqName(this.name); 093 } 094 } else { 095 // e.g. "Time" 096 this.name = name; 097 // e.g. "[Time]" 098 this.uniqueName = dimension.getUniqueName(); 099 } 100 } 101 } 102 103 /** 104 * Returns the name of the hierarchy sans dimension name. 105 * 106 * @return name of hierarchy sans dimension name 107 */ 108 public String getSubName() { 109 return subName; 110 } 111 112 // implement MdxElement 113 public String getUniqueName() { 114 return uniqueName; 115 } 116 117 public String getUniqueNameSsas() { 118 return Util.makeFqName(dimension, name); 119 } 120 121 public String getName() { 122 return name; 123 } 124 125 public String getQualifiedName() { 126 return MondrianResource.instance().MdxHierarchyName.str( 127 getUniqueName()); 128 } 129 130 public abstract boolean isRagged(); 131 132 public String getDescription() { 133 return description; 134 } 135 136 public Dimension getDimension() { 137 return dimension; 138 } 139 140 public Level[] getLevels() { 141 return levels; 142 } 143 144 public Hierarchy getHierarchy() { 145 return this; 146 } 147 148 public boolean hasAll() { 149 return hasAll; 150 } 151 152 public boolean equals(OlapElement mdxElement) { 153 // Use object identity, because a private hierarchy can have the same 154 // name as a public hierarchy. 155 return (this == mdxElement); 156 } 157 158 public OlapElement lookupChild( 159 SchemaReader schemaReader, 160 Id.Segment s, 161 MatchType matchType) 162 { 163 OlapElement oe; 164 if (s instanceof Id.NameSegment) { 165 Id.NameSegment nameSegment = (Id.NameSegment) s; 166 oe = Util.lookupHierarchyLevel(this, nameSegment.getName()); 167 if (oe == null) { 168 oe = Util.lookupHierarchyRootMember( 169 schemaReader, this, nameSegment, matchType); 170 } 171 } else { 172 // Key segment searches bottom level by default. For example, 173 // [Products].&[1] is shorthand for [Products].[Product Name].&[1]. 174 final Id.KeySegment keySegment = (Id.KeySegment) s; 175 oe = levels[levels.length - 1] 176 .lookupChild(schemaReader, keySegment, matchType); 177 } 178 179 if (getLogger().isDebugEnabled()) { 180 StringBuilder buf = new StringBuilder(64); 181 buf.append("HierarchyBase.lookupChild: "); 182 buf.append("name="); 183 buf.append(getName()); 184 buf.append(", childname="); 185 buf.append(s); 186 if (oe == null) { 187 buf.append(" returning null"); 188 } else { 189 buf.append(" returning elementname=").append(oe.getName()); 190 } 191 getLogger().debug(buf.toString()); 192 } 193 return oe; 194 } 195 196 public String getAllMemberName() { 197 return allMemberName; 198 } 199 200 /** 201 * Returns the name of the 'all' level in this hierarchy. 202 * 203 * @return name of the 'all' level 204 */ 205 public String getAllLevelName() { 206 return allLevelName; 207 } 208} 209 210// End HierarchyBase.java