In all cases the config directory is moved and I don't know what to change in MMBase to get this working.
You can set a property in web.xml called 'mmbase.config' like this:
<context-param>
<param-name>mmbase.config</param-name>
<param-value>/home/mydir/myconfigdir</param-value>
</context-param>If not specified, MMBaseContext sets it to the WEB-INF/config dir
Unfortunately with the current version you have to specify a full directory (not always known if you do not know too mcuh about the hosting server), to get any predictable effect.
Included is an adapted MMBaseContext java class. If you replace this class in your MMBase.jar (compile it etc), it should allow you to use a path relative to a 'user.dir' path:
<context-param>
<param-name>user.dir</param-name>
<param-value>/home/mydir</param-value>
</context-param>
<context-param>
<param-name>mmbase.config</param-name>
<param-value>myconfigdir</param-value>
</context-param>IOW if you do not give an absolute path in config.dir, it makes it relative to user.dir.
The default for user.dir is set by the appserver (i.e.e /usr/local/tomcat) so it generally is still not very useful (you still need to know the dir, it just is in a different parameter).
However, with the update code you can also specify that you want the config dir to start at the webroot by starting the path (either MMBase.config or, prettier I guess, user.dir) with the "$WEBROOT" symbol like this:
<context-param>
<param-name>mmbase.config</param-name>
<param-value>$WEBROOT/WEB-INF/classes/config</param-value>
</context-param>or:
<context-param>
<param-name>user.dir</param-name>
<param-value>$WEBROOT</param-value>
</context-param>
<context-param>
<param-name>mmbase.config</param-name>
<param-value>WEB-INF/classes/config</param-value>
</context-param>
Included is the changed MMBaseContext class. I'll check it in in 1.7 later on (have to enter the bug first). Feedback on whether this solves the problem is appreciated.
-- Pierre van Rooden Mediapark, C 107 tel. +31 (0)35 6772815 "Never summon anything bigger than your head."
/*
This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. The license (Mozilla version 1.0) can be read at the MMBase site. See http://www.MMBase.org/license */ package org.mmbase.module.core; import java.util.*; import java.io.*; import javax.servlet.*; import org.mmbase.util.logging.Logger; import org.mmbase.util.logging.Logging; /** * Using MMBaseContext class you can retrieve the servletContext from anywhere * using the get method. * * @author Daniel Ockeloen * @author David van Zeventer * @author Jaco de Groot * @version $Id: MMBaseContext.java,v 1.37 2003/07/18 17:43:02 michiel Exp $ */ public class MMBaseContext { private static final Logger log = Logging.getLoggerInstance(MMBaseContext.class); private static boolean initialized = false; private static boolean htmlRootInitialized = false; private static ServletContext sx; private static String userDir; private static String configPath; private static String htmlRoot; private static String htmlRootUrlPath ="/"; private static boolean htmlRootUrlPathInitialized = false; private static String outputFile; /** * Initialize MMBase using a <code>SevletContext</code>. This method will * check the servlet configuration for context parameters mmbase.outputfile * and mmbase.config. If not found it will look for system properties. * * @throws ServletException if mmbase.config is not set or is not a * directory or doesn't contain the expected * config files. * */ public synchronized static void init(ServletContext servletContext) throws ServletException { if (!initialized) { // store the current context sx = servletContext; // Get the user directory using the user.dir property. // default set to the startdir of the appserver userDir = sx.getInitParameter("user.dir"); if (userDir == null) { userDir = System.getProperty("user.dir"); } // take into account userdir can start at webrootdir if (userDir != null && userDir.indexOf("$WEBROOT") == 0) { userDir = servletContext.getRealPath(userDir.substring(8)); } // Init outputfile. String outputFile = sx.getInitParameter("mmbase.outputfile"); if (outputFile == null) { outputFile = System.getProperty("mmbase.outputfile"); } // take into account configpath can start at webrootdir if (outputFile != null && outputFile.indexOf("$WEBROOT") == 0) { outputFile = servletContext.getRealPath(outputFile.substring(8)); } initOutputfile(outputFile); // Init configpath. String configPath = sx.getInitParameter("mmbase.config"); if (configPath == null) { configPath = System.getProperty("mmbase.config"); if (configPath == null) { // desperate looking for a location.. (say we are a war file..) // keeping the value 'null' will always give a failure.. configPath = servletContext.getRealPath("/WEB-INF/config"); } } // take into account configpath can start at webrootdir if (configPath.indexOf("$WEBROOT") == 0) { configPath = servletContext.getRealPath(configPath.substring(8)); } try { initConfigpath(configPath); } catch(Exception e) { throw new ServletException(e.getMessage()); } // Init logging. initLogging(); initialized = true; } } /** * Initialize MMBase using a config path. Useful when testing * MMBase classes with a main. You can also configure to init * logging or not. * * @throws Exception if mmbase.config is not set or is not a * directory or doesn't contain the expected * config files. * */ public synchronized static void init(String configPath, boolean initLogging) throws Exception { if (!initialized) { // Get the current directory using the user.dir property. userDir = System.getProperty("user.dir"); // Init outputfile. // use of mmbase.outputfile is deprecated! initOutputfile(System.getProperty("mmbase.outputfile")); // Init configpath. initConfigpath(configPath); // Init logging. if (initLogging) { initLogging(); } initialized = true; } } /** * Initialize MMBase using system properties only. This may be useful in * cases where MMBase is used without a servlet. For example when running * JUnit tests. * * @throws Exception if mmbase.config is not set or is not a * directory or doesn't contain the expected * config files. * */ public synchronized static void init() throws Exception { init(System.getProperty("mmbase.config"), true); } private static void initOutputfile(String o) { outputFile = o; if (outputFile != null) { if (!new File(outputFile).isAbsolute()) { outputFile = userDir + File.separator + outputFile; } try { FileOutputStream fos; fos = new FileOutputStream(outputFile, true); PrintStream mystream = new PrintStream(fos); System.setOut(mystream); System.setErr(mystream); } catch (IOException e) { outputFile = null; System.err.println("Failed to set mmbase.outputfile to '" + outputFile + "'."); e.printStackTrace(); } } } private static void initConfigpath(String c) throws Exception { configPath = c; if (configPath == null) { userDir = null; configPath = null; String message = "Parameter mmbase.config not set."; System.err.println(message); throw new Exception(message); } File fileConfigpath = new File(configPath); if (userDir != null && !fileConfigpath.isAbsolute()) { configPath = userDir + File.separator + configPath; fileConfigpath = new File(configPath); } // Make it absolute. Needed for servscan and servdb to // to startup properly. configPath = fileConfigpath.getAbsolutePath(); if (!fileConfigpath.isDirectory()) { userDir = null; configPath = null; String message = "Parameter mmbase.config is not pointing to " + "a directory("+fileConfigpath.getAbsolutePath()+")."; System.err.println(message); throw new Exception(message); } if(!new File(configPath + "/security/security.xml").isFile()) { userDir = null; configPath = null; String message = "File 'security/security.xml' missing in " + "mmbase.config directory("+fileConfigpath.getAbsolutePath()+")."; System.err.println(message); throw new Exception(message); } /* if(!new File(configpath + "/accounts.properties").isFile()) { userDir = null; configpath = null; String message = "File 'accounts.properties' missing in " + "mmbase.config directory("+fileConfigpath.getAbsolutePath()+")."; System.err.println(message); throw new Exception(message); } */ if(!new File(configPath + "/builders").isDirectory()) { userDir = null; configPath = null; String message = "Directory 'builders' missing in " + "mmbase.config directory("+fileConfigpath.getAbsolutePath()+")."; System.err.println(message); throw new Exception(message); } if(!new File(configPath + "/modules").isDirectory()) { userDir = null; configPath = null; String message = "Directory 'modules' missing in " + "mmbase.config directory("+fileConfigpath.getAbsolutePath()+")."; System.err.println(message); throw new Exception(message); } if(!new File(configPath + "/modules/mmbaseroot.xml").isFile()) { userDir = null; configPath = null; String message = "File 'modules/mmbaseroot.xml' missing in " + "mmbase.config directory("+fileConfigpath.getAbsolutePath()+")."; System.err.println(message); throw new Exception(message); } if(!new File(configPath + "/modules/jdbc.xml").isFile()) { userDir = null; configPath = null; String message = "File 'modules/jdbc.xml' missing in " + "mmbase.config directory("+fileConfigpath.getAbsolutePath()+")."; System.err.println(message); throw new Exception(message); } if(!new File(configPath + "/log/log.xml").isFile()) { userDir = null; configPath = null; String message = "File 'log/log.xml' missing in " + "mmbase.config directory("+fileConfigpath.getAbsolutePath()+")."; System.err.println(message); throw new Exception(message); } if (configPath.endsWith(File.separator)) { configPath = configPath.substring(0, configPath.length() - 1); } } private static void initLogging() { // Starting the logger Logging.configure(configPath + File.separator + "log" + File.separator + "log.xml"); log.info("==========================="); log.info("MMBase logging initialized."); log.info("==========================="); log.info("user.dir : " + userDir); log.info("mmbase.config : " + configPath); log.info("mmbase.outputfile : " + outputFile); log.info("version : " + org.mmbase.Version.get()); Runtime rt = Runtime.getRuntime(); log.info("total memory : " + rt.totalMemory() / (1024 * 1024) + " Mbyte"); rt.gc(); log.info("free memory : " + rt.freeMemory() / (1024 * 1024) + " Mbyte"); log.info("system locale : " + Locale.getDefault()); } /** * Initialize mmbase.htmlroot parameter. This method is only needed for * SCAN related servlets and should be called after the init(ServletContext) * method. If the mmbase.htmlroot parameter is not found in the servlet * context or system properties this method will try to set it to the * root directory of the webapp. * * @throws ServletException if mmbase.htmlroot is not set or is not a * directory * */ public synchronized static void initHtmlRoot() throws ServletException { if (!initialized || sx == null) { String message = "The init(ServletContext) method should be called first."; System.err.println(message); throw new RuntimeException(message); } if (!htmlRootInitialized) { // Init htmlroot. htmlRoot = sx.getInitParameter("mmbase.htmlroot"); if (htmlRoot == null) { htmlRoot = System.getProperty("mmbase.htmlroot"); } if (htmlRoot == null) { htmlRoot = sx.getRealPath(""); } if (htmlRoot == null){ String message = "Parameter mmbase.htmlroot not set."; System.err.println(message); throw new ServletException(message); } else { if (userDir != null && !new File(htmlRoot).isAbsolute()) { htmlRoot = userDir + File.separator + htmlRoot; } if (!new File(htmlRoot).isDirectory()) { userDir = null; configPath = null; htmlRoot = null; String message = "Parameter mmbase.htmlroot is not pointing " + "to a directory."; System.err.println(message); throw new ServletException(message); } else { if (htmlRoot.endsWith(File.separator)) { htmlRoot = htmlRoot.substring(0, htmlRoot.length() - 1); } htmlRootInitialized = true; log.info("mmbase.htmlroot : " + htmlRoot); log.info("context : " + getHtmlRootUrlPath()); } } } } /** * Returns the <code>ServeltContext</code> used to initialize MMBase. * Before calling this method the init method should be called. * * @return the <code>ServeltContext</code> used to initialize MMBase or * <code>null</code> if MMBase was initilized without * <code>ServletContext</code> */ public synchronized static ServletContext getServletContext() { if (!initialized) { String message = "The init method should be called first."; System.err.println(message); throw new RuntimeException(message); } return sx; } /** * Returns a string representing the mmbase.config parameter without a * final <code>File.separator</code>. Before calling this method the * init method should be called to make sure this parameter is set. * * @return the mmbase.config parameter or WEB-INF/config */ public synchronized static String getConfigPath() { if (!initialized) { String config = System.getProperty("mmbase.config"); if (config == null) { String message = "The init method should be called first (or start with mmbase.config parameter)"; System.err.println(message); throw new RuntimeException(message); } else { File configDir = new File(config); if(!configDir.exists()) { String message = "Config directory could not be found, does it exist? (" + configDir.getAbsolutePath() + ")"; System.err.println(message); throw new RuntimeException(message); } if(!configDir.canRead()) { String message = "Config directory could not be read, is it readable? (" + configDir.getAbsolutePath() + ")"; System.err.println(message); throw new RuntimeException(message); } if(!configDir.isDirectory()) { String message = "Config directory is not a directory (" + configDir.getAbsolutePath() + ")"; System.err.println(message); throw new RuntimeException(message); } return config; } } return configPath; } /** * Returns a string representing the mmbase.htmlroot parameter without a * final <code>File.separator</code>. Before calling this method the * initHtmlRoot method should be called to make sure this parameter is set. * * @return the mmbase.htmlroot parameter or <code>null</code> if not * initialized */ public synchronized static String getHtmlRoot() { if (!htmlRootInitialized) { String message = "The initHtmlRoot method should be called first."; System.err.println(message); throw new RuntimeException(); } return htmlRoot; } /** * Returns a string representing the mmbase.outputfile parameter. If set, * this is the file to wich all <code>System.out</code> and * <code>System.err</code> output is redirected. Before calling this method * the init method should be called. * * @return the mmbase.outputFile parameter or <code>null</code> if not set * @deprecated use logging system */ public synchronized static String getOutputFile() { if (!initialized) { String message = "The init method should be called first."; System.err.println(message); throw new RuntimeException(message); } return outputFile; } /** * converts a url with a given context, to the resource url. * @param servletContext * @param url A url to the resource, which must exist * @return null on failure, otherwise a resource url. */ private static String convertResourceUrl(ServletContext servletContext, String url) { // return null on failure if(servletContext == null) return null; try { java.net.URL transformed = servletContext.getResource(url); if(transformed == null){ log.error("no resource is mapped to the pathname: '"+url+"'"); return null; } return transformed.toString(); } catch (java.net.MalformedURLException e) { log.error("could not convert the url: '" + e + "'(error converting)"); } return null; } private static String CONTEXT_URL_IDENTIFIER = "jndi:/"; /** * Returns a string representing the HtmlRootUrlPath, this is the path under * the webserver, what is the root for this instance. * this will return '/' or something like '/mmbase/' or so... * @return the HtmlRootUrlPath * @deprecated should not be needed, and this information should be requested from the ServletRequest */ public synchronized static String getHtmlRootUrlPath() { if (! htmlRootUrlPathInitialized) { log.info("Finding root url"); if (! initialized) { String message = "The init method should be called first."; System.err.println(message); throw new RuntimeException(message); } if (sx == null) { // no serlvetContext -> not htmlRootUrlPath htmlRootUrlPathInitialized = true; return htmlRootUrlPath; } String initPath = sx.getInitParameter("mmbase.htmlrooturlpath"); if (initPath != null) { log.debug("Found mmbase.htmlrooturlpath explicitely configured"); htmlRootUrlPath = initPath; } else { // init the htmlRootUrlPath log.debug("Autodetecting htmlrooturlpath "); // fetch resource path for the root servletcontext root... ServletContext rootContext = null; String rootContextUrl = null; String contextUrl = null; if (! sx.getClass().getName().startsWith("com.evermind")) { // Orion horribly fails contextUrl = convertResourceUrl(sx, "/"); rootContext = sx.getContext("/"); // Orion fails here rootContextUrl = convertResourceUrl(rootContext, "/"); } else { log.info("For Orion: Use the parameter mmbase.htmlrooturlpath (in web.xml) if your app is not running on '/' (Cannot detect now)"); } if(contextUrl != null && rootContextUrl != null) { // the beginning of contextUrl is the same as the string rootContextUrl, // the left part is the current urlPath on the server... if(contextUrl.startsWith(rootContextUrl)) { // htmlUrl is gonna be filled htmlRootUrlPath = "/" + contextUrl.substring(rootContextUrl.length(), contextUrl.length()); } else { log.warn("the current context:" + contextUrl + " did not begin with the root context :"+rootContextUrl); } } else if (rootContextUrl == null && contextUrl != null && contextUrl.startsWith(CONTEXT_URL_IDENTIFIER)) { // This works on my tomcat (4.03),.. this is supposed to be the reference implementation? // so what should be the code? // the String will be typically something like "jndi:/hostname/contextname/", so we are looking for the first '/' after the hostname.. int contextStart = contextUrl.substring(CONTEXT_URL_IDENTIFIER.length()).indexOf('/'); if(contextStart != -1) { htmlRootUrlPath = contextUrl.substring(CONTEXT_URL_IDENTIFIER.length() + contextStart); } else { log.warn("Could not determine htmlRootUrlPath. Using default " + htmlRootUrlPath + "\nbut contextUrl : '" + contextUrl + "' did start with: '"+CONTEXT_URL_IDENTIFIER + "'"); } } else { log.warn("Could not determine htmlRootUrlPath. Using default " + htmlRootUrlPath + "(contextUrl :" + contextUrl + " rootContextUrl :" + rootContextUrl + ")"); } } htmlRootUrlPathInitialized = true; } return htmlRootUrlPath; } /** * Returns whether this class has been initialized. * This can be used to determine whether MMBase specific configuration data is accessible. */ public static boolean isInitialized() { return initialized; } }
