jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tri...@apache.org
Subject svn commit: r495531 [1/2] - in /jackrabbit/trunk/jackrabbit-webapp/src/main: java/org/apache/jackrabbit/j2ee/ webapp/ webapp/WEB-INF/ webapp/WEB-INF/bootstrap/ webapp/WEB-INF/repository/ webapp/WEB-INF/templates/ webapp/bootstrap/
Date Fri, 12 Jan 2007 09:38:43 GMT
Author: tripod
Date: Fri Jan 12 01:38:40 2007
New Revision: 495531

URL: http://svn.apache.org/viewvc?view=rev&rev=495531
Log:
JCR-697: .war distribution should be configurable, prompting you to setup JNDI with the Repository Home and Config locations.

Added:
    jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/AbstractConfig.java   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/BootstrapConfig.java
    jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/Installer.java   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JNDIConfig.java   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RMIConfig.java   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/bootstrap/
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/templates/
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/templates/bootstrap.properties   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/templates/repository.xml
      - copied, changed from r494040, jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/repository/repository.xml
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/bootstrap/
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/bootstrap/error.html   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/bootstrap/exists.html   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/bootstrap/missing.html   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/bootstrap/notexists.html   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/bootstrap/reconfigure.html   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/bootstrap/running.html   (with props)
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/bootstrap/success.html   (with props)
Removed:
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/repository/
Modified:
    jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryAccessServlet.java
    jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryStartupServlet.java
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/web.xml
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/index.jsp

Added: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/AbstractConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/AbstractConfig.java?view=auto&rev=495531
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/AbstractConfig.java (added)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/AbstractConfig.java Fri Jan 12 01:38:40 2007
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.jackrabbit.j2ee;
+
+import org.apache.commons.collections.BeanMap;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Properties;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+/**
+ * Abstract configuration class that is based on a bean map.
+ */
+public abstract class AbstractConfig {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(AbstractConfig.class);
+
+    protected boolean valid;
+
+    private BeanMap map = new BeanMap(this);
+
+    /**
+     * Initializes the config with values from the given properties
+     * @param props the config properties
+     */
+    public void init(Properties props) throws ServletException {
+        Iterator iter = props.keySet().iterator();
+        while (iter.hasNext()) {
+            String name = (String) iter.next();
+            String mapName = toMapName(name, '.');
+            try {
+                if (map.containsKey(mapName)) {
+                    map.put(mapName, props.getProperty(name));
+                }
+            } catch (Exception e) {
+                log.error("Error in configuration: {}", e.toString());
+                throw new ServletException("Error in configuration: " + e.toString());
+            }
+        }
+    }
+
+    public void init(ServletConfig ctx) throws ServletException {
+        Enumeration enum = ctx.getInitParameterNames();
+        while (enum.hasMoreElements()) {
+            String name = (String) enum.nextElement();
+            String mapName = toMapName(name, '-');
+            try {
+                if (map.containsKey(mapName)) {
+                    map.put(mapName, ctx.getInitParameter(name));
+                }
+            } catch (Exception e) {
+                log.error("Error in configuration: {}", e.toString());
+                throw new ServletException("Error in configuration: " + e.toString());
+            }
+        }
+    }
+
+    public String toMapName(String name, char delim) {
+        StringBuffer ret = new StringBuffer();
+        String[] elems = Text.explode(name, delim);
+        ret.append(elems[0]);
+        for (int i=1; i<elems.length; i++) {
+            ret.append(elems[i].substring(0, 1).toUpperCase());
+            ret.append(elems[i].substring(1));
+        }
+        return ret.toString();
+    }
+
+    public void validate() {
+        valid = true;
+    }
+
+    public boolean isValid() {
+        return valid;
+    }
+
+    public void logInfos() {
+        log.info("Configuration of {}", Text.getName(this.getClass().getName(), '.'));
+        log.info("----------------------------------------------");
+        Iterator iter = map.keySet().iterator();
+        while (iter.hasNext()) {
+            String name = (String) iter.next();
+            log.info("  {}: {}", name, map.get(name));
+        }
+        log.info("----------------------------------------------");
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/AbstractConfig.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/AbstractConfig.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url rev

Added: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/BootstrapConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/BootstrapConfig.java?view=auto&rev=495531
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/BootstrapConfig.java (added)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/BootstrapConfig.java Fri Jan 12 01:38:40 2007
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.jackrabbit.j2ee;
+
+import java.util.Properties;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletConfig;
+
+/**
+ * The bootstrap configuration hold information about initial startup
+ * parameters like repository config and home.
+ *
+ * It supports the following properties and init parameters:
+ * <xmp>
+ * +-------------------+-------------------+
+ * | Property Name     | Init-Param Name   |
+ * +-------------------+-------------------+
+ * | repository.home   | repository-home   |
+ * | repository.config | repository-config |
+ * | repository.name   | repository-name   |
+ * +-------------------+-------------------+
+ * </xmp>
+ */
+public class BootstrapConfig extends AbstractConfig {
+
+    private String repositoryHome;
+
+    private String repositoryConfig;
+
+    private String repositoryName;
+
+    private JNDIConfig jndiConfig = new JNDIConfig(this);
+
+    private RMIConfig rmiConfig = new RMIConfig(this);
+
+    public void init(Properties props) throws ServletException {
+        super.init(props);
+        jndiConfig.init(props);
+        rmiConfig.init(props);
+    }
+
+    public void init(ServletConfig ctx) throws ServletException {
+        super.init(ctx);
+        jndiConfig.init(ctx);
+        rmiConfig.init(ctx);
+    }
+
+    public String getRepositoryHome() {
+        return repositoryHome;
+    }
+
+    public void setRepositoryHome(String repositoryHome) {
+        this.repositoryHome = repositoryHome;
+    }
+
+    public String getRepositoryConfig() {
+        return repositoryConfig;
+    }
+
+    public void setRepositoryConfig(String repositoryConfig) {
+        this.repositoryConfig = repositoryConfig;
+    }
+
+    public String getRepositoryName() {
+        return repositoryName;
+    }
+
+    public void setRepositoryName(String repositoryName) {
+        this.repositoryName = repositoryName;
+    }
+
+    public JNDIConfig getJndiConfig() {
+        return jndiConfig;
+    }
+
+    public RMIConfig getRmiConfig() {
+        return rmiConfig;
+    }
+
+    public void validate() {
+        valid = repositoryName != null;
+        jndiConfig.validate();
+        rmiConfig.validate();
+    }
+
+
+    public void logInfos() {
+        super.logInfos();
+        if (jndiConfig.isValid()) {
+            jndiConfig.logInfos();
+        }
+        if (rmiConfig.isValid()) {
+            rmiConfig.logInfos();
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/Installer.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/Installer.java?view=auto&rev=495531
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/Installer.java (added)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/Installer.java Fri Jan 12 01:38:40 2007
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.jackrabbit.j2ee;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Provides very basic installation capabilities.
+ */
+public class Installer {
+
+    /**
+     * the default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(Installer.class);
+
+    /**
+     * Return code for installation succeeded
+     */
+    public static final int C_INSTALL_OK = 0;
+
+    /**
+     * Return code for invalid input parameter
+     */
+    public static final int C_INVALID_INPUT = 1;
+
+    /**
+     * Return code for repository home already exists
+     */
+    public static final int C_HOME_EXISTS = 2;
+
+    /**
+     * Return code for repository home is missing
+     */
+    public static final int C_HOME_MISSING = 3;
+
+    /**
+     * Return code for repository config already exists
+     */
+    public static final int C_CONFIG_EXISTS = 4;
+
+    /**
+     * Return code for repository config is missing
+     */
+    public static final int C_CONFIG_MISSING = 5;
+
+    /**
+     * Return code for bootstrap config already exists
+     */
+    public static final int C_BOOTSTRAP_EXISTS = 6;
+
+    /**
+     * Return code for a general install error
+     */
+    public static final int C_INSTALL_ERROR = 7;
+
+    /**
+     * place to store the config file
+     */
+    private final File bootstrapConfigFile;
+
+    /**
+     * the servlet context
+     */
+    private final ServletContext context;
+
+    /**
+     * the place for the repository config template
+     * todo: to be configured
+     */
+    private final String configTemplate = "/WEB-INF/templates/repository.xml";
+
+    /**
+     * the place for the bootstrap properties template
+     * todo: to be configured
+     */
+    private final String bootstrapTemplate = "/WEB-INF/templates/bootstrap.properties";
+
+    /**
+     * Creates a new installer
+     * @param bootstrapConfigFile the location for the config file
+     * @param context the servlet context for accessing resources
+     */
+    public Installer(File bootstrapConfigFile, ServletContext context) {
+        this.bootstrapConfigFile = bootstrapConfigFile;
+        this.context = context;
+    }
+
+    /**
+     * Handles the installation.
+     *
+     * @param req the servlet request with the input parameters
+     * @return the installation return code
+     *
+     * @throws ServletException if a servlet error occurs.
+     * @throws IOException if an I/O error occurs.
+     */
+    public int installRepository(HttpServletRequest req)
+            throws ServletException, IOException {
+        String repHome = req.getParameter("repository_home");
+        String repXml = req.getParameter("repository_xml");
+        String mode = req.getParameter("mode");
+        if (repHome == null || mode == null) {
+            return C_INVALID_INPUT;
+        }
+        if (repXml == null || repXml.length() == 0) {
+            repXml = repHome + "/repository.xml";
+        }
+        File home = new File(repHome);
+        File config = new File(repXml);
+        if ("new".equals(mode)) {
+            if (home.exists()) {
+                log.error("Trying to install new repository home '{}' but already exists", repHome);
+                return C_HOME_EXISTS;
+            }
+            if (config.exists()) {
+                log.error("Trying to install new repository config '{}' but already exists", repXml);
+                return C_CONFIG_EXISTS;
+            }
+            log.info("Creating new repository home '{}'", repHome);
+            home.mkdirs();
+            // install repository xml
+            try {
+                installRepositoryConfig(config);
+            } catch (IOException e) {
+                log.error("Error while installing new repository config '{}': {}", repXml, e.toString());
+                return C_BOOTSTRAP_EXISTS;
+            }
+        } else {
+            if (!home.exists()) {
+                log.error("Trying to use exisintg repository home '{}' but does not exists", repHome);
+                return C_HOME_MISSING;
+            }
+            if (!config.exists()) {
+                log.error("Trying to use existing repository config '{}' but does not exists", repXml);
+                return C_CONFIG_MISSING;
+            }
+        }
+        // install bootstrap.properties
+        try {
+            installBootstrap(bootstrapConfigFile, repHome, repXml);
+        } catch (IOException e) {
+            log.error("Error while installing '{}': {}", bootstrapConfigFile.getPath(), e.toString());
+            return C_INSTALL_ERROR;
+        }
+        return C_INSTALL_OK;
+    }
+
+    /**
+     * Installs the repository config file from the template
+     * @param dest the destination location
+     * @throws IOException if an I/O error occurs.
+     */
+    private void installRepositoryConfig(File dest) throws IOException {
+        log.info("Creating new repository config: {}", dest.getPath());
+        InputStream in = context.getResourceAsStream(configTemplate);
+        OutputStream out = new FileOutputStream(dest);
+        byte[] buffer = new byte[8192];
+        int read;
+        while ((read = in.read(buffer)) >= 0) {
+            out.write(buffer, 0, read);
+        }
+        in.close();
+        out.close();
+    }
+
+    /**
+     * Installs the bootstrap config file from the template
+     * @param dest the destination location
+     * @param repHome the repository home location
+     * @param repXml the repository xml location
+     * @throws IOException if an I/O error occurs
+     */
+    private void installBootstrap(File dest, String repHome, String repXml)
+            throws IOException {
+        log.info("Creating new bootstrap properties: {}", dest.getPath());
+        InputStream in = context.getResourceAsStream(bootstrapTemplate);
+        Properties props = new Properties();
+        props.load(in);
+        props.setProperty("repository.home", repHome);
+        props.setProperty("repository.config", repXml);
+        in.close();
+        OutputStream out = new FileOutputStream(dest);
+        props.store(out, "bootstrap properties for the repository startup servlet.");
+        out.close();
+    }
+
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/Installer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/Installer.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url rev

Added: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JNDIConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JNDIConfig.java?view=auto&rev=495531
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JNDIConfig.java (added)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JNDIConfig.java Fri Jan 12 01:38:40 2007
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.jackrabbit.j2ee;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Properties;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+/**
+ * The JNDI config hold information about JNDI connection details.
+ *
+ * It supports the following properties and init parameters:
+ * <xmp>
+ * +-------------------+--------------------+
+ * | Property Name     | Init-Param Name    |
+ * +-------------------+--------------------+
+ * | jndi.enable       | {provider spec.}   |
+ * | java.naming.*     | java.naming.*      |
+ * +-------------------+--------------------+
+ * </xmp>
+ */
+public class JNDIConfig extends AbstractConfig {
+
+    private boolean jndiEnabled;
+
+    private String jndiName;
+
+    private final BootstrapConfig parentConfig;
+
+    private Properties jndiEnv = new Properties();
+
+
+    public JNDIConfig(BootstrapConfig parentConfig) {
+        this.parentConfig = parentConfig;
+    }
+
+
+    public String getJndiName() {
+        return jndiName;
+    }
+
+    public void setJndiName(String jndiName) {
+        this.jndiName = jndiName;
+    }
+
+    public boolean enabled() {
+        return jndiEnabled;
+    }
+
+    public String getJndiEnabled() {
+        return String.valueOf(jndiEnabled);
+    }
+
+    public void setJndiEnabled(String jndiEnabled) {
+        this.jndiEnabled = Boolean.valueOf(jndiEnabled).booleanValue();
+    }
+
+    public Properties getJndiEnv() {
+        return jndiEnv;
+    }
+
+    public void init(Properties props) throws ServletException {
+        super.init(props);
+        // add all props whose name starts with 'java.namming.' to the env
+        Iterator iter = props.keySet().iterator();
+        while (iter.hasNext()) {
+            String name = (String) iter.next();
+            if (name.startsWith("java.naming.")) {
+                jndiEnv.put(name, props.getProperty(name));
+            }
+        }
+    }
+
+    public void init(ServletConfig ctx) throws ServletException  {
+        super.init(ctx);
+        // add all params whose name starts with 'java.namming.' to the env
+        Enumeration enum = ctx.getInitParameterNames();
+        while (enum.hasMoreElements()) {
+            String name = (String) enum.nextElement();
+            if (name.startsWith("java.naming.")) {
+                jndiEnv.put(name, ctx.getInitParameter(name));
+            }
+        }
+        // enable jndi if url is specified
+        jndiEnabled = jndiEnv.containsKey("java.naming.provider.url");
+    }
+
+
+    public void validate() {
+        if (jndiName == null) {
+            jndiName = parentConfig.getRepositoryName();
+        }
+        valid = true;
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JNDIConfig.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JNDIConfig.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url rev

Added: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RMIConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RMIConfig.java?view=auto&rev=495531
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RMIConfig.java (added)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RMIConfig.java Fri Jan 12 01:38:40 2007
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.jackrabbit.j2ee;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.rmi.registry.Registry;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+/**
+ * The RMI config hold information about RMI connection details.
+ *
+ * It supports the following properties and init parameters:
+ * <xmp>
+ * +-------------------+--------------------+
+ * | Property Name     | Init-Param Name    |
+ * +-------------------+--------------------+
+ * | rmi.enable        | {rmi-port sepc.}   |
+ * | rmi.host          | rmi-host           |
+ * | rmi.port          | rmi-port           |
+ * | rmi.name          | {repository name}  |
+ * | rmi.url           | rmi-url            |
+ * +-------------------+--------------------+
+ * </xmp>
+ */
+public class RMIConfig extends AbstractConfig {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(RMIConfig.class);
+
+    private boolean rmiEnabled;
+
+    private int rmiPort = -1;
+
+    private String rmiHost;
+
+    private String rmiName;
+
+    private String rmiUri;
+
+    private final BootstrapConfig parentConfig;
+
+
+    public RMIConfig(BootstrapConfig parentConfig) {
+        this.parentConfig = parentConfig;
+    }
+
+    public void init(ServletConfig ctx) throws ServletException {
+        super.init(ctx);
+        // enable rmi if port was set
+        rmiEnabled = rmiPort >= 0;
+    }
+
+    public String getRmiName() {
+        return rmiName;
+    }
+
+    public void setRmiName(String rmiName) {
+        this.rmiName = rmiName;
+    }
+
+    public boolean enabled() {
+        return rmiEnabled;
+    }
+
+    public String getRmiEnabled() {
+        return String.valueOf(rmiEnabled);
+    }
+
+    public void setRmiEnabled(String rmiEnabled) {
+        this.rmiEnabled = Boolean.valueOf(rmiEnabled).booleanValue();
+    }
+
+    public int rmiPort() {
+        return rmiPort;
+    }
+
+    public String getRmiPort() {
+        return String.valueOf(rmiPort);
+    }
+
+    public void setRmiPort(String rmiPort) {
+        this.rmiPort = Integer.decode(rmiPort).intValue();
+    }
+
+    public String getRmiHost() {
+        return rmiHost;
+    }
+
+    public void setRmiHost(String rmiHost) {
+        this.rmiHost = rmiHost;
+    }
+
+    public String getRmiUri() {
+        return rmiUri;
+    }
+
+    public void setRmiUri(String rmiUri) {
+        this.rmiUri = rmiUri;
+    }
+
+    public void validate() {
+        if (!rmiEnabled) {
+            return;
+        }
+
+        if (rmiUri != null && rmiUri.length() > 0) {
+            // URI takes precedences, so check whether the configuration has to
+            // be set from the URI
+            try {
+                URI uri = new URI(rmiUri);
+
+                // extract values from the URI, check later
+                rmiHost = uri.getHost();
+                rmiPort = uri.getPort();
+                rmiName = uri.getPath();
+
+            } catch (URISyntaxException e) {
+                log.warn("Cannot parse RMI URI '" + rmiUri + "'.", e);
+                rmiUri = null; // clear RMI URI use another one
+                rmiHost = null; // use default host, ignore rmi-host param
+            }
+
+            // cut of leading slash from name if defined at all
+            if (rmiName != null && rmiName.startsWith("/")) {
+                rmiName = rmiName.substring(1);
+            }
+        }
+
+        // check RMI port
+        if (rmiPort == -1 || rmiPort == 0) {
+            // accept -1 or 0 as a hint to use the default
+            rmiPort = Registry.REGISTRY_PORT;
+        } else if (rmiPort < -1 || rmiPort > 0xFFFF) {
+            // emit a warning if out of range, use defualt in this case
+            log.warn("Invalid port in rmi-port param " + rmiPort + ". using default port.");
+            rmiPort = Registry.REGISTRY_PORT;
+        }
+
+        // check host - use an empty name if null (i.e. not configured)
+        if (rmiHost == null) {
+            rmiHost = "";
+        }
+
+        // check name - use repositoryName if empty or null
+        if (rmiName == null || rmiName.length() ==0) {
+            rmiName = parentConfig.getRepositoryName();
+        }
+
+        // reconstruct the rmiURI now because values might have been changed
+        rmiUri = "//" + rmiHost + ":" + rmiPort + "/" + rmiName;
+        valid = true;
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RMIConfig.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RMIConfig.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url rev

Modified: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryAccessServlet.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryAccessServlet.java?view=diff&rev=495531&r1=495530&r2=495531
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryAccessServlet.java (original)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryAccessServlet.java Fri Jan 12 01:38:40 2007
@@ -20,21 +20,26 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.util.Properties;
+
 import javax.jcr.Repository;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
-import java.net.MalformedURLException;
-import java.rmi.NotBoundException;
-import java.rmi.RemoteException;
-import java.util.Enumeration;
-import java.util.Properties;
 
 /**
  * This Class implements a servlet that is used as unified mechanism to retrieve
- * a jcr repository either through JNID, RMI or JCRWebdavServer.
+ * a jcr repository either through JNDI or RMI.
  */
 public class RepositoryAccessServlet extends HttpServlet {
 
@@ -44,92 +49,147 @@
     private static final Logger log = LoggerFactory.getLogger(RepositoryAccessServlet.class);
 
     /**
-     * the 'repository-name' init parameter
+     * initial param name for the bootstrap config location
      */
-    public final static String INIT_PARAM_REPOSITORY_NAME = "repository-name";
+    public final static String INIT_PARAM_BOOTSTRAP_CONFIG = "bootstrap-config";
 
     /**
-     * the 'rmi-uri' init parameter
+     * Context parameter name for 'this' instance.
      */
-    public final static String INIT_PARAM_RMI_URI = "rmi-uri";
+    private final static String CTX_PARAM_THIS = "repository.access.servlet";
 
     /**
-     * the 'missing-auth-mapping' init parameter
+     * the bootstrap config
      */
-    //public final static String INIT_PARAM_MISSING_AUTH_MAPPING = "missing-auth-mapping";
-
-    private static final String CTX_ATTR_REPOSITORY = "jcr.repository";
+    private BootstrapConfig config;
 
-    private static final String CTX_ATTR_REPOSITORY_NAME = "jcr.repository.name";
-
-    private static final String CTX_ATTR_REPOSITORY_RMI_URI = "jcr.repository.rmiURI";
+    /**
+     * the initialized initial context
+     */
+    private InitialContext jndiContext;
 
-    private static final String CTX_ATTR_REPOSITORY_JNDI_CONTEXT = "jcr.repository.jndiContext";
+    /**
+     * the repository
+     */
+    private Repository repository;
 
     /**
-     * Initializes this servlet
+     * Initializes the servlet.<br>
+     * Please note that only one repository startup servlet may exist per
+     * webapp. it registers itself as context attribute and acts as singleton.
      *
-     * @throws javax.servlet.ServletException
+     * @throws ServletException if a same servlet is already registered or of
+     * another initialization error occurs.
      */
     public void init() throws ServletException {
-        log.info("RepositoryAccessServlet initializing...");
-        // fetching the name
-        String repositoryName = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_NAME);
-        if (repositoryName == null) {
-            repositoryName = "default";
+        // check if servlet is defined twice
+        if (getServletContext().getAttribute(CTX_PARAM_THIS) !=  null) {
+            throw new ServletException("Only one repository access servlet allowed per web-app.");
         }
-        getServletContext().setAttribute(CTX_ATTR_REPOSITORY_NAME, repositoryName);
-
-        // fetching the rmiuri
-        getServletContext().setAttribute(CTX_ATTR_REPOSITORY_RMI_URI, getRMIUri());
-
-        // setup initial context
-        getServletContext().setAttribute(CTX_ATTR_REPOSITORY_JNDI_CONTEXT, getInitialContext());
-
+        getServletContext().setAttribute(CTX_PARAM_THIS, this);
         log.info("RepositoryAccessServlet initialized.");
     }
 
-    private InitialContext getInitialContext() {
-        // retrieve JNDI Context environment
-        try {
-            Properties env = new Properties();
-            Enumeration names = getServletConfig().getInitParameterNames();
-            while (names.hasMoreElements()) {
-                String name = (String) names.nextElement();
-                if (name.startsWith("java.naming.")) {
-                    String initParam = getServletConfig().getInitParameter(name);
-                    if (initParam.equals("")) {
-                        log.info("  ignoring empty JNDI init param: " + name);
-                    } else {
-                        env.put(name, initParam);
-                        log.info("  adding property to JNDI environment: " + name + "=" + initParam);
+    /**
+     * Returns the instance of this servlet
+     * @param ctx the servlet context
+     * @return this servlet
+     */
+    private static RepositoryAccessServlet getInstance(ServletContext ctx) {
+        return (RepositoryAccessServlet) ctx.getAttribute(CTX_PARAM_THIS);
+    }
+
+    /**
+     * Returns the bootstrap config
+     * @return the bootstrap config
+     * @throws ServletException if the config is not valid
+     */
+    private BootstrapConfig getConfig() throws ServletException {
+        if (config == null) {
+            // check if there is a loadable bootstrap config
+            Properties bootstrapProps = new Properties();
+            String bstrp = getServletConfig().getInitParameter(INIT_PARAM_BOOTSTRAP_CONFIG);
+            if (bstrp != null) {
+                // check if it's a web-resource
+                InputStream in = getServletContext().getResourceAsStream(bstrp);
+                if (in == null) {
+                    // check if it's a file
+                    File file = new File(bstrp);
+                    if (file.canRead()) {
+                        try {
+                            in = new FileInputStream(file);
+                        } catch (FileNotFoundException e) {
+                            log.error("Error while opening bootstrap properties: {}", e.toString());
+                            throw new ServletException("Error while opening bootstrap properties: " + e.toString());
+                        }
+                    }
+                }
+                if (in != null) {
+                    try {
+                        bootstrapProps.load(in);
+                    } catch (IOException e) {
+                        log.error("Error while loading bootstrap properties: {}", e.toString());
+                        throw new ServletException("Error while loading bootstrap properties: " + e.toString());
+                    } finally {
+                        try {
+                            in.close();
+                        } catch (IOException e) {
+                            // ignore
+                        }
                     }
                 }
             }
-            return new InitialContext(env);
-        } catch (NamingException e) {
-            log.error("Create initial context: " + e.toString());
-            return null;
+
+            // read bootstrap config
+            BootstrapConfig tmpConfig = new BootstrapConfig();
+            tmpConfig.init(getServletConfig());
+            tmpConfig.init(bootstrapProps);
+            tmpConfig.validate();
+            if (!tmpConfig.isValid()) {
+                log.error("Repository acesss configuration is not valid.");
+                throw new ServletException("Repository access configuration is not valid.");
+            }
+            tmpConfig.logInfos();
+            config = tmpConfig;
         }
+        return config;
     }
 
-    private String getRMIUri() {
-        // setup repository name
-        return getServletConfig().getInitParameter(INIT_PARAM_RMI_URI);
+    /**
+     * Returns the initial jndi context or <code>null</code> if the jndi access
+     * is not configured or erroous.
+     * @return the initial context or <code>null</code>
+     */
+    private InitialContext getInitialContext() {
+        if (jndiContext == null && config.getJndiConfig().enabled()) {
+            // retrieve JNDI Context environment
+            try {
+                jndiContext = new InitialContext(config.getJndiConfig().getJndiEnv());
+            } catch (NamingException e) {
+                log.error("Create initial context: " + e.toString());
+            }
+        }
+        return jndiContext;
     }
 
     /**
-     * tries to retrieve the repository using RMI
+     * Checks if the repository is available via JNDI and returns it.
+     * @return the repository or <code>null</code>
+     * @throws ServletException if this servlet is not properly configured.
      */
-    private static Repository getRepositoryByJNDI(ServletContext ctx) {
+    private Repository getRepositoryByJNDI() throws ServletException {
+        BootstrapConfig config = getConfig();
+        if (!config.getJndiConfig().isValid() || !config.getJndiConfig().enabled()) {
+            return null;
+        }
         // acquire via JNDI
-        String repositoryName = (String) ctx.getAttribute(CTX_ATTR_REPOSITORY_NAME);
-        InitialContext jndiContext = (InitialContext) ctx.getAttribute(CTX_ATTR_REPOSITORY_JNDI_CONTEXT);
-        if (jndiContext == null) {
+        String repositoryName = config.getRepositoryName();
+        InitialContext ctx = getInitialContext();
+        if (ctx == null) {
             return null;
         }
         try {
-            Repository r = (Repository) jndiContext.lookup(repositoryName);
+            Repository r = (Repository) ctx.lookup(repositoryName);
             log.info("Acquired repository via JNDI.");
             return r;
         } catch (NamingException e) {
@@ -139,18 +199,25 @@
     }
 
     /**
-     * tries to retrieve the repository using RMI
+     * Checks if the repository is available via RMI and returns it.
+     * @return the repository or <code>null</code>
+     * @throws ServletException if this servlet is not properly configured.
      */
-    private static Repository getRepositoryByRMI(ServletContext ctx) {
+    private Repository getRepositoryByRMI() throws ServletException {
+        BootstrapConfig config = getConfig();
+        if (!config.getRmiConfig().isValid() || !config.getRmiConfig().enabled()) {
+            return null;
+        }
+
         // acquire via RMI
-        String rmiURI = (String) ctx.getAttribute(CTX_ATTR_REPOSITORY_RMI_URI);
+        String rmiURI = config.getRmiConfig().getRmiUri();
         if (rmiURI == null) {
             return null;
         }
         log.info("  trying to retrieve repository using rmi. uri=" + rmiURI);
         ClientFactoryDelegater cfd;
         try {
-            Class clazz = Class.forName("org.apache.jackrabbit.j2ee.RMIClientFactoryDelegater");
+            Class clazz = Class.forName(getServerFactoryDelegaterClass());
             cfd = (ClientFactoryDelegater) clazz.newInstance();
         } catch (NoClassDefFoundError e) {
             log.error("Unable to locate RMI ClientRepositoryFactory. jcr-rmi.jar missing? " + e.toString());
@@ -171,54 +238,75 @@
     }
 
     /**
-     * Returns the JSR170 repository
+     * Return the fully qualified name of the class providing the client
+     * repository. The class whose name is returned must implement the
+     * {@link ClientFactoryDelegater} interface.
+     *
+     * @return the qfn of the factory class.
+     */
+    protected String getServerFactoryDelegaterClass() {
+        return getClass().getName() + "$RMIClientFactoryDelegater";
+    }
+
+    /**
+     * Returns the JCR repository
      *
-     * @return a jsr170 repository
+     * @return a JCR repository
      * @throws IllegalStateException if the repository is not available in the context.
      */
-    public static Repository getRepository(ServletContext ctx) {
-        Repository repository = (Repository) ctx.getAttribute(CTX_ATTR_REPOSITORY);
-        if (repository != null) {
+    public Repository getRepository() {
+        try {
+            if (repository == null) {
+                // try to retrieve via jndi
+                repository = getRepositoryByJNDI();
+            }
+            if (repository == null) {
+                // try to get via rmi
+                repository = getRepositoryByRMI();
+            }
+            if (repository == null) {
+                throw new ServletException("N/A");
+            }
             return repository;
-        } else {
-            repository = getRepositoryByRMI(ctx);
-        }
-        // try to retrieve via jndi
-        if (repository == null) {
-            repository = getRepositoryByJNDI(ctx);
-        }
-        // error
-        if (repository == null) {
+        } catch (ServletException e) {
             log.error("The repository is not available. Check config of 'RepositoryAccessServlet'.");
             throw new IllegalStateException("The repository is not available.");
-        } else {
-            ctx.setAttribute(CTX_ATTR_REPOSITORY, repository);
-            log.info(repository.getDescriptor(Repository.REP_NAME_DESC) + " v" + repository.getDescriptor(Repository.REP_VERSION_DESC));
-            return repository;
         }
     }
-}
 
-/**
- * optional class for RMI, will only be used, if RMI client is present
- */
-abstract class ClientFactoryDelegater {
+    /**
+     * Returns the JCR repository
+     *
+     * @param ctx the servlet context
+     * @return a JCR repository
+     * @throws IllegalStateException if the repository is not available in the context.
+     */
+    public static Repository getRepository(ServletContext ctx) {
+        return getInstance(ctx).getRepository();
+    }
 
-    public abstract Repository getRepository(String uri)
-            throws RemoteException, MalformedURLException, NotBoundException;
-}
+    /**
+     * optional class for RMI, will only be used, if RMI client is present
+     */
+    protected static abstract class ClientFactoryDelegater {
 
-/**
- * optional class for RMI, will only be used, if RMI server is present
- */
-class RMIClientFactoryDelegater extends ClientFactoryDelegater {
+        public abstract Repository getRepository(String uri)
+                throws RemoteException, MalformedURLException, NotBoundException;
+    }
 
-    // only used to enforce linking upon Class.forName()
-    static String FactoryClassName = ClientRepositoryFactory.class.getName();
+    /**
+     * optional class for RMI, will only be used, if RMI server is present
+     */
+    protected static class RMIClientFactoryDelegater extends ClientFactoryDelegater {
 
-    public Repository getRepository(String uri)
-            throws MalformedURLException, NotBoundException, RemoteException {
-        System.setProperty("java.rmi.server.useCodebaseOnly", "true");
-        return new ClientRepositoryFactory().getRepository(uri);
+        // only used to enforce linking upon Class.forName()
+        static String FactoryClassName = ClientRepositoryFactory.class.getName();
+
+        public Repository getRepository(String uri)
+                throws MalformedURLException, NotBoundException, RemoteException {
+            System.setProperty("java.rmi.server.useCodebaseOnly", "true");
+            return new ClientRepositoryFactory().getRepository(uri);
+        }
     }
-}
\ No newline at end of file
+}
+

Modified: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryStartupServlet.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryStartupServlet.java?view=diff&rev=495531&r1=495530&r2=495531
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryStartupServlet.java (original)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/RepositoryStartupServlet.java Fri Jan 12 01:38:40 2007
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.j2ee;
 
+import org.apache.jackrabbit.api.JackrabbitRepository;
 import org.apache.jackrabbit.core.RepositoryImpl;
 import org.apache.jackrabbit.core.config.RepositoryConfig;
 import org.apache.jackrabbit.rmi.server.ServerAdapterFactory;
@@ -30,8 +31,6 @@
 import java.io.InputStream;
 import java.net.InetAddress;
 import java.net.ServerSocket;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.net.UnknownHostException;
 import java.rmi.AlreadyBoundException;
 import java.rmi.Naming;
@@ -40,22 +39,24 @@
 import java.rmi.registry.LocateRegistry;
 import java.rmi.registry.Registry;
 import java.rmi.server.RMIServerSocketFactory;
-import java.util.Enumeration;
 import java.util.Properties;
 
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 /**
  * The RepositoryStartupServlet starts a jackrabbit repository and registers it
  * to the JNDI environment and optional to the RMI registry.
  * <p id="registerAlgo">
  * <b>Registration with RMI</b>
- * <p>
+ * <p/>
  * Upon successfull creation of the repository in the {@link #init()} method,
  * the repository is registered with an RMI registry if the web application is
  * so configured. To register with RMI, the following web application
@@ -66,36 +67,36 @@
  * repository is to be bound in the registry, and <code>rmi-uri</code>
  * designating an RMI URI complete with host, optional port and name to which
  * the object is bound.
- * <p>
+ * <p/>
  * If the <code>rmi-uri</code> parameter is configured with a non-empty value,
  * the <code>rmi-port</code> and <code>rmi-host</code> parameters are ignored.
  * The <code>repository-name</code> parameter is only considered if a non-empty
  * <code>rmi-uri</code> parameter is configured if the latter does not contain
  * a name to which to bind the repository.
- * <p>
+ * <p/>
  * This is the algorithm used to find out the host, port and name for RMI
  * registration:
  * <ol>
  * <li>If neither a <code>rmi-uri</code> nor a <code>rmi-host</code> nor a
- *      <code>rmi-port</code> parameter is configured, the repository is not
- *      registered with any RMI registry.
+ * <code>rmi-port</code> parameter is configured, the repository is not
+ * registered with any RMI registry.
  * <li>If a non-empty <code>rmi-uri</code> parameter is configured extract the
- *      host name (or IP address), port number and name to bind to from the
- *      URI. If the URI is not valid, host defaults to <code>0.0.0.0</code>
- *      meaning all interfaces on the local host, port defaults to the RMI
- *      default port (<code>1099</code>) and the name defaults to the value
- *      of the <code>repository-name</code> parameter.
+ * host name (or IP address), port number and name to bind to from the
+ * URI. If the URI is not valid, host defaults to <code>0.0.0.0</code>
+ * meaning all interfaces on the local host, port defaults to the RMI
+ * default port (<code>1099</code>) and the name defaults to the value
+ * of the <code>repository-name</code> parameter.
  * <li>If a non-empty <code>rmi-uri</code> is not configured, the host is taken
- *      from the <code>rmi-host</code> parameter, the port from the
- *      <code>rmi-port</code> parameter and the name to bind the repository to
- *      from the <code>repository-name</code> parameter. If the
- *      <code>rmi-host</code> parameter is empty or not configured, the host
- *      defaults to <code>0.0.0.0</code> meaning all interfaces on the local
- *      host. If the <code>rmi-port</code> parameter is empty, not configured,
- *      zero or a negative value, the default port for the RMI registry
- *      (<code>1099</code>) is used.
+ * from the <code>rmi-host</code> parameter, the port from the
+ * <code>rmi-port</code> parameter and the name to bind the repository to
+ * from the <code>repository-name</code> parameter. If the
+ * <code>rmi-host</code> parameter is empty or not configured, the host
+ * defaults to <code>0.0.0.0</code> meaning all interfaces on the local
+ * host. If the <code>rmi-port</code> parameter is empty, not configured,
+ * zero or a negative value, the default port for the RMI registry
+ * (<code>1099</code>) is used.
  * </ol>
- * <p>
+ * <p/>
  * After finding the host and port of the registry, the RMI registry itself
  * is acquired. It is assumed, that host and port primarily designate an RMI
  * registry, which should be active on the local host but has not been started
@@ -105,69 +106,67 @@
  * method is called to get a remote instance of the registry. Note, that
  * <code>getRegistry</code> does not create an actual registry on the given
  * host/port nor does it check, whether an RMI registry is active.
- * <p>
+ * <p/>
  * When the registry has been retrieved, either by creation or by just creating
  * a remote instance, the repository is bound to the configured name in the
  * registry.
- * <p>
+ * <p/>
  * Possible causes for registration failures include:
  * <ul>
  * <li>The web application is not configured to register with an RMI registry at
- *      all.
+ * all.
  * <li>The registry is expected to be running on a remote host but does not.
  * <li>The registry is expected to be running on the local host but cannot be
- *      accessed. Reasons include another application which does not act as an
- *      RMI registry is running on the configured port and thus blocks creation
- *      of a new RMI registry.
+ * accessed. Reasons include another application which does not act as an
+ * RMI registry is running on the configured port and thus blocks creation
+ * of a new RMI registry.
  * <li>An object may already be bound to the same name as is configured to be
- *      used for the repository.
+ * used for the repository.
  * </ul>
+ * <p/>
+ * <b>Note:</b> if a <code>bootstrap-config</code> init parameter is specified the
+ * servlet tries to read the respective resource, either as context resource or
+ * as file. The properties specified in this file override the init params
+ * specified in the <code>web.xml</code>.
+ * <p/>
+ * <p/>
+ * <b>Setup Wizard Functionality</b><br>
+ * When using the first time, the configuraition can miss the relevant
+ * repository parameters in the web.xml. if so, it must contain a
+ * <code>bootstrap-config</code> parameter that referrs to a propertiy file.
+ * This file must exsit for proper working. If not, the repository is not
+ * started.<br>
+ * If the servlet is not configured correctly and accessed via http, it will
+ * provide a simple wizard for the first time configuration. It propmpts for
+ * a new (or existing) repository home and will copy the templates of the
+ * repository.xml and bootstrap.properties to the respective location.
  */
 public class RepositoryStartupServlet extends HttpServlet {
 
-    /** the default logger */
+    /**
+     * the default logger
+     */
     private static final Logger log = LoggerFactory.getLogger(RepositoryStartupServlet.class);
 
-    /** initial param name for the repository config location */
-    public final static String INIT_PARAM_REPOSITORY_CONFIG = "repository-config";
-
-    /** initial param name for the repository home directory */
-    public final static String INIT_PARAM_REPOSITORY_HOME = "repository-home";
-
-    /** initial param name for the repository name */
-    public final static String INIT_PARAM_REPOSITORY_NAME = "repository-name";
-
-    /** initial param name for the rmi port */
-    public final static String INIT_PARAM_RMI_PORT = "rmi-port";
-
-    /** initial param name for the rmi host */
-    public final static String INIT_PARAM_RMI_HOST = "rmi-host";
-
-    /** initial param name for the rmi uri */
-    public final static String INIT_PARAM_RMI_URI = "rmi-uri";
+    /**
+     * the context attribute name foe 'this' instance.
+     */
+    private final static String CTX_PARAM_THIS = "repository.startup.servet";
 
-    /** initial param name for the log4j config properties */
-    public final static String INIT_PARAM_LOG4J_CONFIG = "log4j-config";
+    /**
+     * initial param name for the bootstrap config location
+     */
+    public final static String INIT_PARAM_BOOTSTRAP_CONFIG = "bootstrap-config";
 
-    /** the registered repository */
+    /**
+     * the registered repository
+     */
     private Repository repository;
 
-    /** the name of the repository as configured */
-    private String repositoryName;
-
-    /** the jndi context, created base on configuration */
-    private InitialContext jndiContext;
-
     /**
-     * The rmi uri, in the form of  '//${rmi-host}:${rmi-port}/${repository-name}'
-     * This field is only set to a non-<code>null</code> value, if registration
-     * of the repository to an RMI registry succeeded in the
-     * {@link #registerRMI()} method.
-     *
-     * @see #registerRMI()
-     * @see #unregisterRMI()
+     * the jndi context; created based on configuration
      */
-    private String rmiURI;
+    private InitialContext jndiContext;
 
     /**
      * Keeps a strong reference to the server side RMI repository instance to
@@ -183,114 +182,235 @@
     private Remote rmiRepository;
 
     /**
-     * Initializes the servlet
-     * @throws ServletException
+     * the file to the bootstrap config
+     */
+    private File bootstrapConfigFile;
+
+    /**
+     * The bootstrap configuration
+     */
+    private BootstrapConfig config;
+
+    /**
+     * Initializes the servlet.<br>
+     * Please note that only one repository startup servlet may exist per
+     * webapp. it registers itself as context attribute and acts as singleton.
+     *
+     * @throws ServletException if a same servlet is already registered or of
+     * another initialization error occurs.
      */
     public void init() throws ServletException {
         super.init();
+        // check if servlet is defined twice
+        if (getServletContext().getAttribute(CTX_PARAM_THIS) !=  null) {
+            throw new ServletException("Only one repository startup servlet allowed per web-app.");
+        }
+        getServletContext().setAttribute(CTX_PARAM_THIS, this);
+        startup();
+    }
+
+    /**
+     * Returns an instance of this servlet. Please note, that only 1
+     * repository startup servlet can exist per webapp.
+     *
+     * @param context the servlet context
+     * @return this servlet
+     */
+    public static RepositoryStartupServlet getInstance(ServletContext context) {
+        return (RepositoryStartupServlet) context.getAttribute(CTX_PARAM_THIS);
+    }
+
+    /**
+     * Configures and starts the repository. It registers it then to the
+     * RMI registry and bind is to the JNDI context if so configured.
+     * @throws ServletException if an error occurs.
+     */
+    public void startup() throws ServletException {
+        if (repository != null) {
+            log.error("Startup: Repository already running.");
+            throw new ServletException("Repository already running.");
+        }
         log.info("RepositoryStartupServlet initializing...");
-        initRepository();
         try {
-        registerRMI();
+            configure();
+            initRepository();
+            registerRMI();
             registerJNDI();
+            log.info("RepositoryStartupServlet initialized.");
         } catch (ServletException e) {
             // shutdown repository
             shutdownRepository();
-            log.error("RepositoryStartupServlet initializing failed: "+ e, e);
-            throw e;
+            log.error("RepositoryStartupServlet initializing failed: " + e, e);
         }
-        log.info("RepositoryStartupServlet initialized.");
     }
 
     /**
-     * destroy the servlet
+     * Does a shutdown of the repository and deregisters it from the RMI
+     * registry and unbinds if from the JNDI context if so configured.
      */
-    public void destroy() {
-        super.destroy();
-        if (log == null) {
-            log("RepositoryStartupServlet shutting down...");
+    public void shutdown() {
+        if (repository == null) {
+            log.info("Shutdown: Repository already stopped.");
         } else {
             log.info("RepositoryStartupServlet shutting down...");
-        }
-        shutdownRepository();
-        unregisterRMI();
-        unregisterJNDI();
-        if (log == null) {
-            log("RepositoryStartupServlet shut down.");
-        } else {
+            shutdownRepository();
+            unregisterRMI();
+            unregisterJNDI();
             log.info("RepositoryStartupServlet shut down.");
         }
     }
 
     /**
-     * Creates a new Repository based on configuration
-     * @throws ServletException
+     * Restarts the repository.
+     * @throws ServletException if an error occurs.
+     * @see #shutdown()
+     * @see #startup()
+     */
+    public void restart() throws ServletException {
+        if (repository != null) {
+            shutdown();
+        }
+        startup();
+    }
+
+    /**
+     * destroy the servlet
      */
-    private void initRepository() throws ServletException {
-        // setup home directory
-        String repHome = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_HOME);
-        if (repHome==null) {
-            log.error(INIT_PARAM_REPOSITORY_HOME + " missing.");
-            throw new ServletException(INIT_PARAM_REPOSITORY_HOME + " missing.");
+    public void destroy() {
+        super.destroy();
+        shutdown();
+    }
+
+    /**
+     * Returns the started repository or <code>null</code> if not started
+     * yet.
+     * @return the JCR repository
+     */
+    public Repository getRepository() {
+        return repository;
+    }
+
+    /**
+     * Reads the configuration and initializes the {@link #config} field if
+     * successful.
+     * @throws ServletException if an error occurs.
+     */
+    private void configure() throws ServletException {
+        // check if there is a loadable bootstrap config
+        Properties bootstrapProps = new Properties();
+        String bstrp = getServletConfig().getInitParameter(INIT_PARAM_BOOTSTRAP_CONFIG);
+        if (bstrp != null) {
+            // check if it's a web-resource
+            InputStream in = getServletContext().getResourceAsStream(bstrp);
+            if (in == null) {
+                // check if it's a file
+                bootstrapConfigFile = new File(bstrp);
+                if (bootstrapConfigFile.canRead()) {
+                    try {
+                        in = new FileInputStream(bootstrapConfigFile);
+                    } catch (FileNotFoundException e) {
+                        log.error("Error while opening bootstrap properties: {}", e.toString());
+                        throw new ServletException("Error while opening bootstrap properties: " + e.toString());
+                    }
+                }
+            }
+            if (in != null) {
+                try {
+                    bootstrapProps.load(in);
+                } catch (IOException e) {
+                    log.error("Error while loading bootstrap properties: {}", e.toString());
+                    throw new ServletException("Error while loading bootstrap properties: " + e.toString());
+                } finally {
+                    try {
+                        in.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+            }
         }
-        File repositoryHome;
-        try {
-            repositoryHome = new File(repHome).getCanonicalFile();
-        } catch (IOException e) {
-            log.error(INIT_PARAM_REPOSITORY_HOME + " invalid." + e.toString());
-            throw new ServletException(INIT_PARAM_REPOSITORY_HOME + " invalid." + e.toString());
+
+        // read bootstrap config
+        config = new BootstrapConfig();
+        config.init(getServletConfig());
+        config.init(bootstrapProps);
+        config.validate();
+        if (!config.isValid()
+                || config.getRepositoryHome() == null
+                || config.getRepositoryConfig() == null) {
+            if (bstrp == null) {
+                log.error("Repository startup configuration is not valid.");
+                throw new ServletException("Repository startup configuration is not valid.");
+            } else {
+                log.error("Repository startup configuration is not valid but a bootstrap config is specified.");
+                log.error("Either create the {} file or", bstrp);
+                log.error("use the '/config/index.jsp' for easy configuration.");
+                throw new ServletException("Repository startup configuration is not valid.");
+            }
         }
-        log.info("  repository-home = " + repositoryHome.getPath());
+        config.logInfos();
+    }
 
+    /**
+     * Creates a new Repository based on the configuration and initializes the
+     * {@link #repository} field if successful.
+     *
+     * @throws ServletException if an error occurs
+     */
+    private void initRepository() throws ServletException {
         // get repository config
-        String repConfig = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_CONFIG);
-        if (repConfig==null) {
-            log.error(INIT_PARAM_REPOSITORY_CONFIG + " missing.");
-            throw new ServletException(INIT_PARAM_REPOSITORY_CONFIG + " missing.");
+        File repHome;
+        try {
+            repHome = new File(config.getRepositoryHome()).getCanonicalFile();
+        } catch (IOException e) {
+            log.error("Repository startup configuration invalid: " + e.toString());
+            throw new ServletException("Repository startup configuration invalid: " + e.toString());
         }
-        log.info("  repository-config = " + repConfig);
-
+        String repConfig = config.getRepositoryConfig();
         InputStream in = getServletContext().getResourceAsStream(repConfig);
-        if (in==null) {
+        if (in == null) {
             try {
-                in = new FileInputStream(new File(repositoryHome, repConfig));
+                in = new FileInputStream(new File(repConfig));
             } catch (FileNotFoundException e) {
-                log.error(INIT_PARAM_REPOSITORY_CONFIG + " invalid." + e.toString());
-                throw new ServletException(INIT_PARAM_REPOSITORY_CONFIG + " invalid." + e.toString());
+                // fallback to old config
+                try {
+                    in = new FileInputStream(new File(repHome, repConfig));
+                } catch (FileNotFoundException e1) {
+                    log.error("Repository startup configuration invalid: " + e1.toString());
+                    throw new ServletException("Repository startup configuration invalid: " + e.toString());
+                }
             }
         }
 
-        // get repository name
-        repositoryName = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_NAME);
-        if (repositoryName==null) {
-            repositoryName="default";
-        }
-        log.info("  repository-name = " + repositoryName);
-
         try {
-            repository = createRepository(new InputSource(in), repositoryHome);
+            repository = createRepository(new InputSource(in), repHome);
         } catch (RepositoryException e) {
             throw new ServletException("Error while creating repository", e);
         }
     }
 
     /**
-     * Shuts down the repository
+     * Shuts down the repository. If the repository is an instanceof
+     * {@link JackrabbitRepository} it's {@link JackrabbitRepository#shutdown()}
+     * method is called. in any case, the {@link #repository} field is
+     * <code>nulled</code>.
      */
     private void shutdownRepository() {
-        if (repository instanceof RepositoryImpl) {
-            ((RepositoryImpl) repository).shutdown();
-            repository = null;
+        if (repository instanceof JackrabbitRepository) {
+            ((JackrabbitRepository) repository).shutdown();
         }
+        repository = null;
     }
 
     /**
-     * Creates the repository for the given config and homedir.
+     * Creates the repository instance for the given config and homedir.
+     * Subclasses may override this method of providing own implementations of
+     * a {@link Repository}.
      *
-     * @param is
-     * @param homedir
-     * @return
-     * @throws RepositoryException
+     * @param is input source of the repository config
+     * @param homedir the repository home directory
+     * @return a new jcr repository.
+     * @throws RepositoryException if an error during creation occurs.
      */
     protected Repository createRepository(InputSource is, File homedir)
             throws RepositoryException {
@@ -299,40 +419,29 @@
     }
 
     /**
-     * Registers the repository in the JNDI context
+     * Binds the repository to the JNDI context
+     * @throws ServletException if an error occurs.
      */
     private void registerJNDI() throws ServletException {
-        // registering via jndi
-        Properties env = new Properties();
-        Enumeration names = getServletConfig().getInitParameterNames();
-        while (names.hasMoreElements()) {
-            String name = (String) names.nextElement();
-            if (name.startsWith("java.naming.")) {
-                String initParam = getServletConfig().getInitParameter(name);
-                if (initParam.equals("")) {
-                    log.info("  ignoring empty JNDI init param: " + name);
-                } else {
-                    env.put(name, initParam);
-                    log.info("  adding property to JNDI environment: " + name + "=" + initParam);
-                }
+        JNDIConfig jc = config.getJndiConfig();
+        if (jc.isValid() && jc.enabled()) {
+            try {
+                jndiContext = new InitialContext(jc.getJndiEnv());
+                jndiContext.bind(jc.getJndiName(), repository);
+                log.info("Repository bound to JNDI with name: " + jc.getJndiName());
+            } catch (NamingException e) {
+                throw new ServletException("Unable to bind repository using JNDI.", e);
             }
         }
-        try {
-            jndiContext = new InitialContext(env);
-            jndiContext.bind(repositoryName, repository);
-            log.info("Repository bound to JNDI with name: " + repositoryName);
-        } catch (NamingException e) {
-            throw new ServletException("Unable to bind repository using JNDI.", e);
-        }
     }
 
     /**
-     * Unregisters the repository from the JNDI context
+     * Unbinds the repository from the JNDI context.
      */
     private void unregisterJNDI() {
         if (jndiContext != null) {
             try {
-                jndiContext.unbind(repositoryName);
+                jndiContext.unbind(config.getJndiConfig().getJndiName());
             } catch (NamingException e) {
                 log("Error while unbinding repository from JNDI: " + e);
             }
@@ -344,77 +453,14 @@
      * application. See <a href="#registerAlgo">Registration with RMI</a> in the
      * class documentation for a description of the algorithms used to register
      * the repository with an RMI registry.
+     * @throws ServletException if an error occurs.
      */
     private void registerRMI() throws ServletException {
-        // check registering via RMI
-        String rmiPortStr = getServletConfig().getInitParameter(INIT_PARAM_RMI_PORT);
-        String rmiHost = getServletConfig().getInitParameter(INIT_PARAM_RMI_HOST);
-        String rmiURI = getServletConfig().getInitParameter(INIT_PARAM_RMI_URI);
-
-        // no registration if neither port nor host nor URI is configured
-        if (rmiPortStr == null && rmiHost == null && rmiURI == null) {
+        RMIConfig rc = config.getRmiConfig();
+        if (!rc.isValid() || !rc.enabled()) {
             return;
         }
 
-        // URI takes precedences, so check whether the configuration has to
-        // be set from the URI
-        int rmiPort = -1;
-        String rmiName = null;
-        if (rmiURI != null && rmiURI.length() > 0) {
-            URI uri = null;
-            try {
-                uri = new URI(rmiURI);
-
-                // extract values from the URI, check later
-                rmiHost = uri.getHost();
-                rmiPort = uri.getPort();
-                rmiName = uri.getPath();
-
-            } catch (URISyntaxException use) {
-                log.warn("Cannot parse RMI URI '" + rmiURI + "'.", use);
-                rmiURI = null; // clear RMI URI use another one
-                rmiHost = null; // use default host, ignore rmi-host param
-            }
-
-            // cut of leading slash from name if defined at all
-            if (rmiName != null && rmiName.startsWith("/")) {
-                rmiName = rmiName.substring(1);
-            }
-        } else {
-            // convert RMI port configuration
-        if (rmiPortStr != null) {
-            try {
-                rmiPort = Integer.parseInt(rmiPortStr);
-            } catch (NumberFormatException e) {
-                log.warn("Invalid port in rmi-port param: " + e + ". using default port.");
-                    rmiPort = Registry.REGISTRY_PORT;
-            }
-        }
-        }
-
-        // check RMI port
-        if (rmiPort == -1 || rmiPort == 0) {
-            // accept -1 or 0 as a hint to use the default
-            rmiPort = Registry.REGISTRY_PORT;
-        } else if (rmiPort < -1 || rmiPort > 0xFFFF) {
-            // emit a warning if out of range, use defualt in this case
-            log.warn("Invalid port in rmi-port param " + rmiPort + ". using default port.");
-            rmiPort = Registry.REGISTRY_PORT;
-        }
-
-        // check host - use an empty name if null (i.e. not configured)
-        if (rmiHost == null) {
-            rmiHost = "";
-        }
-
-        // check name - use repositoryName if empty or null
-        if (rmiName == null || rmiName.length() ==0) {
-            rmiName = repositoryName;
-        }
-
-        // reconstruct the rmiURI now because values might have been changed
-        rmiURI = "//" + rmiHost + ":" + rmiPort + "/" + rmiName;
-
         // try to create remote repository
         Remote remote;
         try {
@@ -440,9 +486,9 @@
                 // find the server socket factory: use the default if the
                 // rmiHost is not configured
                 RMIServerSocketFactory sf;
-                if (rmiHost.length() > 0) {
-                    log.debug("Creating RMIServerSocketFactory for host " + rmiHost);
-                    InetAddress hostAddress = InetAddress.getByName(rmiHost);
+                if (rc.getRmiHost().length() > 0) {
+                    log.debug("Creating RMIServerSocketFactory for host " + rc.getRmiHost());
+                    InetAddress hostAddress = InetAddress.getByName(rc.getRmiHost());
                     sf = getRMIServerSocketFactory(hostAddress);
                 } else {
                     // have the RMI implementation decide which factory is the
@@ -454,7 +500,7 @@
                 // create a registry using the default client socket factory
                 // and the server socket factory retrieved above. This also
                 // binds to the server socket to the rmiHost:rmiPort.
-                reg = LocateRegistry.createRegistry(rmiPort, null, sf);
+                reg = LocateRegistry.createRegistry(rc.rmiPort(), null, sf);
 
             } catch (UnknownHostException uhe) {
                 // thrown if the rmiHost cannot be resolved into an IP-Address
@@ -471,27 +517,26 @@
             // potentially active registry. We do not check yet, whether the
             // registry is actually accessible.
             if (reg == null) {
-                log.debug("Trying to access existing registry at " + rmiHost
-                    + ":"+ rmiPort);
+                log.debug("Trying to access existing registry at " + rc.getRmiHost()
+                        + ":" + rc.getRmiPort());
                 try {
-                    reg = LocateRegistry.getRegistry(rmiHost, rmiPort);
+                    reg = LocateRegistry.getRegistry(rc.getRmiHost(), rc.rmiPort());
                 } catch (RemoteException re) {
                     log.error("Cannot create the reference to the registry at "
-                        + rmiHost + ":" + rmiPort, re);
-            }
+                            + rc.getRmiHost() + ":" + rc.getRmiPort(), re);
+                }
             }
 
             // if we finally have a registry, register the repository with the
             // rmiName
             if (reg != null) {
-                log.debug("Registering repository as " + rmiName
-                    + " to registry " + reg);
-                reg.bind(rmiName, remote);
+                log.debug("Registering repository as " + rc.getRmiName()
+                        + " to registry " + reg);
+                reg.bind(rc.getRmiName(), remote);
 
                 // when successfull, keep references
-                this.rmiURI = rmiURI;
                 this.rmiRepository = remote;
-            log.info("Repository bound via RMI with name: " + rmiURI);
+                log.info("Repository bound via RMI with name: " + rc.getRmiUri());
             } else {
                 log.info("RMI registry missing, cannot bind repository via RMI");
             }
@@ -504,18 +549,41 @@
     }
 
     /**
+     * Unregisters the repository from the RMI registry, if it has previously
+     * been registered.
+     */
+    private void unregisterRMI() {
+        if (rmiRepository != null) {
+            // drop strong referenece to remote repository
+            rmiRepository = null;
+
+            // unregister repository
+            try {
+                Naming.unbind(config.getRmiConfig().getRmiUri());
+            } catch (Exception e) {
+                log("Error while unbinding repository from JNDI: " + e);
+            }
+        }
+    }
+
+    /**
      * Return the fully qualified name of the class providing the remote
      * repository. The class whose name is returned must implement the
      * {@link RemoteFactoryDelegater} interface.
+     * <p/>
+     * Subclasses may override this method for providing a name of a own
+     * implementation.
+     *
+     * @return getClass().getName() + "$RMIRemoteFactoryDelegater"
      */
     protected String getRemoteFactoryDelegaterClass() {
-        return "org.apache.jackrabbit.j2ee.RepositoryStartupServlet$RMIRemoteFactoryDelegater";
+        return getClass().getName() + "$RMIRemoteFactoryDelegater";
     }
 
     /**
      * Returns an <code>RMIServerSocketFactory</code> used to create the server
      * socket for a locally created RMI registry.
-     * <p>
+     * <p/>
      * This implementation returns a new instance of a simple
      * <code>RMIServerSocketFactory</code> which just creates instances of
      * the <code>java.net.ServerSocket</code> class bound to the given
@@ -524,12 +592,11 @@
      * creation, such as SSL server sockets.
      *
      * @param hostAddress The <code>InetAddress</code> instance representing the
-     *      the interface on the local host to which the server sockets are
-     *      bound.
-     *
+     *                    the interface on the local host to which the server sockets are
+     *                    bound.
      * @return A new instance of a simple <code>RMIServerSocketFactory</code>
-     *      creating <code>java.net.ServerSocket</code> instances bound to
-     *      the <code>rmiHost</code>.
+     *         creating <code>java.net.ServerSocket</code> instances bound to
+     *         the <code>rmiHost</code>.
      */
     protected RMIServerSocketFactory getRMIServerSocketFactory(
             final InetAddress hostAddress) {
@@ -541,27 +608,6 @@
     }
 
     /**
-     * Unregisters the repository from the RMI registry, if it has previously
-     * been registered.
-     */
-    private void unregisterRMI() {
-        // drop strong referenece to remote repository
-        rmiRepository = null;
-
-        // unregister repository
-        if (rmiURI != null) {
-            try {
-                Naming.unbind(rmiURI);
-            } catch (Exception e) {
-                log("Error while unbinding repository from JNDI: " + e);
-            } finally {
-                // do not try again to unregister
-                rmiURI = null;
-            }
-        }
-    }
-
-    /**
      * optional class for RMI, will only be used, if RMI server is present
      */
     protected static abstract class RemoteFactoryDelegater {
@@ -569,6 +615,7 @@
         public abstract Remote createRemoteRepository(Repository repository)
                 throws RemoteException;
     }
+
     /**
      * optional class for RMI, will only be used, if RMI server is present
      */
@@ -583,5 +630,76 @@
         }
     }
 
+    //-------------------------------------------------< Installer Routines >---
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        if (repository == null) {
+            redirect(req, resp, "/bootstrap/missing.html");
+        } else {
+            redirect(req, resp, "/bootstrap/running.html");
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        if (repository != null) {
+            redirect(req, resp, "/bootstrap/reconfigure.html");
+        } else {
+            int rc = new Installer(bootstrapConfigFile,
+                    getServletContext()).installRepository(req);
+            switch (rc) {
+                case Installer.C_INSTALL_OK:
+                    // restart rep
+                    restart();
+                    if (repository == null) {
+                        redirect(req, resp, "/bootstrap/error.html");
+                    } else {
+                        redirect(req, resp, "/bootstrap/success.html");
+                    }
+                    break;
+                case Installer.C_INVALID_INPUT:
+                    redirect(req, resp, "/bootstrap/missing.html");
+                    break;
+                case Installer.C_CONFIG_EXISTS:
+                case Installer.C_BOOTSTRAP_EXISTS:
+                case Installer.C_HOME_EXISTS:
+                    redirect(req, resp, "/bootstrap/exists.html");
+                    break;
+                case Installer. C_HOME_MISSING:
+                case Installer.C_CONFIG_MISSING:
+                    redirect(req, resp, "/bootstrap/notexists.html");
+                    break;
+                case Installer.C_INSTALL_ERROR:
+                    redirect(req, resp, "/bootstrap/error.html");
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Helper function to send a redirect response respecting the context path.
+     *
+     * @param req the request
+     * @param resp the response
+     * @param loc the location for the redirect
+     * @throws ServletException if an servlet error occurs.
+     * @throws IOException if an I/O error occurs.
+     */
+    private void redirect(HttpServletRequest req,
+                          HttpServletResponse resp, String loc)
+            throws ServletException, IOException {
+        String cp = req.getContextPath();
+        if (cp == null || cp.equals("/")) {
+            cp = "";
+        }
+        resp.sendRedirect(cp + loc);
+    }
 }
 

Added: jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/templates/bootstrap.properties
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/templates/bootstrap.properties?view=auto&rev=495531
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/templates/bootstrap.properties (added)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/templates/bootstrap.properties Fri Jan 12 01:38:40 2007
@@ -0,0 +1,24 @@
+# This is the template file for the 'bootstrap.properties' that will
+# be placed in the repository home directory (or whatever is specified
+# in the "bootstrap-config" init parameter.
+
+# Repository configuration settings (will be adjusted by installer)
+repository.config=/WEB-INF/repository/repository.xml
+repository.home=jackrabbit/repository
+repository.name=jackrabbit.repository
+
+# RMI Settings
+rmi.enabled=true
+rmi.port=0
+rmi.host=localhost
+# If the URI is not specified, it's composed as follows:
+#rmi.uri=//${rmi.host}:${rmi.port}/${repository.name}
+
+# JNDI Settings
+# all properties starting with 'java.naming.' will go into the
+# environment of the initial context
+jndi.enabled=true
+# if the name is not specified, it's initialized with the repository.name
+#jndi.name=${repository.name}
+java.naming.provider.url=http://www.apache.org/jackrabbit
+java.naming.factory.initial=org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory

Propchange: jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/templates/bootstrap.properties
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message