001 /*
002 // $Id: //open/mondrian-release/3.0/src/main/mondrian/olap/MondrianProperties.java#4 $
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) 2001-2002 Kana Software, Inc.
007 // Copyright (C) 2001-2007 Julian Hyde and others
008 // All Rights Reserved.
009 // You must accept the terms of that agreement to use this software.
010 //
011 // jhyde, 22 December, 2002
012 */
013 package mondrian.olap;
014
015 import org.apache.log4j.Logger;
016 import org.eigenbase.util.property.*;
017
018 import java.io.*;
019 import java.net.MalformedURLException;
020 import java.net.URL;
021 import java.net.URLConnection;
022 import java.util.Enumeration;
023 import java.util.Properties;
024
025 /**
026 * <code>MondrianProperties</code> contains the properties which determine the
027 * behavior of a mondrian instance.
028 *
029 * <p>There is a method for property valid in a
030 * <code>mondrian.properties</code> file. Although it is possible to retrieve
031 * properties using the inherited {@link Properties#getProperty(String)}
032 * method, we recommend that you use methods in this class.
033 *
034 * <h2>Note to developers</h2>
035 *
036 * If you add a property, you must:<ul>
037 *
038 * <li>Add a property definition to this class</li>
039 *
040 * <li>Modify the default <code>mondrian.properties</code> file checked into
041 * source control, with a description of the property and its default
042 * value.</li>
043 *
044 * <li>Modify the
045 * <a target="_top" href="{@docRoot}/../../documentation/configuration.php#Property_list">
046 * Configuration Specification</a>.</li>
047 * </ul>
048 *
049 * <p>Similarly if you update or delete a property.
050 *
051 * @author jhyde
052 * @version $Id: //open/mondrian-release/3.0/src/main/mondrian/olap/MondrianProperties.java#4 $
053 * @since 22 December, 2002
054 */
055 public class MondrianProperties extends TriggerableProperties {
056
057 private final PropertySource propertySource;
058 private int populateCount;
059
060 private static final Logger LOGGER =
061 Logger.getLogger(MondrianProperties.class);
062
063 /**
064 * Properties, drawn from {@link System#getProperties}, plus the contents
065 * of "mondrian.properties" if it exists. A singleton.
066 */
067 private static MondrianProperties instance;
068 private static final String mondrianDotProperties = "mondrian.properties";
069
070 /**
071 * Returns the singleton.
072 *
073 * @return Singleton instance
074 */
075 public static synchronized MondrianProperties instance() {
076 if (instance == null) {
077 instance = new MondrianProperties();
078 instance.populate();
079 }
080 return instance;
081 }
082
083 public MondrianProperties() {
084 this.propertySource = new FilePropertySource(new File(mondrianDotProperties));
085 }
086
087 public boolean triggersAreEnabled() {
088 return EnableTriggers.get();
089 }
090
091 /**
092 * Represents a place that properties can be read from, and remembers the
093 * timestamp that we last read them.
094 */
095 public interface PropertySource {
096 /**
097 * Opens an input stream from the source.
098 *
099 * <p>Also checks the 'last modified' time, which will determine whether
100 * {@link #isStale()} returns true.
101 *
102 * @return input stream
103 */
104 InputStream openStream();
105
106 /**
107 * Returns true if the source exists and has been modified since last
108 * time we called {@link #openStream()}.
109 *
110 * @return whether source has changed since it was last read
111 */
112 boolean isStale();
113
114 /**
115 * Returns the description of this source, such as a filename or URL.
116 *
117 * @return description of this PropertySource
118 */
119 String getDescription();
120 }
121
122 /**
123 * Implementation of {@link PropertySource} which reads from a
124 * {@link File}.
125 */
126 static class FilePropertySource implements PropertySource {
127 private final File file;
128 private long lastModified;
129
130 FilePropertySource(File file) {
131 this.file = file;
132 this.lastModified = 0;
133 }
134
135 public InputStream openStream() {
136 try {
137 this.lastModified = file.lastModified();
138 return new FileInputStream(file);
139 } catch (FileNotFoundException e) {
140 throw Util.newInternal(
141 e,
142 "Error while opening properties file '" + file + "'");
143 }
144 }
145
146 public boolean isStale() {
147 return file.exists() &&
148 file.lastModified() > this.lastModified;
149 }
150
151 public String getDescription() {
152 return "file=" + file.getAbsolutePath() +
153 " (exists=" + file.exists() + ")";
154 }
155 }
156
157 /**
158 * Implementation of {@link PropertySource} which reads from a {@link URL}.
159 */
160 static class UrlPropertySource implements PropertySource {
161 private final URL url;
162 private long lastModified;
163
164 UrlPropertySource(URL url) {
165 this.url = url;
166 }
167
168 private URLConnection getConnection() {
169 try {
170 return url.openConnection();
171 } catch (IOException e) {
172 throw Util.newInternal(
173 e,
174 "Error while opening properties file '" + url + "'");
175 }
176 }
177
178 public InputStream openStream() {
179 try {
180 final URLConnection connection = getConnection();
181 this.lastModified = connection.getLastModified();
182 return connection.getInputStream();
183 } catch (IOException e) {
184 throw Util.newInternal(
185 e,
186 "Error while opening properties file '" + url + "'");
187 }
188 }
189
190 public boolean isStale() {
191 final long lastModified = getConnection().getLastModified();
192 return lastModified > this.lastModified;
193 }
194
195 public String getDescription() {
196 return url.toExternalForm();
197 }
198 }
199
200 /**
201 * Loads this property set from: the file "$PWD/mondrian.properties" (if it
202 * exists); the "mondrian.properties" in the CLASSPATH; and from the system
203 * properties.
204 */
205 public void populate() {
206 // Read properties file "mondrian.properties", if it exists. If we have
207 // read the file before, only read it if it is newer.
208 loadIfStale(propertySource);
209
210 URL url = null;
211 File file = new File(mondrianDotProperties);
212 if (file.exists() && file.isFile()) {
213 // Read properties file "mondrian.properties" from PWD, if it
214 // exists.
215 try {
216 url = file.toURI().toURL();
217 } catch (MalformedURLException e) {
218 LOGGER.warn("Mondrian: file '"
219 + file.getAbsolutePath()
220 + "' could not be loaded", e);
221 }
222 } else {
223 // Then try load it from classloader
224 url =
225 MondrianProperties.class.getClassLoader().getResource(
226 mondrianDotProperties);
227 }
228
229 if (url != null) {
230 load(new UrlPropertySource(url));
231 } else {
232 LOGGER.warn("mondrian.properties can't be found under '"
233 + new File(".").getAbsolutePath() + "' or classloader");
234 }
235
236 // copy in all system properties which start with "mondrian."
237 int count = 0;
238 for (Enumeration keys = System.getProperties().keys();
239 keys.hasMoreElements();) {
240 String key = (String) keys.nextElement();
241 String value = System.getProperty(key);
242 if (key.startsWith("mondrian.")) {
243 // NOTE: the super allows us to bybase calling triggers
244 // Is this the correct behavior?
245 if (LOGGER.isDebugEnabled()) {
246 LOGGER.debug("populate: key=" + key + ", value=" + value);
247 }
248 super.setProperty(key, value);
249 count++;
250 }
251 }
252 if (populateCount++ == 0) {
253 LOGGER.info("Mondrian: loaded "
254 + count
255 + " system properties");
256 }
257 }
258
259 /**
260 * Reads properties from a source.
261 * If the source does not exist, or has not changed since we last read it,
262 * does nothing.
263 *
264 * @param source Source of properties
265 */
266 private void loadIfStale(PropertySource source) {
267 if (source.isStale()) {
268 if (LOGGER.isDebugEnabled()) {
269 LOGGER.debug("Mondrian: loading " + source.getDescription());
270 }
271 load(source);
272 }
273 }
274
275 /**
276 * Tries to load properties from a URL. Does not fail, just prints success
277 * or failure to log.
278 *
279 * @param source Source to read properties from
280 */
281 private void load(final PropertySource source) {
282 try {
283 load(source.openStream());
284 if (populateCount == 0) {
285 LOGGER.info("Mondrian: properties loaded from '"
286 + source.getDescription()
287 + "'");
288 }
289 } catch (IOException e) {
290 LOGGER.error("Mondrian: error while loading properties "
291 + "from '"
292 + source.getDescription()
293 + "' ("
294 + e
295 + ")");
296 }
297 }
298
299 /**
300 * Maximum number of simultaneous queries the system will allow.
301 *
302 * <p>Oracle fails if you try to run more than the 'processes' parameter in
303 * init.ora, typically 150. The throughput of Oracle and other databases
304 * will probably reduce long before you get to their limit.</p>
305 */
306 public transient final IntegerProperty QueryLimit = new IntegerProperty(
307 this, "mondrian.query.limit", 40);
308
309 /**
310 * Property containing a list of JDBC drivers to load automatically.
311 * Must be a comma-separated list of class names, and the classes must be
312 * on the class path.
313 */
314 public transient final StringProperty JdbcDrivers =
315 new StringProperty(
316 this,
317 "mondrian.jdbcDrivers",
318 "sun.jdbc.odbc.JdbcOdbcDriver," +
319 "org.hsqldb.jdbcDriver," +
320 "oracle.jdbc.OracleDriver," +
321 "com.mysql.jdbc.Driver");
322
323 /**
324 * Integer property that, if set to a value greater than zero, limits the
325 * maximum size of a result set.
326 */
327 public transient final IntegerProperty ResultLimit =
328 new IntegerProperty(
329 this, "mondrian.result.limit", 0);
330
331 // mondrian.test properties
332
333 /**
334 * String property that determines which tests are run.
335 *
336 * <p>This is a regular expression as defined by
337 * {@link java.util.regex.Pattern}.
338 * If this property is specified, only tests whose names match the pattern
339 * in its entirety will be run.</p>
340 *
341 * @see #TestClass
342 */
343 public transient final StringProperty TestName =
344 new StringProperty(
345 this, "mondrian.test.Name", null);
346
347 /**
348 * String property that determines which test class to run.
349 *
350 * <p>This is the name of the class which either implements
351 * {@code junit.framework.Test} or has a method
352 * {@code public [static] junit.framework.Test suite()}.</p>
353 *
354 * <p>Example:
355 * <blockquote><code>mondrian.test.Class=mondrian.test.FoodMartTestCase</code></blockquote>
356 *
357 * @see #TestName
358 */
359 public transient final StringProperty TestClass =
360 new StringProperty(
361 this, "mondrian.test.Class", null);
362
363 /**
364 * Property containing the connect string which regresssion tests should
365 * use to connect to the database.
366 * Format is specified in {@link Util#parseConnectString(String)}.
367 */
368 public transient final StringProperty TestConnectString =
369 new StringProperty(
370 this, "mondrian.test.connectString", null);
371
372 // miscellaneous
373
374 /**
375 * Property containing the JDBC URL of the FoodMart database.
376 * The default value is to connect to an ODBC data source called
377 * "MondrianFoodMart".
378 */
379 public transient final StringProperty FoodmartJdbcURL = new StringProperty(
380 this, "mondrian.foodmart.jdbcURL", "jdbc:odbc:MondrianFoodMart");
381
382 /**
383 * Property containing the JDBC URL of a test database.
384 * It does not default.
385 */
386 public transient final StringProperty TestJdbcURL = new StringProperty(
387 this, "mondrian.test.jdbcURL", null);
388
389 /**
390 * Property containing the JDBC user of a test database.
391 * The default value is null, to cope with DBMSs that don't need this.
392 */
393 public transient final StringProperty TestJdbcUser = new StringProperty(
394 this, "mondrian.test.jdbcUser", null);
395
396 /**
397 * Property containing the JDBC password of a test database.
398 * The default value is null, to cope with DBMSs that don't need this.
399 */
400 public transient final StringProperty TestJdbcPassword = new StringProperty(
401 this, "mondrian.test.jdbcPassword", null);
402
403 /**
404 * Property that determines when a dimension is considered "large".
405 * If a dimension has more than this number of members, Mondrian uses a
406 * {@link mondrian.rolap.SmartMemberReader smart member reader}.
407 */
408 public transient final IntegerProperty LargeDimensionThreshold =
409 new IntegerProperty(
410 this, "mondrian.rolap.LargeDimensionThreshold", 100);
411
412 /**
413 * Property that, with {@link #SparseSegmentDensityThreshold}, determines
414 * whether to choose a sparse or dense representation when storing
415 * collections of cell values in memory.
416 *
417 * <p>When storing collections of cell values, Mondrian has to choose
418 * between a sparse and a dense representation, based upon the
419 * <code>possible</code> and <code>actual</code> number of values.
420 * The <code>density</code> is <code>actual / possible</code>.
421 *
422 * <p>We use a sparse representation if
423 * <code>(possible -
424 * {@link #SparseSegmentCountThreshold countThreshold}) *
425 * {@link #SparseSegmentDensityThreshold densityThreshold} >
426 * actual</code>
427 *
428 * <p>For example, at the default values
429 * ({@link #SparseSegmentCountThreshold countThreshold} = 1000,
430 * {@link #SparseSegmentDensityThreshold} = 0.5),
431 * we use a dense representation for<ul>
432 * <li>(1000 possible, 0 actual), or
433 * <li>(2000 possible, 500 actual), or
434 * <li>(3000 possible, 1000 actual).
435 * </ul>
436 * Any fewer actual values, or any more
437 * possible values, and Mondrian will use a sparse representation.
438 */
439 public transient final IntegerProperty SparseSegmentCountThreshold =
440 new IntegerProperty(
441 this, "mondrian.rolap.SparseSegmentValueThreshold", 1000);
442
443 /**
444 * Property that, with {@link #SparseSegmentCountThreshold},
445 * determines whether to choose a sparse or dense representation when
446 * storing collections of cell values in memory.
447 */
448 public transient final DoubleProperty SparseSegmentDensityThreshold =
449 new DoubleProperty(
450 this, "mondrian.rolap.SparseSegmentDensityThreshold", 0.5);
451
452 /**
453 * Property that defines
454 * a pattern for which test XML files to run. Pattern has to
455 * match a file name of the form:
456 * <code>query<i>whatever</i>.xml</code> in the directory.
457 *
458 * <p>Example:
459 * <blockquote><code>mondrian.test.QueryFilePattern=queryTest_fec[A-Za-z0-9_]*.xml</code></blockquote>
460 *
461 */
462 public transient final StringProperty QueryFilePattern =
463 new StringProperty(
464 this, "mondrian.test.QueryFilePattern", null);
465
466 /**
467 * Property defining
468 * where the test XML files are.
469 */
470 public transient final StringProperty QueryFileDirectory =
471 new StringProperty(
472 this, "mondrian.test.QueryFileDirectory", null);
473
474 /**
475 * todo:
476 */
477 public transient final IntegerProperty Iterations = new IntegerProperty(
478 this, "mondrian.test.Iterations", 1);
479
480 /**
481 * todo:
482 */
483 public transient final IntegerProperty VUsers = new IntegerProperty(
484 this, "mondrian.test.VUsers", 1);
485
486 /**
487 * Property that returns the time limit for the test run in seconds.
488 * If the test is running after that time, it is terminated.
489 */
490 public transient final IntegerProperty TimeLimit = new IntegerProperty(
491 this, "mondrian.test.TimeLimit", 0);
492
493 /**
494 * Property that indicates whether this is a "warmup test".
495 */
496 public transient final BooleanProperty Warmup = new BooleanProperty(
497 this, "mondrian.test.Warmup", false);
498
499 /**
500 * Property that contains the URL of the catalog to be used by
501 * {@link mondrian.tui.CmdRunner} and XML/A Test.
502 */
503 public transient final StringProperty CatalogURL = new StringProperty(
504 this, "mondrian.catalogURL", null);
505
506 /**
507 * Property that controls
508 * whether aggregation cache hit / miss counters will be enabled
509 */
510 public transient final BooleanProperty EnableCacheHitCounters =
511 new BooleanProperty(
512 this, "mondrian.rolap.agg.enableCacheHitCounters", false);
513
514 /**
515 * Property that controls if warning messages should be printed if a sql
516 * comparison tests do not contain expected sqls for the specified
517 * dialect. The tests are skipped if no expected sqls are
518 * found for the current dialect.
519 *
520 * Possible values are the following:
521 * "NONE": no warning (default)
522 * "ANY": any dialect
523 * "ACCESS"
524 * "DERBY"
525 * "LUCIDDB"
526 * "MYSQL"
527 * ...and any Dialect enum in SqlPattern.Dialect
528 *
529 * Specific tests can overwrite the default setting. The priority is
530 * Settings besides "ANY" in mondrian.properties file < Any setting in the test < "ANY"
531 *
532 */
533 public transient final StringProperty WarnIfNoPatternForDialect =
534 new StringProperty(
535 this, "mondrian.test.WarnIfNoPatternForDialect", "NONE");
536
537 //////////////////////////////////////////////////////////////////////////
538 //
539 // properties relating to aggregates
540 //
541
542 /**
543 * Boolean property that controls whether Mondrian uses aggregate tables.
544 *
545 * <p>If true, then Mondrian uses aggregate tables. This property is
546 * queried prior to each aggregate query so that changing the value of this
547 * property dynamically (not just at startup) is meaningful.
548 *
549 * <p>Aggregates can be read from the database using the
550 * {@link #ReadAggregates} property but will not be used unless this
551 * property is set to true.
552 */
553 public transient final BooleanProperty UseAggregates =
554 new BooleanProperty(
555 this, "mondrian.rolap.aggregates.Use", false);
556
557 /**
558 * Boolean property that determines whether Mondrian should read aggregate
559 * tables.
560 *
561 * <p>If set to true, then Mondrian scans the database for aggregate tables.
562 * Unless mondrian.rolap.aggregates.Use is set to true, the aggregates
563 * found will not be used.
564 */
565 public transient final BooleanProperty ReadAggregates =
566 new BooleanProperty(
567 this, "mondrian.rolap.aggregates.Read", false);
568
569
570 /**
571 * Boolean property that controls whether aggregate tables
572 * are ordered by their volume or row count.
573 *
574 * <p>If true, Mondrian uses the aggregate table with the smallest volume
575 * (number of rows multiplied by number of columns); if false, Mondrian
576 * uses the aggregate table with the fewest rows.
577 */
578 public transient final BooleanProperty ChooseAggregateByVolume =
579 new BooleanProperty(
580 this, "mondrian.rolap.aggregates.ChooseByVolume", false);
581
582 /**
583 * String property containing the name of the file which defines the rules
584 * for recognizing an aggregate table. Can be either a resource in the
585 * Mondrian jar or a URL.
586 *
587 * <p>The default value is "/DefaultRules.xml", which is in the
588 * mondrian.rolap.aggmatcher package in Mondrian.jar.
589 *
590 * <p>Normally, this property is not set by a user.
591 */
592 public transient final StringProperty AggregateRules =
593 new StringProperty(
594 this, "mondrian.rolap.aggregates.rules", "/DefaultRules.xml");
595
596 /**
597 * String property that is the AggRule element's tag value.
598 *
599 * <p>Normally, this property is not set by a user.
600 */
601 public transient final StringProperty AggregateRuleTag =
602 new StringProperty(
603 this, "mondrian.rolap.aggregates.rule.tag", "default");
604
605 /**
606 * Boolean property that controls whether to print the SQL code
607 * generated for aggregate tables.
608 *
609 * <p>If set, then as each aggregate request is processed, both the lost
610 * and collapsed dimension create and insert sql code is printed.
611 * This is for use in the CmdRunner allowing one to create aggregate table
612 * generation sql.
613 */
614 public transient final BooleanProperty GenerateAggregateSql =
615 new BooleanProperty(
616 this, "mondrian.rolap.aggregates.generateSql", false);
617
618 //
619 //////////////////////////////////////////////////////////////////////////
620
621 /**
622 * Boolean property that controls whether a RolapStar's
623 * aggregate data cache is cleared after each query.
624 * If true, no RolapStar will cache aggregate data from one
625 * query to the next (the cache is cleared after each query).
626 */
627 public transient final BooleanProperty DisableCaching =
628 new BooleanProperty(
629 this, "mondrian.rolap.star.disableCaching", false);
630
631 /**
632 * Boolean property that controls whether to notify the Mondrian system
633 * when a {@link MondrianProperties property value} changes.
634 *
635 * <p>This allows objects dependent on Mondrian properties to react (that
636 * is, reload), when a given property changes via, say,
637 * <code>MondrianProperties.instance().populate(null)</code> or
638 * <code>MondrianProperties.instance().QueryLimit.set(50)</code>.
639 */
640 public transient final BooleanProperty EnableTriggers =
641 new BooleanProperty(
642 this, "mondrian.olap.triggers.enable", true);
643
644 /**
645 * Boolean property that controls pretty-print mode.
646 * If set to true, the all SqlQuery SQL strings
647 * will be generated in pretty-print mode, formatted for ease of reading.
648 */
649 public transient final BooleanProperty GenerateFormattedSql =
650 new BooleanProperty(
651 this, "mondrian.rolap.generate.formatted.sql", false);
652
653 /**
654 * Boolean property that controls whether each query axis implicit has the
655 * NON EMPTY option set. The default is false.
656 */
657 public transient final BooleanProperty EnableNonEmptyOnAllAxis =
658 new BooleanProperty(
659 this, "mondrian.rolap.nonempty", false);
660
661 /**
662 * When looking for native evaluation of an expression, expand non native
663 * subexpressions into MemberLists.
664 */
665 public transient final BooleanProperty ExpandNonNative =
666 new BooleanProperty(
667 this, "mondrian.native.ExpandNonNative", false);
668
669 /**
670 * Boolean property that controls whether sibling members are
671 * compared according to order key value fetched from their ordinal
672 * expression. The default is false (only database ORDER BY is used).
673 */
674 public transient final BooleanProperty CompareSiblingsByOrderKey =
675 new BooleanProperty(
676 this, "mondrian.rolap.compareSiblingsByOrderKey", false);
677
678 /**
679 * Boolean property that controls whether to use a cache for frequently
680 * evaluated expressions. With the cache disabled, an expression like
681 * <code>Rank([Product].CurrentMember,
682 * Order([Product].MEMBERS, [Measures].[Unit Sales]))</code> would perform
683 * many redundant sorts. The default is true.
684 */
685 public transient final BooleanProperty EnableExpCache =
686 new BooleanProperty(
687 this, "mondrian.expCache.enable", true);
688
689 /**
690 * Integer property that controls whether to test operators' dependencies,
691 * and how much time to spend doing it.
692 *
693 * <p>If this property is positive, Mondrian's test framework allocates an
694 * expression evaluator which evaluates each expression several times, and
695 * makes sure that the results of the expression are independent of
696 * dimensions which the expression claims to be independent of.
697 *
698 * <p>The default is 0.
699 */
700 public transient final IntegerProperty TestExpDependencies =
701 new IntegerProperty(
702 this, "mondrian.test.ExpDependencies", 0);
703
704 /**
705 * Seed for random number generator used by some of the tests.
706 *
707 *
708 * Any value besides 0 or -1 gives deterministic behavior.
709 * The default value is 1234: most users should use this.
710 * Setting the seed to a different value can increase coverage, and
711 * therefore may uncover new bugs.
712 *
713 * <p>If you set the value to 0, the system will generate its own
714 * pseudo-random seed.
715 *
716 * <p>If you set the value to -1, Mondrian uses the next seed from an
717 * internal random-number generator. This is a little more deterministic
718 * than setting the value to 0.
719 */
720 public transient final IntegerProperty TestSeed =
721 new IntegerProperty(
722 this, "mondrian.test.random.seed", 1234);
723
724 /**
725 * Name of locale property file.
726 *
727 * <p>Used for the {@link mondrian.i18n.LocalizingDynamicSchemaProcessor};
728 * see <a href="{@docRoot}/../../documentation/schema.php#I18n">Internationalization</a>
729 * for more details.</td>
730 *
731 * <p>Default value is null.
732 */
733 public transient final StringProperty LocalePropFile =
734 new StringProperty(
735 this, "mondrian.rolap.localePropFile", null);
736
737 /**
738 * if enabled some NON EMPTY CrossJoin will be computed in SQL
739 */
740 public transient final BooleanProperty EnableNativeCrossJoin =
741 new BooleanProperty(
742 this, "mondrian.native.crossjoin.enable", true);
743
744 /**
745 * if enabled some TopCount will be computed in SQL
746 */
747 public transient final BooleanProperty EnableNativeTopCount =
748 new BooleanProperty(
749 this, "mondrian.native.topcount.enable", true);
750
751 /**
752 * if enabled some Filter() will be computed in SQL
753 */
754 public transient final BooleanProperty EnableNativeFilter =
755 new BooleanProperty(
756 this, "mondrian.native.filter.enable", true);
757
758 /**
759 * some NON EMPTY set operations like member.children, level.members and
760 * member descendants will be computed in SQL
761 */
762 public transient final BooleanProperty EnableNativeNonEmpty =
763 new BooleanProperty(
764 this, "mondrian.native.nonempty.enable", true);
765
766 /**
767 * Alerting action to take in case native evaluation of a function is
768 * enabled but not supported for that function's usage in a particular
769 * query. (No alert is ever raised in cases where native evaluation would
770 * definitely have been wasted effort.)
771 *
772 *
773 *
774 * Recognized actions:
775 *
776 * <ul>
777 *
778 * <li><code>OFF</code>: do nothing (default action, also used if
779 * unrecognized action is specified)
780 *
781 * <li><code>WARN</code>: log a warning to RolapUtil logger
782 *
783 * <li><code>ERROR</code>: throw an instance of
784 * {@link NativeEvaluationUnsupportedException}
785 *
786 * </ul>
787 */
788 public transient final StringProperty AlertNativeEvaluationUnsupported =
789 new StringProperty(this, "mondrian.native.unsupported.alert", "OFF");
790
791 /**
792 * If enabled, first row in the result of an XML/A drill-through request
793 * will be filled with the total count of rows in underlying database.
794 */
795 public transient final BooleanProperty EnableTotalCount =
796 new BooleanProperty(
797 this, "mondrian.xmla.drillthroughTotalCount.enable", true);
798
799 /**
800 * Boolean property that controls whether the MDX parser resolves uses
801 * case-sensitive matching when looking up identifiers. The default is
802 * false.
803 */
804 public transient final BooleanProperty CaseSensitive = new BooleanProperty(
805 this, "mondrian.olap.case.sensitive", false);
806
807
808 /**
809 * Property that defines
810 * limit on the number of rows returned by XML/A drill through request.
811 */
812 public transient final IntegerProperty MaxRows = new IntegerProperty(
813 this, "mondrian.xmla.drillthroughMaxRows", 1000);
814
815 /**
816 * Max number of constraints in a single `IN' SQL clause.
817 *
818 * <p>This value may be variant among database prodcuts and their runtime
819 * settings. Oracle, for example, gives the error "ORA-01795: maximum
820 * number of expressions in a list is 1000".
821 *
822 * <p>Recommended values:<ul>
823 * <li>Oracle: 1,000
824 * <li>DB2: 2,500
825 * <li>Other: 10,000</ul>
826 */
827 public transient final IntegerProperty MaxConstraints = new IntegerProperty(
828 this, "mondrian.rolap.maxConstraints", 1000);
829
830 /**
831 * Boolean property that determines whether Mondrian optimizes predicates.
832 */
833 public transient final BooleanProperty OptimizePredicates =
834 new BooleanProperty(this,
835 "mondrian.rolap.aggregates.optimizePredicates",
836 true);
837
838 /**
839 * Boolean property that defines the
840 * maximum number of passes allowable while evaluating an MDX expression.
841 *
842 * <p>If evaluation exceeds this depth (for example, while evaluating a
843 * very complex calculated member), Mondrian will throw an error.
844 */
845 public transient final IntegerProperty MaxEvalDepth =
846 new IntegerProperty(
847 this, "mondrian.rolap.evaluate.MaxEvalDepth", 10);
848
849 /**
850 * Property that defines the JdbcSchema factory class which
851 * determines the list of tables and columns of a specific datasource.
852 * @see mondrian.rolap.aggmatcher.JdbcSchema
853 */
854 public transient final StringProperty JdbcFactoryClass =
855 new StringProperty(
856 this, "mondrian.rolap.aggregates.jdbcFactoryClass", null);
857
858 /**
859 * Property that defines
860 * the timeout value (in seconds) for queries; 0, the default, indicates no
861 * timeout.
862 */
863 public transient final IntegerProperty QueryTimeout = new IntegerProperty(
864 this, "mondrian.rolap.queryTimeout", 0);
865
866 /**
867 * Property that defines
868 * whether non-existent member errors should be ignored during schema
869 * load.
870 */
871 public transient final BooleanProperty IgnoreInvalidMembers =
872 new BooleanProperty(
873 this, "mondrian.rolap.ignoreInvalidMembers", false);
874
875 /**
876 * Property that defines
877 * whether non-existent member errors should be ignored during query
878 * validation.
879 */
880 public transient final BooleanProperty IgnoreInvalidMembersDuringQuery =
881 new BooleanProperty(
882 this, "mondrian.rolap.ignoreInvalidMembersDuringQuery", false);
883
884 /**
885 * Property that determines how a null member value is represented in the
886 * result output.
887 * <p>AS 2000 shows this as empty value
888 * <p>AS 2005 shows this as "(null)" value
889 */
890 public transient final StringProperty NullMemberRepresentation =
891 new StringProperty(this, "mondrian.olap.NullMemberRepresentation",
892 "#null");
893
894 /**
895 * Property that defines
896 * the iteration limit when computing an aggregate; 0 indicates unlimited.
897 */
898 public transient final IntegerProperty IterationLimit =
899 new IntegerProperty(
900 this, "mondrian.rolap.iterationLimit", 0);
901
902 /**
903 * Property that defines
904 * whether the <code>MemoryMonitor</code> should be enabled. By
905 * default for Java5 and above it is not enabled.
906 */
907 public transient final BooleanProperty MemoryMonitor =
908 new BooleanProperty(
909 this, "mondrian.util.memoryMonitor.enable", false);
910
911 /**
912 * Property that defines
913 * the default <code>MemoryMonitor</code> percentage threshold.
914 */
915 public transient final IntegerProperty MemoryMonitorThreshold =
916 new IntegerProperty(
917 this, "mondrian.util.memoryMonitor.percentage.threshold", 90);
918
919 /**
920 * Property that defines
921 * the name of the class used as a memory monitor.
922 *
923 * <p>If the value is
924 * non-null, it is used by the <code>MemoryMonitorFactory</code>
925 * to create the implementation.
926 */
927 public transient final StringProperty MemoryMonitorClass =
928 new StringProperty(
929 this, "mondrian.util.MemoryMonitor.class", null);
930
931 /**
932 * Property that defines
933 * the name of the class used to compile scalar expressions.
934 *
935 * <p>If the value is
936 * non-null, it is used by the <code>ExpCompiler.Factory</code>
937 * to create the implementation.
938 */
939 public transient final StringProperty ExpCompilerClass = new StringProperty(
940 this, "mondrian.calc.ExpCompiler.class", null);
941
942 /**
943 * Property that defines
944 * when to apply the crossjoin optimization algorithm.
945 *
946 * <p>If a crossjoin input list's size is larger than this property's
947 * value and the axis has the "NON EMPTY" qualifier, then
948 * the crossjoin non-empty optimizer is applied.
949 * Setting this value to '0' means that for all crossjoin
950 * input lists in non-empty axes will have the optimizer applied.
951 * On the other hand, if the value is set larger than any possible
952 * list, say <code>Integer.MAX_VALUE</code>, then the optimizer
953 * will never be applied.
954 */
955 public transient final IntegerProperty CrossJoinOptimizerSize =
956 new IntegerProperty(
957 this, "mondrian.olap.fun.crossjoin.optimizer.size", 0);
958
959 /**
960 * Property that defines
961 * the behavior of division if the denominator evaluates to zero.
962 *
963 * <p>If a division has a non-null numerator and a null denominator,
964 * it evaluates to "Infinity", which conforms to MSAS behavior. However,
965 * the old semantics of evaluating this to NULL (non MSAS-conforming), is
966 * useful in some applications. This property controls whether the
967 * result should be NULL if the denominator is Null.
968 */
969 public transient final BooleanProperty NullDenominatorProducesNull =
970 new BooleanProperty(
971 this, "mondrian.olap.NullDenominatorProducesNull", false);
972
973 /**
974 * Property that defines
975 * whether to generate SQL queries using the <code>GROUPING SETS</code>
976 * construct for rollup. By default it is not enabled.
977 *
978 * <p>Ignored on databases which do not support the
979 * <code>GROUPING SETS</code> construct (see
980 * {@link mondrian.rolap.sql.SqlQuery.Dialect#supportsGroupingSets}).
981 */
982 public transient final BooleanProperty EnableGroupingSets =
983 new BooleanProperty(
984 this, "mondrian.rolap.groupingsets.enable", false);
985
986 /**
987 * Property that defines whether to ignore measure when non joining
988 * dimension is in the tuple during aggregation.
989 *
990 * <p>If there are unrelated dimensions to a measure in context during
991 * aggregation, the measure is ignored in the evaluation context. This
992 * behaviour kicks in only if the cubeusage for this measure has
993 * IgnoreUnrelatedDimensions attribute set to false.
994 *
995 * <p>For example, Gender doesn't join with [Warehouse Sales] measure.
996 *
997 * <p>With mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension=true
998 * Warehouse Sales gets eliminated and is ignored in the aggregate value.
999 * <blockquote>
1000 * <p> [Store Sales] + [Warehouse Sales]
1001 * SUM({Product.members * Gender.members}) 7,913,333.82
1002 * </blockquote>
1003 * <p>With mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension=false
1004 * Warehouse Sales with Gender All level member contributes to the aggregate
1005 * value.
1006 * <blockquote>
1007 * <p> [Store Sales] + [Warehouse Sales]
1008 * SUM({Product.members * Gender.members}) 9,290,730.03
1009 * </blockquote>
1010 * <p>On a report where Gender M, F and All members exist a user will see a
1011 * large aggregated value compared to the aggregated value that can be
1012 * arrived at by suming up values against Gender M and F. This can be
1013 * confusing to the user. This feature can be used to eliminate such a
1014 * situation.
1015 */
1016 public transient final BooleanProperty IgnoreMeasureForNonJoiningDimension =
1017 new BooleanProperty(
1018 this,
1019 "mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension",
1020 false);
1021
1022 /**
1023 * Property determines if elements of dimension (levels, hierarchies, members)
1024 * need to be prefixed with dimension name in MDX query.
1025 * For example when the property is true, the following queries
1026 * will error out. The same queries will work when this property
1027 * is set to false.
1028 * <blockquote>
1029 * <p>
1030 * select {[M]} on 0 from sales
1031 * <p>
1032 * select {[USA]} on 0 from sales
1033 * <p>
1034 * select {[USA].[CA].[Santa Monica]} on 0 from sales
1035 * </blockquote>
1036 * <p>
1037 * When the property is set to true, any query where elements are
1038 * prefixed with dimension name as below will work
1039 * <blockquote>
1040 * <p>
1041 * select {[Gender].[F]} on 0 from sales
1042 * <p>
1043 * select {[Customers].[Santa Monica]} on 0 from sales
1044 * </blockquote>
1045 * <p>
1046 * Please note that this property does not govern the behaviour where in
1047 * <blockquote>
1048 * <p>
1049 * [Gender].[M]
1050 * </blockquote>
1051 * <p>
1052 * is resolved into a fully qualified
1053 * <blockquote>
1054 * <p>
1055 * [Gender].[All Gender].[M]
1056 * </blockquote>
1057 * <p>
1058 * In a scenario where the schema is very large and dimensions have large
1059 * number of members a MDX query that has a invalid member in it will cause
1060 * mondrian to to go through all the dimensions, levels, hierarchies, members
1061 * and properties trying to resolve the element name. This behaviour consumes
1062 * considerable time and resources on the server. Setting this property to
1063 * true will make it fail fast in a scenario where it is desirable
1064 */
1065 public transient final BooleanProperty NeedDimensionPrefix =
1066 new BooleanProperty(
1067 this, "mondrian.olap.elements.NeedDimensionPrefix", false);
1068
1069 /**
1070 * Property that determines whether to cache RolapCubeMember objects,
1071 * each of which associates a member of a shared hierarchy with a
1072 * particular cube in which it is being used.
1073 *
1074 * <p>The default is {@code true}, that is, use a cache. If you wish to use
1075 * the member cache control aspects of {@link mondrian.olap.CacheControl},
1076 * you must set this property to {@code false}.</p>
1077 *
1078 * <p>In future, we plan to make RolapCubeMember more lightweight to
1079 * construct, and we will probably obsolete this cache and this
1080 * property.</p>
1081 */
1082 public transient final BooleanProperty EnableRolapCubeMemberCache =
1083 new BooleanProperty(
1084 this, "mondrian.rolap.EnableRolapCubeMemberCache", true);
1085
1086 /**
1087 * Property that controls the behavior of
1088 * {@link Property#SOLVE_ORDER solve order} of calculated members and sets.
1089 *
1090 * <p>Valid values are "absolute" and "scoped" (the default). See
1091 * {@link SolveOrderModeEnum} for details.</p>
1092 */
1093 public transient final StringProperty SolveOrderMode =
1094 new StringProperty(
1095 this, "mondrian.rolap.SolveOrderMode", SolveOrderModeEnum.ABSOLUTE.name());
1096
1097 /**
1098 * Strategies for applying solve order, exposed via the property
1099 * {@link MondrianProperties#SolveOrderMode}.
1100 */
1101 public enum SolveOrderModeEnum {
1102
1103 /**
1104 * The SOLVE_ORDER value is absolute regardless of
1105 * where it is defined; e.g. a query defined calculated
1106 * member with a SOLVE_ORDER of 1 always takes precedence
1107 * over a cube defined value of 2.
1108 *
1109 * <p>Compatible with Analysis Services 2000, and default behavior
1110 * up to mondrian-3.0.3.
1111 */
1112 ABSOLUTE,
1113
1114 /**
1115 * Cube calculated members are resolved before any session
1116 * scope calculated members, and session scope members are
1117 * resolved before any query defined calculation. The
1118 * SOLVE_ORDER value only applies within the scope in which
1119 * it was defined.
1120 *
1121 * <p>Compatible with Analysis Services 2005, and default behavior
1122 * from mondrian-3.0.4 and later.
1123 */
1124 SCOPED;
1125 }
1126 }
1127
1128 // End MondrianProperties.java