You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by "Shawn C. Dodd" <sd...@agea.com> on 2001/04/26 23:50:20 UTC

Client-side SEARCH implementation

Hello,

My name is Shawn Dodd and I've been evaluating webdavlib for use in
server-to-server environments.  I have a Servlet/EJB application that needs
to talk to Microsoft Exchange 2000's Web Storage System via WebDAV.  Allow
me to compliment you on the quality of your WebDAV client library; I was
able to get it up and running with almost no problems.

I've written an XMLResponseMethod-derived class to generate WebDAV SEARCH
requests (and named it org. apache. webdav. lib. methods. SearchMethod).
I've included the source below.  I'd like to contribute it to your project
under the Apache license (which I've stripped from the source below in order
to save space).

It's not particularly clever work, and there are lots of features I'd like
to add, but it does work against MS WSS/Exchange2k.  You can pass in SQL
queries and get back PROPFIND-style response XML.  I can post sample code
that uses SearchMethod to query WSS if you like.  The code below compiles
against the April 17 nightly build of webdavlib.jar.

Criticisms and comments are welcome.


Shawn

---------------------

package org.apache.webdav.lib.methods;

import java.io.InputStream;
import java.io.IOException;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import org.apache.util.WebdavStatus;
import org.apache.util.XMLPrinter;

import org.apache.webdav.lib.Header;
import org.apache.webdav.lib.Property;
import org.apache.webdav.lib.State;
import org.apache.webdav.lib.WebdavException;

import org.apache.webdav.lib.properties.GetLastModifiedProperty;
import org.apache.webdav.lib.properties.ResourceTypeProperty;

/**
 * This class implements the WebDAV SEARCH Method.
 *
 * <P>     The SEARCH method initiates a server-side search. The body of the
 * request defines the query. The server responds with a text/xml entity
 * matching the WebDAV PROPFIND response.
 *
 * <P>     According to <a
href="http://www.webdav.org/dasl/protocol/draft-dasl-protocol-00.html">
 * the DASL draft</a> a typical request looks like this:
 *
 * <PRE>
 * SEARCH /folder/ HTTP/1.1
 * Host: www.foo.bar
 * Content-type: text/xml; charset="utf-8"
 * Content-Length: xxxx
 *
 * <?xml version="1.0"?>
 * <D:searchrequest xmlns:D = "DAV:" >
 * <D:basicsearch>
 *   <D:select>
 *     <D:prop><D:getcontentlength/></D:prop>
 *   </D:select>
 *   <D:from>
 *     <D:scope>
 *       <D:href>/folder/</D:href>
 *       <D:depth>infinity</D:depth>
 *     </D:scope>
 *   </D:from>
 * </D:basicsearch>
 * </D:searchrequest>
 * </PRE>
 *
 * <P>     However, other query grammars may be used. A typical request
using
 * the <a
href="http://msdn.microsoft.com/library/default.asp?URL=/library/psdk/exchsv
2k/_exch2k_sql_web_storage_system_sql.htm">
 * SQL-based grammar</a> implemented in Microsoft's Web Storage System
 * (currently shipping with Exchange 2000 and SharePoint Portal Server)
looks
 * like this:
 *
 * <PRE>
 * SEARCH /folder/ HTTP/1.1
 * Host: www.foo.bar
 * Content-type: text/xml; charset="utf-8"
 * Content-Length: xxxx
 *
 * <?xml version="1.0"?>
 * <D:searchrequest xmlns:D = "DAV:" >
 *   <D:sql>
 *   SELECT "DAV:contentclass", "DAV:displayname"
 *     FROM "/folder/"
 *    WHERE "DAV:ishidden" = false
 *      AND "DAV:isfolder" = false
 *   </D:sql>
 * </D:searchrequest>
 * </PRE>
 *
 * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
 * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
 * @author <a href="mailto:sdodd@agea.com">Shawn C. Dodd</a>
 */
public class SearchMethod extends XMLResponseMethodBase
    implements DepthSupport {


    // --------------------------------------------------------------
Constants


    /**
     * Request of named properties.
     */
    public static final int BY_NAME = 0;


    /**
     * Request of all properties name and value.
     */
    public static final int ALL = 1;


    /**
     * Request of all properties name.
     */
    public static final int NAMES = 2;


    // -----------------------------------------------------------
Constructors


    /**
     * Method constructor.
     */
    public SearchMethod() {
        name = "SEARCH";
    }


    /**
     * Method constructor.
     */
    public SearchMethod(String path) {
        super(path);
        name = "SEARCH";
    }


    /**
     * Method constructor.
     */
    public SearchMethod(String path, int depth) {
        this(path);
        setDepth(depth);
    }


    /**
     * Method constructor.
     */
    public SearchMethod(String path, int depth, int type) {
        this(path);
        setDepth(depth);
        setType(type);
    }


    /**
     * Construct a SearchMethod using the given XML request body.
     *
     * @param path  Relative path to the WebDAV resource (presumably a
collection).
     * @param query Complete request body in XML including a search query in
your favorite grammar.
     */
    public SearchMethod(String path, String query) {
        this(path);
        setDepth(1);
        setQuery(query);
        setType(BY_NAME);
    }


    /**
     * Construct a SearchMethod using the given XML request body.
     *
     * @param path  relative path to the WebDAV resource (presumably a
collection)
     * @param depth query scope
     * @param query complete request body in XML including a search query in
your favorite grammar
     */
    public SearchMethod(String path, int depth, String query) {
        this(path);
        setDepth(depth);
        setQuery(query);
        setType(BY_NAME);
    }


    // ----------------------------------------------------- Instance
Variables


    /**
     * Type of the Propfind.
     */
    protected int type = ALL;


    /**
     * Depth.
     */
    protected int depth = DEPTH_INFINITY;


    /**
     * The namespace abbreviation that prefixes DAV tags
     */
    protected String prefix = null;


    // -------------------------------------------------------------
Properties




    /**
     * Set header. handle the special case of Depth.
     *
     * @param headerName Header name
     * @param headerValue Header value
     */
    public void setHeader(String headerName, String headerValue) {
        if (headerName.equalsIgnoreCase("Depth")){
            int depth = -1;
            if (headerValue.equals("0")){
                depth = DEPTH_0;
            }
            if (headerValue.equals("1")){
                depth = DEPTH_1;
            }
            else if (headerValue.equalsIgnoreCase("infinity")){
                depth = DEPTH_INFINITY;
            }
            setDepth(depth);
        }
        else{
            super.setHeader(headerName, headerValue);
        }
    }


    /**
     * Type setter.
     *
     * @param type New type value
     */
    public void setType(int type) {
        checkNotUsed();
        this.type = type;
    }


    /**
     * Type getter.
     *
     * @return int type value
     */
    public int getType() {
        return type;
    }


    /**
     * Depth setter.
     *
     * @param depth New depth value
     */
    public void setDepth(int depth) {
        checkNotUsed();
        this.depth = depth;
    }


    /**
     * Depth getter.
     *
     * @return int depth value
     */
    public int getDepth() {
        return depth;
    }


    // --------------------------------------------------- WebdavMethod
Methods


    public void recycle() {
        super.recycle();
        prefix = null;
    }

    /**
     * Generate additional headers needed by the request.
     *
     * @param host the host
     * @param state State token
     */
    public void generateHeaders(String host, State state) {

        super.generateHeaders(host, state);

        super.setHeader("Content-Type", "text/xml; charset=utf-8");

        switch (depth) {
        case DEPTH_0:
            super.setHeader("Depth", "0");
            break;
        case DEPTH_1:
            super.setHeader("Depth", "1");
            break;
        case DEPTH_INFINITY:
            super.setHeader("Depth", "infinity");
            break;
        }

    }

    /**
     * Return the query supplied in the constructor or setQuery(). In
future,
     * this will construct a query in the grammar you're interested in.
     *
     * @return String query
     */
    public String generateQuery() {

        if (query == null || query.trim().length() < 1) {
            // TODO  Must support some mechanism for delegating the
            // generation of the query to a pluggable query grammar
            // support class or package. Right now, executing this
            // method object without first explicitly setting the
            // query is an error.
            return "";
        } else {
            return query;
        }

    }

    /**
     * This method returns an enumeration of URL paths.  If the
PropFindMethod
     * was sent to the URL of a collection, then there will be multiple
URLs.
     * The URLs are picked out of the <code>&lt;D:href&gt;</code> elements
     * of the response.
     *
     * @return an enumeration of URL paths as Strings
     */
    public Enumeration getAllResponseURLs() {
        checkUsed();
        return getResponseHashtable().keys();
    }

    /**
     * Returns an enumeration of <code>Property</code> objects.
     */
    public Enumeration getResponseProperties(String urlPath) {
        checkUsed();

        Response response = (Response) getResponseHashtable().get(urlPath);
        if (response != null) {
            return response.getProperties();
        } else {
            return (new Vector()).elements();
        }

    }
}




Re: Client-side SEARCH implementation

Posted by Remy Maucherat <re...@apache.org>.
> Hello,
>
> My name is Shawn Dodd and I've been evaluating webdavlib for use in
> server-to-server environments.  I have a Servlet/EJB application that
needs
> to talk to Microsoft Exchange 2000's Web Storage System via WebDAV.  Allow
> me to compliment you on the quality of your WebDAV client library; I was
> able to get it up and running with almost no problems.
>
> I've written an XMLResponseMethod-derived class to generate WebDAV SEARCH
> requests (and named it org. apache. webdav. lib. methods. SearchMethod).
> I've included the source below.  I'd like to contribute it to your project
> under the Apache license (which I've stripped from the source below in
order
> to save space).
>
> It's not particularly clever work, and there are lots of features I'd like
> to add, but it does work against MS WSS/Exchange2k.  You can pass in SQL
> queries and get back PROPFIND-style response XML.  I can post sample code
> that uses SearchMethod to query WSS if you like.  The code below compiles
> against the April 17 nightly build of webdavlib.jar.
>
> Criticisms and comments are welcome.

It's a good start and I'll commit it.
Thanks !

Remy