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