Hi, Trying to deploy cocoon (2.1.6) webapp under an already installed jetty server (5.1.1), I met some problems with Xindice (1.1b4) servlet configuration embedded in cocoon.
I had error messages saying that the configuration file of xindice could not be loaded (the trace is listed below). The Xindice servlet declaration in web.xml is as follow : ---- <servlet> <servlet-name>Xindice</servlet-name> <display-name>Xindice XML-RPC Server</display-name> <servlet-class>org.apache.xindice.server.XindiceServlet</servlet-class> <init-param> <param-name>xindice.configuration</param-name> <param-value>WEB-INF/xindice.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> ---- I had a look at Xindice source code and found that the following statement in org/apache/xindice/server/XindiceServlet.java ,loadConfiguration() method (near line #240) : ------ String path = servletConfig.getInitParameter(Xindice.PROP_XINDICE_CONFIGURA TION); if (path != null) { InputStream inputStream = null; if (path.startsWith("/")) { // Absolute file path ... } else { // Relative (to the context) path log.debug("Loading configuration from context path " + path) ; ServletContext context = servletConfig.getServletContext(); inputStream = context.getResourceAsStream(path); } ... } ------- returned a null InputStream when the path is relative, causing the error messages... I changed the line ---- inputStream = context.getResourceAsStream(path) ; ---- by ---- inputStream = new FileInputStream(context.getRealPath(path)) ; ---- And the loading of Xindice servlet configuration file now works fine. I don't know if this modification is accurate, but it solved my problem. I join the modified XindiceServlet.java to this mail if someone is interested in it... Cheers Gilles P.S. : Here is (part of) the trace I had in jetty logs at startup : ----- 14:46:04.770 WARN!! [main] org.mortbay.jetty.Server.main(Server.java:438) >08> EXCEPTION org.mortbay.util.MultiException[org.apache.xindice.util.ConfigurationException: Failed to load configuration.] at org.mortbay.http.HttpServer.doStart(HttpServer.java:673) at org.mortbay.util.Container.start(Container.java:72) at org.mortbay.jetty.Server.main(Server.java:433) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at org.mortbay.start.Main.invokeMain(Main.java:151) at org.mortbay.start.Main.start(Main.java:480) at org.mortbay.start.Main.main(Main.java:94) org.apache.xindice.util.ConfigurationException: Failed to load configuration. at org.apache.xindice.server.XindiceServlet.loadConfiguration(XindiceServlet.java:273) at org.apache.xindice.server.XindiceServlet.init(XindiceServlet.java:103) at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:369) at org.mortbay.jetty.servlet.ServletHolder.start(ServletHolder.java:243) at org.mortbay.jetty.servlet.ServletHandler.initializeServlets(ServletHandler.java:445) at org.mortbay.jetty.servlet.WebApplicationHandler.initializeServlets(WebApplicationHandler.java:310) at org.mortbay.jetty.servlet.WebApplicationContext.doStart(WebApplicationContext.java:512) at org.mortbay.util.Container.start(Container.java:72) at org.mortbay.http.HttpServer.doStart(HttpServer.java:695) at org.mortbay.util.Container.start(Container.java:72) at org.mortbay.jetty.Server.main(Server.java:433) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at org.mortbay.start.Main.invokeMain(Main.java:151) at org.mortbay.start.Main.start(Main.java:480) at org.mortbay.start.Main.main(Main.java:94) Caused by: java.lang.NullPointerException at org.apache.xindice.server.XindiceServlet.loadConfiguration(XindiceServlet.java:261) ... -----
/* * Copyright 1999-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * CVS $Id: XindiceServlet.java,v 1.30 2004/02/11 14:03:09 vgritsenko Exp $ */ package org.apache.xindice.server; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xindice.core.Database; import org.apache.xindice.server.rpc.RPCMessageInterface; import org.apache.xindice.util.Configuration; import org.apache.xindice.util.ConfigurationException; import org.apache.xindice.xml.dom.DOMParser; import org.apache.xmlrpc.XmlRpc; import org.apache.xmlrpc.XmlRpcServer; import org.w3c.dom.Document; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * A <code>HttpServlet</code> that enables XML-RPC access to a Xindice * database instance. * * @author <a href="mailto:[EMAIL PROTECTED]">Kimbro Staken</a> * @author <a href="mailto:[EMAIL PROTECTED]">Vladimir R. Bossicard</a> * @author <a href="mailto:[EMAIL PROTECTED]">Gianugo Rabellino</a> * @author <a href="mailto:[EMAIL PROTECTED]">Vadim Gritsenko</a> * @version CVS $Revision: 1.30 $, $Date: 2004/02/11 14:03:09 $ */ public class XindiceServlet extends HttpServlet { private static final Log log = LogFactory.getLog(XindiceServlet.class); private static final String DEFAULT_XMLRPC_DRIVER = "xerces"; protected XmlRpcServer xmlrpcServer; public void destroy() { // When the servlet engine goes down we need to close the database instance. // By the time destroy() is called, no more client requests can come in, // so no need to worry about multithreading. String[] databases = Database.listDatabases(); for (int i = 0; i < databases.length; i++) { String name = databases[i]; try { Database.getDatabase(name).close(); log.info("Database '" + name + "' successfully closed"); } catch (Exception e) { log.error("Error closing database '" + name + "'", e); } } } /** * Delegate GET requests to the UglyBrowser. */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { UglyBrowser.doGet(request, response); } /** * Sends an XML query to the server and writes the output back. Currenlty * only XML-RPC query is supported. */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { byte[] result = xmlrpcServer.execute(request.getInputStream()); response.setContentType("text/xml"); response.setContentLength(result.length); OutputStream output = response.getOutputStream(); output.write(result); output.flush(); } /** * Initializes database */ public void init(ServletConfig servletConfig) throws ServletException { Configuration configuration = loadConfiguration(servletConfig); // // The configuration is wrapped in a <xindice> element so we need to get the "root-collection" configuration. // try { Configuration[] rootConfigurations = configuration.getChildren("root-collection"); if (rootConfigurations.length == 0) { throw new ConfigurationException("The database configuration is missing the <root-collection> element"); } else { for (int i = 0; i < rootConfigurations.length; i++) { Configuration rootConfiguration = rootConfigurations[i]; String name = rootConfiguration.getAttribute(Database.NAME); // // We need to ensure that the database points to a place where it makes // sense. If the path in the system.xml file is an absolute path, then // honor it. If it's not, we first check for the system property "xindice.db.home" // and if the lookup is successful we use it as the database root parent. If // the property is not set, we use /WEB-INF relative to the servlet context, unless // the war has not been unpacked. In this case, we throw an exception and // ask the user to specify the location of database root // String dbRoot = rootConfiguration.getAttribute(Database.DBROOT, Database.DBROOT_DEFAULT); // // If there is no absolute path, we have to perform some checks. // if (!new File(dbRoot).isAbsolute()) { // Stupid hack but spec compliant: // If getRealPath() returns null the war archive has not been unpacked. String realPath = servletConfig.getServletContext().getRealPath("/WEB-INF"); // Let's see if the property was specified. String home = System.getProperty(Xindice.PROP_XINDICE_DB_HOME); if (log.isDebugEnabled()) { log.debug(Xindice.PROP_XINDICE_DB_HOME + " is set to " + home); } if (home != null) { dbRoot = new File(home + File.separator + dbRoot).getCanonicalPath(); } else if (realPath != null) { dbRoot = new File(realPath + File.separator + dbRoot).getCanonicalPath(); log.warn("The database '" + name + "' root directory has been set to " + dbRoot + ". Keep in mind that if a war upgrade will take place the database will be lost."); } else { throw new ConfigurationException( "The database '" + name + "' configuration points to a relative path, " + "but there was no " + Xindice.PROP_XINDICE_DB_HOME + " property set. " + "Furthermore, the war was not unpacked by the application server " + "so Xindice was unable to find a database location " + "Please check /WEB-INF/system.xml and set an absolute path " + "as the \"dbroot\" attribute of \"root-collection\" " + "or specify a suitable " + Xindice.PROP_XINDICE_DB_HOME + " system property."); } rootConfiguration.setAttribute(Database.DBROOT, dbRoot); } // // We need to use this method to be consistent between deployments (embed, standalone, etc) // and let the Database object maintain the set of Databases. // Database.getDatabase(rootConfiguration); log.info("Database '" + name + "' successfully opened"); } } // Setup the XML-RPC impl to support UTF-8 input via Xerces. XmlRpc.setEncoding("UTF8"); /* * Setup the SAX parser XML-RPC impl will use. * The XmlRpc.setDriver() method takes either the classname or a shorthand * name for the SAX parser it will use. The default (for backwards compatibility * if nothing else) is xerces. */ String xmlrpcDriver = DEFAULT_XMLRPC_DRIVER; Configuration xmlRpcConfiguration = configuration.getChild("xml-rpc"); if (xmlRpcConfiguration != null) { Configuration xmlRpcDriverConfiguration = xmlRpcConfiguration.getChild("driver"); if (xmlRpcDriverConfiguration != null) { // xmlrpcDriver will have non-empty value, guaranteed by providing default value xmlrpcDriver = xmlRpcDriverConfiguration.getAttribute("name", DEFAULT_XMLRPC_DRIVER); } } try { XmlRpc.setDriver(xmlrpcDriver); } catch (Exception e) { throw new ConfigurationException("Failed to set driver for XmlRpc to: " + xmlrpcDriver, e); } // Create the XML-RPC server and add our handler as the default. this.xmlrpcServer = new XmlRpcServer(); try { this.xmlrpcServer.addHandler("$default", new RPCMessageInterface()); } catch (Exception e) { throw new ConfigurationException("Failed to add default handler to XmlRpc server.", e); } log.info("Xindice server successfully started"); } catch (Exception e) { log.fatal("Failed to initialize database, throwing ServletException", e); // Make sure to close database if it was opened already. destroy(); throw new ServletException("Error while handling the configuration", e); } } /** * Loads the Xindice configuration file. The file is searched in the following locations: * <ul> * <li>the <tt>ServletConfig.getInitParameter(Xindice.PROP_XINDICE_CONFIGURATION)</tt> variable located in the servlet * configuration file</li> * <li>use the default configuration stored in the <tt>Xindice</tt> class</li> * </ul> * * <br/> * TODO: we should probably try to load from the file system if we can't load it this way. */ public Configuration loadConfiguration(ServletConfig servletConfig) { try { Document configurationDocument; String path = servletConfig.getInitParameter(Xindice.PROP_XINDICE_CONFIGURATION); if (path != null) { InputStream inputStream = null; if (path.startsWith("/")) { // Absolute file path log.debug("Loading configuration from filesystem path " + path); inputStream = new FileInputStream(path); } else { // Relative (to the context) path log.debug("Loading configuration from context path " + path); ServletContext context = servletConfig.getServletContext(); // inputStream = context.getResourceAsStream(path); inputStream = new FileInputStream(context.getRealPath(path)); } try { configurationDocument = DOMParser.toDocument(inputStream); } finally { try { inputStream.close(); } catch (IOException ignored) { } } } else { log.debug("Loading the standard configuration"); configurationDocument = DOMParser.toDocument(Xindice.DEFAULT_CONFIGURATION); } return new Configuration(configurationDocument, false); } catch (Exception e) { throw new ConfigurationException("Failed to load configuration.", e); } } }