KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > rolap > aggmatcher > DefaultRules


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

10
11 package mondrian.rolap.aggmatcher;
12
13
14 import mondrian.olap.*;
15 import mondrian.rolap.RolapStar;
16 import mondrian.recorder.*;
17 import mondrian.resource.MondrianResource;
18
19 import org.apache.log4j.Logger;
20 import org.eigenbase.xom.*;
21 import org.eigenbase.xom.Parser;
22 import org.eigenbase.util.property.*;
23 import org.eigenbase.util.property.Property;
24
25 import java.io.*;
26 import java.net.MalformedURLException JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Map JavaDoc;
30
31 /**
32  * Container for the default aggregate recognition rules.
33  * It is generated by parsing the default rule xml information found
34  * in the {@link MondrianProperties#AggregateRules} value which normally is
35  * a resource in the jar file (but can be a url).
36  *
37  * <p>It is a singleton since it is used to recognize tables independent of
38  * database connection (each {@link mondrian.rolap.RolapSchema} uses the same
39  * instance).
40  *
41  * @author Richard M. Emberson
42  * @version $Id: //open/mondrian/src/main/mondrian/rolap/aggmatcher/DefaultRules.java#14 $
43  */

44 public class DefaultRules {
45
46     private static final Logger LOGGER = Logger.getLogger(DefaultRules.class);
47
48     private static final MondrianResource mres = MondrianResource.instance();
49     /**
50      * There is a single instance of the {@link DefaultRecognizer} and the
51      * {@link DefaultRules} class is a container of that instance.
52      */

53     public static synchronized DefaultRules getInstance() {
54         if (instance == null) {
55             InputStream inStream = getAggRuleInputStream();
56             if (inStream == null) {
57                 return null;
58             }
59
60             DefaultDef.AggRules defs = makeAggRules(inStream);
61
62             // validate the DefaultDef.AggRules object
63
ListRecorder reclists = new ListRecorder();
64             try {
65                 defs.validate(reclists);
66             } catch (RecorderException e) {
67                 // ignore
68
}
69
70             reclists.logWarningMessage(LOGGER);
71             reclists.logErrorMessage(LOGGER);
72
73             if (reclists.hasErrors()) {
74                 reclists.throwRTException();
75             }
76
77
78             // make sure the tag name exists
79
String JavaDoc tag = MondrianProperties.instance().AggregateRuleTag.get();
80             DefaultDef.AggRule aggrule = defs.getAggRule(tag);
81             if (aggrule == null) {
82                 throw mres.MissingDefaultAggRule.ex(tag);
83             }
84
85             DefaultRules rules = new DefaultRules(defs);
86             rules.setTag(tag);
87             instance = rules;
88         }
89         return instance;
90     }
91
92     private static InputStream getAggRuleInputStream() {
93         String JavaDoc aggRules = MondrianProperties.instance().AggregateRules.get();
94
95         InputStream inStream = DefaultRules.class.getResourceAsStream(aggRules);
96         if (inStream == null) {
97             try {
98                 URL JavaDoc url = new URL JavaDoc(aggRules);
99                 inStream = url.openStream();
100             } catch (MalformedURLException JavaDoc e) {
101                 // ignore
102
} catch (IOException e) {
103                 // ignore
104
}
105         }
106         if (inStream == null) {
107             String JavaDoc msg = mres.CouldNotLoadDefaultAggregateRules.str(aggRules);
108             LOGGER.warn(msg);
109         }
110         return inStream;
111     }
112     private static DefaultRules instance = null;
113
114     static {
115         // When the value of the AggregateRules property is changed, force
116
// system to reload the DefaultRules.
117
// There is no need to provide equals/hashCode methods for this
118
// Trigger since it is a singleton and is never removed.
119
Trigger trigger =
120             new Trigger() {
121                 public boolean isPersistent() {
122                     return true;
123                 }
124                 public int phase() {
125                     return Trigger.PRIMARY_PHASE;
126                 }
127                 public void execute(Property property, String JavaDoc value) {
128                     synchronized (DefaultRules.class) {
129                         DefaultRules oldInstance = DefaultRules.instance;
130                         DefaultRules.instance = null;
131
132                         DefaultRules newInstance = null;
133                         Exception JavaDoc ex = null;
134                         try {
135                             newInstance = DefaultRules.getInstance();
136                         } catch (Exception JavaDoc e) {
137                             ex = e;
138                         }
139                         if (ex != null) {
140                             DefaultRules.instance = oldInstance;
141
142                             throw new Trigger.VetoRT(ex);
143
144                         } else if (newInstance == null) {
145                             DefaultRules.instance = oldInstance;
146
147                             String JavaDoc msg =
148                                 mres.FailedCreateNewDefaultAggregateRules.str(
149                                         property.getPath(), value);
150                             throw new Trigger.VetoRT(msg);
151
152                         } else {
153                             instance = newInstance;
154                         }
155                     }
156                 }
157             };
158
159         final MondrianProperties properties = MondrianProperties.instance();
160         properties.AggregateRules.addTrigger(trigger);
161         properties.AggregateRuleTag.addTrigger(trigger);
162     }
163
164     protected static DefaultDef.AggRules makeAggRules(final File file) {
165         DOMWrapper def = makeDOMWrapper(file);
166         try {
167             DefaultDef.AggRules rules = new DefaultDef.AggRules(def);
168             return rules;
169         } catch (XOMException e) {
170             throw mres.AggRuleParse.ex(file.getName(), e);
171         }
172     }
173
174     protected static DefaultDef.AggRules makeAggRules(final URL JavaDoc url) {
175         DOMWrapper def = makeDOMWrapper(url);
176         try {
177             DefaultDef.AggRules rules = new DefaultDef.AggRules(def);
178             return rules;
179         } catch (XOMException e) {
180             throw mres.AggRuleParse.ex(url.toString(),e);
181         }
182     }
183
184     protected static DefaultDef.AggRules makeAggRules(
185             final InputStream inStream) {
186         DOMWrapper def = makeDOMWrapper(inStream);
187         try {
188             DefaultDef.AggRules rules = new DefaultDef.AggRules(def);
189             return rules;
190         } catch (XOMException e) {
191             throw mres.AggRuleParse.ex("InputStream",e);
192         }
193     }
194
195     protected static DefaultDef.AggRules makeAggRules(
196             final String JavaDoc text,
197             final String JavaDoc name) {
198         DOMWrapper def = makeDOMWrapper(text, name);
199         try {
200             DefaultDef.AggRules rules = new DefaultDef.AggRules(def);
201             return rules;
202         } catch (XOMException e) {
203             throw mres.AggRuleParse.ex(name,e);
204         }
205     }
206
207     protected static DOMWrapper makeDOMWrapper(final File file) {
208         try {
209             return makeDOMWrapper(file.toURL());
210         } catch (MalformedURLException JavaDoc e) {
211             throw mres.AggRuleParse.ex(file.getName(),e);
212         }
213     }
214
215     protected static DOMWrapper makeDOMWrapper(final URL JavaDoc url) {
216         try {
217             final Parser xmlParser = XOMUtil.createDefaultParser();
218             DOMWrapper def = xmlParser.parse(url);
219             return def;
220         } catch (XOMException e) {
221             throw mres.AggRuleParse.ex(url.toString(),e);
222         }
223     }
224
225     protected static DOMWrapper makeDOMWrapper(final InputStream inStream) {
226         try {
227             final Parser xmlParser = XOMUtil.createDefaultParser();
228             DOMWrapper def = xmlParser.parse(inStream);
229             return def;
230         } catch (XOMException e) {
231             throw mres.AggRuleParse.ex("InputStream",e);
232         }
233     }
234
235     protected static DOMWrapper makeDOMWrapper(
236             final String JavaDoc text,
237             final String JavaDoc name) {
238         try {
239             final Parser xmlParser = XOMUtil.createDefaultParser();
240             DOMWrapper def = xmlParser.parse(text);
241             return def;
242         } catch (XOMException e) {
243             throw mres.AggRuleParse.ex(name,e);
244         }
245     }
246
247
248     private final DefaultDef.AggRules rules;
249     private final Map JavaDoc<String JavaDoc, Recognizer.Matcher> factToPattern;
250     private final Map JavaDoc<String JavaDoc, Recognizer.Matcher> foreignKeyMatcherMap;
251     private Recognizer.Matcher ignoreMatcherMap;
252     private Recognizer.Matcher factCountMatcher;
253     private String JavaDoc tag;
254
255     private DefaultRules(final DefaultDef.AggRules rules) {
256         this.rules = rules;
257         this.factToPattern = new HashMap JavaDoc<String JavaDoc, Recognizer.Matcher>();
258         this.foreignKeyMatcherMap = new HashMap JavaDoc<String JavaDoc, Recognizer.Matcher>();
259         this.tag = MondrianProperties.instance().AggregateRuleTag.
260                 getDefaultValue();
261     }
262
263     public void validate(MessageRecorder msgRecorder) {
264         rules.validate(msgRecorder);
265     }
266
267     /**
268      * Sets the name (tag) of this rule.
269      *
270      * @param tag
271      */

272     private void setTag(final String JavaDoc tag) {
273         this.tag = tag;
274     }
275
276     /**
277      * Gets the tag of this rule (this is the value of the
278      * {@link MondrianProperties#AggregateRuleTag} property).
279      */

280     public String JavaDoc getTag() {
281         return this.tag;
282     }
283
284
285     /**
286      * Returns the {@link mondrian.rolap.aggmatcher.DefaultDef.AggRule} whose
287      * tag equals this rule's tag.
288      */

289     public DefaultDef.AggRule getAggRule() {
290         return getAggRule(getTag());
291     }
292
293     /**
294      * Returns the {@link mondrian.rolap.aggmatcher.DefaultDef.AggRule} whose
295      * tag equals the parameter tag, or null if not found.
296      *
297      * @param tag
298      * @return the AggRule with tag value equal to tag parameter, or null.
299      */

300     public DefaultDef.AggRule getAggRule(final String JavaDoc tag) {
301         return this.rules.getAggRule(tag);
302     }
303
304     /**
305      * Gets the {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for this
306      * tableName.
307      *
308      * @param tableName
309      */

310     public Recognizer.Matcher getTableMatcher(final String JavaDoc tableName) {
311         Recognizer.Matcher matcher = factToPattern.get(tableName);
312         if (matcher == null) {
313             // get default AggRule
314
DefaultDef.AggRule rule = getAggRule();
315             DefaultDef.TableMatch tableMatch = rule.getTableMatch();
316             matcher = tableMatch.getMatcher(tableName);
317             factToPattern.put(tableName, matcher);
318         }
319         return matcher;
320     }
321
322     /**
323      * Gets the {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for the
324      * fact count column.
325      */

326     public Recognizer.Matcher getIgnoreMatcher() {
327         if (ignoreMatcherMap == null) {
328             // get default AggRule
329
DefaultDef.AggRule rule = getAggRule();
330             DefaultDef.IgnoreMap ignoreMatch = rule.getIgnoreMap();
331             if (ignoreMatch == null) {
332                 ignoreMatcherMap = new Recognizer.Matcher() {
333                     public boolean matches(String JavaDoc name) {
334                         return false;
335                     }
336                 };
337             } else {
338                 ignoreMatcherMap = ignoreMatch.getMatcher();
339             }
340         }
341         return ignoreMatcherMap;
342     }
343
344     /**
345      * Gets the {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for
346      * columns that should be ignored.
347      *
348      * @return
349      */

350     public Recognizer.Matcher getFactCountMatcher() {
351         if (factCountMatcher == null) {
352             // get default AggRule
353
DefaultDef.AggRule rule = getAggRule();
354             DefaultDef.FactCountMatch factCountMatch =
355                 rule.getFactCountMatch();
356             factCountMatcher = factCountMatch.getMatcher();
357         }
358         return factCountMatcher;
359     }
360
361     /**
362      * Gets the {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for this
363      * foreign key column name.
364      *
365      * @param foreignKeyName
366      */

367     public Recognizer.Matcher getForeignKeyMatcher(String JavaDoc foreignKeyName) {
368         Recognizer.Matcher matcher =
369             foreignKeyMatcherMap.get(foreignKeyName);
370         if (matcher == null) {
371             // get default AggRule
372
DefaultDef.AggRule rule = getAggRule();
373             DefaultDef.ForeignKeyMatch foreignKeyMatch =
374                 rule.getForeignKeyMatch();
375             matcher = foreignKeyMatch.getMatcher(foreignKeyName);
376             foreignKeyMatcherMap.put(foreignKeyName, matcher);
377         }
378         return matcher;
379     }
380
381     /**
382      * Returns true if this candidate aggregate table name "matches" the
383      * factTableName.
384      *
385      * @param factTableName
386      * @param name candidate aggregate table name
387      */

388     public boolean matchesTableName(
389             final String JavaDoc factTableName,
390             final String JavaDoc name) {
391         Recognizer.Matcher matcher = getTableMatcher(factTableName);
392         return matcher.matches(name);
393     }
394
395     /**
396      * Creates a {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for the
397      * given measure name (symbolic name), column name and aggregate name
398      * (sum, count, etc.).
399      */

400     public Recognizer.Matcher getMeasureMatcher(
401             final String JavaDoc measureName,
402             final String JavaDoc measureColumnName,
403             final String JavaDoc aggregateName) {
404         DefaultDef.AggRule rule = getAggRule();
405         Recognizer.Matcher matcher =
406             rule.getMeasureMap().getMatcher(measureName,
407                                             measureColumnName,
408                                             aggregateName);
409         return matcher;
410     }
411
412     /**
413      * Gets a {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for a given
414      * level's hierarchy's name, level name and column name.
415      */

416     public Recognizer.Matcher getLevelMatcher(
417             final String JavaDoc usagePrefix,
418             final String JavaDoc hierarchyName,
419             final String JavaDoc levelName,
420             final String JavaDoc levelColumnName) {
421         DefaultDef.AggRule rule = getAggRule();
422         Recognizer.Matcher matcher =
423             rule.getLevelMap().getMatcher(usagePrefix,
424                                           hierarchyName,
425                                           levelName,
426                                           levelColumnName);
427         return matcher;
428     }
429
430     /**
431      * Uses the {@link DefaultRecognizer} Recognizer to determine if the
432      * given aggTable's columns all match upto the dbFactTable's columns (where
433      * present) making the column usages as a result.
434      */

435     public boolean columnsOK(
436             final RolapStar star,
437             final JdbcSchema.Table dbFactTable,
438             final JdbcSchema.Table aggTable,
439             final MessageRecorder msgRecorder) {
440         Recognizer cb = new DefaultRecognizer(
441                 this,
442                 star,
443                 dbFactTable,
444                 aggTable,
445                 msgRecorder);
446         return cb.check();
447     }
448 }
449
450 // End DefaultRules.java
451
Popular Tags