001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap4j/MondrianOlap4jCube.java#1 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2007-2007 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package mondrian.olap4j;
011    
012    import org.olap4j.metadata.*;
013    import org.olap4j.OlapException;
014    import org.olap4j.impl.*;
015    
016    import java.util.*;
017    
018    /**
019     * Implementation of {@link Cube}
020     * for the Mondrian OLAP engine.
021     *
022     * @author jhyde
023     * @version $Id: //open/mondrian/src/main/mondrian/olap4j/MondrianOlap4jCube.java#1 $
024     * @since May 24, 2007
025     */
026    class MondrianOlap4jCube implements Cube, Named {
027        private final mondrian.olap.Cube cube;
028        final MondrianOlap4jSchema olap4jSchema;
029    
030        MondrianOlap4jCube(
031            mondrian.olap.Cube cube,
032            MondrianOlap4jSchema olap4jSchema)
033        {
034            this.cube = cube;
035            this.olap4jSchema = olap4jSchema;
036        }
037    
038        public Schema getSchema() {
039            return olap4jSchema;
040        }
041    
042        public int hashCode() {
043            return olap4jSchema.hashCode()
044                ^ cube.hashCode();
045        }
046    
047        public boolean equals(Object obj) {
048            if (obj instanceof MondrianOlap4jCube) {
049                MondrianOlap4jCube that = (MondrianOlap4jCube) obj;
050                return this.olap4jSchema == that.olap4jSchema
051                    && this.cube.equals(that.cube);
052            }
053            return false;
054        }
055    
056        public NamedList<Dimension> getDimensions() {
057            NamedList<MondrianOlap4jDimension> list =
058                new NamedListImpl<MondrianOlap4jDimension>();
059            for (mondrian.olap.Dimension dimension : cube.getDimensions()) {
060                list.add(
061                    new MondrianOlap4jDimension(
062                        olap4jSchema, dimension));
063            }
064            return Olap4jUtil.cast(list);
065        }
066    
067        public NamedList<Hierarchy> getHierarchies() {
068            NamedList<MondrianOlap4jHierarchy> list =
069                new NamedListImpl<MondrianOlap4jHierarchy>();
070            for (mondrian.olap.Dimension dimension : cube.getDimensions()) {
071                for (mondrian.olap.Hierarchy hierarchy : dimension.getHierarchies()) {
072                    list.add(
073                        new MondrianOlap4jHierarchy(
074                            olap4jSchema, hierarchy));
075                }
076            }
077            return Olap4jUtil.cast(list);
078        }
079    
080        public List<Measure> getMeasures() {
081            final MondrianOlap4jLevel measuresLevel =
082                (MondrianOlap4jLevel)
083                    getDimensions().get("Measures").getDefaultHierarchy()
084                        .getLevels().get(0);
085            return Olap4jUtil.cast(measuresLevel.getMembers());
086        }
087    
088        public NamedList<NamedSet> getSets() {
089            final NamedListImpl<MondrianOlap4jNamedSet> list =
090                new NamedListImpl<MondrianOlap4jNamedSet>();
091            final MondrianOlap4jConnection olap4jConnection =
092                olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection;
093            for (mondrian.olap.NamedSet namedSet : cube.getNamedSets()) {
094                list.add(olap4jConnection.toOlap4j(cube, namedSet));
095            }
096            return Olap4jUtil.cast(list);
097        }
098    
099        public Collection<Locale> getSupportedLocales() {
100            throw new UnsupportedOperationException();
101        }
102    
103        public String getName() {
104            return cube.getName();
105        }
106    
107        public String getUniqueName() {
108            return cube.getUniqueName();
109        }
110    
111        public String getCaption(Locale locale) {
112            // todo: i81n
113            return cube.getCaption();
114        }
115    
116        public String getDescription(Locale locale) {
117            // todo: i81n
118            return cube.getDescription();
119        }
120    
121        public MondrianOlap4jMember lookupMember(String... nameParts) {
122            final MondrianOlap4jConnection olap4jConnection =
123                olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection;
124            final mondrian.olap.SchemaReader schemaReader =
125                cube.getSchemaReader(olap4jConnection.connection.getRole());
126    
127            final List<mondrian.olap.Id.Segment> segmentList =
128                new ArrayList<mondrian.olap.Id.Segment>();
129            for (String namePart : nameParts) {
130                segmentList.add(
131                    new mondrian.olap.Id.Segment(
132                        namePart, mondrian.olap.Id.Quoting.QUOTED));
133            }
134            final mondrian.olap.Member member =
135                schemaReader.getMemberByUniqueName(segmentList, false);
136            if (member == null) {
137                return null;
138            }
139            return olap4jConnection.toOlap4j(member);
140        }
141    
142        public List<Member> lookupMembers(
143            Set<Member.TreeOp> treeOps,
144            String... nameParts) throws OlapException
145        {
146            final MondrianOlap4jMember member = lookupMember(nameParts);
147            if (member == null) {
148                return Collections.emptyList();
149            }
150    
151            // Add ancestors and/or the parent. Ancestors are prepended, to ensure
152            // hierarchical order.
153            final List<MondrianOlap4jMember> list =
154                new ArrayList<MondrianOlap4jMember>();
155            if (treeOps.contains(Member.TreeOp.ANCESTORS)) {
156                for (MondrianOlap4jMember m = member.getParentMember();
157                    m != null;
158                    m = m.getParentMember()) {
159                    list.add(0, m);
160                }
161            } else if (treeOps.contains(Member.TreeOp.PARENT)) {
162                final MondrianOlap4jMember parentMember = member.getParentMember();
163                if (parentMember != null) {
164                    list.add(parentMember);
165                }
166            }
167    
168            // Add siblings. Siblings which occur after the member are deferred,
169            // because they occur after children and descendants in the
170            // hierarchical ordering.
171            List<MondrianOlap4jMember> remainingSiblingsList = null;
172            if (treeOps.contains(Member.TreeOp.SIBLINGS)) {
173                final MondrianOlap4jMember parentMember = member.getParentMember();
174                NamedList<MondrianOlap4jMember> siblingMembers;
175                if (parentMember != null) {
176                    siblingMembers = parentMember.getChildMembers();
177                } else {
178                    siblingMembers =
179                        Olap4jUtil.cast(member.getHierarchy().getRootMembers());
180                }
181                List<MondrianOlap4jMember> targetList = list;
182                for (MondrianOlap4jMember siblingMember : siblingMembers) {
183                    if (siblingMember.equals(member)) {
184                        targetList =
185                            remainingSiblingsList =
186                                new ArrayList<MondrianOlap4jMember>();
187                    } else {
188                        targetList.add(siblingMember);
189                    }
190                }
191            }
192    
193            // Add the member itself.
194            if (treeOps.contains(Member.TreeOp.SELF)) {
195                list.add(member);
196            }
197    
198            // Add descendants and/or children.
199            if (treeOps.contains(Member.TreeOp.DESCENDANTS)) {
200                for (MondrianOlap4jMember childMember : member.getChildMembers()) {
201                    list.add(childMember);
202                    addDescendants(list, childMember);
203                }
204            } else if (treeOps.contains(Member.TreeOp.CHILDREN)) {
205                for (MondrianOlap4jMember childMember : member.getChildMembers()) {
206                    list.add(childMember);
207                }
208            }
209            // Lastly, add siblings which occur after the member itself. They
210            // occur after all of the descendants in the hierarchical ordering.
211            if (remainingSiblingsList != null) {
212                list.addAll(remainingSiblingsList);
213            }
214            return Olap4jUtil.cast(list);
215        }
216    
217        private static void addDescendants(
218            List<MondrianOlap4jMember> list,
219            MondrianOlap4jMember member)
220        {
221            for (MondrianOlap4jMember childMember : member.getChildMembers()) {
222                list.add(childMember);
223                addDescendants(list, childMember);
224            }
225        }
226    }
227    
228    // End MondrianOlap4jCube.java