source: SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUAbstractRequest.java @ 2880

Last change on this file since 2880 was 2880, checked in by oschonef, 11 years ago
  • ensure that generated URIs are correctly UTF-8 encoded and URI-escaped
  • Property svn:eol-style set to native
File size: 12.0 KB
Line 
1/**
2 * This software is copyright (c) 2011-2013 by
3 *  - Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
4 * This is free software. You can redistribute it
5 * and/or modify it under the terms described in
6 * the GNU General Public License v3 of which you
7 * should have received a copy. Otherwise you can download
8 * it from
9 *
10 *   http://www.gnu.org/licenses/gpl-3.0.txt
11 *
12 * @copyright Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
13 *
14 * @license http://www.gnu.org/licenses/gpl-3.0.txt
15 *  GNU General Public License v3
16 */
17package eu.clarin.sru.client;
18
19import java.net.URI;
20import java.net.URISyntaxException;
21import java.util.HashMap;
22import java.util.Map;
23
24import org.apache.http.client.utils.URIBuilder;
25
26
27
28/**
29 * Abstract base class for SRU requests.
30 *
31 * @see SRUExplainResponse
32 * @see SRUScanResponse
33 * @see SRUSearchRetrieveResponse
34 */
35abstract class SRUAbstractRequest {
36    static final String PARAM_OPERATION                = "operation";
37    static final String PARAM_VERSION                  = "version";
38    static final String PARAM_RECORD_PACKING           = "recordPacking";
39    static final String PARAM_STYLESHEET               = "stylesheet";
40    static final String PARAM_QUERY                    = "query";
41    static final String PARAM_START_RECORD             = "startRecord";
42    static final String PARAM_MAXIMUM_RECORDS          = "maximumRecords";
43    static final String PARAM_RECORD_SCHEMA            = "recordSchema";
44    static final String PARAM_RECORD_X_PATH            = "recordXPath";
45    static final String PARAM_RESULT_SET_TTL           = "resultSetTTL";
46    static final String PARAM_SORT_KEYS                = "sortKeys";
47    static final String PARAM_SCAN_CLAUSE              = "scanClause";
48    static final String PARAM_RESPONSE_POSITION        = "responsePosition";
49    static final String PARAM_MAXIMUM_TERMS            = "maximumTerms";
50    static final String RECORD_PACKING_XML             = "xml";
51    static final String RECORD_PACKING_STRING          = "string";
52    private static final String OP_EXPLAIN             = "explain";
53    private static final String OP_SCAN                = "scan";
54    private static final String OP_SEARCH_RETRIEVE     = "searchRetrieve";
55    private static final String VERSION_1_1            = "1.1";
56    private static final String VERSION_1_2            = "1.2";
57    private static final String PARAM_EXTENSION_PREFIX = "x-";
58    /** for end-point conformance testing only. never use in production. */
59    public static final String X_MALFORMED_OPERATION   =
60            "x-malformed-operation";
61    /** for end-point conformance testing only. never use in production. */
62    public static final String X_MALFORMED_VERSION     =
63            "x-malformed-version";
64    /** for end-point conformance testing only. never use in production. */
65    public static final String MALFORMED_OMIT          = "omit";
66    private static final String MALFORMED_KEY_PREFIX   = "x-malformed";
67
68
69    enum SRUOperation {
70        EXPLAIN, SCAN, SEARCH_RETRIEVE
71    } // enum SRUOperation
72
73
74    class URIHelper {
75        private final URIBuilder uriBuilder;
76
77
78        private URIHelper(URIBuilder builder) {
79            this.uriBuilder = builder;
80        }
81
82
83        public URIHelper append(String name, String value) {
84            if (name == null) {
85                throw new NullPointerException("name == null");
86            }
87            if (name.isEmpty()) {
88                throw new IllegalArgumentException("name is empty");
89            }
90            if (value == null) {
91                throw new NullPointerException("value == null");
92            }
93            if (value.isEmpty()) {
94                throw new IllegalArgumentException("value is empty");
95            }
96
97            uriBuilder.addParameter(name, value);
98            return this;
99        }
100
101
102        public URIHelper append(String name, int value) {
103            return append(name, Integer.toString(value));
104        }
105
106
107        private URI makeURI() throws URISyntaxException {
108            return uriBuilder.build();
109        }
110    } // class URIHelper
111    /** The URL of the endpoint. */
112    protected final String endpointURI;
113    /** The version to be sued  for this request. */
114    protected SRUVersion version;
115    /** A map of extra request data parameters. */
116    protected Map<String, String> extraRequestData;
117    private SRUVersion versionPreformed;
118
119
120    /**
121     * Constructor.
122     *
123     * @param endpointURI
124     *            the URI of the endpoint
125     * @throws NullPointerException
126     *             if any required argument is null
127     */
128    protected SRUAbstractRequest(String endpointURI) {
129        if (endpointURI == null) {
130            throw new NullPointerException("endpointURI == null");
131        }
132        this.endpointURI = endpointURI;
133    }
134
135
136    /**
137     * Get the endpoint URI.
138     *
139     * @return the endpoint URI
140     */
141    public String getEndpointURI() {
142        return endpointURI;
143    }
144
145
146    /**
147     * Set the version for this request.
148     *
149     * @param version a version of <code>null</code> for client default
150     */
151    public void setVersion(SRUVersion version) {
152        this.version = version;
153    }
154
155
156    /**
157     * Get the version for this request.
158     *
159     * @return version for this request or <code>null</code> of client default
160     *         is used
161     */
162    public SRUVersion getVersion() {
163        return version;
164    }
165
166
167    /**
168     * Set an extra request parameter for this request.
169     *
170     * @param name
171     *            the name for the extra request data parameter
172     * @param value
173     *            the value for the extra request data parameter
174     * @throws NullPointerException
175     *             if any required argument is <code>null</code>
176     * @throws IllegalArgumentException
177     *             if any argument is invalid
178     * @see <a href="http://www.loc.gov/standards/sru/specs/extra-data.html">SRU
179     *      Extra Data / Extensions</a>
180     */
181    public void setExtraRequestData(String name, String value) {
182        if (name == null) {
183            throw new NullPointerException("name == null");
184        }
185        if (name.isEmpty()) {
186            throw new IllegalArgumentException("name is an empty string");
187        }
188        if (!name.startsWith(PARAM_EXTENSION_PREFIX)) {
189            throw new IllegalArgumentException("name must start with '" +
190                    PARAM_EXTENSION_PREFIX + "'");
191        }
192        if (value == null) {
193            throw new NullPointerException("value == null");
194        }
195        if (value.isEmpty()) {
196            throw new IllegalArgumentException("value is an empty string");
197        }
198        if (extraRequestData == null) {
199            extraRequestData = new HashMap<String, String>();
200        }
201        extraRequestData.put(name, value);
202    }
203
204
205    /**
206     * Set the value of extra request parameter for this request.
207     *
208     * @param name
209     *            the name for the extra request data parameter
210     * @return the value for the extra request data parameter or
211     *         <code>null</code> if parameter was not set
212     * @throws NullPointerException
213     *             if any required argument is <code>null</code>
214     * @throws IllegalArgumentException
215     *             if any argument is invalid
216     * @see <a href="http://www.loc.gov/standards/sru/specs/extra-data.html">SRU
217     *      Extra Data / Extensions</a>
218     */
219    public String getExtraRequestData(String name) {
220        if (name == null) {
221            throw new NullPointerException("name == null");
222        }
223        if (name.isEmpty()) {
224            throw new IllegalArgumentException("name is an empty string");
225        }
226        if (!name.startsWith(PARAM_EXTENSION_PREFIX)) {
227            throw new IllegalArgumentException("name must start with '" +
228                    PARAM_EXTENSION_PREFIX + "'");
229        }
230        if (extraRequestData != null) {
231            return extraRequestData.get(name);
232        }
233        return null;
234    }
235
236
237    final SRUVersion getVersionPerformed() {
238        return versionPreformed;
239    }
240
241
242    final URI makeURI(SRUVersion defaultVersion)
243            throws SRUClientException {
244        if (defaultVersion == null) {
245            throw new NullPointerException("defaultVersion == null");
246        }
247
248        try {
249            final URIHelper uriBuilder =
250                    new URIHelper(new URIBuilder(endpointURI));
251
252            /*
253             * append operation parameter
254             *
255             * NB: Setting "x-malformed-operation" as an extra request parameter
256             * makes the client to send invalid requests. This is intended to
257             * use for testing endpoints for protocol conformance (i.e. provoke
258             * an error) and SHOULD NEVER be used in production!
259             */
260            final String malformedOperation =
261                    getExtraRequestData(X_MALFORMED_OPERATION);
262            if (malformedOperation == null) {
263                switch (getOperation()) {
264                case EXPLAIN:
265                    uriBuilder.append(PARAM_OPERATION, OP_EXPLAIN);
266                    break;
267                case SCAN:
268                    uriBuilder.append(PARAM_OPERATION, OP_SCAN);
269                    break;
270                case SEARCH_RETRIEVE:
271                    uriBuilder.append(PARAM_OPERATION, OP_SEARCH_RETRIEVE);
272                    break;
273                default:
274                    throw new SRUClientException("unsupported operation: " +
275                            getOperation());
276                } // switch
277            } else {
278                if (!malformedOperation.equals(MALFORMED_OMIT)) {
279                    uriBuilder.append(PARAM_OPERATION, malformedOperation);
280                }
281            }
282
283            /*
284             * append version parameter
285             *
286             * NB: Setting "x-malformed-version" as an extra request parameter
287             * makes the client to send invalid requests. This is intended to
288             * use for testing endpoints for protocol conformance (i.e. provoke
289             * an error) and SHOULD NEVER be used in production!
290             */
291            final String malformedVersion =
292                    getExtraRequestData(X_MALFORMED_VERSION);
293            if (malformedVersion == null) {
294                versionPreformed = (version != null) ? version : defaultVersion;
295                switch (versionPreformed) {
296                case VERSION_1_1:
297                    uriBuilder.append(PARAM_VERSION, VERSION_1_1);
298                    break;
299                case VERSION_1_2:
300                    uriBuilder.append(PARAM_VERSION, VERSION_1_2);
301                    break;
302                default:
303                    throw new SRUClientException("unsupported version: " +
304                            versionPreformed);
305                } // switch
306            } else {
307                if (!malformedVersion.equalsIgnoreCase(MALFORMED_OMIT)) {
308                    uriBuilder.append(PARAM_VERSION, malformedVersion);
309                }
310            }
311
312            // request specific parameters
313            addParametersToURI(uriBuilder);
314
315            // extraRequestData
316            if ((extraRequestData != null) && !extraRequestData.isEmpty()) {
317                for (Map.Entry<String, String> entry :
318                    extraRequestData.entrySet()) {
319                    final String key = entry.getKey();
320
321                    /*
322                     * make sure, we skip the client-internal parameters
323                     * to generate invalid requests ...
324                     */
325                    if (!key.startsWith(MALFORMED_KEY_PREFIX)) {
326                        uriBuilder.append(key, entry.getValue());
327                    }
328                }
329            }
330
331            return uriBuilder.makeURI();
332        } catch (URISyntaxException e) {
333            throw new SRUClientException("error while building request URI", e);
334        }
335    }
336
337
338    /**
339     * <em>Note: this method is not a part of public API.</em>
340     * @return a constant for this
341     */
342    abstract SRUOperation getOperation();
343
344
345    abstract void addParametersToURI(URIHelper uriBuilder)
346            throws SRUClientException;
347
348} // class AbstractSRURequest
Note: See TracBrowser for help on using the repository browser.