idok-commit AT lists.psi.ch
Subject: Commit emails of the iDok project
List archive
[idok-commit] idok commit r191 - branches/rest/java/ch/idok/service/client/search/rest
Chronological Thread
- From: "AFS account Roman Geus" <geus AT savannah.psi.ch>
- To: idok-commit AT lists.psi.ch
- Subject: [idok-commit] idok commit r191 - branches/rest/java/ch/idok/service/client/search/rest
- Date: Tue, 26 Aug 2008 17:36:47 +0200
- List-archive: <https://lists.web.psi.ch/pipermail/idok-commit/>
- List-id: Commit emails of the iDok project <idok-commit.lists.psi.ch>
Author: geus
Date: Tue Aug 26 17:36:47 2008
New Revision: 191
Log:
Added draft of client side search service for REST
Added:
branches/rest/java/ch/idok/service/client/search/rest/RestQueryMatch.java
branches/rest/java/ch/idok/service/client/search/rest/RestSearchIterator.java
branches/rest/java/ch/idok/service/client/search/rest/RestSearchService.java
Added:
branches/rest/java/ch/idok/service/client/search/rest/RestQueryMatch.java
==============================================================================
--- (empty file)
+++ branches/rest/java/ch/idok/service/client/search/rest/RestQueryMatch.java
Tue Aug 26 17:36:47 2008
@@ -0,0 +1,64 @@
+package ch.idok.service.client.search.rest;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.w3c.dom.Node;
+
+import ch.idok.common.util.Base64Coder;
+import ch.idok.service.common.search.QueryMatch;
+
+public class RestQueryMatch implements QueryMatch {
+
+ private String id = null;
+ private String env = null;
+ private byte[] content = null;
+ private Map<String, String> meta = null;
+ private String rev = null;
+ private String repo = null;
+
+ public RestQueryMatch(Node node) {
+ for (Node n = node.getFirstChild(); n != null; n =
n.getNextSibling()) {
+ if (n.getNodeName().equals("Id"))
+ id = n.getTextContent();
+ else if (n.getNodeName().equals("Environment"))
+ env = n.getTextContent();
+ else if (n.getNodeName().equals("Content"))
+ content =
Base64Coder.decode(n.getTextContent().toCharArray());
+ else if (n.getNodeName().equals("Meta")) {
+ meta = new HashMap<String, String>();
+ for (Node e = n.getFirstChild(); e != null; e =
e.getNextSibling()) {
+ meta.put(e.getFirstChild().getTextContent(),
e.getLastChild().getTextContent());
+ }
+ } else if (n.getNodeName().equals("Rev"))
+ rev = n.getTextContent();
+ else if (n.getNodeName().equals("Repo"))
+ repo = n.getTextContent();
+ }
+ }
+
+ public byte[] getContent() {
+ return content;
+ }
+
+ public String getEnvironment() {
+ return env;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public Map<String, String> getMetadata() {
+ return meta;
+ }
+
+ public String getRepo() {
+ return repo;
+ }
+
+ public String getVersion() {
+ return rev;
+ }
+
+}
Added:
branches/rest/java/ch/idok/service/client/search/rest/RestSearchIterator.java
==============================================================================
--- (empty file)
+++
branches/rest/java/ch/idok/service/client/search/rest/RestSearchIterator.java
Tue Aug 26 17:36:47 2008
@@ -0,0 +1,299 @@
+package ch.idok.service.client.search.rest;
+
+import java.util.NoSuchElementException;
+import java.util.logging.Logger;
+
+import javax.security.auth.Subject;
+import javax.ws.rs.core.UriBuilder;
+
+import org.restlet.Client;
+import org.restlet.Context;
+import org.restlet.data.ChallengeResponse;
+import org.restlet.data.ChallengeScheme;
+import org.restlet.data.Method;
+import org.restlet.data.Protocol;
+import org.restlet.data.Request;
+import org.restlet.data.Response;
+import org.restlet.data.Status;
+import org.restlet.resource.DomRepresentation;
+import org.restlet.util.NodeSet;
+import org.w3c.dom.Node;
+
+import ch.idok.common.errorhandling.DmsException;
+import ch.idok.common.errorhandling.ErrorType;
+import ch.idok.common.util.AuthUtil;
+import ch.idok.common.util.DmsCredentials;
+import ch.idok.common.util.ServiceTokenAction;
+import ch.idok.service.client.rest.RestClientProvider;
+import ch.idok.service.common.Iterator;
+import ch.idok.service.common.search.QueryMatch;
+import ch.idok.service.common.search.SearchService;
+import ch.idok.service.server.rest.NegotiateFilter;
+
+/**
+ * Iterator<QueryMatch> that returns search hits obtained through the REST
+ * search interface
+ */
+public class RestSearchIterator implements Iterator<QueryMatch> {
+
+ private final int hitsPerBatch = 10;
+
+ private final RestClientProvider restClientProvider;
+
+ private final Logger logger;
+
+ private final DmsCredentials cred;
+
+ private final String query;
+
+ private final String fields;
+
+ private final long resultType;
+
+ private final Client client;
+
+ /**
+ * The next element to be returned by <code>next()</code> or
+ * <code>nextElement()</code>, null if no further elements exist
+ */
+ private RestQueryMatch nextElement;
+
+ private java.util.Iterator<Node> hits;
+
+ /**
+ * Number of already consumed search hits, i.e. number of
+ * <code>next()</code> or <code>nextElement()</code> calls
+ */
+ int index;
+
+ /**
+ * True if all search hits have been fetched from the REST service
+ */
+ private boolean lastBatch;
+
+ /**
+ * RestSearchIterator constructor
+ */
+ RestSearchIterator(Logger logger, RestClientProvider restClientProvider,
+ DmsCredentials cred, String query, String fields, long
resultType)
+ throws DmsException {
+ this.logger = logger;
+ this.restClientProvider = restClientProvider;
+ this.cred = cred;
+ this.query = query;
+ this.fields = fields;
+ this.resultType = resultType;
+ index = 0;
+ lastBatch = false;
+
+ // Restlet context
+ final Context context = new Context(logger);
+
+ // HTTP client connector to handle the REST call
+ client = new Client(context, Protocol.HTTP);
+
+ // Fetch first batch of search hits
+ fetch();
+ }
+
+ /**
+ * Build the URI for the REST call
+ */
+ private String buildRestSearchURI(String query, String fields,
+ long resultType, int start, int num) throws DmsException {
+ // parse query string
+ String project;
+ String repository;
+ String q;
+ int iColon = query.indexOf("::");
+ int iSlash = query.indexOf('/');
+ if (iSlash < iColon) {
+ project = query.substring(0, iSlash);
+ repository = query.substring(iSlash + 1, iColon);
+ q = query.substring(iColon + 2);
+ } else {
+ throw new DmsException(ErrorType.BAD_ARG, this,
+ "Could not parse query string \"" + query + "\"", "");
+ }
+
+ // Build request URI
+ StringBuilder sb = new StringBuilder();
+ if ((resultType & SearchService.METADATA) != 0)
+ sb.append("meta,");
+ if ((resultType & SearchService.MATCH_ENVIRONEMENT) != 0)
+ sb.append("env,");
+ if ((resultType & SearchService.DOC_CONTENT) != 0)
+ sb.append("doc,");
+ if (sb.length() > 0)
+ sb.deleteCharAt(sb.length() - 1);
+ String outputfields = sb.toString();
+
+ UriBuilder ub = UriBuilder.fromUri(restClientProvider.getBaseUri())
+
.path("search").path(project).path(repository).queryParam("q",
+ q).queryParam("start", Integer.toString(index))
+ .queryParam("num", Integer.toString(num));
+ if (outputfields.length() > 0)
+ ub.queryParam("outputfields", outputfields);
+ final String uri = ub.toString();
+
+ return uri;
+ }
+
+ /**
+ * Build the Request object for the REST call.
+ */
+ private Request buildRequest(DmsCredentials cred, String uri)
+ throws DmsException {
+ final Request request = new Request(Method.GET, uri);
+
+ // Add the client authentication to the call
+ // final ChallengeScheme scheme1 = ChallengeScheme.HTTP_BASIC;
+ // final ChallengeResponse authentication = new
+ // ChallengeResponse(scheme,
+ // "geus", "xxx");
+
+ // authentication
+ // .getParameters()
+ // .add(
+ //
NegotiateFilter.NegotiateAuthenticationHelper.NEGOTIATE_TOKEN_PARAM_NAME,
+ // createAuthToken(cred.getSubject()));
+
+
+ // Use Negotiate authentication
+ final ChallengeScheme scheme = NegotiateFilter.HTTP_NEGOTIATE;
+
+ // Place the Negotiate token in the password field
+ final ChallengeResponse authentication = new
ChallengeResponse(scheme,
+ "", createAuthToken(cred.getSubject()));
+
+ request.setChallengeResponse(authentication);
+ return request;
+ }
+
+ /**
+ * Fetch the next batch for search hits using a REST call.
+ *
+ * <code>hits</code> will contain an iterator to the fetched data.
+ * <code>nextElement</code> will be set to the first new hit or null if
no
+ * further hits could be fetched.
+ *
+ * @throws DmsException
+ */
+ private void fetch() throws DmsException {
+ if (lastBatch)
+ nextElement = null;
+ else {
+ String uri = buildRestSearchURI(query, fields, resultType, index,
+ hitsPerBatch);
+ Request request = buildRequest(cred, uri);
+ logger.info("GET " + uri);
+ final Response response = client.handle(request);
+
+ if (response.getStatus().isSuccess()) {
+ DomRepresentation document = response.getEntityAsDom();
+ NodeSet result = document.getNodes("/Hits/Hit");
+ if (result.size() < hitsPerBatch)
+ lastBatch = true;
+ hits = result.iterator();
+ if (hits.hasNext())
+ nextElement = new RestQueryMatch(hits.next());
+ else
+ nextElement = null;
+ } else if (response.getStatus().equals(
+ Status.CLIENT_ERROR_UNAUTHORIZED)) {
+ throw new DmsException(ErrorType.AUTHENTICATION, null,
+ "REST call failed", "Authentication failed");
+ } else {
+ throw new DmsException(ErrorType.INTERNAL, null,
+ "REST call failed",
+ "An unexpected status was returned: "
+ + response.getStatus());
+ }
+ }
+ }
+
+ /**
+ * Nothing to do. The REST server cleans its state automatically.
+ *
+ * @see ch.idok.service.common.Iterator#destroy()
+ */
+ public void destroy() throws DmsException {
+
+ }
+
+ /**
+ * @see ch.idok.service.common.Iterator#hasNext()
+ */
+ public boolean hasNext() {
+ if (nextElement == null)
+ return false;
+ else
+ return true;
+ }
+
+ /**
+ * @see ch.idok.service.common.Iterator#next()
+ */
+ public QueryMatch next() {
+ try {
+ QueryMatch result = nextElement();
+ if (result == null)
+ throw new NoSuchElementException();
+ return result;
+ } catch (DmsException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @see ch.idok.service.common.Iterator#nextElement()
+ */
+ public QueryMatch nextElement() throws DmsException {
+ QueryMatch result = nextElement;
+ if (result == null)
+ return null;
+ else {
+ index += 1;
+ if (hits.hasNext())
+ nextElement = new RestQueryMatch(hits.next());
+ else {
+ fetch();
+ }
+ return result;
+ }
+ }
+
+ /**
+ * @see ch.idok.service.common.Iterator#remove()
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Create a GSS-API token for the DMS service.
+ */
+ private String createAuthToken(Subject subject) throws DmsException {
+ final String serviceName_ = System
+ .getProperty("ch.idok.service.server.principal");
+ ServiceTokenAction action = new ServiceTokenAction(serviceName_);
+
+ // Push the subject into the current ACC
+ try {
+ Subject.doAsPrivileged(subject, action, null);
+ logger.fine("Successfully created service token for "
+ + action.getServiceName() + " as "
+ + AuthUtil.principalSetToString(subject.getPrincipals())
+ + ".");
+ return action.getToken64();
+ } catch (java.security.PrivilegedActionException pae) {
+ if (pae.getCause() instanceof DmsException)
+ throw (DmsException) pae.getCause();
+ throw new DmsException(ErrorType.INTERNAL, null,
+ "The privileged action threw an unknown exception", "",
pae
+ .getCause());
+ }
+
+ }
+
+}
Added:
branches/rest/java/ch/idok/service/client/search/rest/RestSearchService.java
==============================================================================
--- (empty file)
+++
branches/rest/java/ch/idok/service/client/search/rest/RestSearchService.java
Tue Aug 26 17:36:47 2008
@@ -0,0 +1,47 @@
+package ch.idok.service.client.search.rest;
+
+import java.util.logging.Logger;
+
+import ch.idok.common.errorhandling.DmsException;
+import ch.idok.common.util.DmsCredentials;
+import ch.idok.service.client.rest.RestClientProvider;
+import ch.idok.service.common.Iterator;
+import ch.idok.service.common.search.QueryMatch;
+import ch.idok.service.common.search.SearchService;
+
+/**
+ * Client-side search service that obtains the results from the iDok REST
server
+ */
+public class RestSearchService implements SearchService {
+
+ private final RestClientProvider restClientProvider;
+
+ private final Logger logger;
+
+ /**
+ * Constructor
+ */
+ public RestSearchService(RestClientProvider restClientProvider) {
+ this.restClientProvider = restClientProvider;
+ logger = restClientProvider.getLogger();
+ }
+
+ /**
+ * @see
ch.idok.service.common.search.SearchService#listMetafields(ch.idok.common.util.DmsCredentials,
java.lang.String)
+ */
+ public String[] listMetafields(DmsCredentials cred, String repository)
+ throws DmsException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * @see
ch.idok.service.common.search.SearchService#query(ch.idok.common.util.DmsCredentials,
java.lang.String, java.lang.String, long)
+ */
+ public Iterator<QueryMatch> query(DmsCredentials cred, String query,
+ String fields, long resultType) throws DmsException {
+ return new RestSearchIterator(logger, restClientProvider, cred,
query,
+ fields, resultType);
+ }
+
+}
- [idok-commit] idok commit r191 - branches/rest/java/ch/idok/service/client/search/rest, AFS account Roman Geus, 08/26/2008
Archive powered by MHonArc 2.6.19.