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