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