/**
* Copyright (c) 2014, the Railo Company Ltd.
* Copyright (c) 2015, Lucee Assosication Switzerland
*
* 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.1 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, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.runtime.config;
import static org.apache.commons.collections4.map.AbstractReferenceMap.ReferenceStrength.SOFT;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspWriter;
import lucee.commons.digest.HashUtil;
import lucee.commons.io.FileUtil;
import lucee.commons.io.SystemUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.ResourceProvider;
import lucee.commons.io.res.ResourcesImpl;
import lucee.commons.lang.ClassUtil;
import lucee.commons.lang.StringUtil;
import lucee.commons.lock.KeyLock;
import lucee.commons.lock.KeyLockImpl;
import lucee.loader.engine.CFMLEngine;
import lucee.runtime.CFMLFactory;
import lucee.runtime.CFMLFactoryImpl;
import lucee.runtime.CIPage;
import lucee.runtime.Mapping;
import lucee.runtime.MappingImpl;
import lucee.runtime.PageContext;
import lucee.runtime.cache.tag.CacheHandlerCollection;
import lucee.runtime.cache.tag.CacheHandlerCollections;
import lucee.runtime.cfx.CFXTagPool;
import lucee.runtime.compiler.CFMLCompilerImpl;
import lucee.runtime.debug.DebuggerPool;
import lucee.runtime.engine.ThreadQueue;
import lucee.runtime.exp.ApplicationException;
import lucee.runtime.exp.ExpressionException;
import lucee.runtime.exp.PageException;
import lucee.runtime.exp.SecurityException;
import lucee.runtime.extension.ExtensionDefintion;
import lucee.runtime.extension.RHExtension;
import lucee.runtime.gateway.GatewayEngineImpl;
import lucee.runtime.gateway.GatewayEntry;
import lucee.runtime.lock.LockManager;
import lucee.runtime.lock.LockManagerImpl;
import lucee.runtime.monitor.ActionMonitor;
import lucee.runtime.monitor.ActionMonitorCollector;
import lucee.runtime.monitor.IntervallMonitor;
import lucee.runtime.monitor.RequestMonitor;
import lucee.runtime.net.amf.AMFEngine;
import lucee.runtime.net.amf.AMFEngineDummy;
import lucee.runtime.net.http.ReqRspUtil;
import lucee.runtime.op.Caster;
import lucee.runtime.osgi.OSGiUtil.BundleDefinition;
import lucee.runtime.search.SearchEngine;
import lucee.runtime.security.SecurityManager;
import lucee.runtime.security.SecurityManagerImpl;
import lucee.runtime.tag.TagHandlerPool;
import lucee.runtime.type.scope.Cluster;
import lucee.runtime.writer.CFMLWriter;
import lucee.runtime.writer.CFMLWriterImpl;
import lucee.runtime.writer.CFMLWriterWS;
import lucee.runtime.writer.CFMLWriterWSPref;
import org.apache.commons.collections4.map.ReferenceMap;
import org.osgi.framework.BundleException;
import org.xml.sax.SAXException;
/**
* Web Context
*/
public final class ConfigWebImpl extends ConfigImpl implements ServletConfig, ConfigWeb {
private final ServletConfig config;
private final ConfigServerImpl configServer;
private SecurityManager securityManager;
private static final LockManager lockManager= LockManagerImpl.getInstance(false);
private Resource rootDir;
private final CFMLCompilerImpl compiler=new CFMLCompilerImpl();
private CIPage baseComponentPageCFML;
private CIPage baseComponentPageLucee;
private MappingImpl serverTagMapping;
private MappingImpl serverFunctionMapping;
private KeyLock<String> contextLock=new KeyLockImpl<String>();
private GatewayEngineImpl gatewayEngine;
private DebuggerPool debuggerPool;
private final CFMLFactoryImpl factory;
private CacheHandlerCollections cacheHandlerCollections;
protected IdentificationWeb id;
//private File deployDirectory;
/**
* constructor of the class
* @param configServer
* @param config
* @param configDir
* @param configFile
* @param cloneServer
*/
ConfigWebImpl(CFMLFactoryImpl factory,ConfigServerImpl configServer, ServletConfig config, Resource configDir, Resource configFile) {
super(configDir, configFile);
this.configServer=configServer;
this.config=config;
this.factory=factory;
factory.setConfig(this);
ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
this.rootDir=frp.getResource(ReqRspUtil.getRootPath(config.getServletContext()));
// Fix for tomcat
if(this.rootDir.getName().equals(".") || this.rootDir.getName().equals(".."))
this.rootDir=this.rootDir.getParentResource();
}
@Override
public void reset() {
super.reset();
factory.resetPageContext();
tagHandlerPool.reset();
contextLock=new KeyLockImpl<String>();
baseComponentPageCFML=null;
baseComponentPageLucee=null;
}
@Override
public String getServletName() {
return config.getServletName();
}
@Override
public ServletContext getServletContext() {
return config.getServletContext();
}
@Override
public String getInitParameter(String name) {
return config.getInitParameter(name);
}
@Override
public Enumeration getInitParameterNames() {
return config.getInitParameterNames();
}
protected ConfigServerImpl getConfigServerImpl() {
return configServer;
}
@Override
public ConfigServer getConfigServer(String password) throws ExpressionException {
Password pw = isServerPasswordEqual(password);
if(pw==null) pw=PasswordImpl.passwordToCompare(this, true, password);
return getConfigServer(pw);
}
@Override
public ConfigServer getConfigServer(Password password) throws ExpressionException {
configServer.checkAccess(password);
return configServer;
}
@Override
public ConfigServer getConfigServer(String key, long timeNonce) throws PageException {
configServer.checkAccess(key,timeNonce);
return configServer;
}
public Resource getServerConfigDir() {
return configServer.getConfigDir();
}
/**
* @return Returns the accessor.
*/
@Override
public SecurityManager getSecurityManager() {
return securityManager;
}
/**
* @param securityManager The accessor to set.
*/
protected void setSecurityManager(SecurityManager securityManager) {
((SecurityManagerImpl)securityManager).setRootDirectory(getRootDirectory());
this.securityManager = securityManager;
}
@Override
public CFXTagPool getCFXTagPool() throws SecurityException {
if(securityManager.getAccess(SecurityManager.TYPE_CFX_USAGE)==SecurityManager.VALUE_YES) return super.getCFXTagPool();
throw new SecurityException("no access to cfx functionality", "disabled by security settings");
}
/**
* @return Returns the rootDir.
*/
@Override
public Resource getRootDirectory() {
return rootDir;
}
@Override
public String getUpdateType() {
return configServer.getUpdateType();
}
@Override
public URL getUpdateLocation() {
return configServer.getUpdateLocation();
}
@Override
public LockManager getLockManager() {
return lockManager;
}
/**
* @return the compiler
*/
public CFMLCompilerImpl getCompiler() {
return compiler;
}
public CIPage getBaseComponentPage(int dialect,PageContext pc) throws PageException {
// CFML
if(dialect==CFMLEngine.DIALECT_CFML) {
if(baseComponentPageCFML==null) {
baseComponentPageCFML=(CIPage) getBaseComponentPageSource(dialect,pc).loadPage(pc,false);
}
return baseComponentPageCFML;
}
// Lucee
if(baseComponentPageLucee==null) {
baseComponentPageLucee=(CIPage) getBaseComponentPageSource(dialect,pc).loadPage(pc,false);
}
return baseComponentPageLucee;
}
public void resetBaseComponentPage() {
baseComponentPageCFML=null;
baseComponentPageLucee=null;
}
public Mapping getServerTagMapping() {
if(serverTagMapping==null){
serverTagMapping=getConfigServerImpl().tagMapping.cloneReadOnly(this);
}
return serverTagMapping;
}
public Mapping getServerFunctionMapping() {
if(serverFunctionMapping==null){
serverFunctionMapping=getConfigServerImpl().functionMapping.cloneReadOnly(this);
}
return serverFunctionMapping;
}
private Map<String,Mapping> applicationMappings=new ReferenceMap<String,Mapping>(SOFT,SOFT);
private TagHandlerPool tagHandlerPool=new TagHandlerPool(this);
private SearchEngine searchEngine;
private AMFEngine amfEngine;
// FYI used by Extensions, do not remove
public Mapping getApplicationMapping(String virtual, String physical) {
return getApplicationMapping("application",virtual, physical,null,true,false);
}
public Mapping getApplicationMapping(String type,String virtual, String physical,String archive,boolean physicalFirst, boolean ignoreVirtual) {
String key=type+":"+
virtual.toLowerCase()
+":"+(physical==null?"":physical.toLowerCase())
+":"+(archive==null?"":archive.toLowerCase())
+":"+physicalFirst;
key=Long.toString(HashUtil.create64BitHash(key),Character.MAX_RADIX);
Mapping m=applicationMappings.get(key);
if(m==null){
m=new MappingImpl(
this,virtual,
physical,
archive,Config.INSPECT_UNDEFINED,physicalFirst,false,false,false,true,ignoreVirtual,null,-1,-1
);
applicationMappings.put(key,m);
}
return m;
}
public Mapping[] getApplicationMapping() {
return applicationMappings.values().toArray(new Mapping[applicationMappings.size()]);
}
@Override
public String getLabel() {
String hash=getHash();
String label=hash;
Map<String, String> labels = configServer.getLabels();
if(labels!=null) {
String l = labels.get(hash);
if(!StringUtil.isEmpty(l)) {
label=l;
}
}
return label;
}
public String getHash() {
return SystemUtil.hash(getServletContext());
}
public KeyLock<String> getContextLock() {
return contextLock;
}
protected void setGatewayEntries(Map<String, GatewayEntry> gatewayEntries) {
try {
getGatewayEngine().addEntries(this,gatewayEntries);
} catch (Exception e) {
e.printStackTrace();
}
}
public GatewayEngineImpl getGatewayEngine() {
if(gatewayEngine==null){
gatewayEngine=new GatewayEngineImpl(this);
}
return gatewayEngine;
}
public void setGatewayEngine(GatewayEngineImpl gatewayEngine) {
this.gatewayEngine=gatewayEngine;
}
public TagHandlerPool getTagHandlerPool() {
return tagHandlerPool;
}
public DebuggerPool getDebuggerPool() {
if(debuggerPool==null){
Resource dir = getConfigDir().getRealResource("debugger");
dir.mkdirs();
debuggerPool=new DebuggerPool(dir);
}
return debuggerPool;
}
@Override
public ThreadQueue getThreadQueue() {
return configServer.getThreadQueue();
}
@Override
public int getLoginDelay() {
return configServer.getLoginDelay();
}
@Override
public boolean getLoginCaptcha() {
return configServer.getLoginCaptcha();
}
@Override
public boolean getRememberMe() {
return configServer.getRememberMe();
}
@Override
public Resource getSecurityDirectory(){
return configServer.getSecurityDirectory();
}
@Override
public boolean isMonitoringEnabled(){
return configServer.isMonitoringEnabled();
}
@Override
public RequestMonitor[] getRequestMonitors(){
return configServer.getRequestMonitors();
}
@Override
public RequestMonitor getRequestMonitor(String name) throws PageException{
return configServer.getRequestMonitor(name);
}
@Override
public IntervallMonitor[] getIntervallMonitors(){
return configServer.getIntervallMonitors();
}
@Override
public IntervallMonitor getIntervallMonitor(String name) throws PageException{
return configServer.getIntervallMonitor(name);
}
@Override
public void checkPermGenSpace(boolean check) {
configServer.checkPermGenSpace(check);
}
@Override
public Cluster createClusterScope() throws PageException {
return configServer.createClusterScope();
}
@Override
public boolean hasServerPassword() {
return configServer.hasPassword();
}
public void updatePassword(boolean server, String passwordOld, String passwordNew) throws PageException, IOException, SAXException, BundleException {
PasswordImpl.updatePassword(server?configServer:this,passwordOld,passwordNew);
}
public void updatePassword(boolean server, Password passwordOld, Password passwordNew) throws PageException, IOException, SAXException, BundleException {
PasswordImpl.updatePassword(server?configServer:this,passwordOld,passwordNew);
}
public Password updatePasswordIfNecessary(boolean server,String passwordRaw) {
ConfigImpl config=server?configServer:this;
return PasswordImpl.updatePasswordIfNecessary(config,config.password,passwordRaw);
}
@Override
public Resource getConfigServerDir() {
return configServer.getConfigDir();
}
public Map<String, String> getAllLabels() {
return configServer.getLabels();
}
@Override
public boolean allowRequestTimeout() {
return configServer.allowRequestTimeout();
}
public CFMLWriter getCFMLWriter(PageContext pc, HttpServletRequest req, HttpServletResponse rsp) {
if(writerType==CFML_WRITER_WS)
return new CFMLWriterWS (pc,req,rsp,-1,false,closeConnection(),isShowVersion(),contentLength());
else if(writerType==CFML_WRITER_REFULAR)
return new CFMLWriterImpl (pc,req,rsp,-1,false,closeConnection(),isShowVersion(),contentLength());
else
return new CFMLWriterWSPref (pc,req,rsp,-1,false,closeConnection(),isShowVersion(),contentLength());
}
@Override
public JspWriter getWriter(PageContext pc, HttpServletRequest req, HttpServletResponse rsp) {
return getCFMLWriter(pc, req, rsp);
}
public ActionMonitorCollector getActionMonitorCollector() {
return configServer.getActionMonitorCollector();
}
@Override
public boolean getFullNullSupport() {
return configServer.getFullNullSupport();
}
public boolean hasIndividualSecurityManager() {
return configServer.hasIndividualSecurityManager(getIdentification().getId());
}
@Override
public CFMLFactory getFactory() {
return factory;
}
@Override
public CacheHandlerCollection getCacheHandlerCollection(int type,CacheHandlerCollection defaultValue){
if(cacheHandlerCollections==null)
cacheHandlerCollections=new CacheHandlerCollections(this);
switch(type){
case Config.CACHE_TYPE_FILE: return cacheHandlerCollections.file;
case Config.CACHE_TYPE_FUNCTION: return cacheHandlerCollections.function;
case Config.CACHE_TYPE_HTTP: return cacheHandlerCollections.http;
case Config.CACHE_TYPE_INCLUDE: return cacheHandlerCollections.include;
case Config.CACHE_TYPE_QUERY: return cacheHandlerCollections.query;
case Config.CACHE_TYPE_RESOURCE: return cacheHandlerCollections.resource;
case Config.CACHE_TYPE_WEBSERVICE: return cacheHandlerCollections.webservice;
//case Config.CACHE_TYPE_OBJECT: return cacheHandlerCollections.object;
//case Config.CACHE_TYPE_TEMPLATE: return cacheHandlerCollections.template;
}
return defaultValue;
}
public void releaseCacheHandlers(PageContext pc) {
if(cacheHandlerCollections==null) return;
cacheHandlerCollections.releaseCacheHandlers(pc);
}
protected void setIdentification(IdentificationWeb id) {
this.id=id;
}
@Override
public IdentificationWeb getIdentification() {
return id;
}
public int getServerPasswordType() {
return configServer.getPasswordType();
}
public String getServerPasswordSalt() {
return configServer.getPasswordSalt();
}
public int getServerPasswordOrigin() {
return configServer.getPasswordOrigin();
}
public String getServerSalt() {
return configServer.getSalt();
}
public Password isServerPasswordEqual(String password) {
return configServer.isPasswordEqual(password);
}
public boolean isDefaultPassword() {
if(password==null) return false;
return password==configServer.defaultPassword;
}
@Override
public Collection<BundleDefinition> getAllExtensionBundleDefintions() {
return configServer.getAllExtensionBundleDefintions();
}
@Override
public Collection<RHExtension> getAllRHExtensions() {
return configServer.getAllRHExtensions();
}
@Override
public SearchEngine getSearchEngine(PageContext pc) throws PageException{
if(searchEngine==null) {
try {
Object o = ClassUtil.loadInstance(getSearchEngineClassDefinition().getClazz());
if (o instanceof SearchEngine)
searchEngine=(SearchEngine) o;
else
throw new ApplicationException("class ["+o.getClass().getName()+"] does not implement the interface SearchEngine");
searchEngine.init(this, ConfigWebUtil.getFile(getConfigDir(), ConfigWebUtil.translateOldPath(getSearchEngineDirectory()), "search", getConfigDir(), FileUtil.TYPE_DIR, this));
}
catch (Exception e) {
throw Caster.toPageException(e);
}
}
return searchEngine;
}
@Override
public ActionMonitor getActionMonitor(String name) {
return configServer.getActionMonitor(name);
}
@Override
public Resource getLocalExtensionProviderDirectory() {
return configServer.getLocalExtensionProviderDirectory();
}
protected void setAMFEngine(AMFEngine engine) {
amfEngine=engine;
}
@Override
public AMFEngine getAMFEngine() {
if(amfEngine==null) return AMFEngineDummy.getInstance();
return amfEngine;
}
public boolean installServerExtension(ExtensionDefintion ed) {
return configServer.installExtension(ed);
}
@Override
public RHExtension[] getServerRHExtensions() {
return configServer.getRHExtensions();
}
@Override
public List<ExtensionDefintion> loadLocalExtensions() {
return configServer.loadLocalExtensions();
}
}