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) 2007-2012 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.rolap;
011
012import mondrian.olap.Access;
013import mondrian.olap.Id;
014import mondrian.olap.Member;
015import mondrian.rolap.sql.MemberChildrenConstraint;
016import mondrian.rolap.sql.TupleConstraint;
017
018import java.sql.SQLException;
019import java.util.*;
020
021/**
022 * Implementation of {@link MemberReader} which replaces given members
023 * with a substitute.
024 *
025 * <p>Derived classes must implement the {@link #substitute(RolapMember)} and
026 * {@link #desubstitute(RolapMember)} methods.
027 *
028 * @author jhyde
029 * @since Oct 5, 2007
030 */
031public abstract class SubstitutingMemberReader extends DelegatingMemberReader {
032    private final TupleReader.MemberBuilder memberBuilder =
033        new SubstitutingMemberBuilder();
034
035    /**
036     * Creates a SubstitutingMemberReader.
037     *
038     * @param memberReader Parent member reader
039     */
040    SubstitutingMemberReader(MemberReader memberReader) {
041        super(memberReader);
042    }
043
044    // Helper methods
045
046    private List<RolapMember> desubstitute(List<RolapMember> members) {
047        List<RolapMember> list = new ArrayList<RolapMember>(members.size());
048        for (RolapMember member : members) {
049            list.add(desubstitute(member));
050        }
051        return list;
052    }
053
054    private List<RolapMember> substitute(List<RolapMember> members) {
055        List<RolapMember> list = new ArrayList<RolapMember>(members.size());
056        for (RolapMember member : members) {
057            list.add(substitute(member));
058        }
059        return list;
060    }
061
062    // ~ -- Implementations of MemberReader methods ---------------------------
063
064    @Override
065    public RolapMember getLeadMember(RolapMember member, int n) {
066        return substitute(
067            memberReader.getLeadMember(desubstitute(member), n));
068    }
069
070    @Override
071    public List<RolapMember> getMembersInLevel(
072        RolapLevel level)
073    {
074        return substitute(memberReader.getMembersInLevel(level));
075    }
076
077    @Override
078    public void getMemberRange(
079        RolapLevel level,
080        RolapMember startMember,
081        RolapMember endMember,
082        List<RolapMember> list)
083    {
084        memberReader.getMemberRange(
085            level,
086            desubstitute(startMember),
087            desubstitute(endMember),
088            new SubstitutingMemberList(list));
089    }
090
091    @Override
092    public int compare(
093        RolapMember m1,
094        RolapMember m2,
095        boolean siblingsAreEqual)
096    {
097        return memberReader.compare(
098            desubstitute(m1),
099            desubstitute(m2),
100            siblingsAreEqual);
101    }
102
103    @Override
104    public RolapHierarchy getHierarchy() {
105        return memberReader.getHierarchy();
106    }
107
108    @Override
109    public boolean setCache(MemberCache cache) {
110        // cache semantics don't make sense if members are not comparable
111        throw new UnsupportedOperationException();
112    }
113
114    @Override
115    public List<RolapMember> getMembers() {
116        // might make sense, but I doubt it
117        throw new UnsupportedOperationException();
118    }
119
120    @Override
121    public List<RolapMember> getRootMembers() {
122        return substitute(memberReader.getRootMembers());
123    }
124
125    @Override
126    public void getMemberChildren(
127        RolapMember parentMember,
128        List<RolapMember> children)
129    {
130        memberReader.getMemberChildren(
131            desubstitute(parentMember),
132            new SubstitutingMemberList(children));
133    }
134
135    @Override
136    public void getMemberChildren(
137        List<RolapMember> parentMembers,
138        List<RolapMember> children)
139    {
140        memberReader.getMemberChildren(
141            desubstitute(parentMembers),
142            new SubstitutingMemberList(children));
143    }
144
145    @Override
146    public int getMemberCount() {
147        return memberReader.getMemberCount();
148    }
149
150    @Override
151    public RolapMember lookupMember(
152        List<Id.Segment> uniqueNameParts,
153        boolean failIfNotFound)
154    {
155        return substitute(
156            memberReader.lookupMember(uniqueNameParts, failIfNotFound));
157    }
158
159    public Map<? extends Member, Access> getMemberChildren(
160        RolapMember member,
161        List<RolapMember> children,
162        MemberChildrenConstraint constraint)
163    {
164        return memberReader.getMemberChildren(
165            desubstitute(member),
166            new SubstitutingMemberList(children),
167            constraint);
168    }
169
170    public Map<? extends Member, Access> getMemberChildren(
171        List<RolapMember> parentMembers,
172        List<RolapMember> children,
173        MemberChildrenConstraint constraint)
174    {
175        return memberReader.getMemberChildren(
176            desubstitute(parentMembers),
177            new SubstitutingMemberList(children),
178            constraint);
179    }
180
181    @Override
182    public List<RolapMember> getMembersInLevel(
183        RolapLevel level, TupleConstraint constraint)
184    {
185        return substitute(
186            memberReader.getMembersInLevel(
187                level, constraint));
188    }
189
190    @Override
191    public RolapMember getDefaultMember() {
192        return substitute(memberReader.getDefaultMember());
193    }
194
195    @Override
196    public RolapMember getMemberParent(RolapMember member) {
197        return substitute(memberReader.getMemberParent(desubstitute(member)));
198    }
199
200    @Override
201    public TupleReader.MemberBuilder getMemberBuilder() {
202        return memberBuilder;
203    }
204
205    /**
206     * List which writes through to an underlying list, substituting members
207     * as they are written and desubstituting as they are read.
208     */
209    class SubstitutingMemberList extends AbstractList<RolapMember> {
210        private final List<RolapMember> list;
211
212        SubstitutingMemberList(List<RolapMember> list) {
213            this.list = list;
214        }
215
216        @Override
217        public RolapMember get(int index) {
218            return desubstitute(list.get(index));
219        }
220
221        @Override
222        public int size() {
223            return list.size();
224        }
225
226        @Override
227        public RolapMember set(int index, RolapMember element) {
228            return desubstitute(list.set(index, substitute(element)));
229        }
230
231        @Override
232        public void add(int index, RolapMember element) {
233            list.add(index, substitute(element));
234        }
235
236        @Override
237        public RolapMember remove(int index) {
238            return list.remove(index);
239        }
240    }
241
242    private class SubstitutingMemberBuilder
243        implements TupleReader.MemberBuilder
244    {
245        public MemberCache getMemberCache() {
246            return memberReader.getMemberBuilder().getMemberCache();
247        }
248
249        public Object getMemberCacheLock() {
250            return memberReader.getMemberBuilder().getMemberCacheLock();
251        }
252
253        public RolapMember makeMember(
254            RolapMember parentMember,
255            RolapLevel childLevel,
256            Object value,
257            Object captionValue,
258            boolean parentChild,
259            SqlStatement stmt,
260            Object key,
261            int column) throws SQLException
262        {
263            return substitute(
264                memberReader.getMemberBuilder().makeMember(
265                    desubstitute(parentMember),
266                    childLevel,
267                    value,
268                    captionValue,
269                    parentChild,
270                    stmt,
271                    key,
272                    column));
273        }
274
275        public RolapMember allMember() {
276            return substitute(memberReader.getHierarchy().getAllMember());
277        }
278    }
279}
280
281// End SubstitutingMemberReader.java