You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xindice-dev@xml.apache.org by vg...@apache.org on 2007/05/25 03:43:43 UTC

svn commit: r541504 [2/7] - in /xml/xindice/trunk: ./ config/ java/scratchpad/webadmin/ java/src/org/apache/xindice/client/xmldb/embed/ java/src/org/apache/xindice/core/ java/src/org/apache/xindice/core/data/ java/src/org/apache/xindice/core/filer/ jav...

Modified: xml/xindice/trunk/java/src/org/apache/xindice/util/StringUtilities.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/util/StringUtilities.java?view=diff&rev=541504&r1=541503&r2=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/util/StringUtilities.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/util/StringUtilities.java Thu May 24 18:43:39 2007
@@ -73,7 +73,7 @@
         for (int i = sb.length(); i < width; i++) {
             sb.append(' ');
         }
-        
+
         if (sb.length() > width) {
             sb.setLength(width);
         }
@@ -94,7 +94,7 @@
         for (int i = sb.length(); i < width; i++) {
             sb.insert(0, ' ');
         }
-        
+
         if (sb.length() > width) {
             return sb.toString().substring(sb.length() - width);
         } else {
@@ -162,7 +162,7 @@
     public static int findWhiteSpace(String value, int start) {
         char[] chars = value.toCharArray();
         for (int i = start; i < chars.length; i++) {
-            if (chars[i] <= 32) {
+            if (Character.isWhitespace(chars[i])) {
                 return i;
             }
         }
@@ -192,9 +192,8 @@
     public static String javaEncode(String value) {
         StringTokenizer st = new StringTokenizer(value, "\b\t\n\f\r\"\'\\", true);
         StringBuffer sb = new StringBuffer(value.length());
-        String token;
         while (st.hasMoreTokens()) {
-            token = st.nextToken();
+            String token = st.nextToken();
             if (token.equals("\b")) {
                 sb.append("\\b");
             } else if (token.equals("\t")) {
@@ -224,5 +223,69 @@
         } else {
             return s1.equals(s2);
         }
+    }
+
+    /**
+     * Converts input text into its XML representation by escaping all special symbols,
+     * if any are present.
+     *
+     * @param text Input string
+     * @return String with all the special symbols escaped 
+     */
+    public static String escapeXml(String text) {
+        char[] value = text.toCharArray();
+        StringBuffer buf = new StringBuffer();
+        int start = 0;
+        int len = 0;
+
+        for (int i = 0; i < value.length; i++) {
+            String outval = null;
+
+            switch (value[i]) {
+                case '&':
+                    outval = "&amp;";
+                    break;
+                case '\'':
+                    outval = "&apos;";
+                    break;
+                case '\"':
+                    outval = "&quot;";
+                    break;
+                case '<':
+                    outval = "&lt;";
+                    break;
+                case '>':
+                    outval = "&gt;";
+                    break;
+                default :
+                    len++;
+                    break;
+            }
+
+            if (outval != null) {
+                if (len > 0) {
+                    buf.append(value, start, len);
+                }
+                buf.append(outval);
+                start = i + 1;
+                len = 0;
+            }
+        }
+
+        if (len > 0) {
+            buf.append(value, start, len);
+        }
+
+        return buf.toString();
+    }
+
+    public static boolean isBlank(String str) {
+        for (int i = 0; i < str.length(); i++) {
+            if (!Character.isWhitespace(str.charAt(i))) {
+                return false;
+            }
+        }
+
+        return true;
     }
 }

Added: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/Location.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/Location.java?view=auto&rev=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/Location.java (added)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/Location.java Thu May 24 18:43:39 2007
@@ -0,0 +1,126 @@
+/*
+ * 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.xindice.webadmin;
+
+import org.apache.xindice.core.Collection;
+import org.apache.xindice.core.DBException;
+import org.apache.xindice.core.Database;
+
+/**
+ * Helper class for parsing path information to get database, collection
+ * and resource name.
+ */
+public class Location {
+    private Collection collection;
+    private String name;
+    private boolean isRoot;
+
+    /**
+     * Create Location instance out of path information. There are several
+     * possible outcomes: <ul>
+     * <li>Path is empty or "/" - both collection and name are null, isRoot
+     * equals true;
+     * <li>Path matches some collection's canonical name - collection is
+     * set to that collection, name is null, isRoot equals false;
+     * <li>Path matches some document's canonical name - collection is set
+     * to the document's collection, name is document name, isRoot equals
+     * false;
+     * <li>Path could not be recognized, no database/collection match found -
+     * both collection and name are null, isRoot equals false
+     * </ul>
+     * In case there are collection and document that have the same name,
+     * collection has a precedence over the document.
+     * For example, if path is /db/col1/test, and collection col1 contains
+     * child collection test and a document test, collection test will be
+     * returned, not a document.
+     *
+     * @param path Path string
+     * @throws DBException
+     */
+    public Location(String path) throws DBException {
+        if (path == null || path.length() == 0 || path.equals("/")) {
+            isRoot = true;
+            return;
+        }
+
+        Database db = getDatabase(path);
+        if (db == null) {
+            collection = null;
+            name = null;
+            return;
+        }
+
+        StringBuffer buf = new StringBuffer(path);
+
+        // strip database name
+        String dbName = db.getName();
+        buf.delete(0, dbName.length() + 1);
+
+        Collection col;
+        if (buf.length() == 0 || (buf.length() == 1 && buf.charAt(0) == '/')) {
+            col = db;
+        } else {
+            col = db.getCollection(buf.toString());
+        }
+
+        String resourceName = null;
+        if (col == null) { // no collection found -> try resource
+            if (buf.charAt(buf.length() - 1) ==  '/') {
+                buf.deleteCharAt(buf.length() - 1);
+            }
+
+            int split = buf.lastIndexOf("/");
+            resourceName = buf.substring(split + 1, buf.length());
+            String colPath = buf.substring(0, split);
+
+            if (colPath.length() > 0) {
+                col = db.getCollection(colPath);
+            } else {
+                col = db;
+            }
+        }
+
+        collection = col;
+        if (collection != null) {
+            this.name = resourceName;
+        }
+    }
+
+    private Database getDatabase(String path) {
+        if (path.charAt(0) != '/') {
+            return null;
+        }
+
+        int end = path.indexOf('/', 1);
+        String dbName = (end != -1) ? path.substring(1, end) : path.substring(1);
+
+        return Database.getDatabase(dbName);
+    }
+
+    public Collection getCollection() {
+        return collection;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean isRoot() {
+        return isRoot;
+    }
+}

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/Location.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/Location.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision Author Date

Added: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/PartialResponse.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/PartialResponse.java?view=auto&rev=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/PartialResponse.java (added)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/PartialResponse.java Thu May 24 18:43:39 2007
@@ -0,0 +1,150 @@
+/*
+ * 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.xindice.webadmin;
+
+import org.apache.xindice.util.StringUtilities;
+
+import java.util.ArrayList;
+
+/**
+ * PartialResponse represents response part of the multi-status response
+ * document. Every partial response has its correspondent URL information
+ * (href element) and one or more elements with additional request-specific
+ * information.
+ */
+public class PartialResponse {
+    private final String href;
+    private ArrayList children;
+
+    public PartialResponse(String href) {
+        this.href = href;
+    }
+
+    public String getHref() {
+        return href;
+    }
+
+    /**
+     * Adds another element to the list of children of this partial response.
+     *
+     * @param name Element name
+     * @param value Element value
+     */
+    public void addContent(String name, String value) {
+        Content child = new Content(name);
+        child.setValue(value);
+        addContent(child);
+    }
+
+    /**
+     * Adds another element to the list of children of this partial response.
+     *
+     * @param child Existing element
+     */
+    public void addContent(Content child) {
+        if (children == null) {
+            children = new ArrayList();
+        }
+        children.add(child);
+    }
+
+    /**
+     * Builds XML out of partial response object.
+     *
+     * @return XML string
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer(1024);
+        buf.append("<response>");
+        buf.append("<href>").append(StringUtilities.escapeXml(href)).append("</href>");
+
+        if (children != null && children.size() != 0) {
+            for (int i = 0; i < children.size(); i++) {
+                buf.append(((Content) children.get(i)).getContent());
+            }
+        }
+
+        buf.append("</response>");
+
+        return buf.toString();
+    }
+
+    /**
+     * Content class holds request-specific information in a tree-like
+     * structure. Every element of this tree can either be empty, have a
+     * text value or hold children elements.
+     */
+    public static class Content {
+        private ArrayList children;
+        private String name;
+        private String value;
+
+        public Content(String name) {
+            this.name = name;
+        }
+
+        public Content(String name, String value) {
+            this.name = name;
+            this.value = value;
+        }
+
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        public Content addChild(String name) {
+            Content child = new Content(name);
+            addChild(child);
+            return child;
+        }
+
+        public Content addChild(String name, String value) {
+            Content child = addChild(name);
+            child.setValue(value);
+            return child;
+        }
+
+        public void addChild(Content child) {
+            if (children == null) {
+                children = new ArrayList();
+            }
+            children.add(child);
+        }
+
+        public String getValue() {
+            return value;
+        }
+
+        private StringBuffer getContent() {
+            StringBuffer buf = new StringBuffer(1024);
+
+            buf.append("<").append(name).append(">");
+            if (value != null) {
+                buf.append(StringUtilities.escapeXml(value));
+            } else if (children != null && children.size() != 0) {
+                for (int i = 0; i < children.size(); i++) {
+                    buf.append(((Content) children.get(i)).getContent());
+                }
+            }
+
+            buf.append("</").append(name).append(">");
+
+            return buf;
+        }
+    }
+}

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/PartialResponse.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/PartialResponse.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision Author Date

Added: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminManager.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminManager.java?view=auto&rev=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminManager.java (added)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminManager.java Thu May 24 18:43:39 2007
@@ -0,0 +1,206 @@
+/*
+ * 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.xindice.webadmin;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.apache.xindice.webadmin.webdav.components.DAVComponent;
+import org.apache.xindice.webadmin.viewer.HtmlCollectionViewer;
+import org.apache.xindice.webadmin.viewer.HtmlResourceViewer;
+import org.apache.xindice.webadmin.viewer.HtmlDatabaseViewer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.HashMap;
+import java.util.ArrayList;
+
+/**
+ * Manager class that is responsible for reading configuration, initializing
+ * all components, and dispatching calls.
+ *
+ * WebAdminManager configuration has several sections descibing different
+ * components:
+ * <ul>
+ * <li>methods - list of supported WebDAV methods
+ * <li>colviewers - list of collection-level operations for WebAdmin
+ * <li>resviewers - list of resource-level operations for WebAdmin
+ * <li>dbviewers - list of database-level operations for WebAdmin
+ * </ul>
+ */
+public class WebAdminManager {
+
+    private static final HashMap methods = new HashMap();
+    private static final HashMap colViewers = new HashMap();
+    private static final HashMap resViewers = new HashMap();
+    private static final HashMap dbViewers = new HashMap();
+
+    private static String[] methodsList;
+    private static String[] colViewersList;
+    private static String[] resViewersList;
+    private static String[] dbViewersList;
+
+    private static final Log log = LogFactory.getLog(WebAdminManager.class);
+
+    public WebAdminManager(Document config) {
+        Node node = config.getElementsByTagName("methods").item(0);
+        try {
+            methodsList = processSection(node, "method", methods);
+        } catch (Exception e) {
+            log.error("Failed to load WebDAV methods", e);
+        }
+
+        node = config.getElementsByTagName("colviewers").item(0);
+        try {
+            colViewersList = processSection(node, "viewer", colViewers);
+        } catch (Exception e) {
+            log.error("Failed to load collection viewers", e);
+        }
+
+        node = config.getElementsByTagName("resviewers").item(0);
+        try {
+            resViewersList = processSection(node, "viewer", resViewers);
+        } catch (Exception e) {
+            log.error("Failed to load resource viewers", e);
+        }
+
+        node = config.getElementsByTagName("dbviewers").item(0);
+        try {
+            dbViewersList = processSection(node, "viewer", dbViewers);
+        } catch (Exception e) {
+            log.error("Failed to load DB viewers", e);
+        }
+    }
+
+    private String[] processSection(Node node, String name, HashMap storage) throws Exception {
+        NodeList nodes = node.getChildNodes();
+        ArrayList list = new ArrayList();
+        for (int i = 0; i < nodes.getLength(); i++) {
+
+            Node child = nodes.item(i);
+            if (child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals(name)) {
+                NamedNodeMap attrs = child.getAttributes();
+
+                String className = attrs.getNamedItem("class").getNodeValue();
+                Object object = Class.forName(className).newInstance();
+
+                String id = attrs.getNamedItem("id").getNodeValue();
+                if (id != null && id.length() > 0) {
+                    storage.put(id, object);
+                    list.add(id);
+
+                    Node attr = attrs.getNamedItem("default");
+                    if (attr != null && "true".equals(attr.getNodeValue())) {
+                        storage.put("default", object);
+                    }
+                }
+            }
+        }
+
+        return (String[]) list.toArray(new String[0]);
+    }
+
+    /**
+     * Gets class that handles specific DAV request.
+     *
+     * @param id Method name (e.g. PROPFIND, MKCOL)
+     * @return applicable class, if it has been configured, null otherwise
+     */
+    public DAVComponent getMethod(String id) {
+        return (DAVComponent) methods.get(id);
+    }
+
+    /**
+     * Gets class that handles specific collection-level operation for WebAdmin.
+     *
+     * @param id Opration id
+     * @return applicable class, if it has been configured, null otherwise
+     */
+    public HtmlCollectionViewer getCollectionViewer(String id) {
+        if (id == null || id.length() == 0) {
+            id = "default";
+        }
+
+        return (HtmlCollectionViewer) colViewers.get(id);
+    }
+
+    /**
+     * Gets class that handles specific resource-level operation for WebAdmin.
+     *
+     * @param id Opration id
+     * @return applicable class, if it has been configured, null otherwise
+     */
+    public HtmlResourceViewer getResourceViewer(String id) {
+        if (id == null || id.length() == 0) {
+            id = "default";
+        }
+
+        return (HtmlResourceViewer) resViewers.get(id);
+    }
+
+    /**
+     * Gets class that handles specific database-level operation for WebAdmin.
+     *
+     * @param id Opration id
+     * @return applicable class, if it has been configured, null otherwise
+     */
+    public HtmlDatabaseViewer getDatabaseViewer(String id) {
+        if (id == null || id.length() == 0) {
+            id = "default";
+        }
+
+        return (HtmlDatabaseViewer) dbViewers.get(id);
+    }
+
+    /**
+     * Gets all supported methods.
+     *
+     * @return Array of all supported WebDAV methods.
+     */
+    public static String[] getMethods() {
+        return methodsList;
+    }
+
+    /**
+     * Gets all supported database-level operations.
+     *
+     * @return Array of all supported database-level operations.
+     */
+    public static String[] getDatabaseViewers() {
+        return dbViewersList;
+    }
+
+    /**
+     * Gets all supported collection-level operations.
+     *
+     * @return Array of all supported collection-level operations.
+     */
+    public static String[] getCollectionViewers() {
+        return colViewersList;
+    }
+
+    /**
+     * Gets all supported resource-level operations.
+     *
+     * @return Array of all supported resource-level operations.
+     */
+    public static String[] getResourceViewers() {
+        return resViewersList;
+    }
+}

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminManager.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision Author Date

Modified: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminServlet.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminServlet.java?view=diff&rev=541504&r1=541498&r2=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminServlet.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminServlet.java Thu May 24 18:43:39 2007
@@ -19,21 +19,28 @@
 
 package org.apache.xindice.webadmin;
 
-import java.io.File;
 import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.InputStream;
 
 import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.avalon.fortress.ContainerManager;
-import org.apache.avalon.fortress.impl.DefaultContainerManager;
-import org.apache.avalon.fortress.util.FortressConfig;
-import org.apache.avalon.framework.container.ContainerUtil;
 import org.apache.xindice.server.XindiceServlet;
-import org.apache.xindice.core.Database;
+import org.apache.xindice.xml.dom.DOMParser;
+import org.apache.xindice.core.DBException;
+import org.apache.xindice.core.Collection;
+import org.apache.xindice.webadmin.webdav.components.DAVComponent;
+import org.apache.xindice.webadmin.webdav.WebdavStatus;
+import org.apache.xindice.webadmin.webdav.DAVRequest;
+import org.apache.xindice.webadmin.webdav.DAVResponse;
+import org.apache.xindice.webadmin.util.MimeTable;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
 
 /**
  * @author <a href="mailto:jan@metzner.org">Jan Metzner</a>
@@ -41,71 +48,144 @@
  */
 public class WebAdminServlet extends XindiceServlet {
 
-	protected WebAdminContainer m_container;
-	protected ContainerManager m_containerManager;
+    protected WebAdminManager mgr;
 
-	/**
-	 * Initializes Servlet and creates a WebAdminContainer instance
-	 *
-	 * @exception ServletException if an error occurs
-	 */
-	public void init(ServletConfig servletConfig) throws ServletException {
-		super.init(servletConfig);
-		try {
-
-			ServletContext servletContext = servletConfig.getServletContext();
-
-			final FortressConfig config = new FortressConfig();
-			config.setContainerClass(WebAdminContainer.class);
-			config.setContextDirectory( servletContext.getRealPath("/") );
-			config.setWorkDirectory( (File) servletContext
-				.getAttribute( "javax.servlet.context.tempdir" ) );
-			config.setContainerConfiguration(
-				"resource://org/apache/xindice/webadmin/WebAdmin.xconf");
-			config.setLoggerManagerConfiguration(
-				"resource://org/apache/xindice/webadmin/WebAdmin.xlog");
-
-			m_containerManager = new DefaultContainerManager( config.getContext() );
-			ContainerUtil.initialize(m_containerManager);
-
-			m_container = (WebAdminContainer)m_containerManager.getContainer();
-		} catch(Exception e)	{
-			throw new ServletException( "Error during initialization", e );
-		}
-	}
-
-	/**
-	 * Pass all servlet requests through to container to be handled.
-	 *
-	 * @param req a HttpServletRequest instance
-	 * @param res a HttpServletResponse instance
-	 * @exception IOException if an IO error occurs
-	 * @exception ServletException if a servlet error occurs
-	 */
-	public void service(HttpServletRequest req, HttpServletResponse res)
-		throws IOException, ServletException {
-
-		// get request path
-		String path = req.getPathInfo();
-		if(path == null) {
-			path = "";
-		}
-
-		// xmlrpc request are handled by the XindiceServlet
-		if(req.getMethod().equalsIgnoreCase("POST") && path.length() < 2) {
-			super.doPost(req, res);
-		} else {
-			// HACK Get first database and use it. Should be changed to support multiple databases
-            String[] databases = Database.listDatabases();
-			m_container.handleRequest(req, res, Database.getDatabase(databases[0]));
-		}
-	}
-
-	/**
-	 * Disposes of container manager and container instance.
-	 */
-	public void destroy() {
-		super.destroy();
-		ContainerUtil.dispose(m_containerManager);
-	}
+    private static final Log log = LogFactory.getLog(WebAdminServlet.class);
+    private static final String WEBADMIN_CONFIGURATION = "webadmin.configuration";
+    private static final String MIMETABLE_CONFIGURATION = "mimetable.configuration";
+
+    /**
+     * Initializes Servlet and creates a WebAdminContainer instance
+     *
+     * @exception ServletException if an error occurs
+     */
+    public void init(ServletConfig servletConfig) throws ServletException {
+
+        super.init(servletConfig);
+        try {
+            String path = servletConfig.getInitParameter(WEBADMIN_CONFIGURATION);
+            Document configuration = loadFile(path, servletConfig);
+            mgr = new WebAdminManager(configuration);
+        } catch(Exception e) {
+            throw new ServletException("Could not process WebAdmin configuration", e);
+        }
+
+        try {
+            String path = servletConfig.getInitParameter(MIMETABLE_CONFIGURATION);
+            Document configuration = loadFile(path, servletConfig);
+            MimeTable.addMimeConfig(configuration);
+
+        } catch(Exception e) {
+            log.error("Could not process Mime Table configuration", e);
+        }
+    }
+
+    private Document loadFile(String path, ServletConfig config) throws Exception {
+        InputStream inputStream = null;
+
+        try {
+            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 = config.getServletContext();
+                inputStream = context.getResourceAsStream("/" + path);
+            }
+
+            Document configuration = null;
+            if (inputStream != null) {
+                configuration = DOMParser.toDocument(inputStream);
+            }
+
+            return configuration;
+        } finally {
+            try {
+                if (inputStream != null) {
+                    inputStream.close();
+                }
+            } catch (IOException ignored) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Pass all servlet requests through to container to be handled.
+     *
+     * @param req a HttpServletRequest instance
+     * @param res a HttpServletResponse instance
+     * @exception IOException if an IO error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void service(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
+
+        // get request path
+        String path = req.getPathInfo();
+
+        // xmlrpc request are handled by the XindiceServlet
+        if(req.getMethod().equalsIgnoreCase("POST") && (path == null || path.length() < 2)) {
+            super.doPost(req, res);
+        } else {
+            process(req, res);
+        }
+    }
+
+    private void process(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
+
+        // get request path
+        String path = req.getPathInfo();
+
+        // get content
+        Location target;
+        try {
+            target = new Location(path);
+        } catch (DBException e) {
+            log.error(e);
+            throw new ServletException(e);
+        }
+
+        Collection col = target.getCollection();
+        String resource = target.getName();
+
+        // choose html interface
+        String viewer = req.getParameter("viewer");
+
+        if (viewer == null || viewer.length() == 0) { // not html request
+            DAVComponent method = mgr.getMethod(req.getMethod());
+
+            if (method == null) {
+                // method is not supported
+                if (log.isWarnEnabled()) {
+                    log.warn("Method " + req.getMethod() + " is not supported.");
+                }
+                res.setStatus(WebdavStatus.SC_NOT_IMPLEMENTED);
+                return;
+            }
+
+            DAVRequest request = new DAVRequest(req);
+            DAVResponse response = new DAVResponse(res);
+            method.execute(request, response, target);
+        } else { // html request
+            if (col == null) {
+                if (!"/".equals(path)) {
+                    String redirect = req.getContextPath() + req.getServletPath() + "/?viewer=" + viewer;
+                    res.sendRedirect(redirect);
+                }
+
+                mgr.getDatabaseViewer(viewer).execute(req, res);
+            } else if (resource == null) {
+                // redirect if path does not end with /
+                if (!path.endsWith("/")) {
+                    String redirect = req.getContextPath() + req.getServletPath() + path + "/?viewer=" + viewer;
+                    res.sendRedirect(redirect);
+                }
+
+                mgr.getCollectionViewer(viewer).execute(req, res, col);
+            } else {
+                mgr.getResourceViewer(viewer).execute(req, res, col, resource);
+            }
+        }
+    }
 }

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/WebAdminServlet.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu May 24 18:43:39 2007
@@ -1 +1 @@
-Author Date Id Revision
+Id Revision Author Date

Modified: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/CollectionConfigurationHelper.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/CollectionConfigurationHelper.java?view=diff&rev=541504&r1=541498&r2=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/CollectionConfigurationHelper.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/CollectionConfigurationHelper.java Thu May 24 18:43:39 2007
@@ -14,69 +14,155 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- * $Id$
- */ 
+ * CVS $Id$
+ */
 
 package org.apache.xindice.webadmin.util;
 
 import org.apache.xindice.core.Collection;
 import org.apache.xindice.util.Configuration;
-import org.apache.xindice.util.XindiceException;
+import org.apache.xindice.util.ReadOnlyException;
+import org.apache.xindice.xml.TextWriter;
+import org.apache.xindice.xml.dom.DocumentImpl;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 /** 
- *  
+ * Helper class for oprations on collection configuration
+ *
  * @author <a href="mailto:jmetzner@apache.org">Jan Metzner</a>
  * @version $Id$ 
  */
 
-public interface CollectionConfigurationHelper {
-
-	/** Role identifying Component */
-    String ROLE = CollectionConfigurationHelper.class.getName();
+public class CollectionConfigurationHelper {
 
+    private static final Log log = LogFactory.getLog(CollectionConfigurationHelper.class);
     public static final String CONF_ELE = "collection";
-    
-	public static final String COL_NAME_ATTR = "name";
-
+    public static final String COL_NAME_ATTR = "name";
     public static final String INLINE_META_ATTR = "inline-metadata";
-
     public static final String COMPRESSED_ATTR = "compressed";
-
     public static final String FILER_ELE = "filer";
-
     public static final String FILER_CLASS_ATTR = "class";
-
     public static final boolean DEFAULT_INLINE_META = true;
-
     public static final boolean DEFAULT_COMPRESSED = true;
+    public static final String DEFAULT_FILER_CLASS = "org.apache.xindice.core.filer.BTreeFiler";
 
-    public static final String DEFAULT_FILER_CLASS =
-        "org.apache.xindice.core.filer.BTreeFiler";
-        
-    public boolean isAutoEnableInlineMeta();
-    
-	public boolean getDefaultInlineMetadata();
-	
-	public boolean getDefaultCompressed();
-	
-	public String getDefaultFilerClass();
-	
-	public boolean isInlineMetaEnabled(final Collection col);
-
-    public Configuration createDefaultConfiguration(String name);
-
-    public Configuration createConfiguration(
-        String name,
-        String compressed,
-        String inlineMeta,
-        String filerClass);
-
-    public void enableCollectionInlineMetadata(Collection col)
-        throws XindiceException;
-
-    public Configuration copyConfiguration(final Configuration srcConfig);
-
-    public Configuration copyConfiguration(
-        String name,
-        final Configuration srcConfig);
-}
\ No newline at end of file
+    /**
+     * Configures the CollectionConfigurationHelper with the default 
+     * Collection Configuration. Example:
+     * <pre>
+     * &lt;col-config id="col-config" autoenableinlinemeta="true"&gt;
+     *   &lt;collection compressed="true" inline-meta="true"&gt;
+     *     &lt;filer class="org.apache.xindice.core.filer.BTreeFiler" /&gt;
+     *   &lt;/collection&gt;
+     * &lt;/col-config&gt;
+     * </pre>
+     * A name Attribute will be ignored.
+     * If the Attribute autoenableinlinemeta is set true, the Collection is not Inline 
+     * Metadata enabled and a Binary is inserted, the Collection will be automatically
+     * Inline Metadata enabled.
+     */
+    public static boolean getDefaultInlineMetadata() {
+        return DEFAULT_INLINE_META;
+    }
+
+    public static boolean getDefaultCompressed() {
+        return DEFAULT_COMPRESSED;
+    }
+
+    public static String getDefaultFilerClass() {
+        return DEFAULT_FILER_CLASS;
+    }
+
+    public static boolean isInlineMetaEnabled(final Collection col) {
+        Configuration config = col.getConfig();
+        return config.getBooleanAttribute(INLINE_META_ATTR, false);
+    }
+
+    public static Configuration createDefaultConfiguration(String name) {
+        return createConfiguration(name, null, null, null);
+    }
+
+    public static Configuration createConfiguration(String name, String compressed, String inlineMeta, String filerClass) {
+        Document doc = new DocumentImpl();
+        Element colEle = doc.createElement(CONF_ELE);
+        if (name == null || name.length() == 0) {
+            throw new IllegalArgumentException("null name");
+        }
+        colEle.setAttribute(COL_NAME_ATTR, name);
+        if (compressed == null || (!compressed.equalsIgnoreCase("true") && !compressed.equalsIgnoreCase("false"))) {
+            compressed = Boolean.toString(DEFAULT_COMPRESSED);
+        }
+        colEle.setAttribute(COMPRESSED_ATTR, compressed);
+        if (inlineMeta == null || (!inlineMeta.equalsIgnoreCase("true") && !inlineMeta.equalsIgnoreCase("false"))) {
+            inlineMeta = Boolean.toString(DEFAULT_INLINE_META);
+        }
+        colEle.setAttribute(INLINE_META_ATTR, inlineMeta);
+        doc.appendChild(colEle);
+        Element filEle = doc.createElement(FILER_ELE);
+        if (filerClass == null || filerClass.length() == 0) {
+            filerClass = DEFAULT_FILER_CLASS;
+        }
+        filEle.setAttribute(FILER_CLASS_ATTR, filerClass);
+        colEle.appendChild(filEle);
+        if (log.isDebugEnabled()) {
+            log.debug("Created Configuration: \n" + TextWriter.toString(doc));
+        }
+        return new Configuration(doc.getDocumentElement(), false);
+    }
+
+    public static Configuration copyConfiguration(final Configuration srcConfig) {
+        Configuration newConfig = createConfiguration();
+        try {
+            return copyConfigurationContent(srcConfig, newConfig);
+        } catch (ReadOnlyException e) {
+            log.error(e);
+            return null;
+        }
+    }
+
+    public static Configuration copyConfiguration(String name, final Configuration srcConfig) {
+        Configuration destConfig = createConfiguration();
+        try {
+            copyConfigurationContent(srcConfig, destConfig);
+            destConfig.setAttribute(COL_NAME_ATTR, name);
+        } catch (ReadOnlyException e) {
+            // ignore, cannot happen
+        }
+
+        return destConfig;
+    }
+
+    private static Configuration copyConfigurationContent(final Configuration srcConfig, Configuration destConfig)
+        throws ReadOnlyException {
+
+        if (srcConfig.hasAttributes()) {
+            String[] attrs = srcConfig.listAttributes();
+            for (int i = 0; i < attrs.length; i++) {
+                destConfig.setAttribute(attrs[i], srcConfig.getAttribute(attrs[i]));
+            }
+        }
+        if (srcConfig.hasValue()) {
+            String value = srcConfig.getValue(null);
+            if (value != null) {
+                destConfig.setValue(value);
+            }
+        }
+        if (srcConfig.hasChildren()) {
+            Configuration[] childConf = srcConfig.getChildren();
+            for (int i = 0; i < childConf.length; i++) {
+                Configuration childDestConfig = destConfig.getChild(childConf[i].getName(), true);
+                copyConfigurationContent(childConf[i], childDestConfig);
+            }
+        }
+
+        return destConfig;
+    }
+
+    private static Configuration createConfiguration() {
+        Document doc = new DocumentImpl();
+        return new Configuration(doc.createElement(CONF_ELE), false);
+    }
+}

Modified: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/DAVOperations.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/DAVOperations.java?view=diff&rev=541504&r1=541498&r2=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/DAVOperations.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/DAVOperations.java Thu May 24 18:43:39 2007
@@ -19,80 +19,232 @@
 
 package org.apache.xindice.webadmin.util;
 
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.avalon.framework.service.ServiceException;
 import org.apache.xindice.core.Collection;
 import org.apache.xindice.core.DBException;
+import org.apache.xindice.core.FaultCodes;
+import org.apache.xindice.core.data.Key;
+import org.apache.xindice.core.data.Entry;
+import org.apache.xindice.webadmin.webdav.WebdavStatus;
+import org.apache.xindice.webadmin.Location;
+import org.apache.xindice.util.Configuration;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Collections;
 
-/** 
- * Some usefull Operations like Copy or Move.
- * 
+/**
+ * Helper for copy/move operations.
+ *
  * @author <a href="mailto:jmetzner@apache.org">Jan Metzner</a>
- * @version $Id$ 
+ * @version $Id$
  */
-public interface DAVOperations {
 
-	/** Role identifying Component */
-	String ROLE = DAVOperations.class.getName();
-	
-    /**
-     * Copies the collection or resource spcified by parentCol and name
-     * to the destination specified by the destination header of the request.
-     *
-     * @param req servlet request.
-     * @param parentCol parent collection.
-     * @param name name of the source resource/collection
-     * @return WEBDAV Status Code.
-     * @throws DBException while writing the new resource/collection.
-     */
-    public abstract int copy(
-        HttpServletRequest req,
-        Collection parentCol,
-        String name)
-        throws DBException, ServiceException;
-        
-    /**
-     * gets the destination path header from Copy and Move requests.
-     *
-     * @param req servlet request.
-     * @return destination path or null if the header does not exits.
-     */
-    public abstract String getDestinationPath(HttpServletRequest req);
-    
-    /**
-     * Parses the overwrite header of the given request.
-     *
-     * @param req servlet request.
-     * @return the boolean value of the overwrite header
-     *         (true if the header does not exist).
-     */
-    public abstract boolean getOverwrite(HttpServletRequest req);
-    
+public class DAVOperations {
+
+    private static final Log log = LogFactory.getLog(DAVOperations.class);
+
     /**
-     * copies the entire collection to a new destination.
-     *
-     * @param srcCol source collection.
-     * @param destParentCol parent collection of the destination.
-     * @param name name of the new collection.
-     * @throws DBException while creating the new collection.
-     * @return the new created collection.
+     * Copies collection to the new destination
+     * @param col Collection to be copied
+     * @param dest Destination path (includes DB name)
+     * @param overwrite true if previously existed collection at dest path can be overwritten
+     * @return
+     * @throws DBException
      */
-    public abstract Collection copyCollection(
-        Collection srcCol,
-        Collection destParentCol,
-        String name)
-        throws DBException, ServiceException;
-        
+    public static Map copy(Collection col, String dest, boolean overwrite, boolean deep) throws DBException {
+
+        Location destLocation = new Location(dest);
+        Collection destCollection = destLocation.getCollection();
+        String destName = destLocation.getName();
+        Map results = new HashMap();
+
+        if (destLocation.isRoot()) {
+            results.put(dest, new Integer(WebdavStatus.SC_BAD_REQUEST));
+            return results;
+        } else if (destCollection == null) {
+            // either intermidiate collection does not exist or destination points to
+            // the first level collection (database).
+            results.put(dest, new Integer(WebdavStatus.SC_CONFLICT));
+            return results;
+        } else if (deep && destCollection.getCanonicalName().startsWith(col.getCanonicalName())) {
+            // destination points to a location inside target collection subtree.
+            // deep copy does not make sense in that case
+            results.put(dest, new Integer(WebdavStatus.SC_FORBIDDEN));
+            return results;
+        }
+
+        // FIXME: the operations are not atomic, they can fail because of another
+        // thread deleting or creating collections. Introduce locks.
+        if (destName != null) { // destination collection does not exist
+
+            results.putAll(copyCollection(col, destCollection, destName, deep));
+            if (results.size() == 0) {
+                results.put(dest, new Integer(WebdavStatus.SC_CREATED));
+            }
+        } else { // existing collection
+
+            if (overwrite) {
+                // overwrites the collection
+                String name = destCollection.getName();
+                Collection parent = destCollection.getParentCollection();
+                // delete collection
+                parent.dropCollection(destCollection);
+                results.putAll(copyCollection(col, parent, name, deep));
+                if (results.size() == 0) {
+                    results.put(dest, new Integer(WebdavStatus.SC_NO_CONTENT));
+                }
+            } else {
+                results.put(dest, new Integer(WebdavStatus.SC_PRECONDITION_FAILED));
+            }
+
+        }
+
+        return results;
+    }
+
     /**
-     * copies the collection content (resources and collections).
-     *
-     * @param srcCol source collection.
-     * @param destCol destination collection.
-     * @throws DBException while creating the new content.
+     * Copies a resource to a new location.
+     * @param col Source collection
+     * @param name Resource name
+     * @param dest Path to the new location. It includes db name and new resource name
+     * @param overwrite true if previously existed resource at dest path can be overwritten
+     * @return
+     * @throws DBException
      */
-    public abstract void copyCollectionContent(
-        Collection srcCol,
-        Collection destCol)
-        throws DBException, ServiceException;
-}
\ No newline at end of file
+    public static int copy(Collection col, String name, String dest, boolean overwrite) throws DBException {
+
+        Location destLocation = new Location(dest);
+        Collection destCollection = destLocation.getCollection();
+        String destName = destLocation.getName();
+
+        if (destLocation.isRoot()) {
+            // resource cannot be added to root directly, database has to be created manually
+            return WebdavStatus.SC_FORBIDDEN;
+        } else if (destCollection == null) {
+            return WebdavStatus.SC_CONFLICT;
+        } else if (col == destCollection && name.equals(destName)) {
+            return WebdavStatus.SC_FORBIDDEN;
+        }
+
+        // get source
+        Entry object = col.getEntry(name);
+        if (object == null) {
+            return WebdavStatus.SC_NOT_FOUND;
+        }
+
+        int status;
+        try {
+            if (object.getEntryType() == Entry.BINARY) { // insert Binary
+                if (overwrite) {
+                    if (destCollection.setBinary(new Key(destName), (byte[]) object.getValue())) {
+                        status = WebdavStatus.SC_CREATED;
+                    } else {
+                        status = WebdavStatus.SC_NO_CONTENT;
+                    }
+                } else {
+                    destCollection.insertBinary(destName, (byte[]) object.getValue());
+                    status = WebdavStatus.SC_CREATED;
+                }
+            } else if (object.getEntryType() == Entry.DOCUMENT) {
+                if (overwrite) {
+                    if (destCollection.setDocument(new Key(destName), (Document) object.getValue())) {
+                        status = WebdavStatus.SC_CREATED;
+                    } else {
+                        status = WebdavStatus.SC_NO_CONTENT;
+                    }
+                } else {
+                    destCollection.insertDocument(destName, (Document) object.getValue());
+                    status = WebdavStatus.SC_CREATED;
+                }
+            } else {
+                // placeholder, won't get here
+                status = WebdavStatus.SC_FORBIDDEN;
+            }
+        } catch (DBException e) {
+            if (e.faultCode == FaultCodes.COL_DUPLICATE_RESOURCE) {
+                status = WebdavStatus.SC_PRECONDITION_FAILED;
+            } else if (e.faultCode == FaultCodes.COL_NO_FILER) {
+                status = WebdavStatus.SC_FORBIDDEN;
+            } else if (e.faultCode == FaultCodes.COL_COLLECTION_NOT_FOUND) {
+                status = WebdavStatus.SC_CONFLICT;
+            } else if (e.faultCode == FaultCodes.COL_CANNOT_STORE) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Collection Inline Metadata is not enabled!");
+                }
+                status = WebdavStatus.SC_FORBIDDEN;
+            } else {
+                throw e;
+            }
+        }
+
+        return status;
+    }
+
+    private static Map copyCollection(Collection col, Collection parent, String name, boolean deep)
+            throws DBException {
+
+        Configuration config = CollectionConfigurationHelper.copyConfiguration(name, col.getConfig());
+        Collection newCol = parent.createCollection(name, config);
+
+        if (deep) {
+            return copyCollectionContent(col, newCol);
+        } else {
+            return Collections.EMPTY_MAP;
+        }
+    }
+
+    private static Map copyCollectionContent(Collection srcCol, Collection destCol) throws DBException {
+        HashMap result = new HashMap();
+
+        // copy resources
+        String[] resList = srcCol.listDocuments();
+        for (int i = 0; i < resList.length; i++) {
+            Entry object = srcCol.getEntry(resList[i]);
+            if (object.getEntryType() == Entry.DOCUMENT) {
+                destCol.setDocument(resList[i], (Document) object.getValue());
+            } else {
+                destCol.setBinary(resList[i], (byte[]) object.getValue());
+            }
+        }
+
+        // copy child collections content collections
+        /* From the specification:
+           If an error occurs while copying an internal collection, the server MUST NOT
+           copy any resources identified by members of this collection (i.e., the server
+           must skip this subtree), as this would create an inconsistent namespace.
+           After detecting an error, the COPY operation SHOULD try to finish as much
+           of the original copy operation as possible (i.e., the server should still
+           attempt to copy other subtrees and their members, that are not descendents
+           of an error-causing collection).
+          */
+        String[] colList = srcCol.listCollections();
+        for (int i = 0; i < colList.length; i++) {
+            Collection srcChild = srcCol.getCollection(colList[i]);
+            Collection destChild = destCol.getCollection(colList[i]);
+            try {
+                result.putAll(copyCollectionContent(srcChild, destChild));
+            } catch (DBException e) {
+                int code;
+                if (e.faultCode == FaultCodes.COL_NO_FILER) {
+                    code = WebdavStatus.SC_FORBIDDEN;
+                } else if (e.faultCode == FaultCodes.COL_COLLECTION_NOT_FOUND) {
+                    code = WebdavStatus.SC_CONFLICT;
+                } else if (e.faultCode == FaultCodes.COL_CANNOT_STORE) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Collection Inline Metadata is not enabled!");
+                    }
+                    code = WebdavStatus.SC_FORBIDDEN;
+                } else {
+                    throw e;
+                }
+
+                result.put(destChild.getCanonicalName(), new Integer(code));
+            }
+        }
+
+        return result;
+    }
+}

Modified: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/MimeTable.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/MimeTable.java?view=diff&rev=541504&r1=541498&r2=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/MimeTable.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/util/MimeTable.java Thu May 24 18:43:39 2007
@@ -14,54 +14,192 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- * $Id$
+ * CVS $Id$
  */
 
 package org.apache.xindice.webadmin.util;
 
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.xindice.xml.dom.DOMParser;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+
 /**
- * MimeTable maps a file extension to a mime type. 
+ * MimeTable maps a file extension to a mime type.
  *
  * @author <a href="mailto:jmetzner@apache.org">Jan Metzner</a>
  * @version $Id$
  */
-public interface MimeTable {
-	
-	/** Role identifying Component */	
-	String ROLE = MimeTable.class.getName();
-	
-	/** the default mime type for binaries */
-	public static final String BINARY_MIME_TYPE = "application/octet-stream";
-
-	/** the default mime type for xml documents */
-	public static final String XML_MIME_TYPE = "text/xml";
-
-	/**
-	 * returns the mime type of the given object.
-	 * 
-	 * @param resource the object. 
-	 * @param name the name of the object.
-	 * @return mime type for this object.
-	 */
-	public abstract String getMimeType(Object resource, String name);
-	
-	/**
-	 * returns the mime type for the given name.
-	 * if no mime for this name is available the default xml mime type is returned.
-	 * 
-	 * @param recourceName the name of the resource.
-	 * @return mime type for this resource name.
-	 */
-	public abstract String getMimeType(String recourceName);
-	
-	/**
-	 * returns the mime type for the given name.
-	 * if no mime for this name is available the parameter defaultXml specifies if
-	 * the xml mime type or the binary mime type are returned.
-	 * 
-	 * @param resourceName
-	 * @param defaultXml
-	 * @return
-	 */
-	public abstract String getMimeType(String resourceName, boolean defaultXml);
-}
\ No newline at end of file
+public class MimeTable {
+
+    /** the default mime type for binaries */
+    public static final String BINARY_MIME_TYPE = "application/octet-stream";
+
+    /** the default mime type for xml documents */
+    public static final String XML_MIME_TYPE = "text/xml";
+
+    /** holds the extensions/mime types */
+    protected static Hashtable mimeMappings = new Hashtable();
+
+    private final static Log log = LogFactory.getLog(MimeTable.class);
+
+    /**
+     * Configures the Mime table.
+     * the configuration can look like the Configuration in the
+     * addMimeConfig(Configuration config) Method<br />
+     * <br/>
+     * or if the Configuration should be loaded out of an extra file:
+     * <pre>
+     * &lt;mime location="/some/path"&gt;
+     * </pre>
+     * or if the Configuration should be loaded out of the Classpath:
+     * <pre>
+     * &lt;mime location="resource://org.a.MyFile"&gt;
+     * </pre>
+     */
+    public static void configure(String location) {
+        // load mime table
+        boolean loadFromClasspath = false;
+        if (location.startsWith("resource://")) {
+            loadFromClasspath = true;
+            location = location.substring(11);
+        }
+
+        try {
+            if (loadFromClasspath) {
+                InputStream is = Thread.currentThread().getContextClassLoader().getResource(location).openStream();
+                if (log.isDebugEnabled()) {
+                    log.debug("Load Configuration from Classpath: " + location);
+                }
+                addMimeConfig(DOMParser.toDocument(is));
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug("Load Configuration from File: " + location);
+                }
+                addMimeConfig(DOMParser.toDocument(location));
+            }
+        } catch (Exception e) {
+            log.error("Could not load MimeTable configuration", e);
+        }
+    }
+
+    /**
+     * Add the given mime Document to this mime table.
+     * the mime Document looks like this:
+     * <pre>
+     * &lt;mime&gt;
+     *  &lt;mime-mapping&gt;
+     *   &lt;extension&gt;xml&lt;/extension&gt;
+     *   &lt;mime-type&gt;xml&lt;/mime-type&gt;
+     *  &lt;/mime-mapping&gt;
+     * ...
+     * &lt;/mime&gt;
+     * </pre>
+     *
+     * @param doc mime config.
+     */
+    public static void addMimeConfig(Document doc) {
+        NodeList mapping = doc.getChildNodes();
+        for (int i = 0; i < mapping.getLength(); i++) {
+            NodeList thisMapping = mapping.item(i).getChildNodes();
+            String ext = "";
+            String type = "";
+            for (int j = 0; j < thisMapping.getLength(); j++) {
+                if (thisMapping.item(j).getNodeName().equalsIgnoreCase("extension")) {
+                    ext = thisMapping.item(j).getNodeValue();
+                } else if (thisMapping.item(j).getNodeName().equalsIgnoreCase("mime-type")) {
+                    type = thisMapping.item(j).getNodeValue();
+                }
+            }
+            mimeMappings.put(ext, type);
+        }
+    }
+
+    /**
+     * Returns the mime type for the given name.
+     * If no mime for this name is available the parameter defaultXml specifies if
+     * the xml mime type or the binary mime type are returned.
+     *
+     * @param resourceName
+     * @return mime type for this resource name
+     */
+    public static String getMimeType(String resourceName) {
+        int split = resourceName.lastIndexOf('.');
+        String mime = null;
+        if (split > 0) {
+            mime = (String) mimeMappings.get(resourceName.substring(split + 1));
+        }
+
+        if (mime != null) {
+            return mime;
+        } else {
+            return BINARY_MIME_TYPE;
+        }
+    }
+
+    private static void writeMappingAsXml(HashMap mappings, Writer out) throws IOException {
+        out.write("<?xml version=\"1.0\"?>\n");
+        out.write("<mime>\n");
+        for (Iterator i = mappings.keySet().iterator(); i.hasNext();) {
+            String ext = (String) i.next();
+            String type = (String) mappings.get(ext);
+
+            out.write("    <mime-mapping>\n");
+            out.write("        <extension>" + ext + "</extension>\n");
+            out.write("        <mime-type>" + type + "</mime-type>\n");
+            out.write("    </mime-mapping>\n");
+        }
+        out.write("</mime>");
+    }
+
+    private static HashMap parseApacheHttpdMime(String location) throws IOException {
+        HashMap mappings = new HashMap();
+        BufferedReader f = new BufferedReader(new FileReader(location));
+        String line;
+        while ((line = f.readLine()) != null) {
+            int startComment = line.indexOf('#');
+            if (startComment >= 0) {
+                line = line.substring(0, startComment);
+            }
+            line = line.trim();
+            String[] parsedLine = line.split(" |\\t");
+            if (parsedLine.length >= 2) {
+                for (int i = 1; i < parsedLine.length; i++) {
+                    if (parsedLine[i].length() > 0) {
+                        mappings.put(parsedLine[i], parsedLine[0]);
+                    }
+                }
+            }
+        }
+        return mappings;
+    }
+
+    private static void convertApacheHttpdMimeToXml(String source, String destination) throws IOException {
+        HashMap mappings = parseApacheHttpdMime(source);
+        BufferedWriter output = new BufferedWriter(new FileWriter(destination));
+        writeMappingAsXml(mappings, output);
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (args.length != 2) {
+            System.out.println("Convert Apache httpd mime file to a xml file");
+            System.out.println("Usage: java org.apache.xindice.webadmin.util.MimeTable httpdfile xmlfile");
+            System.exit(1);
+        }
+
+        convertApacheHttpdMimeToXml(args[0], args[1]);
+        System.out.println("Converted " + args[0] + " to " + args[1]);
+    }
+}

Modified: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlCollectionViewer.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlCollectionViewer.java?view=diff&rev=541504&r1=541498&r2=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlCollectionViewer.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlCollectionViewer.java Thu May 24 18:43:39 2007
@@ -36,17 +36,12 @@
 public interface HtmlCollectionViewer {
 
 	/**
-	 * Role identifying Component
-	 */	
-	String ROLE = HtmlCollectionViewer.class.getName();
-	
-	/**
-	 * executes request to a collection.
+	 * Executes request to a collection.
 	 * 
 	 * @param req request from servlet.
 	 * @param res servlet response.
 	 * @param col requested collection (not null).
 	 */
-	public void execute(HttpServletRequest req, HttpServletResponse res,
-		Collection col) throws ServletException, IOException; 
+	public void execute(HttpServletRequest req, HttpServletResponse res, Collection col)
+            throws ServletException, IOException;
 }

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlCollectionViewer.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu May 24 18:43:39 2007
@@ -1 +1 @@
-Author Date Id Revision
+Id Revision Author Date

Added: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlDatabaseViewer.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlDatabaseViewer.java?view=auto&rev=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlDatabaseViewer.java (added)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlDatabaseViewer.java Thu May 24 18:43:39 2007
@@ -0,0 +1,39 @@
+/*
+ * 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.xindice.webadmin.viewer;
+
+import org.apache.xindice.core.Collection;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletException;
+import java.io.IOException;
+
+/**
+ * Xindice Html Database Interface Component.
+ */
+public interface HtmlDatabaseViewer {
+
+    /**
+     * executes request to a collection.
+     *
+     * @param req request from servlet.
+     * @param res servlet response.
+     */
+    public void execute(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;
+}

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlDatabaseViewer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlDatabaseViewer.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision Author Date

Modified: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlResourceViewer.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlResourceViewer.java?view=diff&rev=541504&r1=541498&r2=541504
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlResourceViewer.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlResourceViewer.java Thu May 24 18:43:39 2007
@@ -34,19 +34,15 @@
  * @version $Id$
  */
 public interface HtmlResourceViewer {
-	
-	/** Role identifying Component */
-	String ROLE = HtmlResourceViewer.class.getName();
-	
+
 	/**
 	 * executes request to a resource.
 	 * 
 	 * @param req request from servlet.
 	 * @param res servlet response.
-	 * @param parentCol parent collection of the requested resource (not null).
+	 * @param col parent collection of the requested resource (not null).
 	 * @param resourceName name of the requested resource.
 	 */
-	public void execute(HttpServletRequest req, HttpServletResponse res,
-	 	Collection parentCol, String resourceName)
+	public void execute(HttpServletRequest req, HttpServletResponse res, Collection col, String resourceName)
 	 	throws ServletException, IOException;
 }

Propchange: xml/xindice/trunk/java/src/org/apache/xindice/webadmin/viewer/HtmlResourceViewer.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu May 24 18:43:39 2007
@@ -1 +1 @@
-Author Date Id Revision
+Id Revision Author Date