/**
* Speedo: an implementation of JDO compliant personality on top of JORM generic
* I/O sub-system.
* Copyright (C) 2001-2004 France Telecom R&D
*
* This library 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 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*
* Contact: speedo@objectweb.org
*
* Authors: S.Chassande-Barrioz.
*
*/
package org.objectweb.speedo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.objectweb.fractal.adl.Factory;
import org.objectweb.fractal.adl.FactoryFactory;
import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.ContentController;
import org.objectweb.fractal.util.Fractal;
import org.objectweb.jorm.api.PMapper;
import org.objectweb.jorm.mapper.rdb.lib.ConnectionSpecJDBC;
import org.objectweb.perseus.cache.api.CacheAttributeController;
import org.objectweb.perseus.concurrency.pessimistic.PessimisticConcurrencyManagerAC;
import org.objectweb.perseus.dependency.api.DependencyGraph;
import org.objectweb.perseus.persistence.concurrency.PConcurrencyManager;
import org.objectweb.perseus.persistence.api.TransactionalPersistenceManagerAttributeController;
import org.objectweb.perseus.persistence.api.WorkingSetFilter;
import org.objectweb.perseus.pool.api.PoolAttributes;
import org.objectweb.speedo.api.Debug;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.api.SpeedoVersion;
import org.objectweb.speedo.api.TransactionListener;
import org.objectweb.speedo.jmx.JMXConfigurator;
import org.objectweb.speedo.jmx.api.MX4J_HtmlAdaptorCA;
import org.objectweb.speedo.lib.BooleanHelper;
import org.objectweb.speedo.lib.FractalHelper;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.locale.LocaleHelper;
import org.objectweb.speedo.mapper.api.JormFactoryAttributes;
import org.objectweb.speedo.mapper.api.MapperAttributes;
import org.objectweb.speedo.mapper.rdb.JDBCMapperAttributes;
import org.objectweb.speedo.mim.api.MemoryInstanceManagerAttribute;
import org.objectweb.speedo.pm.api.POManagerFactoryItf;
import org.objectweb.speedo.pm.api.POManagerInstanciatorAC;
import org.objectweb.speedo.pm.api.POManagerItf;
import org.objectweb.speedo.query.api.QueryManager;
import org.objectweb.speedo.query.api.QueryManagerAttribute;
import org.objectweb.speedo.sequence.api.SequenceManager;
import org.objectweb.speedo.workingset.lib.AbstractTransaction;
import org.objectweb.util.monolog.Monolog;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Loggable;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;
/**
* This class is a client helper which permits to create a new speedo
* instance. Due to the personality constraint the POManagerFactoryItf
* implementation must have a public empty contructor. But the use of
* the fractal components (www.objectweb.org/fractal) needs to use a
* fractal implementation (Julia) to initialize the speedo component.
*
* This class is an implementation of the POManagerFactoryItf interface which
* delegates all calls on a delegate, the real component.
* This class is responsible of the Speedo configuration from a set of property
* specified by a Map (String optionName, Object value). Configuring Speedo
* means to assign parameter to some components or maybe change the architecture
* of Speedo (change some component).
*
* This class must be subclassed for each personality of Speedo.
*
* @author S.Chassande-Barrioz
*/
public abstract class AbstractSpeedo
implements POManagerFactoryItf, SpeedoProperties {
private static final long serialVersionUID = 8894700146086754547L;
private final static String LOGGER_NAME = SpeedoProperties.LOGGER_NAME + ".init";
private final static String OPTIMISTIC_CONCURRENCY_TEMPLATE =
"org.objectweb.perseus.concurrency.optimistic.OptimisticConcurrencyManager";
private final static String DBDELEGATE_CONCURRENCY_TEMPLATE =
"org.objectweb.perseus.persistence.concurrency.PDbDelegateConcurrencyManager";
public final static String PM_POOL_PATH = "po-manager-pool";
public final static String PMI_PATH = "po-manager-instanciator";
public final static String MIM_PATH = "memory-instance-manager";
public final static String MEMORY_CACHE_PATH = "tpm.cache-manager";
public final static String DEPENDENCY_GRAPH_PATH = "tpm.dependency-graph";
public final static String QUERY_CACHE_PATH = "compiled-query-cache";
public final static String QUERY_MANAGER = "query-manager";
public final static String CONNECTION_POOL_PATH = "mapper.pool";
public final static String MONOLOG_FACTORY_PATH = "monolog-factory";
public final static String PRIMITIVE_MAPPER_PATH = "mapper.mapper";
public final static String JORM_FACTORY_PATH = "mapper.jorm-factory";
public final static String COMPOSITE_TPM_PATH = "tpm";
public final static String TPM_PATH = "tpm.transactional-persistence-manager";
public final static String PMF_PATH = "po-manager-factory";
public final static String JMX_AGENT_PATH = "agent";
public final static String HTML_JMX_AGENT_PATH = JMX_AGENT_PATH + ".html";
private final static String FRACTAL_PROVIDER = "fractal.provider";
private final static String DEFAULT_FRACTAL_PROVIDER
= "org.objectweb.fractal.julia.Julia";
private final static String JULIA_LOADER = "julia.loader";
private final static String DEFAULT_JULIA_LOADER
= "org.objectweb.fractal.julia.loader.DynamicLoader";
private final static String JULIA_CONFIG = "julia.config";
private final static String DEFAULT_JULIA_CONFIG = "julia.cfg";
private static Factory factory = null;
private static Factory getADLFactory () throws Exception {
if (factory == null) {
factory = FactoryFactory.getFactory(FactoryFactory.FRACTAL_BACKEND);
}
return factory;
}
/**
* The persistence manager factory delegate
*/
protected POManagerFactoryItf delegate = null;
protected Logger logger = null;
protected Component speedo = null;
protected boolean isPropertiesInitialized = false;
protected boolean jmxOn = false;
public AbstractSpeedo() {
}
/**
* It creates and initializes a real POManagerFactory with
* Julia (Fractal implementation).
*/
public AbstractSpeedo(Map props) throws Throwable {
try {
init(props);
isPropertiesInitialized = true;
} catch(Throwable e) {
System.err.println("Error during the instanciation of the Speedo " +
"persistence manager factory:");
e.printStackTrace(System.err);
throw e;
}
}
public abstract Personality getPersonality();
protected abstract void throwUserException(String msg);
protected abstract boolean isOptimisticTransaction(Map props);
public void stopComponent() {
logger.log(BasicLevel.INFO, "Stopping Speedo");
try {
Fractal.getLifeCycleController(speedo).stopFc();
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "Cannot stop Speedo: ", e);
}
}
public POManagerFactoryItf getPMFComponent() throws Exception {
return delegate;
}
public Object getConcurrencyManagerComponent() throws Exception {
return getSubComponent(speedo, "tpm.concurrency-manager");
}
public DependencyGraph getDependencyGraph() throws Exception {
Component cmC = (Component) getConcurrencyManagerComponent();
Object dg = Fractal.getBindingController(cmC).lookupFc("dependency-graph");
return (DependencyGraph) dg;
}
public Collection getMemoryCacheEntries() throws Exception {
Component cm = getSubComponent(speedo, MEMORY_CACHE_PATH);
Component cmC = getSubComponent(cm, "cache-manager");
CacheAttributeController cacheAttr = (CacheAttributeController)
Fractal.getAttributeController(cmC);
return cacheAttr.getCurrentEntryIdentifiers();
}
public POManagerFactoryItf getDelegate() {
return delegate;
}
// IMPLEMENTATION OF THE POManagerFactoryItf INTERFACE //
//-----------------------------------------------------//
public POManagerItf getPOManager() {
return delegate.getPOManager();
}
public POManagerItf lookup() {
return delegate.lookup();
}
public SequenceManager getSequenceManager() {
return delegate.getSequenceManager();
}
public void setSequenceManager(SequenceManager sequenceManager) {
delegate.setSequenceManager(sequenceManager);
}
public QueryManager getQueryManager() {
return delegate.getQueryManager();
}
public void setQueryManager(QueryManager queryManager) {
delegate.setQueryManager(queryManager);
}
public void unbindPM() {
delegate.unbindPM();
}
public void bindPM2Thread(POManagerItf pm) {
delegate.bindPM2Thread(pm);
}
public void poManagerClosed(POManagerItf pr) {
delegate.poManagerClosed(pr);
}
public void clean() {
delegate.clean();
}
public Properties getProperties() {
return delegate.getProperties();
}
// methods for speedo configuration //
//----------------------------------//
protected Component getSpeedoComponent(Map props) throws Throwable {
if (speedo == null) {
//use Julia as Fractal implementation
System.setProperty(FRACTAL_PROVIDER, DEFAULT_FRACTAL_PROVIDER);
System.setProperty(JULIA_LOADER, DEFAULT_JULIA_LOADER);
System.setProperty(JULIA_CONFIG, DEFAULT_JULIA_CONFIG);
//Allocate a Logger through the LoggerFactory component
Monolog.initialize();
LoggerFactory loggerFactory = Monolog.monologFactory;
logger = loggerFactory.getLogger(LOGGER_NAME);
//Choose the fractal template according to the JMX option
String templateName;
if (props != null && BooleanHelper.parse(
getProperty(props, JMX, "false", false), false)) {
templateName = "SpeedoJMX";
} else {
templateName = "Speedo";
}
//Choose the fractal template corresponding to the personality
templateName = getPersonality()
.getPersonalityClassName("org.objectweb.speedo", templateName);
//instanciate the Speedo component
Component speedoTemplate = null;
try {
speedoTemplate = (Component)getADLFactory().newComponent(
templateName,
Collections.singletonMap("template", "true"));
speedo = Fractal.getFactory(speedoTemplate).newFcInstance();
} catch (Throwable e) {
System.err.println("Error during the template loading or the " +
"component instanciation '" + speedoTemplate + "': ");
throw e;
}
Fractal.getNameController(speedo).setFcName("org.objectweb.speedo");
delegate = (POManagerFactoryItf)
speedo.getFcInterface("po-manager-factory");
}
return speedo;
}
public void init(Map pmfProps) throws Throwable {
getSpeedoComponent(pmfProps);
logger.log(BasicLevel.INFO, "Speedo " + SpeedoVersion.SPEEDO_VERSION
+ LocaleHelper.getSpeedoRB().getString("start"));
configure(pmfProps);
delegate.getProperties().putAll(pmfProps);
Fractal.getLifeCycleController(speedo).startFc();
if (jmxOn) {
new JMXConfigurator(speedo, logger).init();
}
logger.log(BasicLevel.INFO, "Speedo " + SpeedoVersion.SPEEDO_VERSION
+ LocaleHelper.getSpeedoRB().getString("ready"));
}
protected void configure(Map pmfProps) throws Throwable {
Map props = new HashMap(pmfProps);
applyProperties(props, pmfProps);
//Warn the unknwon properties
for (Iterator it = props.entrySet().iterator(); it.hasNext();) {
Map.Entry me = (Map.Entry) it.next();
String key = (String) me.getKey();
if (key.startsWith(CACHE_CLASS_POLICY+"(")
|| key.startsWith(USER_CACHE_CLASS_POLICY+"(")
|| key.startsWith(PREFETCH_ON_GENCLASS+"(")
|| key.startsWith(PREFETCH_ON_QUERY+"(")
|| key.startsWith(PREFETCH_ON_EXTENT+"(")
|| key.startsWith(SHAREABLE)
) {
continue;
}
String value = (String) me.getValue();
logger.log(BasicLevel.WARN, "The (" + key + ", " + value
+ ") property is not managed");
}
}
protected void applyProperties(Map props, Map pmfProps) throws Throwable {
//Debug Mode
String strval = getProperty(props, SpeedoProperties.DEBUG, null, true);
if (strval != null) {
Debug.ON = Boolean.valueOf(strval).booleanValue();
logger.log(BasicLevel.INFO, SpeedoProperties.DEBUG + ": " + Debug.ON);
}
configureMIM(getSubComponent(speedo, MIM_PATH), props);
configurePOMI(getSubComponent(speedo, PMI_PATH), props);
boolean useConnectionFactory = configureMapper(props);
configurePool(getSubComponent(speedo, PM_POOL_PATH),
"PersistenceManager pool: ",
PM_POOL_MIN,
PM_POOL_MAX,
PM_POOL_TTL,
PM_POOL_INACTIVETTL,
PM_POOL_TIMEOUT,
props);
configureCache(getSubComponent(speedo, MEMORY_CACHE_PATH),
"Persistent objects cache: ",
CACHE_SIZE,
CACHE_AUTO_CLEAN_SIZE,
CACHE_AUTO_CLEAN_THRESHOLD,
CACHE_REPLCAEMENT,
props);
configureCache(getSubComponent(speedo, QUERY_CACHE_PATH),
"Compiled query cache: ",
COMPILED_QUERY_CACHE_SIZE,
COMPILED_QUERY_CACHE_AUTO_CLEAN_SIZE,
COMPILED_QUERY_CACHE_AUTO_CLEAN_THRESHOLD,
COMPILED_QUERY_CACHE_POLICY,
props);
configureTPM(getSubComponent(speedo, TPM_PATH),
"Transactionnal persistence manager: ",
TRANSACTION_FILTERS,
props);
strval = getProperty(props, IMRICATED_PM_ALLOWED, "false", true);
boolean imbricatedPM = Boolean.valueOf(strval).booleanValue();
if (imbricatedPM) {
logger.log(BasicLevel.INFO, LocaleHelper.getSpeedoRB().getString("pmreused"));
}
configurePrefetching(props);
configureConcurrencyManager(props);
configureTransaction(props, pmfProps, useConnectionFactory);
jmxOn = configureJMX(props);
}
protected String getProperty(Map m,
String propName,
String defaultValue,
boolean remove) {
Object res = remove ? m.remove(propName) : m.get(propName);
if (res instanceof String) {
return (String) res;
} else {
return defaultValue;
}
}
protected boolean removeProps(Map props, String[] wanted) {
boolean found = false;
for (int i = 0; i < wanted.length; i++) {
found |= props.remove(wanted[i]) != null;
}
return found;
}
private Component getSubComponent(Component parent,
String path) throws Exception {
return FractalHelper.getSubComponent(parent, path, logger);
}
private void configureMIM(Component mimC, Map props) throws Exception {
MemoryInstanceManagerAttribute mima = (MemoryInstanceManagerAttribute)
Fractal.getAttributeController(mimC);
mima.setPersonality(getPersonality());
}
private void configurePOMI(Component pomiC, Map props) throws Exception {
POManagerInstanciatorAC pomiac = (POManagerInstanciatorAC)
Fractal.getAttributeController(pomiC);
pomiac.setPOManagerTemplateName("org.objectweb.speedo.pm."
+ getPersonality().getName() + ".lib."
+ getPersonality().getName().toUpperCase() + "POManager");
pomiac.setTransactionTemplateName("org.objectweb.speedo.workingset."
+ getPersonality().getName() + ".lib."
+ getPersonality().getName().toUpperCase() + "TransactionImpl");
}
private void configurePool(Component pool,
String poolLabel,
String minProp,
String maxProp,
String ttlProp,
String inactivettlProp,
String timeoutProp,
Map props) throws Exception {
String strval = null;
int poolMinSize = -2;
int poolMaxSize = -2;
long poolTTL = -2;
long poolInactiveTTL = -2;
long poolTimeout = -2;
boolean conf = false;
StringBuffer sb = new StringBuffer(poolLabel);
final String sep = ", ";
if (minProp != null) {
strval = getProperty(props, minProp, "", true);
if (strval.length() > 0) {
poolMinSize = Integer.parseInt(strval);
if (conf) {
sb.append(sep);
}
sb.append("min=" + strval);
conf = true;
}
}
if (maxProp != null) {
strval = getProperty(props, maxProp, "", true);
if (strval.length() > 0) {
if (strval.equalsIgnoreCase("nolimit")) {
poolMaxSize = -1;
} else {
poolMaxSize = Integer.parseInt(strval);
}
if (conf) {
sb.append(sep);
}
sb.append("max=" + strval);
conf = true;
}
}
if (ttlProp != null) {
strval = getProperty(props, ttlProp, "", true);
if (strval.length() > 0) {
try {
poolTTL = 1000 * Long.parseLong(strval);
} catch (NumberFormatException e) {
poolTTL = -1;
strval = "NOTTL";
}
if (conf) {
sb.append(sep);
}
sb.append("ttl=" + strval);
conf = true;
}
}
if (inactivettlProp != null) {
strval = getProperty(props, inactivettlProp, "", true);
if (strval.length() > 0) {
try {
poolInactiveTTL = 1000 * Long.parseLong(strval);
} catch (NumberFormatException e) {
poolInactiveTTL = -1;
strval = "NOTTL";
}
if (conf) {
sb.append(sep);
}
sb.append("inactivettlProp=" + strval);
conf = true;
}
}
if (timeoutProp != null) {
strval = getProperty(props, timeoutProp, "", true);
if (strval.length() > 0) {
try {
poolTimeout = Long.parseLong(strval);
} catch (NumberFormatException e) {
poolTimeout = -1;
strval = "WAIT";
}
if (conf) {
sb.append(sep);
}
sb.append("timeout=" + strval);
conf = true;
}
}
if (conf) {
logger.log(BasicLevel.INFO, sb.toString());
PoolAttributes poolAttr;
try {
poolAttr = (PoolAttributes)
Fractal.getAttributeController(pool);
} catch (Exception e) {
Component[] children = Fractal.getContentController(speedo).getFcSubComponents();
String[] strs= new String[children.length];
for (int i = 0; i < strs.length; ++i) {
strs[i] = Fractal.getNameController(children[i]).getFcName();
}
throw new RuntimeException("" + Arrays.asList(strs));
}
if (poolMaxSize > -2) {
poolAttr.setMaxSize(poolMaxSize);
}
if (poolMinSize > -2) {
poolAttr.setMinSize(poolMinSize);
}
if (poolTTL > -2) {
poolAttr.setTTL(poolTTL);
}
if (poolInactiveTTL > -2) {
poolAttr.setInactiveTTL(poolInactiveTTL);
}
if (poolTimeout > -2) {
poolAttr.setTimeout(poolTimeout);
}
}
}
/**
* Configures the memory cache.
* @param cm is the cache composite component
* @param props is the speedo initialisation properties
*/
private void configureCache(Component cm,
String cacheLabel,
String sizeProp,
String autoCleanSizeProp,
String autoCleanThresholdProp,
String policyProp,
Map props)
throws Exception {
int cacheSize = -2;
String autoCleanSize = null;
String autoCleanThreshold = null;
String policy = null;
//configure the cache size
StringBuffer sb = new StringBuffer(cacheLabel);
final String sep = ", ";
boolean conf = false;
String strval = getProperty(props, sizeProp, "", true);
if (strval.length()>0) {
if (strval.equalsIgnoreCase("nolimit")) {
cacheSize = CacheAttributeController.NO_LIMIT;
} else {
cacheSize = Integer.parseInt(strval);
}
if (conf) {
sb.append(sep);
}
sb.append("max size=" + strval);
conf = true;
}
//configure the cache auto clean size
strval = getProperty(props, autoCleanSizeProp, "", true);
if (strval.length() > 0) {
autoCleanSize = strval;
if (conf) {
sb.append(sep);
}
sb.append("auto replacement size=" + strval);
conf = true;
}
//configure the cache auto clean size
strval = getProperty(props, autoCleanThresholdProp, "", true);
if (strval.length() > 0) {
autoCleanThreshold = strval;
if (conf) {
sb.append(sep);
}
sb.append("auto replacement threshold=" + strval);
conf = true;
}
//configure the replacement policy of the cache (Replacement manager)
strval = getProperty(props, policyProp, "", true);
if (strval.length() > 0) {
policy = strval;
if (conf) {
sb.append(sep);
}
sb.append("replacement policy=" + strval);
conf = true;
}
if (!conf) {
return;
}
logger.log(BasicLevel.INFO, sb.toString());
Component cmC = getSubComponent(cm, "cache-manager");
CacheAttributeController cacheAttr = (CacheAttributeController)
Fractal.getAttributeController(cmC);
if (cacheSize > -2) {
cacheAttr.setMaxObjects(cacheSize);
}
if (autoCleanSize != null) {
cacheAttr.setAutoCleanSize(autoCleanSize);
}
if (autoCleanThreshold != null) {
cacheAttr.setAutoCleanThreshold(autoCleanThreshold);
}
if (policy != null) {
String tempName = null;
if (CACHE_REPLCAEMENT_LRU.equalsIgnoreCase(policy)) {
} else if (CACHE_REPLCAEMENT_MRU.equalsIgnoreCase(policy)) {
tempName = "org.objectweb.perseus.cache.replacement.lib.MRUReplacementManager";
} else if (CACHE_REPLCAEMENT_FIFO.equalsIgnoreCase(policy)) {
tempName = "org.objectweb.perseus.cache.replacement.lib.FIFOReplacementManager";
} else {
logger.log(BasicLevel.ERROR, new SpeedoException(
"Unmanaged cache replacement policy: " + policy));
}
if (tempName != null) {
//unbind the rm from the composite
Fractal.getBindingController(cm).unbindFc("replacement-manager");
//unbind the rm from the primitive cm
Fractal.getBindingController(cmC).unbindFc("replacement-manager");
//unbind the primitive cm from the old rm
Fractal.getBindingController(
getSubComponent(cm, "replacement-manager"))
.unbindFc("unbind-manager");
//remove the old rm from the composite
Fractal.getContentController(cm).removeFcSubComponent(
getSubComponent(cm, "replacement-manager"));
//instanciate the new component
Component new_rm = (Component)getADLFactory().newComponent(tempName, null);
Fractal.getNameController(new_rm).setFcName("replacement-manager");
//Add the new rm in the composite
Fractal.getContentController(cm).addFcSubComponent(new_rm);
Object rm = new_rm.getFcInterface("replacement-manager");
//bind the rm to the composite
Fractal.getBindingController(cm).bindFc("replacement-manager", rm);
//bind the rm to the primitive cm
Fractal.getBindingController(cmC).bindFc("replacement-manager", rm);
//bind the primitive cm to the new rm
Fractal.getBindingController(new_rm).bindFc("unbind-manager",
cmC.getFcInterface("unbind-manager"));
}
}
}
/**
* Configures the transactional persistence manager
* @param tpm is the component
* @param props is the speedo initialisation properties
*/
private void configureTPM(Component tpm,
String tpmLabel,
String filtersProp,
Map props)
throws Exception {
String strval = getProperty(props, filtersProp, "", true);
Collection filters = new ArrayList(1);
//configure the list of filters (separated by ",")
if (strval.length()>0) {
filters = new ArrayList();
String filterClassName;
while (strval.length() > 0) {
int coma = strval.indexOf(",");
if (coma != -1) {
filterClassName = strval.substring(0, coma);
strval = strval.substring(coma + 1);
} else {
filterClassName = strval;
strval = "";
}
try {
//instanciate a filter class
WorkingSetFilter filter = (WorkingSetFilter) Class.forName(filterClassName).newInstance();
//add it to the list
filters.add(filter);
} catch (Exception e) {
System.err.println("Error during the configuration of the tpm");
e.printStackTrace(System.err);
throw e;
}
}
}
//add the filters to the tpm
if (!filters.isEmpty()) {
TransactionalPersistenceManagerAttributeController tpmAttr = (TransactionalPersistenceManagerAttributeController)
Fractal.getAttributeController(tpm);
tpmAttr.setFilters(filters);
}
}
private void configureTransaction(Map props, Map pmfProps, boolean useConnectionFactory) throws Exception {
//deprecated properties
final String TM_NAME_old = "org.objectweb.perseus.connector.ra.jdo.TMName";
String strval = getProperty(props, TM_NAME_old, "", true);
if (strval.length()>0) {
logger.log(BasicLevel.WARN, "Property " + TM_NAME_old
+ " is deprecated, you must use " + TM_NAME);
if (getProperty(props, TM_NAME, null, true) == null) {
pmfProps.put(TM_NAME, strval);
}
}
// Transaction managed by an application server
strval = getProperty(props, MANAGED, "", false);
if (strval.length()>0) {
boolean b = BooleanHelper.parse(strval, false);
if (!useConnectionFactory && b) {
String msg = "In a managed environnement, a connection factory is required";
logger.log(BasicLevel.ERROR, msg);
throwUserException(msg);
}
logger.log(BasicLevel.INFO, MANAGED + LocaleHelper.getSpeedoRB().getString("speedused")
+ (b
? LocaleHelper.getSpeedoRB().getString("managed")
: LocaleHelper.getSpeedoRB().getString("standalone")));
//TransactionManager JNDI name
strval = getProperty(props, TM_NAME, "", true);
logger.log(BasicLevel.INFO, TM_NAME + "="
+ (strval.length()>0
? strval
: LocaleHelper.getSpeedoRB().getString("tmspec")));
} else {
props.remove(TM_NAME);
}
//Listener of Transaction life cycle (statistic)
strval = getProperty(props, TX_LISTENER, "", true);
if (strval.length()>0) {
try {
AbstractTransaction.txListener = (TransactionListener)
Class.forName(strval).newInstance();
if (AbstractTransaction.txListener instanceof Loggable) {
((Loggable) AbstractTransaction.txListener)
.setLoggerFactory(Monolog.monologFactory);
}
logger.log(BasicLevel.INFO, "Transaction listener: " + strval);
} catch (Exception e) {
logger.log(BasicLevel.WARN,
LocaleHelper.getSpeedoRB().getString("txlisten")
+ " ('" + strval + "'): ", e);
}
}
}
private void configureConcurrencyManager(Map props) throws Exception {
String tempName;
StringBuffer sb = new StringBuffer(LocaleHelper.getSpeedoRB().getString("txconcmgt"));
String strval = getProperty(props, TRANSACTION_LOCKING,
SPEEDO_TRANSACTION_LOCKING, true);
boolean dbLocking = strval.equals(DB_TRANSACTION_LOCKING);
boolean optimistic = isOptimisticTransaction(props);;
if (dbLocking && optimistic) {
logger.log(BasicLevel.WARN, sb.toString()
+ LocaleHelper.getSpeedoRB().getString("dbpessim"));
optimistic = false;
}
sb.append("mode=").append((optimistic ? LocaleHelper.getSpeedoRB().getString("optim")
: LocaleHelper.getSpeedoRB().getString("pessim")));
//fetch the composite TPM
Component composite_tpm = getSubComponent(speedo, COMPOSITE_TPM_PATH);
Component cm = getSubComponent(composite_tpm, "concurrency-manager");
if (dbLocking) {
tempName = DBDELEGATE_CONCURRENCY_TEMPLATE;
sb.append(LocaleHelper.getSpeedoRB().getString("concdeleg"));
} else {
sb.append(LocaleHelper.getSpeedoRB().getString("concspeed"));
if (!optimistic) {
//Configure the pessimistic concurrency manager
//policy= mutex | rw-fifo | rw-reader
strval = getProperty(props,
TRANSACTION_LOCKING_PESSIMISTIC_POLICY,
TRANSACTION_LOCKING_PESSIMISTIC_POLICY_RW_FIFO, true);
PessimisticConcurrencyManagerAC pcmAC = null;
if (!strval.equals(TRANSACTION_LOCKING_PESSIMISTIC_POLICY_RW_FIFO)) {
pcmAC = (PessimisticConcurrencyManagerAC)
Fractal.getAttributeController(cm);
strval = strval.toUpperCase();
if (!strval.startsWith("POLICY_")) {
strval = "POLICY_" + strval;
}
pcmAC.setPolicy(strval);
sb.append(LocaleHelper.getSpeedoRB().getString("lockpol")).append(strval);
}
//locking level = instance | field
strval = getProperty(props,
TRANSACTION_LOCKING_LEVEL_ENABLETHIN,
"false", true);
boolean b = BooleanHelper.parse(strval, false);
if (b) {
logger.log(BasicLevel.INFO, LocaleHelper.getSpeedoRB().getString("thinlock"));
pcmAC = (PessimisticConcurrencyManagerAC)
Fractal.getAttributeController(cm);
pcmAC.setThinkLockAllowed(true);
sb.append(LocaleHelper.getSpeedoRB().getString("thlklvl"));
}
logger.log(BasicLevel.INFO, sb.toString());
return;
}
tempName = OPTIMISTIC_CONCURRENCY_TEMPLATE;
}
//optimistic or dblocking
logger.log(BasicLevel.INFO, sb.toString());
ContentController tpmCC = Fractal.getContentController(composite_tpm);
//fetch the primitive concurrency manager
BindingController tpmBC = Fractal.getBindingController(
getSubComponent(composite_tpm, "transactional-persistence-manager"));
tpmBC.unbindFc("concurrency-manager");
//Remove the old pessimistic concurrency manager
BindingController cmBC = Fractal.getBindingController(cm);
String[] bds = cmBC.listFc();
for (int i = 0; i < bds.length; i++) {
cmBC.unbindFc(bds[i]);
}
tpmCC.removeFcSubComponent(cm);
//instanciate the new ConcurrencyManager
cm = (Component)getADLFactory().newComponent(tempName, null);
//Add the new concurrency manager into the composite
tpmCC.addFcSubComponent(cm);
//bind the server interface of the new concurrency manager
cmBC = Fractal.getBindingController(cm);
if (dbLocking) {
cmBC.bindFc(PConcurrencyManager.STATE_MANAGER_BINDING,
tpmCC.getFcInternalInterface("state-manager"));
cmBC.bindFc(PConcurrencyManager.STORAGE_MANAGER_BINDING,
tpmCC.getFcInternalInterface("storage-manager"));
} else {//optimistic
cmBC.bindFc(PConcurrencyManager.DEPENDENCY_GRAPH_BINDING,
getSubComponent(composite_tpm, "dependency-graph")
.getFcInterface("dependency-graph"));
}
//bind the client interface of the new ConcurrencyManager
tpmBC.bindFc("concurrency-manager", cm.getFcInterface("concurrency-manager"));
}
private void configurePrefetching(Map props) throws Throwable {
//Data prefetching on queries
boolean prefetch = true;
StringBuffer sb = new StringBuffer(LocaleHelper.getSpeedoRB().getString("prefetch"));
String strval = getProperty(props, PREFETCH, "", true);
if (strval.length()>0) {
prefetch = BooleanHelper.parse(strval, false);
}
Component qm = getSubComponent(speedo, QUERY_MANAGER);
QueryManagerAttribute qma = ((QueryManagerAttribute) Fractal.getAttributeController(qm));
if (!prefetch) {
qma.setPrefetchActivatedOnQuery(false);
qma.setPrefetchActivatedOnExtent(false);
logger.log(BasicLevel.INFO, sb.append(LocaleHelper.getSpeedoRB().getString("NONE")).toString());
return;
}
boolean prefetchOnQuery = qma.getPrefetchActivatedOnQuery();
boolean prefetchOnExtent = qma.getPrefetchActivatedOnExtent();
boolean prefetchOnGenClass = true;
String sep = ", ";
boolean oneOf = false;
strval = getProperty(props, PREFETCH_ON_QUERY, "", true);
if (strval.length()>0) {
prefetchOnQuery = BooleanHelper.parse(strval, false);
}
if (prefetchOnQuery) {
if (oneOf) {
sb.append(sep);
}
sb.append(LocaleHelper.getSpeedoRB().getString("QUERY"));
}
oneOf |= prefetchOnQuery;
qma.setPrefetchActivatedOnQuery(prefetchOnQuery);
strval = getProperty(props, PREFETCH_ON_EXTENT, "", true);
if (strval.length()>0) {
prefetchOnExtent = BooleanHelper.parse(strval, false);
}
if (prefetchOnExtent) {
if (oneOf) {
sb.append(sep);
}
sb.append(LocaleHelper.getSpeedoRB().getString("EXTENT"));
}
oneOf |= prefetchOnExtent;
qma.setPrefetchActivatedOnExtent(prefetchOnExtent);
strval = getProperty(props, PREFETCH_ON_GENCLASS, "", true);
if (strval.length()>0) {
prefetchOnGenClass= BooleanHelper.parse(strval, false);
}
if (prefetchOnGenClass) {
if (oneOf) {
sb.append(sep);
}
sb.append(LocaleHelper.getSpeedoRB().getString("COLLECTION"));
}
oneOf |= prefetchOnGenClass;
logger.log(BasicLevel.INFO, sb.toString());
}
/**
* Configures the mapper component
* @param props is the properties of Speedo
* @return true if a connection factory is used, false if the JDBC driver is
* used directly.
* @throws Throwable if an error or an exception occurs
*/
private boolean configureMapper(Map props) throws Throwable {
boolean useConnectionFactory;
String mapperName = getProperty(props, MAPPER_NAME, "rdb.automatic", true);
Component component = getSubComponent(speedo, PRIMITIVE_MAPPER_PATH);
String strval = null;
//Choose the mapper in according to the connection factory (JCA or JDBC)
String cfName = getProperty(props, JDO_OPTION_CONNECTION_FACTORY_NAME, null, true);
useConnectionFactory = cfName != null && cfName.length() > 0;
Object o = Fractal.getAttributeController(component);
MapperAttributes ma = (MapperAttributes) o;
if (useConnectionFactory) {
Object cf = null;
//There is a connection factory
try {
InitialContext ic = new InitialContext();
cf = ic.lookup(cfName);
} catch (NamingException e) {
throw new SpeedoException(
"Problem to get the connection factory in JNDI ("
+ cfName + ")", e);
}
if (cf == null) {
throw new SpeedoException(
"No connection factory registered in JNDI with the name "
+ cfName);
} else if (cf instanceof ConnectionSpecJDBC) {
// Use the JDBC Mapper ==> nothing to do
} else if (cf instanceof javax.sql.DataSource) {
// Use the JDBC Mapper ==> nothing to do
} else if (cf instanceof javax.resource.cci.ConnectionFactory) {
throw new SpeedoException("JCA datasource no yet supported");
} else {
throw new SpeedoException("The connection factory registered "
+ "in JNDI is not supported by Speedo " + cfName + " => "
+ cf);
}
boolean ignoring = removeProps(props, new String[]{
JDO_OPTION_CONNECTION_DRIVER_NAME_OLD,
JDO_OPTION_CONNECTION_DRIVER_NAME_OLD2,
JDO_OPTION_CONNECTION_DRIVER_NAME,
JDO_OPTION_CONNECTION_URL,
JDO_OPTION_CONNECTION_USER_NAME,
JDO_OPTION_CONNECTION_PASSWORD});
if (ignoring) {
logger.log(BasicLevel.WARN,
LocaleHelper.getSpeedoRB().getString("ignjdbcinfo"));
}
ignoring = removeProps(props, new String[]{
CONNECTION_POOL_MIN,
CONNECTION_POOL_MAX,
CONNECTION_POOL_TTL,
CONNECTION_POOL_TIMEOUT});
if (ignoring) {
logger.log(BasicLevel.WARN,
LocaleHelper.getSpeedoRB().getString("ignconninfo"));
}
//Assign the connection factory to the mapper
logger.log(BasicLevel.INFO, LocaleHelper.getSpeedoRB().getString("connfact")
+ LocaleHelper.getSpeedoRB().getString("jndinm") + cfName
+ LocaleHelper.getSpeedoRB().getString("factfound") + cf
+ LocaleHelper.getSpeedoRB().getString("mappernm") + mapperName);
PMapper mapper = (PMapper) component.getFcInterface("mapper");
mapper.setMapperName(mapperName);
mapper.setConnectionFactory(cf);
} else {
JDBCMapperAttributes jdbcma = (JDBCMapperAttributes) ma;
//deprecated properties
strval = getProperty(props, JDO_OPTION_CONNECTION_DRIVER_NAME_OLD, "", true);
if (strval.length()>0) {
logger.log(BasicLevel.WARN, LocaleHelper.getSpeedoRB().getString("property")
+ " " + JDO_OPTION_CONNECTION_DRIVER_NAME_OLD
+ LocaleHelper.getSpeedoRB().getString("deprecuse") + JDO_OPTION_CONNECTION_DRIVER_NAME);
if (getProperty(props, JDO_OPTION_CONNECTION_DRIVER_NAME, null, false) == null) {
props.put(JDO_OPTION_CONNECTION_DRIVER_NAME, strval);
}
}
strval = getProperty(props, JDO_OPTION_CONNECTION_DRIVER_NAME_OLD2, "", true);
if (strval.length()>0) {
logger.log(BasicLevel.WARN, LocaleHelper.getSpeedoRB().getString("property")
+ " " + JDO_OPTION_CONNECTION_DRIVER_NAME_OLD2
+ LocaleHelper.getSpeedoRB().getString("deprecuse") + JDO_OPTION_CONNECTION_DRIVER_NAME);
if (getProperty(props, JDO_OPTION_CONNECTION_DRIVER_NAME, null, false) == null) {
props.put(JDO_OPTION_CONNECTION_DRIVER_NAME, strval);
}
}
String jdbcDriverCN = getProperty(props, JDO_OPTION_CONNECTION_DRIVER_NAME, null, true);
String jdbcUser = getProperty(props, JDO_OPTION_CONNECTION_USER_NAME, null, true);
String jdbcUrl = getProperty(props, JDO_OPTION_CONNECTION_URL, null, true);
String jdbcPass = getProperty(props, JDO_OPTION_CONNECTION_PASSWORD, null, true);
logger.log(BasicLevel.INFO, LocaleHelper.getSpeedoRB().getString("jdbcdrv")
+ LocaleHelper.getSpeedoRB().getString("driver") + jdbcDriverCN
+ LocaleHelper.getSpeedoRB().getString("url") + jdbcUrl
+ LocaleHelper.getSpeedoRB().getString("user") + jdbcUser
+ LocaleHelper.getSpeedoRB().getString("mappernm") + mapperName);
jdbcma.setMapperName(mapperName);
jdbcma.setDriverClassName(jdbcDriverCN);
jdbcma.setURL(jdbcUrl);
jdbcma.setUserName(jdbcUser);
jdbcma.setPassword(jdbcPass);
jdbcma.setPoolConnection(true);
//configure the pool of connection
configurePool(getSubComponent(speedo, CONNECTION_POOL_PATH),
"Connection pool: ",
CONNECTION_POOL_MIN,
CONNECTION_POOL_MAX,
CONNECTION_POOL_TTL,
CONNECTION_POOL_INACTIVETTL,
CONNECTION_POOL_TIMEOUT,
props);
}
strval = (String) props.remove(CONNECTION_CHECK);
if (strval != null) {
boolean v = BooleanHelper.parse(strval, false);
ma.setCheckConnectivityAtStartup(v);
if (!v) {
logger.log(BasicLevel.INFO, LocaleHelper.getSpeedoRB().getString("noconnchk"));
}
}
//initialize the JormFactory with the mappingStructureRule attribute
byte mappingStructureRule = JormFactoryAttributes.CREATE_IF_REQUIRED;
strval = getProperty(props, MAPPING_STRUCTURE, "", true);
if (strval.length()>0) {
mappingStructureRule = getMappingStructure(strval);
if (mappingStructureRule == -1) {
mappingStructureRule = JormFactoryAttributes.CREATE_IF_REQUIRED;
logger.log(BasicLevel.WARN,
LocaleHelper.getSpeedoRB().getString("unexpprop")
+ MAPPING_STRUCTURE
+ LocaleHelper.getSpeedoRB().getString("pfound")
+ strval
+ LocaleHelper.getSpeedoRB().getString("pexpect")
+ MAPPING_STRUCTURE_DN
+ " | " + MAPPING_STRUCTURE_DD
+ " | " + MAPPING_STRUCTURE_CIR
+ " | " + MAPPING_STRUCTURE_FC
+ "]");
}
}
component = getSubComponent(speedo, JORM_FACTORY_PATH);
JormFactoryAttributes jfa = (JormFactoryAttributes)
Fractal.getAttributeController(component);
jfa.setMappingStructureRule(mappingStructureRule);
logger.log(BasicLevel.INFO, LocaleHelper.getSpeedoRB().getString("datast")
+ getMappingStructureString(mappingStructureRule));
jfa.setPersonality(getPersonality());
Properties jormFactoryProperties = new Properties();
for (Iterator it = props.entrySet().iterator(); it.hasNext();) {
Map.Entry me = (Map.Entry) it.next();
String key = (String) me.getKey();
String value = (String) me.getValue();
boolean knownProperty = true;
if (key.indexOf('(') != -1) {
jormFactoryProperties.put(key, value);
} else {
knownProperty = false;
}
if (knownProperty) {
logger.log(BasicLevel.INFO, key + ": " + value);
it.remove();
}
}
jfa.setSpeedoProperties(jormFactoryProperties);
return useConnectionFactory;
}
private boolean configureJMX(Map props) throws Throwable {
String val = (String) props.remove(JMX);
if (!BooleanHelper.parse(val, false)) {
return false;
}
//JMX must me configured
if (Monolog.monologFactory.getLogger(JMX)
.isLoggable(BasicLevel.DEBUG)) {
//active MX4J logging
System.setProperty("mx4j.log.priority", "debug");
}
val = (String) props.remove(JMX_HTTP_PORT);
int port = 0;
if (val != null) {
try {
port = Integer.parseInt(val);
} catch (NumberFormatException e) {
logger.log(BasicLevel.WARN, LocaleHelper.getSpeedoRB().getString("badhttp") + val);
port = -1;
}
}
Component component = getSubComponent(speedo, HTML_JMX_AGENT_PATH);
if (port < 0) {
//unbind the html sub component
Fractal.getBindingController(component).unbindFc("adminAtt");
// remove the html sub component from the agent component.
Fractal.getContentController(
getSubComponent(speedo, JMX_AGENT_PATH))
.removeFcSubComponent(component);
logger.log(BasicLevel.INFO, LocaleHelper.getSpeedoRB().getString("jmxactiv"));
} else {
if (port == 0) {
//TODO: find a free port for the http console
port = 8000;
}
//get the host
String host = (String) props.remove(JMX_HTTP_HOST);
if (host == null || host.length() == 0) {
host = JMX_HTTP_DEFAULT_HOST;
}
//Assign the port and the host to the component
MX4J_HtmlAdaptorCA att = (MX4J_HtmlAdaptorCA)
Fractal.getAttributeController(component);
att.setPort(port);
att.setHost(host);
logger.log(BasicLevel.INFO, LocaleHelper.getSpeedoRB().getString("jmxhttp")
+ port
+ LocaleHelper.getSpeedoRB().getString("forhost")
+ host
+ LocaleHelper.getSpeedoRB().getString("activated"));
}
return true;
}
public static String getMappingStructureString(byte b) {
switch(b) {
case JormFactoryAttributes.DO_NOTHING:
return MAPPING_STRUCTURE_DN;
case JormFactoryAttributes.DELETE_DATA:
return MAPPING_STRUCTURE_DD;
case JormFactoryAttributes.FORCE_CREATE:
return MAPPING_STRUCTURE_FC;
case JormFactoryAttributes.CREATE_IF_REQUIRED:
return MAPPING_STRUCTURE_CIR;
default:
return "UNKNOWN";
}
}
public static byte getMappingStructure(String strval) {
if (MAPPING_STRUCTURE_DN.equals(strval)) {
return JormFactoryAttributes.DO_NOTHING;
} else if (MAPPING_STRUCTURE_DD.equals(strval)) {
return JormFactoryAttributes.DELETE_DATA;
} else if (MAPPING_STRUCTURE_CIR.equals(strval)) {
return JormFactoryAttributes.CREATE_IF_REQUIRED;
} else if (MAPPING_STRUCTURE_FC.equals(strval)) {
return JormFactoryAttributes.FORCE_CREATE;
} else {
return -1;
}
}
}