/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.quercus.servlet; import com.caucho.config.ConfigException; import com.caucho.quercus.QuercusContext; import com.caucho.quercus.QuercusRuntimeException; import com.caucho.quercus.module.QuercusModule; import com.caucho.util.L10N; import com.caucho.vfs.Path; import javax.naming.Context; import javax.naming.InitialContext; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.util.logging.Level; import java.util.logging.Logger; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; /** * Servlet to call PHP through javax.script. */ public class QuercusServlet extends HttpServlet { private static final L10N L = new L10N(QuercusServlet.class); private static final Logger log = Logger.getLogger(QuercusServlet.class.getName()); private QuercusContext _quercus; private QuercusServletImpl _impl; private boolean _isCompile; private boolean _isLazyCompile = true; private boolean _isCompileFailover = true; private double _profileProbability; private boolean _isRequireSource = true; private DataSource _database; private boolean _isStrict; private boolean _isLooseParse = true; private int _pageCacheSize = -1; private int _regexpCacheSize = -1; private boolean _isConnectionPool = true; private String _iniPath; private String _scriptEncoding; private String _mysqlVersion; private String _phpVersion; protected File _licenseDirectory; private ArrayList<QuercusModule> _moduleList = new ArrayList<QuercusModule>(); private ArrayList<PhpClassConfig> _classList = new ArrayList<PhpClassConfig>(); private ArrayList<PhpClassConfig> _classImplList = new ArrayList<PhpClassConfig>(); private ArrayList<PhpIni> _phpIniList = new ArrayList<PhpIni>(); private ArrayList<ServerEnv> _serverEnvList = new ArrayList<ServerEnv>(); public QuercusServlet() { checkJavaVersion(); } protected QuercusServletImpl getQuercusServlet(boolean isResin) { QuercusServletImpl impl = null; if (isResin) { try { Class<?> cl = Class.forName( "com.caucho.quercus.servlet.ProResinQuercusServlet"); Constructor<?> cons = cl.getConstructor(File.class); impl = (QuercusServletImpl) cons.newInstance(_licenseDirectory); //impl = (QuercusServletImpl) cl.newInstance(); } catch (ConfigException e) { log.log(Level.FINEST, e.toString(), e); log.info("Quercus compiled mode requires Resin " + "personal or professional licenses"); log.info(e.getMessage()); } catch (Exception e) { log.log(Level.FINEST, e.toString(), e); } if (impl == null) { try { Class<?> cl = Class.forName( "com.caucho.quercus.servlet.ResinQuercusServlet"); impl = (QuercusServletImpl) cl.newInstance(); } catch (Exception e) { log.log(Level.FINEST, e.toString(), e); } } } if (impl == null) { try { Class<?> cl = Class.forName( "com.caucho.quercus.servlet.ProQuercusServlet"); Constructor<?> cons = cl.getConstructor(java.io.File.class); impl = (QuercusServletImpl) cons.newInstance(_licenseDirectory); //impl = (QuercusServletImpl) cl.newInstance(); } catch (ConfigException e) { log.log(Level.FINEST, e.toString(), e); log.info("Quercus compiled mode requires " + "valid Quercus professional licenses"); log.info(e.getMessage()); } catch (Exception e) { log.log(Level.FINEST, e.toString(), e); } } if (impl == null) impl = new QuercusServletImpl(); log.info("QuercusServlet starting as " + impl.getClass().getSimpleName()); return impl; } /** * Make sure Quercus is running on JDK 1.5+. */ private static void checkJavaVersion() { String version = System.getProperty("java.version"); if (version.startsWith("1.3.") || version.startsWith("1.4.")) throw new QuercusRuntimeException(L.l( "Quercus requires JDK 1.5 or higher.")); } /** * Set true if quercus should be compiled into Java. */ public void setCompile(String isCompile) throws ConfigException { if ("true".equals(isCompile) || "".equals(isCompile)) { _isCompile = true; _isLazyCompile = false; } else if ("false".equals(isCompile)) { _isCompile = false; _isLazyCompile = false; } else if ("lazy".equals(isCompile)) { _isLazyCompile = true; } else throw new ConfigException(L.l( "'{0}' is an unknown compile value. " + "Values are 'true', 'false', or 'lazy'.", isCompile)); } /** * Set true interpreted pages should be used for pages that fail to compile. */ public void setCompileFailover(String isCompileFailover) throws ConfigException { if ("true".equals(isCompileFailover) || "".equals(isCompileFailover)) { _isCompileFailover = true; } else if ("false".equals(isCompileFailover)) { _isCompileFailover = false; } else throw new ConfigException(L.l( "'{0}' is an unknown compile-failover value. " + " Values are 'true' or 'false'.", isCompileFailover)); } /** * Sets the frequency of profiling, expressed as a probability. */ public void setProfileProbability(double probability) throws ConfigException { _profileProbability = probability; } /** * Set true if the source php is required */ public void setRequireSource(boolean isRequireSource) { _isRequireSource = isRequireSource; } /** * Set the default data source. */ public void setDatabase(DataSource database) throws ConfigException { if (database == null) throw new ConfigException(L.l("invalid database")); _database = database; } /** * Sets the strict mode. */ public void setStrict(boolean isStrict) { _isStrict = isStrict; } /** * Sets the strict mode. */ public void setLooseParse(boolean isLooseParse) { _isLooseParse = isLooseParse; } /* * Sets the max size of the page cache. */ public void setPageCacheEntries(int entries) { _pageCacheSize = entries; } /* * Sets the max size of the page cache. */ public void setPageCacheSize(int size) { _pageCacheSize = size; } /* * Sets the max size of the regexp cache. */ public void setRegexpCacheSize(int size) { _regexpCacheSize = size; } /* * Turns connection pooling on or off. */ public void setConnectionPool(boolean isEnable) { _isConnectionPool = isEnable; } /** * Adds a quercus module. */ public void addModule(QuercusModule module) throws ConfigException { //getQuercus().addModule(module); _moduleList.add(module); } /** * Adds a quercus class. */ public void addClass(PhpClassConfig classConfig) throws ConfigException { //getQuercus().addJavaClass(classConfig.getName(), classConfig.getType()); _classList.add(classConfig); } /** * Adds a quercus class. */ public void addImplClass(PhpClassConfig classConfig) throws ConfigException { //getQuercus().addImplClass(classConfig.getName(), classConfig.getType()); _classImplList.add(classConfig); } /** * Adds a quercus.ini configuration */ public PhpIni createPhpIni() throws ConfigException { PhpIni ini = new PhpIni(); _phpIniList.add(ini); return ini; } /** * Adds a $_SERVER configuration */ public ServerEnv createServerEnv() throws ConfigException { ServerEnv ini = new ServerEnv(); _serverEnvList.add(ini); return ini; } public boolean isUnicodeSemantics() { for (PhpIni ini : _phpIniList) { String value = ini._propertyMap.get("unicode.semantics"); if (value != null && ! value.equals("0") && ! value.equals("false") && ! value.equals("off")) { return true; } } return false; } /** * Sets a php.ini file. */ public void setIniFile(String relPath) { /* Quercus quercus = getQuercus(); String realPath = getServletContext().getRealPath(relPath); Path path = quercus.getPwd().lookup(realPath); */ _iniPath = relPath; } /** * Sets the script encoding. */ public void setScriptEncoding(String encoding) throws ConfigException { _scriptEncoding = encoding; } /** * Sets the version of the client mysql library to report as. */ public void setMysqlVersion(String version) { _mysqlVersion = version; } /** * Sets the php version that Quercus should report itself as. */ public void setPhpVersion(String version) { _phpVersion = version; } /** * Sets the directory for Resin/Quercus licenses. */ public void setLicenseDirectory(String relPath) { _licenseDirectory = new File(getServletContext().getRealPath(relPath)); } /** * Initializes the servlet. */ public void init(ServletConfig config) throws ServletException { super.init(config); Enumeration<String> paramNames = config.getInitParameterNames(); while (paramNames.hasMoreElements()) { String paramName = paramNames.nextElement(); String paramValue = config.getInitParameter(paramName); setInitParam(paramName, paramValue); } initImpl(config); } /** * Sets a named init-param to the passed value. * * @throws ServletException if the init-param is not recognized */ protected void setInitParam(String paramName, String paramValue) throws ServletException { if ("compile".equals(paramName)) { setCompile(paramValue); } else if ("database".equals(paramName)) { try { Context ic = new InitialContext(); DataSource ds; if (! paramValue.startsWith("java:comp")) { try { ds = (DataSource) ic.lookup("java:comp/env/" + paramValue); } catch (Exception e) { // for glassfish ds = (DataSource) ic.lookup(paramValue); } } else { ds = (DataSource) ic.lookup(paramValue); } if (ds == null) throw new ServletException(L.l( "database '{0}' is not valid", paramValue)); setDatabase(ds); } catch (Exception e) { throw new ServletException(e); } } else if ("ini-file".equals(paramName)) { setIniFile(paramValue); } else if ("mysql-version".equals(paramName)) { setMysqlVersion(paramValue); } else if ("php-version".equals(paramName)) { setPhpVersion(paramValue); } else if ("script-encoding".equals(paramName)) { setScriptEncoding(paramValue); } else if ("strict".equals(paramName)) { setStrict("true".equals(paramValue)); } else if ("loose-parse".equals(paramName)) { setLooseParse("true".equals(paramValue)); } else if ("page-cache-entries".equals(paramName) || "page-cache-size".equals(paramName)) { setPageCacheSize(Integer.parseInt(paramValue)); } else if ("regexp-cache-size".equals(paramName)) { setRegexpCacheSize(Integer.parseInt(paramValue)); } else if ("connection-pool".equals(paramName)) { setConnectionPool("true".equals(paramValue)); } else if ("require-source".equals(paramName)) { setRequireSource("true".equals(paramValue)); } else if ("license-directory".equals(paramName)) { setLicenseDirectory(paramValue); } else throw new ServletException( L.l("'{0}' is not a recognized init-param", paramName)); } private void initImpl(ServletConfig config) throws ServletException { Class configClass = config.getClass(); _impl = getQuercusServlet(configClass.getName().startsWith("com.caucho")); if (isUnicodeSemantics()) _impl.getQuercus().setUnicodeSemantics(true); _impl.init(config); QuercusContext quercus = getQuercus(); quercus.setCompile(_isCompile); quercus.setLazyCompile(_isLazyCompile); quercus.setCompileFailover(_isCompileFailover); quercus.setProfileProbability(_profileProbability); quercus.setRequireSource(_isRequireSource); quercus.setDatabase(_database); quercus.setStrict(_isStrict); quercus.setLooseParse(_isLooseParse); quercus.setPageCacheSize(_pageCacheSize); quercus.setRegexpCacheSize(_regexpCacheSize); quercus.setConnectionPool(_isConnectionPool); if (_iniPath != null) { String realPath = getServletContext().getRealPath(_iniPath); quercus.setIniFile(getQuercus().getPwd().lookup(realPath)); } if (_scriptEncoding != null) quercus.setScriptEncoding(_scriptEncoding); if (_mysqlVersion != null) quercus.setMysqlVersion(_mysqlVersion); if (_phpVersion != null) quercus.setPhpVersion(_phpVersion); for (QuercusModule module : _moduleList) { quercus.addModule(module); } for (PhpClassConfig cls : _classList) { quercus.addJavaClass(cls.getName(), cls.getType()); } for (PhpClassConfig cls : _classImplList) { quercus.addImplClass(cls.getName(), cls.getType()); } for (PhpIni ini : _phpIniList) { for (Map.Entry<String,String> entry : ini._propertyMap.entrySet()) { quercus.setIni(entry.getKey(), entry.getValue()); } } for (ServerEnv serverEnv : _serverEnvList) { for (Map.Entry<String,String> entry : serverEnv._propertyMap.entrySet()) { quercus.setServerEnv(entry.getKey(), entry.getValue()); } } } /** * Service. */ public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { _impl.service(request, response); } /** * Returns the Quercus instance. */ private QuercusContext getQuercus() { if (_quercus == null) _quercus = _impl.getQuercus(); return _quercus; } /** * Closes the servlet instance. */ public void destroy() { _quercus.close(); _impl.destroy(); } public static class PhpIni { HashMap<String,String> _propertyMap = new HashMap<String,String>(); PhpIni() { } /** * Sets an arbitrary property. */ public void setProperty(String key, String value) { //_quercus.setIni(key, value); _propertyMap.put(key, value); } } public static class ServerEnv { HashMap<String,String> _propertyMap = new HashMap<String,String>(); ServerEnv() { } /** * Sets an arbitrary property. */ public void setProperty(String key, String value) { //_quercus.setServerEnv(key, value); _propertyMap.put(key, value); } } }