initial version of frontend layer
[opensuse:webpin2.git] / api / webpin.api / src / main / java / org / opensuse / webpin / api / SolrQueryServerResource.java
1 /*
2  * Created on Aug 3, 2010
3  */
4 package org.opensuse.webpin.api;
5
6 import java.net.ConnectException;
7 import java.util.LinkedList;
8 import java.util.List;
9
10 import org.apache.solr.client.solrj.SolrQuery;
11 import org.apache.solr.client.solrj.SolrServer;
12 import org.apache.solr.client.solrj.SolrServerException;
13 import org.apache.solr.client.solrj.SolrRequest.METHOD;
14 import org.apache.solr.client.solrj.response.QueryResponse;
15 import org.apache.solr.common.SolrDocumentList;
16 import org.restlet.Request;
17 import org.restlet.Response;
18 import org.restlet.Restlet;
19 import org.restlet.data.Status;
20 import org.springframework.beans.factory.annotation.Required;
21
22 public abstract class SolrQueryServerResource extends Restlet {
23
24         private static final String[] EMPTY_STRING_ARRAY = {};
25         
26         private int defaultRows;
27         private String solrQueryType;
28         private SolrServer solrServer;
29         
30         @Required public void setDefaultRows(int defaultRows) {
31                 this.defaultRows = defaultRows;
32         }
33         
34         @Required public void setSolrQueryType(String solrQueryType) {
35                 this.solrQueryType = solrQueryType;
36         }
37         
38         @Required public void setSolrServer(SolrServer solrServer) {
39                 this.solrServer = solrServer;
40         }
41         
42         public static interface QueryMethod {
43                 String configure(Request request, Response response, SolrQueryServerResource rsc, SolrQuery query, List<String> filterQueries);
44         }
45         
46         protected final String getStringAttribute(final Request request, final String name, final String defaultValue) {
47         Object o = request.getAttributes().get(name);
48         if (o == null) {
49             o = request.getResourceRef().getQueryAsForm().getFirstValue(name);
50         }
51         if (o == null) {
52                 return defaultValue;
53         } else {
54             return o.toString();
55         }
56         }
57         
58         protected final String getStringAttribute(final Request request, final Response response, final String name) {
59         Object o = request.getAttributes().get(name);
60         if (o == null) {
61             o = request.getResourceRef().getQueryAsForm().getFirstValue(name);
62         }
63         if (o == null) {
64             response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "missing parameter: " + name);
65             throw new IllegalArgumentException("missing parameter: " + name);
66         } else {
67             return o.toString();
68         }
69         }
70
71         protected final int getIntAttribute(final Request request, final Response response, final String name, final int defaultValue) {
72                 final String s;
73                 {
74                 Object o = request.getAttributes().get(name);
75                 if (o == null) {
76                     o = request.getResourceRef().getQueryAsForm().getFirstValue(name);
77                 }
78                 if (o == null) {
79                         return defaultValue;
80                 } else {
81                     s = o.toString();
82                 }
83                 }
84                 try {
85                         return Integer.parseInt(s);
86                 } catch (final NumberFormatException e) {
87             response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "invalid value for numeric parameter " + name + ": " + s);
88             throw new IllegalArgumentException("invalid value for numeric parameter " + name + ": " + s);
89                 }
90         }
91         
92         protected final int getIntAttribute(final Request request, final Response response, final String name) {
93                 final String s = getStringAttribute(request, response, name);
94                 try {
95                         return Integer.parseInt(s);
96                 } catch (final NumberFormatException e) {
97             response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "invalid value for numeric parameter " + name + ": " + s);
98             throw new IllegalArgumentException("invalid value for numeric parameter " + name + ": " + s);
99                 }
100         }
101
102         protected static final class QueryResult {
103                 public final SolrDocumentList results;
104                 public final String query;
105                 public QueryResult(final QueryResponse response, final String query) {
106                         this.results = response.getResults();
107                         this.query = query;
108                 }
109         }
110         
111         protected final SolrQueryServerResource.QueryResult query(final QueryMethod queryMethod, final Request request, final Response response) {
112             final int start = getIntAttribute(request, response, "start", 0);
113             final int rows = getIntAttribute(request, response, "rows", defaultRows);
114             final String distVersion;
115             final String distName;
116             {
117                     final String dist = getStringAttribute(request, "dist", null);
118                 if (dist != null) {
119                         final int index = dist.indexOf("_");
120                         if (index > 0) {
121                                 distName = dist.substring(0, index);
122                                 {
123                                         final String v = dist.substring(index + 1);
124                                         if (v.contains(".")) {
125                                                 distVersion = v;
126                                         } else {
127                                                 distVersion = v.substring(0, 2) + "." + v.substring(2);
128                                         }
129                                 }
130                         } else {
131                                 distName = dist;
132                                 distVersion = null;
133                         }
134                 } else {
135                         distVersion = null;
136                         distName = null;
137                 }
138             }
139
140             final SolrQuery query = new SolrQuery()
141             .setQuery("")
142                 .setQueryType(solrQueryType)
143                 .setFields("*")
144                 .setIncludeScore(true)
145                 .setStart(start)
146                 .setRows(rows)
147                 ;
148
149             final List<String> filterQueries = new LinkedList<String>();
150             final String queryDescription = queryMethod.configure(request, response, this, query, filterQueries);
151             
152             if (distName != null) {
153                 filterQueries.add("distname:"+distName);
154             }
155             if (distVersion != null) {
156                 filterQueries.add("distversion:"+distVersion);
157             }
158         if (! filterQueries.isEmpty()) {
159                 query.setFilterQueries(filterQueries.toArray(EMPTY_STRING_ARRAY));
160         }
161         
162                 final QueryResponse resp;
163                 try {
164                         resp = solrServer.query(query, METHOD.GET);
165                 } catch (final SolrServerException e) {
166                         if (e.getCause() instanceof ConnectException) {
167                                 response.setStatus(Status.SERVER_ERROR_SERVICE_UNAVAILABLE, "failed to contact Solr");
168                         } else {
169                                 response.setStatus(Status.SERVER_ERROR_INTERNAL, "failed to query Solr: " + e.getMessage());
170                         }
171             return null; // make compiler happy
172                 }
173                 return new QueryResult(resp, queryDescription);
174         }
175         
176 }