KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > rolap > CacheControlImpl


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/rolap/CacheControlImpl.java#2 $
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) 2006-2007 Julian Hyde
7 // All Rights Reserved.
8 // You must accept the terms of that agreement to use this software.
9 */

10 package mondrian.rolap;
11
12 import mondrian.olap.*;
13 import mondrian.resource.MondrianResource;
14 import mondrian.olap.CacheControl;
15
16 import javax.sql.DataSource JavaDoc;
17 import java.util.*;
18 import java.io.PrintWriter JavaDoc;
19
20 /**
21  * Implementation of {@link CacheControl} API.
22  *
23  * @author jhyde
24  * @version $Id: //open/mondrian/src/main/mondrian/rolap/CacheControlImpl.java#2 $
25  * @since Sep 27, 2006
26  */

27 public class CacheControlImpl implements CacheControl {
28     public CellRegion createMemberRegion(Member member, boolean descendants) {
29         final ArrayList<Member> list = new ArrayList<Member>();
30         list.add(member);
31         return new MemberCellRegion(list, descendants);
32     }
33
34     public CellRegion createMemberRegion(
35         boolean lowerInclusive,
36         Member lowerMember,
37         boolean upperInclusive,
38         Member upperMember,
39         boolean descendants)
40     {
41         if (lowerMember == null) {
42             lowerInclusive = false;
43         }
44         if (upperMember == null) {
45             upperInclusive = false;
46         }
47         return new MemberRangeCellRegion(
48             (RolapMember) lowerMember, lowerInclusive,
49             (RolapMember) upperMember, upperInclusive,
50             descendants);
51     }
52
53     public CellRegion createCrossjoinRegion(CellRegion... regions) {
54         assert regions != null;
55         assert regions.length >= 2;
56         final HashSet<Dimension> set = new HashSet<Dimension>();
57         final List<CellRegionImpl> list = new ArrayList<CellRegionImpl>();
58         for (CellRegion region : regions) {
59             int prevSize = set.size();
60             List<Dimension> dimensionality = region.getDimensionality();
61             set.addAll(dimensionality);
62             if (set.size() < prevSize + dimensionality.size()) {
63                 throw MondrianResource.instance().
64                     CacheFlushCrossjoinDimensionsInCommon.ex(
65                     getDimensionalityList(regions));
66             }
67
68             flattenCrossjoin((CellRegionImpl) region, list);
69         }
70         return new CrossjoinCellRegion(list);
71     }
72
73     // Returns e.g. "'[[Product]]', '[[Time], [Product]]'"
74
private String JavaDoc getDimensionalityList(CellRegion[] regions) {
75         StringBuilder JavaDoc buf = new StringBuilder JavaDoc();
76         int k = 0;
77         for (CellRegion region : regions) {
78             if (k++ > 0) {
79                 buf.append(", ");
80             }
81             buf.append("'");
82             buf.append(region.getDimensionality().toString());
83             buf.append("'");
84         }
85         return buf.toString();
86     }
87
88     public CellRegion createUnionRegion(CellRegion... regions)
89     {
90         if (regions == null) {
91             throw new NullPointerException JavaDoc();
92         }
93         if (regions.length < 2) {
94             throw new IllegalArgumentException JavaDoc();
95         }
96         final List<CellRegionImpl> list = new ArrayList<CellRegionImpl>();
97         for (CellRegion region : regions) {
98             if (!region.getDimensionality().equals(
99                 regions[0].getDimensionality())) {
100                 throw MondrianResource.instance().
101                     CacheFlushUnionDimensionalityMismatch.ex(
102                     regions[0].getDimensionality().toString(),
103                     region.getDimensionality().toString());
104             }
105             list.add((CellRegionImpl) region);
106         }
107         return new UnionCellRegion(list);
108     }
109
110     public CellRegion createMeasuresRegion(Cube cube) {
111         final Dimension measuresDimension = cube.getDimensions()[0];
112         final Member[] measures =
113             cube.getSchemaReader(null).getLevelMembers(
114                 measuresDimension.getHierarchy().getLevels()[0],
115                 false);
116         return new MemberCellRegion(Arrays.asList(measures), false);
117     }
118
119     public void flush(CellRegion region) {
120         final List<Dimension> dimensionality = region.getDimensionality();
121         boolean found = false;
122         for (Dimension dimension : dimensionality) {
123             if (dimension.isMeasures()) {
124                 found = true;
125                 break;
126             }
127         }
128         if (!found) {
129             throw MondrianResource.instance().
130                 CacheFlushRegionMustContainMembers.ex();
131         }
132         final UnionCellRegion union = normalize((CellRegionImpl) region);
133         for (CellRegionImpl cellRegion : union.regions) {
134             // Figure out the bits.
135
flushNonUnion(cellRegion);
136         }
137     }
138
139     public void trace(String JavaDoc message) {
140         // ignore message
141
}
142
143     public void flushSchemaCache() {
144         throw new UnsupportedOperationException JavaDoc();
145     }
146
147     // todo: document
148
public void flushSchema(
149         String JavaDoc catalogUrl,
150         String JavaDoc connectionKey,
151         String JavaDoc jdbcUser,
152         String JavaDoc dataSourceStr)
153     {
154         RolapSchema.Pool.instance().remove(
155             catalogUrl,
156             connectionKey,
157             jdbcUser,
158             dataSourceStr);
159     }
160
161     // todo: document
162
public void flushSchema(
163         String JavaDoc catalogUrl,
164         DataSource JavaDoc dataSource)
165     {
166         RolapSchema.Pool.instance().remove(
167             catalogUrl,
168             dataSource);
169     }
170
171     protected void flushNonUnion(CellRegion region) {
172         throw new UnsupportedOperationException JavaDoc();
173     }
174
175     /**
176      * Normalizes a CellRegion into a union of crossjoins of member regions.
177      *
178      * @param region Region
179      * @return normalized region
180      */

181     UnionCellRegion normalize(CellRegionImpl region) {
182         // Search for Union within a Crossjoin.
183
// Crossjoin(a1, a2, Union(r1, r2, r3), a4)
184
// becomes
185
// Union(
186
// Crossjoin(a1, a2, r1, a4),
187
// Crossjoin(a1, a2, r2, a4),
188
// Crossjoin(a1, a2, r3, a4))
189

190         // First, decompose into a flat list of non-union regions.
191
List<CellRegionImpl> nonUnionList = new LinkedList<CellRegionImpl>();
192         flattenUnion(region, nonUnionList);
193
194         for (int i = 0; i < nonUnionList.size(); i++) {
195             while (true) {
196                 CellRegionImpl nonUnionRegion = nonUnionList.get(i);
197                 UnionCellRegion firstUnion = findFirstUnion(nonUnionRegion);
198                 if (firstUnion == null) {
199                     break;
200                 }
201                 List<CellRegionImpl> list = new ArrayList<CellRegionImpl>();
202                 for (CellRegionImpl unionComponent : firstUnion.regions) {
203                     // For each unionComponent in (r1, r2, r3),
204
// create Crossjoin(a1, a2, r1, a4).
205
CellRegionImpl cj =
206                         copyReplacing(
207                             nonUnionRegion,
208                             firstUnion,
209                             unionComponent);
210                     list.add(cj);
211                 }
212                 // Replace one element which contained a union with several
213
// which contain one fewer union. (Double-linked list helps
214
// here.)
215
nonUnionList.remove(i);
216                 nonUnionList.addAll(i, list);
217             }
218         }
219         return new UnionCellRegion(nonUnionList);
220     }
221
222     private CellRegionImpl copyReplacing(
223         CellRegionImpl region,
224         CellRegionImpl seek,
225         CellRegionImpl replacement)
226     {
227         if (region == seek) {
228             return replacement;
229         }
230         if (region instanceof UnionCellRegion) {
231             final UnionCellRegion union = (UnionCellRegion) region;
232             List<CellRegionImpl> list = new ArrayList<CellRegionImpl>();
233             for (CellRegionImpl child : union.regions) {
234                 list.add(copyReplacing(child, seek, replacement));
235             }
236             return new UnionCellRegion(list);
237         }
238         if (region instanceof CrossjoinCellRegion) {
239             final CrossjoinCellRegion crossjoin = (CrossjoinCellRegion) region;
240             List<CellRegionImpl> list = new ArrayList<CellRegionImpl>();
241             for (CellRegionImpl child : crossjoin.components) {
242                 list.add(copyReplacing(child, seek, replacement));
243             }
244             return new CrossjoinCellRegion(list);
245         }
246         // This region is atomic, and since regions are immutable we don't need
247
// to clone.
248
return region;
249     }
250
251     /**
252      * Flatten a region into a list of regions none of which are unions.
253      *
254      * @param region Cell region
255      * @param list Target list
256      */

257     private void flattenUnion(
258         CellRegionImpl region,
259         List<CellRegionImpl> list)
260     {
261         if (region instanceof UnionCellRegion) {
262             UnionCellRegion union = (UnionCellRegion) region;
263             for (CellRegionImpl region1 : union.regions) {
264                 flattenUnion(region1, list);
265             }
266         } else {
267             list.add(region);
268         }
269     }
270
271     /**
272      * Flattens a region into a list of regions none of which are unions.
273      *
274      * @param region Cell region
275      * @param list Target list
276      */

277     private void flattenCrossjoin(
278         CellRegionImpl region,
279         List<CellRegionImpl> list)
280     {
281         if (region instanceof CrossjoinCellRegion) {
282             CrossjoinCellRegion crossjoin = (CrossjoinCellRegion) region;
283             for (CellRegionImpl component : crossjoin.components) {
284                 flattenCrossjoin(component, list);
285             }
286         } else {
287             list.add(region);
288         }
289     }
290
291     private UnionCellRegion findFirstUnion(CellRegion region) {
292         final CellRegionVisitor visitor =
293             new CellRegionVisitorImpl() {
294                 public void visit(UnionCellRegion region) {
295                     throw new FoundOne(region);
296                 }
297             };
298         try {
299             ((CellRegionImpl) region).accept(visitor);
300             return null;
301         } catch (FoundOne foundOne) {
302             return foundOne.region;
303         }
304     }
305
306     /**
307      * Returns a list of members of the Measures dimension which are mentioned
308      * somewhere in a region specification.
309      *
310      * @param region Cell region
311      * @return List of members mentioned in cell region specification
312      */

313     static List<Member> findMeasures(CellRegion region) {
314         final List<Member> list = new ArrayList<Member>();
315         final CellRegionVisitor visitor =
316             new CellRegionVisitorImpl() {
317                 public void visit(MemberCellRegion region) {
318                     if (region.dimension.isMeasures()) {
319                         list.addAll(region.memberList);
320                     }
321                 }
322
323                 public void visit(MemberRangeCellRegion region) {
324                     if (region.level.getDimension().isMeasures()) {
325                         // FIXME: don't allow range on measures dimension
326
assert false : "ranges on measures dimension";
327                     }
328                 }
329             };
330         ((CellRegionImpl) region).accept(visitor);
331         return list;
332     }
333
334     static List<RolapStar> getStarList(CellRegion region) {
335         // Figure out which measure (therefore star) it belongs to.
336
List<RolapStar> starList = new ArrayList<RolapStar>();
337         final List<Member> measuresList = findMeasures(region);
338         for (Member member : measuresList) {
339             RolapStoredMeasure measure = (RolapStoredMeasure) member;
340             final RolapStar.Measure starMeasure =
341                 (RolapStar.Measure) measure.getStarMeasure();
342             if (!starList.contains(starMeasure.getStar())) {
343                 starList.add(starMeasure.getStar());
344             }
345         }
346         return starList;
347     }
348
349     public void printCacheState(
350         PrintWriter JavaDoc pw,
351         CellRegion region)
352     {
353         List<RolapStar> starList = getStarList(region);
354         for (RolapStar star : starList) {
355             star.print(pw, "", false);
356         }
357     }
358
359     /**
360      * Cell region formed by a list of members.
361      *
362      * @see MemberRangeCellRegion
363      */

364     static class MemberCellRegion implements CellRegionImpl {
365         private final List<Member> memberList;
366         private final Dimension dimension;
367         private final boolean descendants;
368
369         MemberCellRegion(List<Member> memberList, boolean descendants) {
370             assert memberList.size() > 0;
371             this.memberList = memberList;
372             this.dimension = (memberList.get(0)).getDimension();
373             this.descendants = descendants;
374         }
375
376         public List<Dimension> getDimensionality() {
377             return Collections.singletonList(dimension);
378         }
379
380         public String JavaDoc toString() {
381             final StringBuilder JavaDoc sb = new StringBuilder JavaDoc("Member(");
382             for (int i = 0; i < memberList.size(); i++) {
383                 if (i > 0) {
384                     sb.append(", ");
385                 }
386                 Member member = memberList.get(i);
387                 sb.append(member.toString());
388             }
389             sb.append(")");
390             return sb.toString();
391         }
392
393         public void accept(CellRegionVisitor visitor) {
394             visitor.visit(this);
395         }
396
397         public List<Member> getMemberList() {
398             return memberList;
399         }
400     }
401
402     /**
403      * Cell region formed a range of members between a lower and upper bound.
404      */

405     static class MemberRangeCellRegion implements CellRegionImpl {
406         private final RolapMember lowerMember;
407         private final boolean lowerInclusive;
408         private final RolapMember upperMember;
409         private final boolean upperInclusive;
410         private final boolean descendants;
411         private final RolapLevel level;
412
413         MemberRangeCellRegion(
414             RolapMember lowerMember,
415             boolean lowerInclusive,
416             RolapMember upperMember,
417             boolean upperInclusive,
418             boolean descendants)
419         {
420             assert lowerMember != null || upperMember != null;
421             assert lowerMember == null
422                 || upperMember == null
423                 || lowerMember.getLevel() == upperMember.getLevel();
424             assert !(lowerMember == null && lowerInclusive);
425             assert !(upperMember == null && upperInclusive);
426             this.lowerMember = lowerMember;
427             this.lowerInclusive = lowerInclusive;
428             this.upperMember = upperMember;
429             this.upperInclusive = upperInclusive;
430             this.descendants = descendants;
431             this.level = lowerMember == null ?
432                 upperMember.getLevel() :
433                 lowerMember.getLevel();
434         }
435
436         public List<Dimension> getDimensionality() {
437             return Collections.singletonList(level.getDimension());
438         }
439
440         public RolapLevel getLevel() {
441             return level;
442         }
443
444         public String JavaDoc toString() {
445             final StringBuilder JavaDoc sb = new StringBuilder JavaDoc("Range(");
446             if (lowerMember == null) {
447                 sb.append("null");
448             } else {
449                 sb.append(lowerMember);
450                 if (lowerInclusive) {
451                     sb.append(" inclusive");
452                 } else {
453                     sb.append(" exclusive");
454                 }
455             }
456             sb.append(" to ");
457             if (upperMember == null) {
458                 sb.append("null");
459             } else {
460                 sb.append(upperMember);
461                 if (upperInclusive) {
462                     sb.append(" inclusive");
463                 } else {
464                     sb.append(" exclusive");
465                 }
466             }
467             sb.append(")");
468             return sb.toString();
469         }
470
471         public void accept(CellRegionVisitor visitor) {
472             visitor.visit(this);
473         }
474
475         public boolean getLowerInclusive() {
476             return lowerInclusive;
477         }
478
479         public RolapMember getLowerBound() {
480             return lowerMember;
481         }
482
483         public boolean getUpperInclusive() {
484             return upperInclusive;
485         }
486
487         public RolapMember getUpperBound() {
488             return upperMember;
489         }
490     }
491
492     /**
493      * Cell region formed by a cartesian product of two or more CellRegions.
494      */

495     static class CrossjoinCellRegion implements CellRegionImpl {
496         final List<Dimension> dimensions;
497         private List<CellRegionImpl> components =
498             new ArrayList<CellRegionImpl>();
499
500         CrossjoinCellRegion(List<CellRegionImpl> regions) {
501             final List<Dimension> dimensionality = new ArrayList<Dimension>();
502             compute(regions, components, dimensionality);
503             dimensions = Collections.unmodifiableList(dimensionality);
504         }
505
506         private static void compute(
507             List<CellRegionImpl> regions,
508             List<CellRegionImpl> components,
509             List<Dimension> dimensionality)
510         {
511             final Set<Dimension> dimensionSet = new HashSet<Dimension>();
512             for (CellRegionImpl region : regions) {
513                 addComponents(region, components);
514
515                 final List<Dimension> regionDimensionality =
516                     region.getDimensionality();
517                 dimensionality.addAll(regionDimensionality);
518                 dimensionSet.addAll(regionDimensionality);
519                 assert dimensionSet.size() == dimensionality.size() :
520                     "dimensions in common";
521             }
522         }
523
524         public void accept(CellRegionVisitor visitor) {
525             visitor.visit(this);
526             for (CellRegion component : components) {
527                 CellRegionImpl cellRegion = (CellRegionImpl) component;
528                 cellRegion.accept(visitor);
529             }
530         }
531
532         private static void addComponents(
533             CellRegionImpl region,
534             List<CellRegionImpl> list)
535         {
536             if (region instanceof CrossjoinCellRegion) {
537                 CrossjoinCellRegion crossjoinRegion =
538                     (CrossjoinCellRegion) region;
539                 for (CellRegionImpl component : crossjoinRegion.components) {
540                     list.add(component);
541                 }
542             } else {
543                 list.add(region);
544             }
545         }
546
547         public List<Dimension> getDimensionality() {
548             return dimensions;
549         }
550
551         public String JavaDoc toString() {
552             final StringBuilder JavaDoc sb = new StringBuilder JavaDoc("Crosssjoin(");
553             for (int i = 0; i < components.size(); i++) {
554                 if (i > 0) {
555                     sb.append(", ");
556                 }
557                 CellRegion component = components.get(i);
558                 sb.append(component.toString());
559             }
560             sb.append(")");
561             return sb.toString();
562         }
563
564         public List<CellRegion> getComponents() {
565             return (List<CellRegion>) (List) components;
566         }
567     }
568
569     private static class UnionCellRegion implements CellRegionImpl {
570         private final List<CellRegionImpl> regions;
571
572         UnionCellRegion(List<CellRegionImpl> regions) {
573             this.regions = regions;
574             assert regions.size() >= 1;
575
576             // All regions must have same dimensionality.
577
for (int i = 1; i < regions.size(); i++) {
578                 final CellRegion region0 = regions.get(0);
579                 final CellRegion region = regions.get(i);
580                 assert region0.getDimensionality().equals(
581                     region.getDimensionality());
582             }
583         }
584
585         public List<Dimension> getDimensionality() {
586             return regions.get(0).getDimensionality();
587         }
588
589         public String JavaDoc toString() {
590             final StringBuilder JavaDoc sb = new StringBuilder JavaDoc("Union(");
591             for (int i = 0; i < regions.size(); i++) {
592                 if (i > 0) {
593                     sb.append(", ");
594                 }
595                 CellRegion component = regions.get(i);
596                 sb.append(component.toString());
597             }
598             sb.append(")");
599             return sb.toString();
600         }
601
602         public void accept(CellRegionVisitor visitor) {
603             visitor.visit(this);
604             for (CellRegionImpl cellRegion : regions) {
605                 cellRegion.accept(visitor);
606             }
607         }
608     }
609
610     interface CellRegionImpl extends CellRegion {
611         void accept(CellRegionVisitor visitor);
612     }
613
614     /**
615      * Visitor which visits various sub-types of {@link CellRegion}.
616      */

617     interface CellRegionVisitor {
618         void visit(MemberCellRegion region);
619         void visit(MemberRangeCellRegion region);
620         void visit(UnionCellRegion region);
621         void visit(CrossjoinCellRegion region);
622     }
623
624     private static class FoundOne extends RuntimeException JavaDoc {
625         private final UnionCellRegion region;
626
627         public FoundOne(UnionCellRegion region) {
628             this.region = region;
629         }
630     }
631
632     /**
633      * Default implementation of {@link CellRegionVisitor}.
634      */

635     private static class CellRegionVisitorImpl implements CellRegionVisitor {
636         public void visit(MemberCellRegion region) {
637             // nothing
638
}
639
640         public void visit(MemberRangeCellRegion region) {
641             // nothing
642
}
643
644         public void visit(UnionCellRegion region) {
645             // nothing
646
}
647
648         public void visit(CrossjoinCellRegion region) {
649             // nothing
650
}
651     }
652 }
653
654 // End CacheControlImpl.java
655
Popular Tags