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-2013 Pentaho and others
009// All Rights Reserved.
010*/
011package mondrian.olap;
012
013import mondrian.resource.MondrianResource;
014
015import java.util.List;
016
017/**
018 * <code>CubeBase</code> is an abstract implementation of {@link Cube}.
019 *
020 * @author jhyde
021 * @since 6 August, 2001
022 */
023public abstract class CubeBase extends OlapElementBase implements Cube {
024
025    /** constraints indexes for adSchemaMembers
026     *
027     * http://msdn.microsoft.com/library/psdk/dasdk/mdx8h4k.htm
028     * check "Restrictions in the MEMBER Rowset" under MEMBER Rowset section
029     */
030    public static final int CATALOG_NAME = 0;
031    public static final int SCHEMA_NAME = 1;
032    public static final int CUBE_NAME = 2;
033    public static final int DIMENSION_UNIQUE_NAME = 3;
034    public static final int HIERARCHY_UNIQUE_NAME = 4;
035    public static final int LEVEL_UNIQUE_NAME = 5;
036    public static final int LEVEL_NUMBER = 6;
037    public static final int MEMBER_NAME = 7;
038    public static final int MEMBER_UNIQUE_NAME = 8;
039    public static final int MEMBER_CAPTION = 9;
040    public static final int MEMBER_TYPE = 10;
041    public static final int Tree_Operator = 11;
042    public static final int maxNofConstraintsForAdSchemaMember = 12;
043    public static final int MDTREEOP_SELF = 0;
044    public static final int MDTREEOP_CHILDREN = 1;
045    public static final int MDPROP_USERDEFINED0 = 19;
046
047    protected final String name;
048    private final String uniqueName;
049    private final String description;
050    protected Dimension[] dimensions;
051
052    /**
053     * Creates a CubeBase.
054     *
055     * @param name Name
056     * @param caption Caption
057     * @param description Description
058     * @param dimensions List of dimensions
059     */
060    protected CubeBase(
061        String name,
062        String caption,
063        boolean visible,
064        String description,
065        Dimension[] dimensions)
066    {
067        this.name = name;
068        this.caption = caption;
069        this.visible = visible;
070        this.description = description;
071        this.dimensions = dimensions;
072        this.uniqueName = Util.quoteMdxIdentifier(name);
073    }
074
075    // implement OlapElement
076    public String getName() {
077        return name;
078    }
079
080    public String getUniqueName() {
081        // return e.g. '[Sales Ragged]'
082        return uniqueName;
083    }
084
085    public String getQualifiedName() {
086        return MondrianResource.instance().MdxCubeName.str(getName());
087    }
088
089    public Dimension getDimension() {
090        return null;
091    }
092
093    public Hierarchy getHierarchy() {
094        return null;
095    }
096
097    public String getDescription() {
098        return description;
099    }
100
101    public Dimension[] getDimensions() {
102        return dimensions;
103    }
104
105    public Hierarchy lookupHierarchy(Id.NameSegment s, boolean unique) {
106        for (Dimension dimension : dimensions) {
107            Hierarchy[] hierarchies = dimension.getHierarchies();
108            for (Hierarchy hierarchy : hierarchies) {
109                String name = unique
110                    ? hierarchy.getUniqueName() : hierarchy.getName();
111                if (name.equals(s.getName())) {
112                    return hierarchy;
113                }
114            }
115        }
116        return null;
117    }
118
119    public OlapElement lookupChild(
120        SchemaReader schemaReader,
121        Id.Segment s,
122        MatchType matchType)
123    {
124        Dimension mdxDimension = lookupDimension(s);
125        if (mdxDimension != null) {
126            return mdxDimension;
127        }
128
129        final List<Dimension> dimensions = schemaReader.getCubeDimensions(this);
130
131        // Look for hierarchies named '[dimension.hierarchy]'.
132        if (s instanceof Id.NameSegment) {
133            Hierarchy hierarchy = lookupHierarchy((Id.NameSegment)s, false);
134            if (hierarchy != null) {
135                return hierarchy;
136            }
137        }
138
139        // Try hierarchies, levels and members.
140        for (Dimension dimension : dimensions) {
141            OlapElement mdxElement = dimension.lookupChild(
142                schemaReader, s, matchType);
143            if (mdxElement != null) {
144                if (mdxElement instanceof Member
145                    && MondrianProperties.instance().NeedDimensionPrefix.get())
146                {
147                    // With this property setting, don't allow members to be
148                    // referenced without at least a dimension prefix. We
149                    // allow [Store].[USA].[CA] or even [Store].[CA] but not
150                    // [USA].[CA].
151                    continue;
152                }
153                return mdxElement;
154            }
155        }
156        return null;
157    }
158
159    /**
160     * Looks up a dimension in this cube based on a component of its name.
161     *
162     * @param s Name segment
163     * @return Dimension, or null if not found
164     */
165    public Dimension lookupDimension(Id.Segment s) {
166        if (!(s instanceof Id.NameSegment)) {
167            return null;
168        }
169        final Id.NameSegment nameSegment = (Id.NameSegment) s;
170        for (Dimension dimension : dimensions) {
171            if (Util.equalName(dimension.getName(), nameSegment.name)) {
172                return dimension;
173            }
174        }
175        return null;
176    }
177
178    // ------------------------------------------------------------------------
179
180    /**
181     * Returns the first level of a given type in this cube.
182     *
183     * @param levelType Level type
184     * @return First level of given type, or null
185     */
186    private Level getTimeLevel(LevelType levelType) {
187        for (Dimension dimension : dimensions) {
188            if (dimension.getDimensionType() == DimensionType.TimeDimension) {
189                Hierarchy[] hierarchies = dimension.getHierarchies();
190                for (Hierarchy hierarchy : hierarchies) {
191                    Level[] levels = hierarchy.getLevels();
192                    for (Level level : levels) {
193                        if (level.getLevelType() == levelType) {
194                            return level;
195                        }
196                    }
197                }
198            }
199        }
200        return null;
201    }
202
203    public Level getYearLevel() {
204        return getTimeLevel(LevelType.TimeYears);
205    }
206
207    public Level getQuarterLevel() {
208        return getTimeLevel(LevelType.TimeQuarters);
209    }
210
211    public Level getMonthLevel() {
212        return getTimeLevel(LevelType.TimeMonths);
213    }
214
215    public Level getWeekLevel() {
216        return getTimeLevel(LevelType.TimeWeeks);
217    }
218}
219
220// End CubeBase.java