KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > rolap > RolapSchemaReader


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/rolap/RolapSchemaReader.java#42 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 2003-2007 Julian Hyde
7 // All Rights Reserved.
8 // You must accept the terms of that agreement to use this software.
9 //
10 // jhyde, Feb 24, 2003
11 */

12 package mondrian.rolap;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Arrays JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.HashMap JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20
21 import javax.sql.DataSource JavaDoc;
22
23 import mondrian.olap.*;
24 import mondrian.olap.type.StringType;
25 import mondrian.rolap.sql.TupleConstraint;
26 import mondrian.rolap.sql.MemberChildrenConstraint;
27 import mondrian.calc.Calc;
28 import mondrian.calc.ExpCompiler;
29 import mondrian.calc.DummyExp;
30 import mondrian.calc.impl.AbstractCalc;
31 import mondrian.calc.impl.GenericCalc;
32
33 import org.apache.log4j.Logger;
34 import org.eigenbase.util.property.Property;
35
36 /**
37  * A <code>RolapSchemaReader</code> allows you to read schema objects while
38  * observing the access-control profile specified by a given role.
39  *
40  * @author jhyde
41  * @since Feb 24, 2003
42  * @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapSchemaReader.java#42 $
43  */

44 public abstract class RolapSchemaReader implements SchemaReader {
45     private final Role role;
46     private final Map JavaDoc<Hierarchy, MemberReader> hierarchyReaders = new HashMap JavaDoc<Hierarchy, MemberReader>();
47     private final RolapSchema schema;
48     private final SqlConstraintFactory sqlConstraintFactory =
49             SqlConstraintFactory.instance();
50     private static final Logger LOGGER = Logger.getLogger(RolapSchemaReader.class);
51
52     RolapSchemaReader(Role role, RolapSchema schema) {
53         assert role != null : "precondition: role != null";
54         this.role = role;
55         this.schema = schema;
56     }
57
58     public Role getRole() {
59         return role;
60     }
61
62     public Member[] getHierarchyRootMembers(Hierarchy hierarchy) {
63         final Role.HierarchyAccess hierarchyAccess = role.getAccessDetails(hierarchy);
64         Level firstLevel;
65         if (hierarchyAccess == null) {
66             firstLevel = hierarchy.getLevels()[0];
67         } else {
68             firstLevel = hierarchyAccess.getTopLevel();
69             if (firstLevel == null) {
70                 firstLevel = hierarchy.getLevels()[0];
71             }
72         }
73         return getLevelMembers(firstLevel, true);
74     }
75
76     synchronized MemberReader getMemberReader(Hierarchy hierarchy) {
77         MemberReader memberReader = hierarchyReaders.get(hierarchy);
78         if (memberReader == null) {
79             memberReader = ((RolapHierarchy) hierarchy).getMemberReader(role);
80             hierarchyReaders.put(hierarchy, memberReader);
81         }
82         return memberReader;
83     }
84
85     public void getMemberRange(Level level, Member startMember, Member endMember, List JavaDoc<Member> list) {
86         getMemberReader(level.getHierarchy()).getMemberRange(
87                 (RolapLevel) level, (RolapMember) startMember,
88                 (RolapMember) endMember, (List JavaDoc) list);
89     }
90
91     public int compareMembersHierarchically(Member m1, Member m2) {
92         RolapMember member1 = (RolapMember) m1;
93         RolapMember member2 = (RolapMember) m2;
94         final RolapHierarchy hierarchy = member1.getHierarchy();
95         Util.assertPrecondition(hierarchy == m2.getHierarchy());
96         return getMemberReader(hierarchy).compare(member1, member2, true);
97     }
98
99     public Member getMemberParent(Member member) {
100         Member parentMember = member.getParentMember();
101         // Skip over hidden parents.
102
while (parentMember != null && parentMember.isHidden()) {
103             parentMember = parentMember.getParentMember();
104         }
105         // Skip over non-accessible parents.
106
if (parentMember != null) {
107             final Role.HierarchyAccess hierarchyAccess =
108                     role.getAccessDetails(member.getHierarchy());
109             if (hierarchyAccess != null &&
110                     hierarchyAccess.getAccess(parentMember) == Access.NONE) {
111                 return null;
112             }
113         }
114         return parentMember;
115     }
116
117     public int getMemberDepth(Member member) {
118         final Role.HierarchyAccess hierarchyAccess = role.getAccessDetails(member.getHierarchy());
119         if (hierarchyAccess != null) {
120             int memberDepth = member.getLevel().getDepth();
121             final Level topLevel = hierarchyAccess.getTopLevel();
122             if (topLevel != null) {
123                 memberDepth -= topLevel.getDepth();
124             }
125             return memberDepth;
126         } else if (((RolapLevel) member.getLevel()).isParentChild()) {
127             // For members of parent-child hierarchy, members in the same level may have
128
// different depths.
129
int depth = 0;
130             for (Member m = member.getParentMember(); m != null; m = m.getParentMember()) {
131                 depth++;
132             }
133             return depth;
134         } else {
135             return member.getLevel().getDepth();
136         }
137     }
138
139
140     public Member[] getMemberChildren(Member member) {
141         return getMemberChildren(member, null);
142     }
143
144     public Member[] getMemberChildren(Member member, Evaluator context) {
145         MemberChildrenConstraint constraint =
146                 sqlConstraintFactory.getMemberChildrenConstraint(context);
147         List JavaDoc<RolapMember> memberList =
148             internalGetMemberChildren(member, constraint);
149         return memberList.toArray(new Member[memberList.size()]);
150     }
151
152     private List JavaDoc<RolapMember> internalGetMemberChildren(
153             Member member, MemberChildrenConstraint constraint) {
154         List JavaDoc<RolapMember> children = new ArrayList JavaDoc<RolapMember>();
155         final Hierarchy hierarchy = member.getHierarchy();
156         final MemberReader memberReader = getMemberReader(hierarchy);
157         memberReader.getMemberChildren(
158                 (RolapMember) member, children, constraint);
159         return children;
160     }
161
162     /**
163      * check, whether members children are cached, and
164      * if yes - return children count
165      * if no - return -1
166      */

167     public int getChildrenCountFromCache(Member member) {
168         final Hierarchy hierarchy = member.getHierarchy();
169         final MemberReader memberReader = getMemberReader(hierarchy);
170         if( !(memberReader instanceof MemberCache)) {
171             return -1;
172         }
173         List JavaDoc list = ((MemberCache)memberReader).getChildrenFromCache((RolapMember)member, null);
174         if (list == null) {
175           return -1;
176         }
177         return list.size();
178     }
179
180     /**
181      * Returns number of members in a level,
182      * if the information can be retrieved from cache.
183      * Otherwise {@link Integer#MIN_VALUE}.
184      */

185     private int getLevelCardinalityFromCache(Level level) {
186         final Hierarchy hierarchy = level.getHierarchy();
187         final MemberReader memberReader = getMemberReader(hierarchy);
188         if( !(memberReader instanceof MemberCache)) {
189             return Integer.MIN_VALUE;
190         }
191         List JavaDoc list = ((MemberCache)memberReader).getLevelMembersFromCache((RolapLevel)level, null);
192         if (list == null) {
193           return Integer.MIN_VALUE;
194         }
195         return list.size();
196     }
197
198     public int getLevelCardinality(
199         Level level,
200         boolean approximate,
201         boolean materialize)
202     {
203         int rowCount = Integer.MIN_VALUE;
204         if (approximate) {
205             // See if the schema has an approximation.
206
rowCount = level.getApproxRowCount();
207         }
208
209         if (rowCount == Integer.MIN_VALUE) {
210             // See if the precise row count is available in cache.
211
rowCount = getLevelCardinalityFromCache(level);
212         }
213
214         if (rowCount == Integer.MIN_VALUE) {
215             if (materialize) {
216                 // Either the approximate row count hasn't been set,
217
// or they want the precise row count.
218
rowCount = getLevelMembers(level, false).length;
219                 // Cache it for future.
220
((RolapLevel) level).setApproxRowCount(rowCount);
221             }
222         }
223         return rowCount;
224     }
225
226     public Member[] getMemberChildren(Member[] members) {
227         return getMemberChildren(members, null);
228     }
229
230     public Member[] getMemberChildren(Member[] members, Evaluator context) {
231         if (members.length == 0) {
232             return RolapUtil.emptyMemberArray;
233         } else {
234             MemberChildrenConstraint constraint =
235                     sqlConstraintFactory.getMemberChildrenConstraint(context);
236             final Hierarchy hierarchy = members[0].getHierarchy();
237             final MemberReader memberReader = getMemberReader(hierarchy);
238             List JavaDoc<RolapMember> children = new ArrayList JavaDoc<RolapMember>();
239             memberReader.getMemberChildren(
240                 (List JavaDoc<RolapMember>) (List JavaDoc) Arrays.asList(members),
241                 children,
242                 constraint);
243             return RolapUtil.toArray(children);
244         }
245     }
246
247     public abstract Cube getCube();
248
249     public OlapElement getElementChild(OlapElement parent, String JavaDoc name) {
250         return getElementChild(parent, name, MatchType.EXACT);
251     }
252
253     public OlapElement getElementChild(
254         OlapElement parent, String JavaDoc name, MatchType matchType)
255     {
256         return parent.lookupChild(this, name, matchType);
257     }
258
259     public Member getMemberByUniqueName(
260         String JavaDoc[] uniqueNameParts, boolean failIfNotFound) {
261         return getMemberByUniqueName(
262             uniqueNameParts, failIfNotFound, MatchType.EXACT);
263     }
264
265     public Member getMemberByUniqueName(
266             String JavaDoc[] uniqueNameParts, boolean failIfNotFound,
267             MatchType matchType) {
268         // In general, this schema reader doesn't have a cube, so we cannot
269
// start looking up members.
270
return null;
271     }
272
273     public OlapElement lookupCompound(
274         OlapElement parent,
275         String JavaDoc[] names,
276         boolean failIfNotFound,
277         int category)
278     {
279         return lookupCompound(
280             parent, names, failIfNotFound, category, MatchType.EXACT);
281     }
282
283     public OlapElement lookupCompound(
284             OlapElement parent,
285             String JavaDoc[] names,
286             boolean failIfNotFound,
287             int category,
288             MatchType matchType)
289     {
290         return Util.lookupCompound(
291                 this, parent, names, failIfNotFound, category, matchType);
292     }
293
294     public Member lookupMemberChildByName(Member parent, String JavaDoc childName)
295     {
296         return lookupMemberChildByName(parent, childName, MatchType.EXACT);
297     }
298
299     public Member lookupMemberChildByName(
300         Member parent, String JavaDoc childName, MatchType matchType)
301     {
302         LOGGER.debug("looking for child \"" + childName + "\" of " + parent);
303         try {
304             MemberChildrenConstraint constraint =
305                 (matchType == MatchType.EXACT) ?
306                     sqlConstraintFactory.getChildByNameConstraint(
307                         (RolapMember)parent, childName) :
308                     sqlConstraintFactory.getMemberChildrenConstraint(null);
309             List JavaDoc<RolapMember> children = internalGetMemberChildren(parent, constraint);
310             if (children.size() > 0) {
311                 return
312                     RolapUtil.findBestMemberMatch(
313                         children,
314                         (RolapMember) parent,
315                         children.get(0).getLevel(),
316                         childName,
317                         matchType,
318                         true);
319             }
320         } catch (NumberFormatException JavaDoc e) {
321             // this was thrown in SqlQuery#quote(boolean numeric, Object value). This happens when
322
// Mondrian searches for unqualified Olap Elements like [Month], because it tries to look up
323
// a member with that name in all dimensions. Then it generates for example
324
// "select .. from time where year = Month" which will result in a NFE because
325
// "Month" can not be parsed as a number. The real bug is probably, that Mondrian
326
// looks at members at all.
327
//
328
// @see RolapCube#lookupChild()
329
LOGGER.debug("NumberFormatException in lookupMemberChildByName for parent = \"" + parent + "\", childName=\"" + childName + "\", exception: " + e.getMessage());
330         }
331         return null;
332     }
333
334     public Member getCalculatedMember(String JavaDoc[] nameParts) {
335         // There are no calculated members defined against a schema.
336
return null;
337     }
338
339     public NamedSet getNamedSet(String JavaDoc[] nameParts) {
340         if (nameParts.length != 1) {
341             return null;
342         }
343         final String JavaDoc name = nameParts[0];
344         return schema.getNamedSet(name);
345     }
346
347     public Member getLeadMember(Member member, int n) {
348         final MemberReader memberReader = getMemberReader(member.getHierarchy());
349         return memberReader.getLeadMember((RolapMember) member, n);
350     }
351
352     public Member[] getLevelMembers(Level level, boolean includeCalculated) {
353         return getLevelMembers(level, null);
354     }
355
356     public Member[] getLevelMembers(Level level, Evaluator context) {
357         TupleConstraint constraint =
358                 sqlConstraintFactory.getLevelMembersConstraint(
359                     context,
360                     new Level [] { level });
361         final MemberReader memberReader = getMemberReader(level.getHierarchy());
362         final List JavaDoc<RolapMember> membersInLevel =
363             memberReader.getMembersInLevel(
364                 (RolapLevel) level, 0, Integer.MAX_VALUE, constraint);
365         return RolapUtil.toArray(membersInLevel);
366     }
367
368     public Level[] getHierarchyLevels(Hierarchy hierarchy) {
369         assert hierarchy != null;
370         final Role.HierarchyAccess hierarchyAccess = role.getAccessDetails(hierarchy);
371         final Level[] levels = hierarchy.getLevels();
372         if (hierarchyAccess == null) {
373             return levels;
374         }
375         Level topLevel = hierarchyAccess.getTopLevel();
376         Level bottomLevel = hierarchyAccess.getBottomLevel();
377         if ((topLevel == null) && (bottomLevel == null)) {
378             return levels;
379         }
380         if (topLevel == null) {
381             topLevel = levels[0];
382         }
383         if (bottomLevel == null) {
384             bottomLevel = levels[levels.length - 1];
385         }
386         final int levelCount = bottomLevel.getDepth() - topLevel.getDepth() + 1;
387         Level[] restrictedLevels = new Level[levelCount];
388         System.arraycopy(levels, topLevel.getDepth(), restrictedLevels, 0, levelCount);
389         Util.assertPostcondition(restrictedLevels.length >= 1, "return.length >= 1");
390         return restrictedLevels;
391     }
392
393     public Member getHierarchyDefaultMember(Hierarchy hierarchy) {
394         assert hierarchy != null;
395         Member defaultMember = hierarchy.getDefaultMember();
396         // If the whole hierarchy is inaccessible, return the intrinsic default member.
397
// This is important to construct a evaluator.
398
if (role.getAccess(hierarchy) != Access.NONE) {
399             // If there's not an accessible intrinsic default member,
400
// lookup the top accessible level's first accessible member.
401
if (defaultMember == null || (!role.canAccess(defaultMember))) {
402                 Member[] rootMembers = this.getHierarchyRootMembers(hierarchy);
403                 defaultMember = (rootMembers.length > 0) ? rootMembers[0] : null;
404             }
405         }
406         return defaultMember;
407     }
408
409     public boolean isDrillable(Member member) {
410         final RolapLevel level = (RolapLevel) member.getLevel();
411         if (level.getParentExp() != null) {
412             // This is a parent-child level, so its children, if any, come from
413
// the same level.
414
//
415
// todo: More efficient implementation
416
return getMemberChildren(member).length > 0;
417         } else {
418             // This is a regular level. It has children iff there is a lower
419
// level.
420
final Level childLevel = level.getChildLevel();
421             return (childLevel != null) &&
422                     (role.getAccess(childLevel) != Access.NONE);
423         }
424     }
425
426     public boolean isVisible(Member member) {
427         return !member.isHidden() && role.canAccess(member);
428     }
429
430     public Cube[] getCubes() {
431         List JavaDoc<RolapCube> cubes = schema.getCubeList();
432         List JavaDoc<Cube> visibleCubes = new ArrayList JavaDoc<Cube>(cubes.size());
433
434         for (Cube cube : cubes) {
435             if (role.canAccess(cube)) {
436                 visibleCubes.add(cube);
437             }
438         }
439
440         return visibleCubes.toArray(new Cube[visibleCubes.size()]);
441     }
442
443     public List JavaDoc<Member> getCalculatedMembers(Hierarchy hierarchy) {
444         return Collections.emptyList();
445     }
446
447     public List JavaDoc<Member> getCalculatedMembers(Level level) {
448         return Collections.emptyList();
449     }
450
451     public List JavaDoc<Member> getCalculatedMembers() {
452         return Collections.emptyList();
453     }
454
455     public NativeEvaluator getNativeSetEvaluator(
456             FunDef fun, Exp[] args, Evaluator evaluator, Calc calc) {
457         RolapEvaluator revaluator = (RolapEvaluator)
458                 AbstractCalc.simplifyEvaluator(calc, evaluator);
459         return schema.getNativeRegistry().createEvaluator(revaluator, fun, args);
460     }
461
462     public Parameter getParameter(String JavaDoc name) {
463         // Scan through schema parameters.
464
for (RolapSchemaParameter parameter : schema.parameterList) {
465             if (Util.equalName(parameter.getName(), name)) {
466                 return parameter;
467             }
468         }
469
470         // Scan through mondrian and system properties.
471
List JavaDoc<Property> propertyList = MondrianProperties.instance().getPropertyList();
472         for (Property property : propertyList) {
473             if (property.getPath().equals(name)) {
474                 return new SystemPropertyParameter(name, false);
475             }
476         }
477         if (System.getProperty(name) != null) {
478             return new SystemPropertyParameter(name, true);
479         }
480
481         return null;
482     }
483
484     public DataSource JavaDoc getDataSource() {
485         return schema.getInternalConnection().getDataSource();
486     }
487
488     RolapSchema getSchema() {
489         return schema;
490     }
491
492     /**
493      * Implementation of {@link Parameter} which is sourced from system
494      * propertes (see {@link System#getProperties()} or mondrian properties
495      * (see {@link MondrianProperties}.
496      *
497      * <p>The name of the property is the same as the key into the
498      * {@link java.util.Properties} object; for example "java.version" or
499      * "mondrian.trace.level".
500      */

501     private static class SystemPropertyParameter
502         extends ParameterImpl
503     {
504         /**
505          * true if source is a system property;
506          * false if source is a mondrian property.
507          */

508         private final boolean system;
509         /**
510          * Definition of mondrian property, or null if system property.
511          */

512         private final Property propertyDefinition;
513
514         public SystemPropertyParameter(String JavaDoc name, boolean system) {
515             super(name,
516                 Literal.nullValue,
517                 "System property '" + name + "'",
518                 new StringType());
519             this.system = system;
520             this.propertyDefinition =
521                 system ? null :
522                 MondrianProperties.instance().getPropertyDefinition(name);
523         }
524
525         public Scope getScope() {
526             return Scope.System;
527         }
528
529         public boolean isModifiable() {
530             return false;
531         }
532
533         public Calc compile(ExpCompiler compiler) {
534             return new GenericCalc(new DummyExp(getType())) {
535                 public Calc[] getCalcs() {
536                     return new Calc[0];
537                 }
538
539                 public Object JavaDoc evaluate(Evaluator evaluator) {
540                     if (system) {
541                         final String JavaDoc name = SystemPropertyParameter.this.getName();
542                         return System.getProperty(name);
543                     } else {
544                         return propertyDefinition.stringValue();
545                     }
546                 }
547             };
548         }
549     }
550 }
551
552 // End RolapSchemaReader.java
553
Popular Tags