KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > rolap > HierarchyUsage


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/rolap/HierarchyUsage.java#19 $
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) 2002-2002 Kana Software, Inc.
7 // Copyright (C) 2002-2006 Julian Hyde and others
8 // All Rights Reserved.
9 // You must accept the terms of that agreement to use this software.
10 //
11 // jhyde, 21 March, 2002
12 */

13 package mondrian.rolap;
14
15 import mondrian.olap.*;
16 import mondrian.resource.MondrianResource;
17
18 import org.apache.log4j.Logger;
19
20 /**
21  * A <code>HierarchyUsage</code> is the usage of a hierarchy in the context
22  * of a cube. Private hierarchies can only be used in their own
23  * cube. Public hierarchies can be used in several cubes. The problem comes
24  * when several cubes which the same public hierarchy are brought together
25  * in one virtual cube. There are now several usages of the same public
26  * hierarchy. Which one to use? It depends upon what measure we are
27  * currently using. We should use the hierarchy usage for the fact table
28  * which underlies the measure. That is what determines the foreign key to
29  * join on.
30  *
31  * A <code>HierarchyUsage</code> is identified by
32  * <code>(hierarchy.sharedHierarchy, factTable)</code> if the hierarchy is
33  * shared, or <code>(hierarchy, factTable)</code> if it is private.
34  *
35  * @author jhyde
36  * @since 21 March, 2002
37  * @version $Id: //open/mondrian/src/main/mondrian/rolap/HierarchyUsage.java#19 $
38  */

39 public class HierarchyUsage {
40     private static final Logger LOGGER = Logger.getLogger(HierarchyUsage.class);
41
42     enum Kind {
43         UNKNOWN,
44         SHARED,
45         VIRTUAL,
46         PRIVATE
47     }
48
49     /**
50      * Fact table (or relation) which this usage is joining to. This
51      * identifies the usage, and determines which join conditions need to be
52      * used.
53      */

54     protected final MondrianDef.Relation fact;
55
56     /**
57      * This matches the hierarchy - may not be unique.
58      * NOT NULL.
59      */

60     private final String JavaDoc hierarchyName;
61
62     /**
63      * not NULL for DimensionUsage
64      * not NULL for Dimension
65      */

66     private final String JavaDoc name;
67
68     /**
69      * This is the name used to look up the hierachy usage. When the dimension
70      * has only a single hierachy, then the fullName is simply the
71      * CubeDimension name; there is no need to use the default dimension name.
72      * But, when the dimension has more than one hierachy, then the fullName
73      * is the CubeDimension dotted with the dimension hierachy name.
74      */

75     private final String JavaDoc fullName;
76
77     /**
78      * The foreign key by which this {@link Hierarchy} is joined to
79      * the {@link #fact} table.
80      */

81     private final String JavaDoc foreignKey;
82
83     /**
84      * not NULL for DimensionUsage
85      * NULL for Dimension
86      */

87     private final String JavaDoc source;
88
89     /**
90      * May be null, this is the field that is used to disambiguate column
91      * names in aggregate tables
92      */

93     private final String JavaDoc usagePrefix;
94
95     // NOT USED
96
private final String JavaDoc level;
97     //final String type;
98
//final String caption;
99

100     /**
101      * Dimension table which contains the primary key for the hierarchy.
102      * (Usually the table of the lowest level of the hierarchy.)
103      */

104     private MondrianDef.Relation joinTable;
105     /**
106      * The expression (usually a {@link MondrianDef.Column}) by which the
107      * hierarchy which is joined to the fact table.
108      */

109     private MondrianDef.Expression joinExp;
110
111     private final Kind kind;
112
113     /**
114      *
115      *
116      * @param cube
117      * @param hierarchy
118      * @param cubeDim
119      */

120     HierarchyUsage(RolapCube cube,
121                    RolapHierarchy hierarchy,
122                    MondrianDef.CubeDimension cubeDim) {
123
124         assert cubeDim != null : "precondition: cubeDim != null";
125
126         this.fact = cube.fact;
127
128         // Attributes common to all Hierarchy kinds
129
// name
130
// foreignKey
131
this.name = cubeDim.name;
132         this.foreignKey = cubeDim.foreignKey;
133
134         if (cubeDim instanceof MondrianDef.DimensionUsage) {
135             this.kind = Kind.SHARED;
136
137
138             // Shared Hierarchy attributes
139
// source
140
// level
141
MondrianDef.DimensionUsage du =
142                       (MondrianDef.DimensionUsage) cubeDim;
143             // Bug 657 - disable hierarchy aliasing
144
if (! du.name.equals(du.source)) {
145                 StringBuilder JavaDoc buf = new StringBuilder JavaDoc();
146                 buf.append("Cube \"");
147                 buf.append(cube.getName());
148                 buf.append("\": DimensionUsage name (\"");
149                 buf.append(du.name);
150                 buf.append("\") must equal source (\"");
151                 buf.append(du.source);
152                 buf.append("\")");
153                 throw new MondrianException(buf.toString());
154             }
155
156             //this.hierarchyName = du.source;
157
this.hierarchyName = hierarchy.getName();
158             int index = this.hierarchyName.indexOf('.');
159             if (index == -1) {
160                 this.fullName = this.name;
161                 this.source = du.source;
162             } else {
163                 String JavaDoc hname= this.hierarchyName.substring(
164                         index+1, this.hierarchyName.length());
165
166                 StringBuilder JavaDoc buf = new StringBuilder JavaDoc(32);
167                 buf.append(this.name);
168                 buf.append('.');
169                 buf.append(hname);
170                 this.fullName = buf.toString();
171
172                 buf.setLength(0);
173                 buf.append(du.source);
174                 buf.append('.');
175                 buf.append(hname);
176                 this.source = buf.toString();
177             }
178
179             this.level = du.level;
180             this.usagePrefix = du.usagePrefix;
181
182             init(cube, hierarchy, du);
183
184         } else if (cubeDim instanceof MondrianDef.Dimension) {
185             this.kind = Kind.PRIVATE;
186
187             // Private Hierarchy attributes
188
// type
189
// caption
190
MondrianDef.Dimension d = (MondrianDef.Dimension) cubeDim;
191
192             this.hierarchyName = hierarchy.getName();
193             this.fullName = this.name;
194
195             this.source = null;
196             this.usagePrefix = d.usagePrefix;
197             this.level = null;
198
199             init(cube, hierarchy, null);
200
201         } else if (cubeDim instanceof MondrianDef.VirtualCubeDimension) {
202             this.kind = Kind.VIRTUAL;
203
204             // Virtual Hierarchy attributes
205
MondrianDef.VirtualCubeDimension vd =
206                         (MondrianDef.VirtualCubeDimension) cubeDim;
207
208             this.hierarchyName = cubeDim.name;
209             this.fullName = this.name;
210
211             this.source = null;
212             this.usagePrefix = null;
213             this.level = null;
214
215             init(cube, hierarchy, null);
216
217         } else {
218             getLogger().warn("HierarchyUsage<init>: Unknown cubeDim="
219                 +cubeDim.getClass().getName());
220
221             this.kind = Kind.UNKNOWN;
222
223             this.hierarchyName = cubeDim.name;
224             this.fullName = this.name;
225
226             this.source = null;
227             this.usagePrefix = null;
228             this.level = null;
229
230             init(cube, hierarchy, null);
231         }
232         if (getLogger().isDebugEnabled()) {
233             getLogger().debug(toString()
234                 + ", cubeDim="
235                 + cubeDim.getClass().getName());
236         }
237
238     }
239
240     protected Logger getLogger() {
241         return LOGGER;
242     }
243
244     public String JavaDoc getHierarchyName() {
245         return this.hierarchyName;
246     }
247     public String JavaDoc getFullName() {
248         return this.fullName;
249     }
250     public String JavaDoc getName() {
251         return this.name;
252     }
253     public String JavaDoc getForeignKey() {
254         return this.foreignKey;
255     }
256     public String JavaDoc getSource() {
257         return this.source;
258     }
259     public String JavaDoc getLevelName() {
260         return this.level;
261     }
262     public String JavaDoc getUsagePrefix() {
263         return this.usagePrefix;
264     }
265
266     public MondrianDef.Relation getJoinTable() {
267         return this.joinTable;
268     }
269     public MondrianDef.Expression getJoinExp() {
270         return this.joinExp;
271     }
272
273     public Kind getKind() {
274         return this.kind;
275     }
276     public boolean isShared() {
277         return this.kind == Kind.SHARED;
278     }
279     public boolean isVirtual() {
280         return this.kind == Kind.VIRTUAL;
281     }
282     public boolean isPrivate() {
283         return this.kind == Kind.PRIVATE;
284     }
285
286     public boolean equals(Object JavaDoc o) {
287         if (o instanceof HierarchyUsage) {
288             HierarchyUsage other = (HierarchyUsage) o;
289             return (this.kind == other.kind) &&
290                 Util.equals(this.fact, other.fact) &&
291                 Util.equalName(this.hierarchyName, other.hierarchyName) &&
292                 Util.equalName(this.name, other.name) &&
293                 Util.equalName(this.source, other.source) &&
294                 Util.equalName(this.foreignKey, other.foreignKey);
295         } else {
296             return false;
297         }
298     }
299
300     public int hashCode() {
301         int h = fact.hashCode();
302         h = Util.hash(h, hierarchyName);
303         h = Util.hash(h, name);
304         h = Util.hash(h, source);
305         h = Util.hash(h, foreignKey);
306         return h;
307     }
308
309     public String JavaDoc toString() {
310         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(100);
311         buf.append("HierarchyUsage: ");
312         buf.append("kind=");
313         buf.append(this.kind.name());
314         buf.append(", hierarchyName=");
315         buf.append(this.hierarchyName);
316         buf.append(", fullName=");
317         buf.append(this.fullName);
318         buf.append(", foreignKey=");
319         buf.append(this.foreignKey);
320         buf.append(", source=");
321         buf.append(this.source);
322         buf.append(", level=");
323         buf.append(this.level);
324         buf.append(", name=");
325         buf.append(this.name);
326
327         return buf.toString();
328     }
329
330     void init(RolapCube cube,
331               RolapHierarchy hierarchy,
332               MondrianDef.DimensionUsage cubeDim) {
333
334         // Three ways that a hierarchy can be joined to the fact table.
335
if (cubeDim != null && cubeDim.level != null) {
336
337             // 1. Specify an explicit 'level' attribute in a <DimensionUsage>.
338
RolapLevel joinLevel = (RolapLevel)
339                     Util.lookupHierarchyLevel(hierarchy, cubeDim.level);
340             if (joinLevel == null) {
341                 throw MondrianResource.instance()
342                         .DimensionUsageHasUnknownLevel.ex(
343                                 hierarchy.getUniqueName(),
344                                 cube.getUniqueName(),
345                                 cubeDim.level);
346             }
347             this.joinTable = findJoinTable(hierarchy, joinLevel.getKeyExp().getTableAlias());
348             this.joinExp = joinLevel.getKeyExp();
349         } else if (hierarchy.xmlHierarchy != null &&
350                 hierarchy.xmlHierarchy.primaryKey != null) {
351             // 2. Specify a "primaryKey" attribute of in <Hierarchy>. You must
352
// also specify the "primaryKeyTable" attribute if the hierarchy
353
// is a join (hence has more than one table).
354
this.joinTable = findJoinTable(hierarchy,
355                 hierarchy.xmlHierarchy.primaryKeyTable);
356             this.joinExp = new MondrianDef.Column(this.joinTable.getAlias(),
357                     hierarchy.xmlHierarchy.primaryKey);
358         } else {
359             // 3. If neither of the above, the join is assumed to be to key of
360
// the last level.
361
final Level[] levels = hierarchy.getLevels();
362             RolapLevel joinLevel = (RolapLevel) levels[levels.length - 1];
363             this.joinTable = findJoinTable(hierarchy,
364                 joinLevel.getKeyExp().getTableAlias());
365             this.joinExp = joinLevel.getKeyExp();
366         }
367 /*
368 RME
369         Util.assertTrue(Util.equals(foreignKey, hierarchy.foreignKey));
370 */

371
372         // Unless this hierarchy is drawing from the fact table, we need
373
// a join expresion and a foreign key.
374
final boolean inFactTable = this.joinTable.equals(cube.getFact());
375         if (!inFactTable) {
376             if (this.joinExp == null) {
377                 throw MondrianResource.instance()
378                         .MustSpecifyPrimaryKeyForHierarchy.ex(
379                                 hierarchy.getUniqueName(),
380                                 cube.getUniqueName());
381             }
382             if (foreignKey == null) {
383                 throw MondrianResource.instance()
384                         .MustSpecifyForeignKeyForHierarchy.ex(
385                                 hierarchy.getUniqueName(),
386                                 cube.getUniqueName());
387             }
388         }
389     }
390
391     /**
392      * Chooses the table with which to join a hierarchy to the fact table.
393      *
394      * @param hierarchy Hierarchy to be joined
395      * @param tableName Alias of the table; may be omitted if the hierarchy
396      * has only one table
397      * @return A table, never null
398      */

399     private MondrianDef.Relation findJoinTable(
400         RolapHierarchy hierarchy,
401         String JavaDoc tableName)
402     {
403         final MondrianDef.Relation table;
404         if (tableName == null) {
405             table = hierarchy.getUniqueTable();
406             if (table == null) {
407                 throw MondrianResource.instance()
408                     .MustSpecifyPrimaryKeyTableForHierarchy.ex(
409                         hierarchy.getUniqueName());
410             }
411         } else {
412             table = hierarchy.getRelation().find(tableName);
413             if (table == null) {
414                 // todo: i18n msg
415
throw Util.newError(
416                     "no table '" + tableName +
417                     "' found in hierarchy " + hierarchy.getUniqueName());
418             }
419         }
420         return table;
421     }
422
423 }
424
425 // End HierarchyUsage.java
426
Popular Tags