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.rolap;
012
013import mondrian.olap.*;
014import mondrian.rolap.TupleReader.MemberBuilder;
015import mondrian.rolap.sql.MemberChildrenConstraint;
016import mondrian.rolap.sql.TupleConstraint;
017
018import java.util.*;
019
020/**
021 * <code>CacheMemberReader</code> implements {@link MemberReader} by reading
022 * from a pre-populated array of {@link mondrian.olap.Member}s.
023 * <p>Note: CacheMemberReader can not handle ragged hierarchies. (HR
024 * Tests fail if {@link SmartMemberReader} is replaced with
025 * CacheMemberReader).
026 *
027 * @author jhyde
028 * @since 21 December, 2001
029 */
030class CacheMemberReader implements MemberReader, MemberCache {
031    private final MemberSource source;
032    private final List<RolapMember> members;
033    /** Maps a {@link MemberKey} to a {@link RolapMember}. */
034    private final Map<Object, RolapMember> mapKeyToMember;
035
036    CacheMemberReader(MemberSource source) {
037        this.source = source;
038        if (false) {
039            // we don't want the reader to write back to our cache
040            Util.discard(source.setCache(this));
041        }
042        this.mapKeyToMember = new HashMap<Object, RolapMember>();
043        this.members = source.getMembers();
044        for (int i = 0; i < members.size(); i++) {
045            RolapMember member = RolapUtil.strip(members.get(i));
046            ((RolapMemberBase) member).setOrdinal(i);
047        }
048    }
049
050    // implement MemberReader
051    public RolapHierarchy getHierarchy() {
052        return source.getHierarchy();
053    }
054
055    public boolean setCache(MemberCache cache) {
056        // we do not support cache writeback -- we must be masters of our
057        // own cache
058        return false;
059    }
060
061    public RolapMember substitute(RolapMember member) {
062        return member;
063    }
064
065    public RolapMember desubstitute(RolapMember member) {
066        return member;
067    }
068
069    public RolapMember getMemberByKey(
070        RolapLevel level, List<Comparable> keyValues)
071    {
072        assert keyValues.size() == 1;
073        return mapKeyToMember.get(keyValues.get(0));
074    }
075
076    // implement MemberReader
077    public List<RolapMember> getMembers() {
078        return members;
079    }
080
081    // implement MemberCache
082    public Object makeKey(RolapMember parent, Object key) {
083        return new MemberKey(parent, key);
084    }
085
086    // implement MemberCache
087    public RolapMember getMember(Object key) {
088        return mapKeyToMember.get(key);
089    }
090    public RolapMember getMember(Object key, boolean mustCheckCacheStatus) {
091        return mapKeyToMember.get(key);
092    }
093
094    // implement MemberCache
095    public Object putMember(Object key, RolapMember value) {
096        return mapKeyToMember.put(key, value);
097    }
098
099    // don't need to implement this MemberCache method because we're never
100    // used in a context where it is needed
101    public void putChildren(
102        RolapMember member,
103        MemberChildrenConstraint constraint,
104        List<RolapMember> children)
105    {
106        throw new UnsupportedOperationException();
107    }
108
109    // don't need to implement this MemberCache method because we're never
110    // used in a context where it is needed
111    public void putChildren(
112        RolapLevel level,
113        TupleConstraint constraint,
114        List<RolapMember> children)
115    {
116        throw new UnsupportedOperationException();
117    }
118
119    // this cache is immutable
120    public boolean isMutable()
121    {
122        return false;
123    }
124
125    public RolapMember removeMember(Object key)
126    {
127        throw new UnsupportedOperationException();
128    }
129
130    public RolapMember removeMemberAndDescendants(Object key)
131    {
132        throw new UnsupportedOperationException();
133    }
134
135    // don't need to implement this MemberCache method because we're never
136    // used in a context where it is needed
137    public List<RolapMember> getChildrenFromCache(
138        RolapMember member,
139        MemberChildrenConstraint constraint)
140    {
141        return null;
142    }
143
144    // don't need to implement this MemberCache method because we're never
145    // used in a context where it is needed
146    public List<RolapMember> getLevelMembersFromCache(
147        RolapLevel level,
148        TupleConstraint constraint)
149    {
150        return null;
151    }
152
153    public RolapMember lookupMember(
154        List<Id.Segment> uniqueNameParts,
155        boolean failIfNotFound)
156    {
157        return RolapUtil.lookupMember(this, uniqueNameParts, failIfNotFound);
158    }
159
160    public List<RolapMember> getRootMembers() {
161        List<RolapMember> list = new ArrayList<RolapMember>();
162        for (RolapMember member : members) {
163            if (member.getParentMember() == null) {
164                list.add(member);
165            }
166        }
167        return list;
168    }
169
170    public List<RolapMember> getMembersInLevel(
171        RolapLevel level)
172    {
173        List<RolapMember> list = new ArrayList<RolapMember>();
174        int levelDepth = level.getDepth();
175        for (RolapMember member : members) {
176            if (member.getLevel().getDepth() == levelDepth) {
177                list.add(member);
178            }
179        }
180        return list;
181    }
182
183    public List<RolapMember> getMembersInLevel(
184        RolapLevel level,
185        TupleConstraint constraint)
186    {
187        return getMembersInLevel(level);
188    }
189
190    public int getLevelMemberCount(RolapLevel level) {
191        int count = 0;
192        int levelDepth = level.getDepth();
193        for (Member member : members) {
194            if (member.getLevel().getDepth() == levelDepth) {
195                ++count;
196            }
197        }
198        return count;
199    }
200
201    public void getMemberChildren(
202        RolapMember parentMember,
203        List<RolapMember> children)
204    {
205        for (Member member : members) {
206            if (member.getParentMember() == parentMember) {
207                ((List)children).add(member);
208            }
209        }
210    }
211
212    public Map<? extends Member, Access> getMemberChildren(
213        RolapMember member,
214        List<RolapMember> children,
215        MemberChildrenConstraint constraint)
216    {
217        getMemberChildren(member, children);
218        return Util.toNullValuesMap(children);
219    }
220
221    public void getMemberChildren(
222        List<RolapMember> parentMembers,
223        List<RolapMember> children)
224    {
225        for (Member member : members) {
226            if (parentMembers.contains(member.getParentMember())) {
227                ((List)children).add(member);
228            }
229        }
230    }
231
232    public Map<? extends Member, Access> getMemberChildren(
233        List<RolapMember> parentMembers,
234        List<RolapMember> children,
235        MemberChildrenConstraint constraint)
236    {
237        getMemberChildren(parentMembers, children);
238        return Util.toNullValuesMap(children);
239    }
240
241    public RolapMember getLeadMember(RolapMember member, int n) {
242        if (n >= 0) {
243            for (int ordinal = member.getOrdinal(); ordinal < members.size();
244                 ordinal++)
245            {
246                if ((members.get(ordinal).getLevel() == member.getLevel())
247                    && (n-- == 0))
248                {
249                    return members.get(ordinal);
250                }
251            }
252            return (RolapMember) member.getHierarchy().getNullMember();
253
254        } else {
255            for (int ordinal = member.getOrdinal(); ordinal >= 0; ordinal--) {
256                if ((members.get(ordinal).getLevel() == member.getLevel())
257                    && (n++ == 0))
258                {
259                    return members.get(ordinal);
260                }
261            }
262            return (RolapMember) member.getHierarchy().getNullMember();
263        }
264    }
265
266    public void getMemberRange(
267        RolapLevel level,
268        RolapMember startMember,
269        RolapMember endMember,
270        List<RolapMember> list)
271    {
272        assert startMember != null;
273        assert endMember != null;
274        assert startMember.getLevel() == endMember.getLevel();
275        final int endOrdinal = endMember.getOrdinal();
276        for (int i = startMember.getOrdinal(); i <= endOrdinal; i++) {
277            if (members.get(i).getLevel() == endMember.getLevel()) {
278                list.add(members.get(i));
279            }
280        }
281    }
282
283    public int getMemberCount() {
284        return members.size();
285    }
286
287    public int compare(
288        RolapMember m1,
289        RolapMember m2,
290        boolean siblingsAreEqual)
291    {
292        if (m1 == m2) {
293            return 0;
294        }
295        if (siblingsAreEqual
296            && (m1.getParentMember() == m2.getParentMember()))
297        {
298            return 0;
299        }
300        Util.assertTrue(members.get(m1.getOrdinal()) == m1);
301        Util.assertTrue(members.get(m2.getOrdinal()) == m2);
302
303        return (m1.getOrdinal() < m2.getOrdinal()) ? -1 : 1;
304    }
305
306    public MemberBuilder getMemberBuilder() {
307        return null;
308    }
309
310    public RolapMember getDefaultMember() {
311        RolapMember defaultMember =
312            (RolapMember) getHierarchy().getDefaultMember();
313        if (defaultMember != null) {
314            return defaultMember;
315        }
316        return getRootMembers().get(0);
317    }
318
319    public RolapMember getMemberParent(RolapMember member) {
320        return member.getParentMember();
321    }
322}
323
324// End CacheMemberReader.java