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