/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.hibernate.jmx;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.jar.JarFile;
import javax.management.Notification;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.jmx.StatisticsService;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.transaction.JBossTransactionManagerLookup;
import org.hibernate.transaction.JTATransactionFactory;
import org.jboss.deployment.DeploymentException;
import org.jboss.deployment.DeploymentInfo;
import org.jboss.hibernate.ListenerInjector;
import org.jboss.hibernate.cache.DeployedTreeCacheProvider;
import org.jboss.logging.Logger;
import org.jboss.mx.loading.RepositoryClassLoader;
import org.jboss.util.naming.Util;
import org.jboss.system.ServiceMBeanSupport;
/**
* The {@link HibernateMBean} implementation.
*
* @version $Revision: 60195 $
* @author Alexey Loubyansky
* @author Gavin King
* @author Steve Ebersole
* @author Dimitris Andreadis
*/
public class Hibernate extends ServiceMBeanSupport implements HibernateMBean
{
private static final Logger log = Logger.getLogger(Hibernate.class);
public static final String SESSION_FACTORY_CREATE = "hibernate.sessionfactory.create";
public static final String SESSION_FACTORY_DESTROY = "hibernate.sessionfactory.destroy";
// Configuration attributes "passed through" to Hibernate
private String datasourceName;
private String dialect;
private String defaultSchema;
private String defaultCatalog;
private Boolean sqlCommentsEnabled;
private Integer maxFetchDepth;
private Integer jdbcFetchSize;
private Integer jdbcBatchSize;
private Boolean batchVersionedDataEnabled;
private Boolean jdbcScrollableResultSetEnabled;
private Boolean getGeneratedKeysEnabled;
private Boolean streamsForBinaryEnabled;
private String hbm2ddlAuto;
private String querySubstitutions;
private Boolean showSqlEnabled;
private String username;
private String password;
private Boolean secondLevelCacheEnabled = Boolean.TRUE;
private Boolean queryCacheEnabled;
private String cacheProviderClass;
private ObjectName deployedTreeCacheObjectName;
private Boolean minimalPutsEnabled;
private String cacheRegionPrefix;
private Boolean structuredCacheEntriesEnabled;
private Boolean statGenerationEnabled;
private Boolean reflectionOptimizationEnabled;
// Configuration attributes used by the MBean
private String sessionFactoryName;
private String sessionFactoryInterceptor;
private String listenerInjector;
private URL harUrl;
private boolean scanForMappingsEnabled = false;
private HashSet archiveClasspathUrls = new HashSet();
private HashSet directoryClasspathUrls = new HashSet();
// Internal state
private boolean dirty = false;
private SessionFactory sessionFactory;
private Date runningSince;
private ObjectName hibernateStatisticsServiceName;
protected void createService() throws Exception
{
log.trace( "forcing bytecode provider -> javassist" );
// todo : really need a much better solution for this...
System.setProperty( Environment.BYTECODE_PROVIDER, "javassist" );
}
/**
* Configure Hibernate and bind the SessionFactory to JNDI.
*/
public void startService() throws Exception
{
log.debug("Hibernate MBean starting; " + this);
// be defensive...
if (sessionFactory != null)
{
destroySessionFactory();
}
harUrl = determineHarUrl();
if (harUrl != null)
{
log.trace("starting in har deployment mode");
// we are part of a har deployment...
if (scanForMappingsEnabled)
{
log.trace("scan for mappings was enabled");
scanForMappings();
}
}
else
{
// we are not contained within a har deployment...
log.trace("starting in non-har deployment mode");
scanForMappings();
}
buildSessionFactory();
}
/**
* Close the SessionFactory.
*/
public void stopService() throws Exception
{
destroySessionFactory();
archiveClasspathUrls.clear();
directoryClasspathUrls.clear();
}
private URL determineHarUrl() throws Exception
{
log.trace("Attempting to determine HarUrl...");
DeploymentInfo deploymentInfo = getDeploymentInfo();
if (deploymentInfo == null)
{
log.warn("Unable to locate deployment info [" + getServiceName() + "]");
return null;
}
String urlStr = deploymentInfo.url.getFile();
log.trace("checking our deployment unit [" + urlStr + "]");
if (urlStr.endsWith(".har") || urlStr.endsWith(".har/"))
{
return deploymentInfo.url;
}
else
{
return null;
}
}
private final Configuration buildConfiguration() throws Exception{
log.debug("Building SessionFactory; " + this);
Configuration cfg = new Configuration();
cfg.getProperties().clear(); // avoid reading hibernate.properties and Sys-props
// Handle custom listeners....
ListenerInjector listenerInjector = generateListenerInjectorInstance();
if (listenerInjector != null)
{
listenerInjector.injectListeners(getServiceName(), cfg);
}
// Handle config settings....
transferSettings(cfg.getProperties());
// Handle mappings....
handleMappings(cfg);
// Handle interceptor....
Interceptor interceptorInstance = generateInterceptorInstance();
if (interceptorInstance != null)
{
cfg.setInterceptor(interceptorInstance);
}
return cfg;
}
/**
* Centralize the logic needed for starting/binding the SessionFactory.
*
* @throws Exception
*/
private void buildSessionFactory() throws Exception
{
Configuration cfg = buildConfiguration();
// Generate sf....
sessionFactory = cfg.buildSessionFactory();
try
{
// Handle stat-mbean creation/registration....
if (sessionFactory.getStatistics() != null && sessionFactory.getStatistics().isStatisticsEnabled())
{
String serviceName = getServiceName().toString();
if( serviceName.indexOf("type=service") != -1 )
{
serviceName = serviceName.replaceAll("type=service","type=stats");
}
else
{
serviceName = serviceName + ",type=stats";
}
hibernateStatisticsServiceName = new ObjectName( serviceName );
StatisticsService hibernateStatisticsService = new StatisticsService();
hibernateStatisticsService.setSessionFactory(sessionFactory);
getServer().registerMBean(hibernateStatisticsService, hibernateStatisticsServiceName);
}
// Handle JNDI binding....
bind();
}
catch (Exception e)
{
forceCleanup();
throw e;
}
dirty = false;
sendNotification(new Notification(SESSION_FACTORY_CREATE, getServiceName(), getNextNotificationSequenceNumber()));
runningSince = new Date();
log.info("SessionFactory successfully built and bound into JNDI [" + sessionFactoryName + "]");
}
/**
* Centralize the logic needed to unbind/close a SessionFactory.
*
* @throws Exception
*/
private void destroySessionFactory() throws Exception
{
if (sessionFactory != null)
{
// TODO : exact situations where we need to clear the 2nd-lvl cache?
// (to allow clean release of the classloaders)
// Most likely, if custom classes are directly cached (UserTypes); anything else?
unbind();
sessionFactory.close();
sessionFactory = null;
runningSince = null;
if (hibernateStatisticsServiceName != null)
{
try
{
getServer().unregisterMBean(hibernateStatisticsServiceName);
}
catch (Throwable t)
{
// just log it
log.warn("unable to cleanup statistics mbean", t);
}
}
sendNotification(new Notification(SESSION_FACTORY_DESTROY, getServiceName(), getNextNotificationSequenceNumber()));
}
}
private void handleMappings(Configuration cfg)
{
//if scanForMappingsEnabled=true we dont want to add the xyz.har file
//as scanForMappingsEnabled=true has already added it to archiveClasspathUrls
if (harUrl != null && !scanForMappingsEnabled )
{
final File file = new File(harUrl.getFile());
if (file.isDirectory())
{
cfg.addDirectory(file);
}
else
{
cfg.addJar(file);
}
}
Iterator itr = archiveClasspathUrls.iterator();
while (itr.hasNext())
{
final File archive = (File)itr.next();
log.debug("Passing archive [" + archive + "] to Hibernate Configration");
cfg.addJar(archive);
}
itr = directoryClasspathUrls.iterator();
while (itr.hasNext())
{
final File directory = (File)itr.next();
log.debug("Passing directory [" + directory + "] to Hibernate Configration");
cfg.addDirectory(directory);
}
}
/**
* Scan the current context's classloader to locate any potential sources of Hibernate mapping files.
*
* @throws DeploymentException
*/
private void scanForMappings() throws DeploymentException
{
// Won't this cause problems if start() is called from say the console?
// a way around is to locate our DeploymentInfo and grab its ucl attribute
// for use here.
URL[] urls = null;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl instanceof RepositoryClassLoader)
{
urls = ((RepositoryClassLoader)cl).getClasspath();
}
else if (cl instanceof URLClassLoader)
{
urls = ((URLClassLoader)cl).getURLs();
}
else
{
throw new DeploymentException("Unable to determine urls from classloader [" + cl + "]");
}
// Search the urls for each of the classpath entries for any containing
// hibernate mapping files or archives
for (int i = 0; i < urls.length; i++)
{
final File entry = new File(urls[i].getFile());
log.trace("checking classpath entry [" + entry + "]");
if (!entry.exists())
{
continue;
}
if (!entry.isDirectory())
{
// This entry is not a directory, meaning it is a file of
// some sort. If it is an archive, we are interested in it...
if (isArchive(entry))
{
log.trace("classpath entry was an archive file...");
archiveClasspathUrls.add(entry);
}
else
{
log.trace("classpath entry was a non-archive file...");
}
}
else
{
log.trace("classpath entry was a directory...");
// we have a directory, add it to the list of directory classpath urls
directoryClasspathUrls.add(entry);
}
}
}
/**
* Simple helper method to determine whether a given File instance represents an archive which complies with the JAR
* specification.
*
* @param file The file to test.
*
* @return True if the incoming file for certain represents an archive; false otherwise.
*/
private boolean isArchive(File file)
{
try
{
new JarFile(file);
return true;
}
catch (Throwable t)
{
return false;
}
}
public void createSchema() throws Exception{
new SchemaExport( buildConfiguration() ).create(false, true);
}
public void dropSchema() throws Exception{
new SchemaExport( buildConfiguration() ).drop(false, true);
}
/**
* Transfer the state represented by our current attribute values into the given Properties instance, translating our
* attributes into the appropriate Hibernate settings.
*
* @param settings The Properties instance to which to add our state.
*/
private void transferSettings(Properties settings)
{
if (cacheProviderClass == null)
{
cacheProviderClass = "org.hibernate.cache.HashtableCacheProvider";
}
log.debug("Using JDBC batch size : " + jdbcBatchSize);
setUnlessNull(settings, Environment.DATASOURCE, datasourceName);
setUnlessNull(settings, Environment.DIALECT, dialect);
setUnlessNull(settings, Environment.CACHE_PROVIDER, cacheProviderClass);
setUnlessNull(settings, Environment.CACHE_REGION_PREFIX, cacheRegionPrefix);
setUnlessNull(settings, Environment.USE_MINIMAL_PUTS, minimalPutsEnabled);
setUnlessNull(settings, Environment.HBM2DDL_AUTO, hbm2ddlAuto);
setUnlessNull(settings, Environment.DEFAULT_SCHEMA, defaultSchema);
setUnlessNull(settings, Environment.STATEMENT_BATCH_SIZE, jdbcBatchSize);
setUnlessNull(settings, Environment.USE_SQL_COMMENTS, sqlCommentsEnabled);
setUnlessNull(settings, Environment.STATEMENT_FETCH_SIZE, jdbcFetchSize);
setUnlessNull(settings, Environment.USE_SCROLLABLE_RESULTSET, jdbcScrollableResultSetEnabled);
setUnlessNull(settings, Environment.USE_QUERY_CACHE, queryCacheEnabled);
setUnlessNull(settings, Environment.USE_STRUCTURED_CACHE, structuredCacheEntriesEnabled);
setUnlessNull(settings, Environment.QUERY_SUBSTITUTIONS, querySubstitutions);
setUnlessNull(settings, Environment.MAX_FETCH_DEPTH, maxFetchDepth);
setUnlessNull(settings, Environment.SHOW_SQL, showSqlEnabled);
setUnlessNull(settings, Environment.USE_GET_GENERATED_KEYS, getGeneratedKeysEnabled);
setUnlessNull(settings, Environment.USER, username);
setUnlessNull(settings, Environment.PASS, password);
setUnlessNull(settings, Environment.BATCH_VERSIONED_DATA, batchVersionedDataEnabled);
setUnlessNull(settings, Environment.USE_STREAMS_FOR_BINARY, streamsForBinaryEnabled);
setUnlessNull(settings, Environment.USE_REFLECTION_OPTIMIZER, reflectionOptimizationEnabled);
setUnlessNull(settings, Environment.GENERATE_STATISTICS, statGenerationEnabled);
setUnlessNull(settings, Environment.TRANSACTION_MANAGER_STRATEGY, JBossTransactionManagerLookup.class.getName());
setUnlessNull(settings, Environment.TRANSACTION_STRATEGY, JTATransactionFactory.class.getName());
if (deployedTreeCacheObjectName != null)
{
String objNameString = deployedTreeCacheObjectName.toString();
if (objNameString != null && !"".equals(objNameString))
{
settings.setProperty(DeployedTreeCacheProvider.OBJECT_NAME_PROP, objNameString);
}
}
settings.setProperty(Environment.FLUSH_BEFORE_COMPLETION, "true");
settings.setProperty(Environment.AUTO_CLOSE_SESSION, "true");
// This is really H3-version-specific:
// in 3.0.3 and later, this should be the ConnectionReleaseMode enum;
// in 3.0.2, this is a true/false setting;
// in 3.0 -> 3.0.1, there is no such setting
//
// so we just set them both :)
settings.setProperty("hibernate.connection.agressive_release", "true");
settings.setProperty("hibernate.connection.release_mode", "after_statement");
}
/**
* Simple helper method for transferring individual settings to a properties
* instance only if the setting's value is not null.
*
* @param props The properties instance into which to transfer the setting
* @param key The key under which to transfer the setting
* @param value The value of the setting.
*/
private void setUnlessNull(Properties props, String key, Object value)
{
if (value != null)
{
props.setProperty(key, value.toString());
}
}
private ListenerInjector generateListenerInjectorInstance()
{
if (listenerInjector == null)
{
return null;
}
log.info("attempting to use listener injector [" + listenerInjector + "]");
try
{
return (ListenerInjector)Thread.currentThread()
.getContextClassLoader()
.loadClass(listenerInjector)
.newInstance();
}
catch (Throwable t)
{
log.warn("Unable to generate specified listener injector", t);
}
return null;
}
private Interceptor generateInterceptorInstance()
{
if (sessionFactoryInterceptor == null)
{
return null;
}
log.info("Generating session factory interceptor instance [" + sessionFactoryInterceptor + "]");
try
{
return (Interceptor)Thread.currentThread()
.getContextClassLoader()
.loadClass(sessionFactoryInterceptor)
.newInstance();
}
catch (Throwable t)
{
log.warn("Unable to generate session factory interceptor instance", t);
}
return null;
}
/**
* Perform the steps necessary to bind the managed SessionFactory into JNDI.
*
* @throws HibernateException
*/
private void bind() throws HibernateException
{
InitialContext ctx = null;
try
{
ctx = new InitialContext();
Util.bind(ctx, sessionFactoryName, sessionFactory);
}
catch (NamingException e)
{
throw new HibernateException("Unable to bind SessionFactory into JNDI", e);
}
finally
{
if (ctx != null)
{
try
{
ctx.close();
}
catch (Throwable ignore)
{
// ignore
}
}
}
}
/**
* Perform the steps necessary to unbind the managed SessionFactory from JNDI.
*
* @throws HibernateException
*/
private void unbind() throws HibernateException
{
InitialContext ctx = null;
try
{
ctx = new InitialContext();
Util.unbind(ctx, sessionFactoryName);
}
catch (NamingException e)
{
throw new HibernateException("Unable to unbind SessionFactory from JNDI", e);
}
finally
{
if (ctx != null)
{
try
{
ctx.close();
}
catch (Throwable ignore)
{
// ignore
}
}
}
}
private void forceCleanup()
{
try
{
sessionFactory.close();
sessionFactory = null;
}
catch (Throwable ignore)
{
// ignore
}
}
public String toString()
{
return super.toString() + " [ServiceName=" + serviceName + ", JNDI=" + sessionFactoryName + "]";
}
// Managed operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void rebuildSessionFactory() throws Exception
{
destroySessionFactory();
buildSessionFactory();
}
// RO managed attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public boolean isDirty()
{
return dirty;
}
public boolean isSessionFactoryRunning()
{
return sessionFactory != null;
}
public String getVersion()
{
return Environment.VERSION;
}
public SessionFactory getInstance()
{
return sessionFactory;
}
public URL getHarUrl()
{
return harUrl;
}
public ObjectName getStatisticsServiceName()
{
return hibernateStatisticsServiceName;
}
public Date getRunningSince()
{
return runningSince;
}
// R/W managed attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public String getSessionFactoryName()
{
return sessionFactoryName;
}
public void setSessionFactoryName(String sessionFactoryName)
{
this.sessionFactoryName = sessionFactoryName;
dirty = true;
}
public String getDatasourceName()
{
return datasourceName;
}
public void setDatasourceName(String datasourceName)
{
this.datasourceName = datasourceName;
dirty = true;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
dirty = true;
}
public void setPassword(String password)
{
this.password = password;
dirty = true;
}
public String getDefaultSchema()
{
return defaultSchema;
}
public void setDefaultSchema(String defaultSchema)
{
this.defaultSchema = defaultSchema;
dirty = true;
}
public String getDefaultCatalog()
{
return defaultCatalog;
}
public void setDefaultCatalog(String defaultCatalog)
{
this.defaultCatalog = defaultCatalog;
}
public String getHbm2ddlAuto()
{
return hbm2ddlAuto;
}
public void setHbm2ddlAuto(String hbm2ddlAuto)
{
this.hbm2ddlAuto = hbm2ddlAuto;
dirty = true;
}
public String getDialect()
{
return dialect;
}
public void setDialect(String dialect)
{
this.dialect = dialect;
dirty = true;
}
public Integer getMaxFetchDepth()
{
return maxFetchDepth;
}
public void setMaxFetchDepth(Integer maxFetchDepth)
{
this.maxFetchDepth = maxFetchDepth;
dirty = true;
}
public Integer getJdbcBatchSize()
{
return jdbcBatchSize;
}
public void setJdbcBatchSize(Integer jdbcBatchSize)
{
this.jdbcBatchSize = jdbcBatchSize;
dirty = true;
}
public Integer getJdbcFetchSize()
{
return jdbcFetchSize;
}
public void setJdbcFetchSize(Integer jdbcFetchSize)
{
this.jdbcFetchSize = jdbcFetchSize;
dirty = true;
}
public Boolean getJdbcScrollableResultSetEnabled()
{
return jdbcScrollableResultSetEnabled;
}
public void setJdbcScrollableResultSetEnabled(Boolean jdbcScrollableResultSetEnabled)
{
this.jdbcScrollableResultSetEnabled = jdbcScrollableResultSetEnabled;
dirty = true;
}
public Boolean getGetGeneratedKeysEnabled()
{
return getGeneratedKeysEnabled;
}
public void setGetGeneratedKeysEnabled(Boolean getGeneratedKeysEnabled)
{
this.getGeneratedKeysEnabled = getGeneratedKeysEnabled;
dirty = true;
}
public String getQuerySubstitutions()
{
return querySubstitutions;
}
public void setQuerySubstitutions(String querySubstitutions)
{
this.querySubstitutions = querySubstitutions;
dirty = true;
}
public Boolean getSecondLevelCacheEnabled()
{
return secondLevelCacheEnabled;
}
public void setSecondLevelCacheEnabled(Boolean secondLevelCacheEnabled)
{
this.secondLevelCacheEnabled = secondLevelCacheEnabled;
dirty = true;
}
public Boolean getQueryCacheEnabled()
{
return queryCacheEnabled;
}
public void setQueryCacheEnabled(Boolean queryCacheEnabled)
{
this.queryCacheEnabled = queryCacheEnabled;
dirty = true;
}
public String getCacheProviderClass()
{
return cacheProviderClass;
}
public void setCacheProviderClass(String cacheProviderClass)
{
this.cacheProviderClass = cacheProviderClass;
dirty = true;
}
public String getCacheRegionPrefix()
{
return cacheRegionPrefix;
}
public void setCacheRegionPrefix(String cacheRegionPrefix)
{
this.cacheRegionPrefix = cacheRegionPrefix;
dirty = true;
}
public Boolean getMinimalPutsEnabled()
{
return minimalPutsEnabled;
}
public void setMinimalPutsEnabled(Boolean minimalPutsEnabled)
{
this.minimalPutsEnabled = minimalPutsEnabled;
dirty = true;
}
public Boolean getUseStructuredCacheEntriesEnabled()
{
return structuredCacheEntriesEnabled;
}
public void setUseStructuredCacheEntriesEnabled(Boolean structuredCacheEntriesEnabled)
{
this.structuredCacheEntriesEnabled = structuredCacheEntriesEnabled;
}
public Boolean getShowSqlEnabled()
{
return showSqlEnabled;
}
public void setShowSqlEnabled(Boolean showSqlEnabled)
{
this.showSqlEnabled = showSqlEnabled;
dirty = true;
}
public Boolean getSqlCommentsEnabled()
{
return sqlCommentsEnabled;
}
public void setSqlCommentsEnabled(Boolean commentsEnabled)
{
this.sqlCommentsEnabled = commentsEnabled;
}
public String getSessionFactoryInterceptor()
{
return sessionFactoryInterceptor;
}
public void setSessionFactoryInterceptor(String sessionFactoryInterceptor)
{
this.sessionFactoryInterceptor = sessionFactoryInterceptor;
dirty = true;
}
public String getListenerInjector()
{
return listenerInjector;
}
public void setListenerInjector(String listenerInjector)
{
this.listenerInjector = listenerInjector;
}
public ObjectName getDeployedTreeCacheObjectName()
{
return deployedTreeCacheObjectName;
}
public void setDeployedTreeCacheObjectName(ObjectName deployedTreeCacheObjectName)
{
this.deployedTreeCacheObjectName = deployedTreeCacheObjectName;
}
public Boolean getBatchVersionedDataEnabled()
{
return batchVersionedDataEnabled;
}
public void setBatchVersionedDataEnabled(Boolean batchVersionedDataEnabled)
{
this.batchVersionedDataEnabled = batchVersionedDataEnabled;
this.dirty = true;
}
public Boolean getStreamsForBinaryEnabled()
{
return streamsForBinaryEnabled;
}
public void setStreamsForBinaryEnabled(Boolean streamsForBinaryEnabled)
{
this.streamsForBinaryEnabled = streamsForBinaryEnabled;
this.dirty = true;
}
public Boolean getReflectionOptimizationEnabled()
{
return reflectionOptimizationEnabled;
}
public void setReflectionOptimizationEnabled(Boolean reflectionOptimizationEnabled)
{
this.reflectionOptimizationEnabled = reflectionOptimizationEnabled;
this.dirty = true;
}
public Boolean getStatGenerationEnabled()
{
return statGenerationEnabled;
}
public void setStatGenerationEnabled(Boolean statGenerationEnabled)
{
this.statGenerationEnabled = statGenerationEnabled;
}
public boolean isScanForMappingsEnabled()
{
return scanForMappingsEnabled;
}
public void setScanForMappingsEnabled(boolean scanForMappingsEnabled)
{
this.scanForMappingsEnabled = scanForMappingsEnabled;
}
}