001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2002-2005 Julian Hyde 008// Copyright (C) 2005-2009 Pentaho and others 009// All Rights Reserved. 010// 011// jhyde, Dec 23, 2002 012*/ 013package mondrian.util; 014 015import mondrian.olap.MondrianProperties; 016import mondrian.olap.Util; 017 018import org.eigenbase.util.property.StringProperty; 019 020/** 021 * The <code>MemoryMonitorFactory</code> is used to get the application's 022 * <code>MemoryMonitor</code>. The <code>MemoryMonitorFactory</code> is 023 * based upon the <code>ObjectFactory.Singleton</code> generic. The 024 * <code>MemoryMonitorFactory</code> implementation has a single, default 025 * <code>MemoryMonitor</code> per JVM instance which can be overridden 026 * using the provided <code>ThreadLocal</code> variable. Normally, this 027 * <code>ThreadLocal</code> override should only be used during JUnit testing. 028 * The JUnit test, set the <code>ThreadLocal</code> variable to the name of its 029 * own implementation of the <code>MemoryMonitor</code> interface and 030 * then calls the <code>ObjectFactory</code> <code>getObject</code> method. 031 * After doing the test, the <code>ThreadLocal</code> variable should 032 * be cleared. 033 * <p> 034 * The <code>ObjectFactory.Singleton</code> permits the use 035 * of <code>System</code> properties to provide a class name to the 036 * factory. This can be used to create a <code>MemoryMonitor</code> 037 * that is not the default one. The property name is the 038 * <code>MemoryMonitor</code> class name, "mondrian.util.MemoryMonitor". 039 * 040 * @author <a>Richard M. Emberson</a> 041 * @since Feb 03 2007 042 */ 043public final class MemoryMonitorFactory 044 extends ObjectFactory.Singleton<MemoryMonitor> 045{ 046 047 /** 048 * Single instance of the <code>MemoryMonitorFactory</code>. 049 */ 050 private static final MemoryMonitorFactory factory; 051 static { 052 factory = new MemoryMonitorFactory(); 053 } 054 055 /** 056 * Access the <code>MemoryMonitorFactory</code> instance. 057 * 058 * @return the <code>MemoryMonitor</code>. 059 */ 060 public static MemoryMonitor getMemoryMonitor() { 061 return factory.getObject(); 062 } 063 064 /** 065 * ThreadLocal used to hold the class name of an <code>MemoryMonitor</code> 066 * implementation. Generally, this should only be used for testing. 067 */ 068 private static final ThreadLocal<String> ClassName = 069 new ThreadLocal<String>(); 070 071 /** 072 * Get the class name of a <code>MemoryMonitor</code> implementation 073 * or null. 074 * 075 * @return the class name or null. 076 */ 077 private static String getThreadLocalClassName() { 078 return ClassName.get(); 079 } 080 081 /** 082 * Sets the class name of a <code>MemoryMonitor</code> implementation. 083 * This should be called (obviously) before calling the 084 * <code>MemoryMonitorFactory</code> <code>getMemoryMonitor</code> 085 * method to get the <code>MemoryMonitor</code> implementation. 086 * Generally, this is only used for testing. 087 * 088 * @param className Class name 089 */ 090 public static void setThreadLocalClassName(String className) { 091 ClassName.set(className); 092 } 093 094 /** 095 * Clears the class name (regardless of whether a class name was set). 096 * When a class name is set using <code>setThreadLocalClassName</code>, 097 * the setting whould be done in a try-block and a call to this 098 * clear method should be in the finally-clause of that try-block. 099 */ 100 public static void clearThreadLocalClassName() { 101 ClassName.set(null); 102 if (factory.testSingleInstance != null) { 103 factory.testSingleInstance.removeAllListener(); 104 factory.testSingleInstance = null; 105 } 106 if (factory.singleInstance instanceof MemoryMonitor.Test) { 107 ((MemoryMonitor.Test) factory.singleInstance).resetFromTest(); 108 } 109 } 110 111 /** 112 * The constructor for the <code>MemoryMonitorFactory</code>. This passes 113 * the <code>MemoryMonitor</code> class to the <code>ObjectFactory</code> 114 * base class. 115 */ 116 private MemoryMonitorFactory() { 117 super(MemoryMonitor.class); 118 } 119 120 /** 121 * Returns whether the use of a <code>MemoryMonitor</code> is enabled. 122 * 123 * @return <code>true</code> if enabled and <code>false</code> otherwise. 124 */ 125 protected boolean enabled() { 126 return MondrianProperties.instance().MemoryMonitor.get(); 127 } 128 129 /** 130 * Get the class name set in the <code>ThreadLocal</code> or null. 131 * 132 * @return class name or null. 133 */ 134 protected String getClassName() { 135 return getThreadLocalClassName(); 136 } 137 138 /** 139 * Return the <code>MemoryMonitorFactory</code property name. 140 * 141 * @return <code>MemoryMonitorFactory</code> property name 142 */ 143 protected StringProperty getStringProperty() { 144 return MondrianProperties.instance().MemoryMonitorClass; 145 } 146 147 /** 148 * The <code>MemoryMonitorFactory</code>'s implementation of the 149 * <code>ObjectFactory</code>'s abstract method which returns 150 * the default <code>MemoryMonitor</code> instance. 151 * For Java4 or if the <code>MemoryMonitorFactory</code> is not enabled 152 * then this method returns the "faux" <code>MemoryMonitor</code> 153 * implementation, it does nothing. When enabled and for 154 * Java5 and above JVMs, and instance of the 155 * <code>NotificationMemoryMonitor</code> is returned. 156 * 157 * @param parameterTypes not used 158 * @param parameterValues not used 159 * @return <code>MemoryMonitor</code> instance 160 * @throws CreationException if the <code>MemoryMonitor</code> can not be 161 * created. 162 */ 163 protected MemoryMonitor getDefault( 164 Class[] parameterTypes, 165 Object[] parameterValues) 166 throws CreationException 167 { 168 return (! enabled() || Util.PreJdk15) 169 // not enabled or Java4 or below 170 ? new FauxMemoryMonitor() 171 // enabled and Java5 or above 172 : new NotificationMemoryMonitor(); 173 } 174 175} 176 177// End MemoryMonitorFactory.java