Added by Wander Grevink, last edited by Wander Grevink on May 23, 2006  (view change)

Labels:

Enter labels to add to this page:
Wait Image 
Looking for a label? Just start typing.
/*
 * Copyright 2006 Hippo
 *
 * Licensed under the Apache License, Version 2.0 (the  "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" 
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package nl.hippo.webdav.utils;

import java.io.StringWriter;
import java.util.Properties;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.webdav.lib.methods.OptionsMethod;
import org.apache.webdav.lib.methods.SearchMethod;

/**
 * <p>
 * A utility class for searching a Hippo repository (or any other WebDav compliant server) using DASL
 * </p><p>
 * Using this class boils down to:
 * <ol>
 *  <li>Create an instance by calling the constructor</li>
 *  <li>Initialize it by calling setConfig() and setDasl()</li>
 *  <li>Execute it by calling execute()</li>
 * </ol>
 * See SearchMain for a concrete example.
 * </p>
 * 
 * @author wgrevink
 */
public class Search {

    private Properties config;
    private String dasl;

    
    /**
     * The one and only constructor
     */
    public Search() {
    }

    
    /**
     * Set configuration properties 
     * @param properties Should contain all configuration properties, see etc/search.properties for details and defaults. 
     */
    public void setConfig(Properties properties) {
        this.config = properties;
    }

    
    /**
     * Specify the DASL to execute
     * @param dasl The String representation of a DASL query, see etc/dasl.xml for an example.
     */
    public void setDasl(String dasl) {
        this.dasl = dasl;
    }

    
    /**
     * Execute the specified query using the specified configuration. 
     * @return The result of the DASL query (an XML String)
     * @throws RuntimeException if an error ocurred. In a real world application it 
     * would probably be better to throw a dedicated checked exception type.
     */
    public String execute() throws RuntimeException {
        if (dasl == null || config == null) {
            die("Search has not properly been initialized, please call setConfig() and setDasl() before calling execute()." );
        }
        
        HttpClient client = new HttpClient();
        client.setState(initHttpState());
    
        if (searchMethodSupported(client)) {
            return executeSearch(client);
        }
        else {
            return ("The server doesn't support the SEARCH method");
        }
    }

    // Privates

    /**
     * Perform the actual search
     * @return The result of the DASL query (an XML String)
     */
    private String executeSearch(HttpClient client) {
        try {
            SearchMethod searchMethod = new SearchMethod(getUrl(), dasl);
            client.executeMethod(searchMethod);
            return document2String(searchMethod.getResponseDocument());
        }
        catch (Exception e) {
            die("Error while executing SEARCH", e);
        }
        return null;
    }

    
    /**
     * Check if the WebDAV SEARCH method is supported 
     * @return true if the configured server supports the SEARCH method
     */
    private boolean searchMethodSupported(HttpClient client) {
        try {
            OptionsMethod optionsMethod = new OptionsMethod(getUrl());
            client.executeMethod(optionsMethod);
            return optionsMethod.isAllowed("SEARCH");
        }
        catch (Exception e) {
            die("Error while checking if SEARCH is supported", e);
        }
        return false;
    }

    // Getters

    private String getUsername() {
        return config.getProperty("username");
    }

    private String getPassword() {
        return config.getProperty("password");
    }

    private String getRealm() {
        return config.getProperty("realm");
    }

    private String getHost() {
        return config.getProperty("host");
    }

    private String getUrl() {
        String host = config.getProperty("host");
        String port = config.getProperty("port");
        String repopath = config.getProperty("repopath");
        String rootpath = config.getProperty("rootpath");
        String docpath = config.getProperty("docpath");

        return new String("http://" + host + ":" + port + "/" + repopath + "/" + rootpath + "/" + docpath);
    }

    // Utilities

    private String document2String(Document doc) {
        StringWriter response = new StringWriter();
        try {
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer();
            transformer.transform(new DOMSource(doc), new StreamResult(response));
        }
        catch (Exception e) {
            die("Error while parsing response", e);
        }
        return response.toString();
    }

    private HttpState initHttpState() {
        HttpState state = new HttpState();
        Credentials credentials = new UsernamePasswordCredentials(getUsername(), getPassword());
        state.setCredentials(getRealm(), getHost(), credentials);
        return state;
    }

    //In a real world application it would probably be better to throw
    //a dedicated checked exception type iso. the non-checked RuntimeException
    private void die(String message, Exception e) throws RuntimeException {
        throw new RuntimeException(message + " => " + e.getMessage());
    }
    private void die(String message) throws RuntimeException {
        throw new RuntimeException(message);
    }

}