package com.gentics.cr;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;
import java.util.Vector;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.log4j.Logger;
import com.gentics.api.lib.datasource.Datasource;
import com.gentics.cr.configuration.GenericConfiguration;
import com.gentics.cr.exceptions.CRException;
import com.gentics.cr.exceptions.ConfigurationException;
import com.gentics.cr.plink.PathResolver;
import com.gentics.cr.sql.ConnectionProvider;
import com.gentics.cr.template.ITemplateManager;
import com.gentics.cr.template.VelocityTemplateManagerFactory;
import com.gentics.cr.util.CRUtil;
/**
* CRConfigUtil extends CRConfig with all sorts of getters and setters for common config entries.
* Last changed: $Date: 2010-04-01 15:24:02 +0200 (Do, 01 Apr 2010) $
* @version $Revision: 541 $
* @author $Author: supnig@constantinopel.at $
*/
public class CRConfigUtil extends CRConfig {
/**
* generated unique id for serialization.
*/
private static final long serialVersionUID = -1599393624385876283L;
/**
* Key under which the RequestProcessorConfigs are stored.
*/
public static final String REQUEST_PROCESSOR_KEY = "RP";
/**
* Lazy init mode key. If lazy init is set to true in configuration,
* then we will not instantly fetch a datasource, but we will do that
* on the first request.
*/
private static final String DB_LAZY_INIT_MODE_KEY = "dblazyinit";
/**
* Path where the {@link com.gentics.cr.rest.velocity.VelocityContentRepository} looks for templates when no other path is specified.
*/
public static final String DEFAULT_TEMPLATE_PATH = CRUtil
.resolveSystemProperties("${com.gentics.portalnode.confpath}/templates/");
private static Logger log = Logger.getLogger(CRConfigUtil.class);
private static final String DATASOURCE_HANDLE_KEY = "DS-HANDLE";
private static final String FOLDER_TYPE_KEY = "FOLDERTYPE";
private static final String PAGE_TYPE_KEY = "PAGETYPE";
private static final String BINARY_TYPE_KEY = "BINARYTYPE";
private static final String APPRULE_KEY = "APPLICATIONRULE";
private static final String PLINK_TEMPLATE_KEY = "PLINKTEMPLATE";
private static final String CONTENTID_REGEX_KEY = "CONTENTID_REGEX";
private static final String FILTERCHAIN_KEY = "FILTERCHAIN";
private static final String SHARED_CACHE_KEY = "USESHAREDCACHES";
private static final String CONTENTID_URL_KEY = "USECONTENTIDURL";
private static final String DATASOURCE_PROPS_KEY = "DS";
private static final String PORTALNODE_COMPATIBILITY_MODE_KEY = "PORTALNODECOMPATIBILITY";
private static final String XSLT_URL_KEY = "XSLTURL";
private static final String USER_PERMISSION_ATTR_KEY = "USERPERMISSIONATTRIBUTE";
private static final String OBJECT_PERMISSION_ATTR_KEY = "OBJECTPERMISSIONATTRIBUTE";
private static final String RP_CLASS_KEY = "RPCLASS";
private static final String ENCODING_KEY = "RESPONSE-CHARSET";
private static final String XML_URL_KEY = "XMLURL";
private String name = null;
/**
* Variable holding opened {@link Datasource} by this configuration. So we can
* release it when we got destroyed.
*/
//private Datasource ds = null;
/**
* Create new instance of CRConfigUtil.
*/
public CRConfigUtil() {
}
/**
* Create new instance of {@link CRConfigUtil} from
* {@link GenericConfiguration}.
* @param conf
* @param name
*/
public CRConfigUtil(final GenericConfiguration conf, final String name) {
this.name = name;
setProperties(conf.getProperties());
setSubConfigs(conf.getSubConfigs());
}
/**
* Destructor to release {@link Datasource}s generated by {@link #initDS()}.
*/
protected final void finalize() {
}
/**
* Init Datasource with Handle Properties and Datasource Properties.
*/
public final void initDS() {
log.debug("Creating Datasource for " + this.getName());
// DO DATASOURCE INIT ONLY OF NOT IN LAZY INIT MODE
boolean lazyload = false;
String lzString = (String) this.get(DB_LAZY_INIT_MODE_KEY);
if (lzString != null) {
lazyload = Boolean.parseBoolean(lzString);
}
if (!lazyload) {
// Init datasources so that the connections can be initialized
// The initialized handles will be cached and then returned when
// the datasource is fetched again
Datasource ds = getDatasource();
if (ds != null) {
CRDatabaseFactory.releaseDatasource(ds);
}
}
for (int i = 1; i <= getRequestProcessorSize(); i++) {
CRConfigUtil requestProcessorConfig = getRequestProcessorConfig(i);
requestProcessorConfig.initDS();
}
}
/**
* Set Name of Config.
*
* @param name
*/
public void setName(final String name) {
log.debug("Set name: " + name);
this.name = name;
}
/**
* Gets the configs name.
* @return name as string
*/
public String getName() {
return this.name;
}
/**
* Gets the applications binary type.
* @return by default this is 10008 but can be overriden using the {@link com.gentics.cr.CRConfigUtil#BINARY_TYPE_KEY}
*/
public String getBinaryType() {
String bt = (String) this.get(BINARY_TYPE_KEY);
if (bt == null) {
bt = "10008";
}
return (bt);
}
/**
* Sets the applications binary type.
* @param type
*/
public void setBinaryType(final String type) {
this.set(BINARY_TYPE_KEY, type);
}
/**
* Gets the applications folder type.
* @return type
*/
public String getFolderType() {
String ft = (String) this.get(FOLDER_TYPE_KEY);
if (ft == null) {
ft = "10002";
}
return (ft);
}
/**
* Sets the applications folder type.
* @param type
*/
public void setFolderType(final String type) {
this.set(FOLDER_TYPE_KEY, type);
}
/**
* Gets the applications page type.
* @return type
*/
public String getPageType() {
String pt = (String) this.get(PAGE_TYPE_KEY);
if (pt == null) {
pt = "10007";
}
return (pt);
}
/**
* Sets the applications page type.
* @param type
*/
public void setPageType(final String type) {
this.set(PAGE_TYPE_KEY, type);
}
/**
* Gets the application rule.
* @return rule
*/
public String getApplicationRule() {
return ((String) this.get(APPRULE_KEY));
}
/**
* Sets the application rule.
* @param rule
*/
public void setApplicationRule(final String rule) {
this.set(APPRULE_KEY, rule);
}
/**
* Alias for getProperties Method.
* @return flat properties as Properties Class
*/
public Properties getProps() {
return (this.getProperties());
}
/**
* Sets the applications PLink Template.
* @param template
*/
public void setPlinkTemplate(final String template) {
this.set(PLINK_TEMPLATE_KEY, template);
}
/**
* Gets the applications PLink Template.
* @return PLink template as string. Defaults to "$url"
*/
public String getPlinkTemplate() {
String tmp = null;
tmp = (String) this.get(PLINK_TEMPLATE_KEY);
if (tmp != null && !"".equals(tmp)) {
return tmp;
}
log.warn("No plinktemplate set. Using default template '$url'.");
return "$url";
}
/**
* Gets the Datasource of this config
* - only RequestProcessor configs have Datasources set
* When a Datasource is requested it has to be released after usage using
* CRDatabaseFactory.releaseDatasource(ds); where ds is the Datasource instance.
* @return Datasource or null if config has no Datasource
*/
public Datasource getDatasource() {
return CRDatabaseFactory.getDatasource(this);
}
/**
* Get a pooled JDBCConnection and create a new pool if none exists.
* Such a direct connection can be used for custom request processors that require a pooled connection
*
* ATTENTION: The pool has to be released when the application shuts down using the releaseJDBCPool method
*
* @return pooled jdbc connection.
* @throws Exception
*/
public synchronized Connection getPooledJDBCConnection() throws Exception {
return ConnectionProvider.getPooledJDBCConnection(this);
}
/**
* Releases the JDBC Connection pool that was used by any connection from
* getPooledJDBCConnection.
* @throws Exception
*/
public synchronized void releaseJDBCPool() throws Exception {
ConnectionProvider.releaseJDBCPool(this);
}
/**
* Gets the PathResolver of this config
* - only RequestProcessor configs have PathResolvers set.
* @return PathResolver or null if config has no PathResolver
*/
public PathResolver getPathResolver() {
PathResolver pathResolver = new PathResolver(this, this.getApplicationRule());
if (pathResolver != null) {
log.debug("Loaded Pathresolver for " + this.getName());
} else {
log.error("Could not initialize Pathresolver for " + this.getName());
}
return pathResolver;
}
/**
* Default to String method.
* @return Class name and Config name
*/
public String toString() {
return this.getClass().getName() + ":" + this.getName();
}
/**
* Sets the response encoding of the application.
* @param response_encoding
*/
public void setEncoding(final String response_encoding) {
this.set(ENCODING_KEY, response_encoding);
}
/**
* Gets the applications configured Encoding.
* @return Encoding as String, defaults to "utf-8"
*/
public String getEncoding() {
String enc = (String) this.get(ENCODING_KEY);
if (enc != null && !"".equals(enc)) {
return (enc);
}
return ("utf-8");
}
/**
* Sets the RequestProcessor class used by this RP instance
* - only RP configs have RP classes.
* @param requestProcessorClass
*/
public void setRequestProcessorClass(final String requestProcessorClass) {
this.set(RP_CLASS_KEY, requestProcessorClass);
}
/**
* Gets the RequestProcessor class used by this RP instance
* - only RP configs have RP classes.
* @return class name as string or null if not set
*/
public String getRequestProcessorClass() {
return (String) this.get(RP_CLASS_KEY);
}
/**
* Sets the applications objectperissionattribute.
* @param objectpermissionattribute
*/
public void setObjectPermissionAttribute(final String objectpermissionattribute) {
this.set(OBJECT_PERMISSION_ATTR_KEY, objectpermissionattribute);
}
/**
* Gets the applications objectperissionattribute.
* @return objectpermissionattribute
*/
public String getObjectPermissionAttribute() {
return (String) this.get(OBJECT_PERMISSION_ATTR_KEY);
}
/**
* Sets the applications userperissionattribute.
* @param userpermissionattribute
*/
public void setUserPermissionAttribute(final String userpermissionattribute) {
this.set(USER_PERMISSION_ATTR_KEY, userpermissionattribute);
}
/**
* Gets the applications userpermissionattribute.
* @return userpermissionattribute
*/
public String getUserPermissionAttribute() {
return (String) this.get(USER_PERMISSION_ATTR_KEY);
}
/**
* Sets the applications XML url.
* @param xmlUrl
*/
public void setXmlUrl(final String xmlUrl) {
this.set(XML_URL_KEY, xmlUrl);
}
/**
* Gets the applications XML url.
* @return url
*/
public String getXmlUrl() {
return (String) this.get(XML_URL_KEY);
}
/**
* Sets the applications Xslt url.
* @param xsltUrl
*/
public void setXsltUrl(final String xsltUrl) {
this.set(XSLT_URL_KEY, xsltUrl);
}
/**
* Gets the applications Xslt url.
* @return url
*/
public String getXsltUrl() {
return (String) this.get(XSLT_URL_KEY);
}
/**
* Sets the applications Contentid Regex.
* @param contentid_regex
*/
public void setContentidRegex(final String contentid_regex) {
this.set(CONTENTID_REGEX_KEY, contentid_regex);
}
/**
* Gets the applications Contentid Regex.
* @return regex
*/
public String getContentidRegex() {
return (String) this.get(CONTENTID_REGEX_KEY);
}
/**
* Gets the applications filterchain.
* @return filterchain or null if no filterchain is set
*/
public ArrayList<String> getFilterChain() {
return getPropertiesAsSortedCollection(FILTERCHAIN_KEY);
}
/**
* Get the names of all {@link RequestProcessor}s in this config.
* @return Collection with the names of the {@link RequestProcessor}s
*/
public final Collection<String> getRequestProcessorNames() {
if (getSubConfigSize() > 0) {
GenericConfiguration requestProcessorsConfigs = (GenericConfiguration) get(REQUEST_PROCESSOR_KEY);
if (requestProcessorsConfigs != null) {
ConcurrentHashMap<String, GenericConfiguration> requestProcessorTable = requestProcessorsConfigs
.getSubConfigs();
if (requestProcessorTable != null && !requestProcessorTable.isEmpty()) {
return requestProcessorTable.keySet();
}
}
}
return new Vector<String>(0);
}
/**
* Gets count of requestprocessors configured in this config.
* @return count
*/
public int getRequestProcessorSize() {
Object obj = get(REQUEST_PROCESSOR_KEY);
if (obj != null && obj instanceof GenericConfiguration) {
return ((GenericConfiguration) obj).getSubConfigSize();
}
return 0;
}
/**
* get Configuration of the specified RequestProcessor.
* @param requestProcessorId Number of the RequestProcessor
* @return Configuration of the specified RequestProcessor. null in case something bad happens
*/
public CRConfigUtil getRequestProcessorConfig(final int requestProcessorId) {
return (getRequestProcessorConfig("" + requestProcessorId));
}
/**
* get Configuration of the specified RequestProcessor.
* @param requestProcessorId Number of the RequestProcessor
* @return Configuration of the specified RequestProcessor. null in case something bad happens
*/
public CRConfigUtil getRequestProcessorConfig(final String requestProcessorId) {
Object obj = get(REQUEST_PROCESSOR_KEY + "." + requestProcessorId);
if (obj != null && obj instanceof GenericConfiguration) {
return new CRConfigUtil((GenericConfiguration) obj, this.getName() + "." + REQUEST_PROCESSOR_KEY + "."
+ requestProcessorId);
} else {
log.fatal("RequestProcessor" + requestProcessorId
+ " cannot be found. Maybe your config cannot be initialized correctly.");
return null;
}
}
/**
* Returns a new instance of the {@link RequestProcessor} configured in the
* configuration with the given requestProcessorId.
* @param requestProcessorId Id of the RequestProcessor
* @return RequestProcessor RequestProcessor from configuration
* @throws CRException when the RequestProcessor cannot be created
*/
public final RequestProcessor getNewRequestProcessorInstance(final int requestProcessorId) throws CRException {
return getNewRequestProcessorInstance("" + requestProcessorId);
}
/**
* Returns a new instance of the {@link com.gentics.cr.RequestProcessor} configured in the
* configuration with the given requestProcessorId.
* @param requestProcessorName Name of the RequestProcessor
* @return RequestProcessor RequestProcessor from configuration
* @throws CRException when the RequestProcessor cannot be created
*/
public final RequestProcessor getNewRequestProcessorInstance(final String requestProcessorName) throws CRException {
CRConfigUtil requestProcessorConfig = this.getRequestProcessorConfig(requestProcessorName);
if (requestProcessorConfig == null) {
log.error("Cannot initialize RequestProcessor " + requestProcessorName);
throw new ConfigurationException("config", "We cannot get the " + "configuration for the RequestProcessor",
CRException.ERRORTYPE.FATAL_ERROR);
}
String requestProcessorClass = requestProcessorConfig.getRequestProcessorClass();
log.debug("Instanciate RequestProcessor" + requestProcessorName + " from class " + requestProcessorClass);
try {
RequestProcessor rp = (RequestProcessor) Class.forName(requestProcessorClass)
.getConstructor(new Class[] { CRConfig.class }).newInstance(requestProcessorConfig);
return rp;
} catch (Exception e) {
throw new CRException(e);
}
}
/**
* gets if application is running in portalnode compatibility mode.
* @return true if app is running in portalnode compatibility mode
*/
public boolean getPortalNodeCompMode() {
String pnComp = (String) get(PORTALNODE_COMPATIBILITY_MODE_KEY);
return Boolean.parseBoolean(pnComp);
}
/**
* Sets the applications portalnode compatibility mode.
* @param mode
*/
public void setPortalNodeCompMode(final String mode) {
this.set(PORTALNODE_COMPATIBILITY_MODE_KEY, mode);
}
/**
* Gets the configured template manager.
* @return template manager or null if it is not set
*/
public ITemplateManager getTemplateManager() {
if (!this.getPortalNodeCompMode()) {
ITemplateManager tmplManager = null;
try {
tmplManager = VelocityTemplateManagerFactory.getConfiguredVelocityTemplateManagerInstance(
this.getEncoding(),
DEFAULT_TEMPLATE_PATH);
} catch (Exception e) {
CRException ex = new CRException(e);
log.error(ex.getMessage(), ex);
}
return tmplManager;
}
return null;
}
/**
* @return true if application is to use shared caches.
*/
public boolean useSharedCache() {
String pnSC = (String) get(PORTALNODE_COMPATIBILITY_MODE_KEY);
return Boolean.parseBoolean(pnSC);
}
/**
* Sets if the application should use shared caches.
* @param sharedCache
* @return value of sharedcache after it has been set
*/
public boolean useSharedCache(final boolean sharedCache) {
this.set(SHARED_CACHE_KEY, Boolean.toString(sharedCache));
return useSharedCache();
}
/**
* defines if to use contentidurl.
* @return true if using conteitdurl
*/
public boolean usesContentidUrl() {
String pnCU = (String) get(CONTENTID_URL_KEY);
return Boolean.parseBoolean(pnCU);
}
/**
* Get the Datasource Properties for the current config.
* @return Datasource Properties or null if not set
*/
public Properties getDatasourceProperties() {
Object obj = get(DATASOURCE_PROPS_KEY);
if (obj != null && obj instanceof GenericConfiguration) {
Properties dsprops = ((GenericConfiguration) obj).getRebuiltPropertyTree();
Properties ret = new Properties();
//DATASOURCE PROPERTY KEYS NEED TO BE LOWERCASE IN ORDER TO BE UNDERSTOOD BY THE DRIVER
//DATASOURCE PROPERTIES NEED TO BE RESOLVED AND REBUILT
for (Entry<Object, Object> e : dsprops.entrySet()) {
String key = (String) e.getKey();
ret.put(key.toLowerCase(), e.getValue());
}
return ret;
}
return (null);
}
/**
* Get the Datasource Handle Properties for the current config.
* @return Datasource Handle Properties or null if not set
*/
public Properties getDatasourceHandleProperties() {
Object obj = get(DATASOURCE_HANDLE_KEY);
if (obj != null && obj instanceof GenericConfiguration) {
Properties dsprops = ((GenericConfiguration) obj).getRebuiltPropertyTree();
Properties ret = new Properties();
//DATASOURCE PROPERTY KEYS NEED TO BE LOWERCASE IN ORDER TO BE UNDERSTOOD BY THE DRIVER
for (Entry<Object, Object> e : dsprops.entrySet()) {
String key = ((String) e.getKey()).toLowerCase();
//Driver class has to be spelled "driverClass"
if ("driverclass".equals(key)) {
key = "driverClass";
} else if ("pooling.testonborrow".equals(key)) {
key = "pooling.testOnBorrow";
} else if ("pooling.validationquery".equals(key)) {
key = "pooling.validationQuery";
}
ret.put(key, e.getValue());
}
return ret;
}
return (null);
}
}