/*
* 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: *
* 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");
}
}
/**
* 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;
}
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);
}
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;
}
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);
}
}