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

Last change on this file since 2024 was 2024, checked in by oschonef, 12 years ago
  • be more robust, when parsing responses
  • add mechanism to send invalid requests (NB: use to provoke errors when testing endpoints for protocol conformance)
  • Property svn:eol-style set to native
File size: 34.5 KB
Line 
1package eu.clarin.sru.client;
2
3import java.io.ByteArrayInputStream;
4import java.io.IOException;
5import java.io.InputStream;
6import java.net.URI;
7import java.net.UnknownHostException;
8import java.util.ArrayList;
9import java.util.List;
10import java.util.concurrent.ConcurrentHashMap;
11import java.util.concurrent.ConcurrentMap;
12import java.util.concurrent.TimeUnit;
13
14import javax.xml.stream.XMLStreamException;
15import javax.xml.stream.XMLStreamReader;
16
17import org.apache.commons.lang.NullArgumentException;
18import org.apache.http.HttpEntity;
19import org.apache.http.HttpResponse;
20import org.apache.http.HttpStatus;
21import org.apache.http.StatusLine;
22import org.apache.http.client.ClientProtocolException;
23import org.apache.http.client.HttpClient;
24import org.apache.http.client.methods.HttpGet;
25import org.apache.http.impl.client.DefaultHttpClient;
26import org.apache.http.params.CoreProtocolPNames;
27import org.apache.http.util.EntityUtils;
28import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
30
31import eu.clarin.sru.client.SRUScanHandler.WhereInList;
32
33
34public class SRUClient {
35    private static final String SRU_NS =
36            "http://www.loc.gov/zing/srw/";
37    private static final String SRU_DIAGNOSIC_NS =
38            "http://www.loc.gov/zing/srw/diagnostic/";
39    private static final String SRU_DIAGNOSTIC_RECORD_SCHEMA =
40            "info:srw/schema/1/diagnostics-v1.1";
41    private static final String VERSION_1_1 = "1.1";
42    private static final String VERSION_1_2 = "1.2";
43    private static final String RECORD_PACKING_XML = "xml";
44    private static final String RECORD_PACKING_STRING = "string";
45    private static final Logger logger =
46            LoggerFactory.getLogger(SRUClient.class);
47    private final SRUVersion defaultVersion;
48    private final HttpClient httpClient;
49    private final ConcurrentMap<String, SRURecordDataParser> parsers =
50            new ConcurrentHashMap<String, SRURecordDataParser>();
51    private final XmlStreamReaderProxy proxy = new XmlStreamReaderProxy();
52
53
54    public SRUClient(SRUVersion defaultVersion) {
55        if (defaultVersion == null) {
56            throw new NullPointerException("version == null");
57        }
58        this.defaultVersion = defaultVersion;
59        this.httpClient = new DefaultHttpClient();
60        this.httpClient.getParams().setParameter(CoreProtocolPNames.USER_AGENT,
61                    "eu.clarin.sru.client/0.0.1");
62    }
63
64
65    public void registerRecordParser(SRURecordDataParser parser)
66            throws SRUClientException {
67        if (parser == null) {
68            throw new NullPointerException("parser == null");
69        }
70        final String recordSchema = parser.getRecordSchema();
71        if (recordSchema == null) {
72            throw new NullPointerException("parser.getRecordSchema() == null");
73        }
74        if (recordSchema.isEmpty()) {
75            throw new IllegalArgumentException(
76                    "parser.getRecordSchema() returns empty string");
77        }
78
79        SRURecordDataParser old = parsers.putIfAbsent(recordSchema, parser);
80        if (old != null) {
81            throw new SRUClientException(
82                    "record data parser already registered: " + recordSchema);
83        }
84    }
85
86
87    public void explain(SRUExplainRequest request, SRUExplainHandler handler)
88            throws SRUClientException {
89        if (request == null) {
90            throw new NullPointerException("request == null");
91        }
92        if (handler == null) {
93            throw new NullArgumentException("handler == null");
94        }
95        logger.debug("explain");
96
97        final long ts_start = System.nanoTime();
98
99        // create URI and perform request
100        final URI uri = request.makeURI(defaultVersion);
101        HttpResponse response = executeRequest(uri);
102        HttpEntity entity = response.getEntity();
103        if (entity == null) {
104            throw new SRUClientException("cannot get entity");
105        }
106
107        InputStream stream = null;
108        SRUXMLStreamReader reader = null;
109        try {
110            stream = entity.getContent();
111
112            final long ts_parsing = System.nanoTime();
113            reader = createReader(stream, true);
114            parseExplainResponse(reader, request, handler);
115            final long ts_end = System.nanoTime();
116
117            final long millisTotal =
118                    TimeUnit.NANOSECONDS.toMillis(ts_end - ts_start);
119            final long millisNetwork =
120                    TimeUnit.NANOSECONDS.toMillis(ts_parsing - ts_start);
121            final long millisParsing =
122                    TimeUnit.NANOSECONDS.toMillis(ts_end - ts_parsing);
123            logger.debug("{} byte(s) in {} milli(s) ({} milli(s) network / {} milli(s) parsing)",
124                    new Object[] { reader.getByteCount(),
125                            millisTotal, millisNetwork, millisParsing });
126            handler.onRequestStatistics((int) reader.getByteCount(),
127                    millisTotal, millisNetwork, millisParsing);
128        } catch (IllegalStateException e) {
129            throw new SRUClientException("error reading response", e);
130        } catch (IOException e) {
131            throw new SRUClientException("error reading response", e);
132        } catch (XMLStreamException e) {
133            throw new SRUClientException("error reading response", e);
134        } finally {
135            if (reader != null) {
136                try {
137                    reader.close();
138                } catch (XMLStreamException e) {
139                    /* IGNORE */
140                }
141            }
142            if (stream != null) {
143                try {
144                    stream.close();
145                } catch (IOException e) {
146                    /* IGNORE */
147                }
148            }
149        }
150    }
151
152
153    public void scan(SRUScanRequest request, SRUScanHandler handler)
154            throws SRUClientException {
155        if (request == null) {
156            throw new NullPointerException("request == null");
157        }
158        if (handler == null) {
159            throw new NullArgumentException("handler == null");
160        }
161        logger.debug("searchRetrieve: scanClause = {}", request.getScanClause());
162
163        final long ts_start = System.nanoTime();
164
165        // create URI and perform request
166        final URI uri = request.makeURI(defaultVersion);
167        HttpResponse response = executeRequest(uri);
168        HttpEntity entity = response.getEntity();
169        if (entity == null) {
170            throw new SRUClientException("cannot get entity");
171        }
172
173        InputStream stream = null;
174        SRUXMLStreamReader reader = null;
175        try {
176            stream = entity.getContent();
177
178            final long ts_parsing = System.nanoTime();
179            reader = createReader(stream, true);
180            parseScanResponse(reader, request, handler);
181            final long ts_end = System.nanoTime();
182
183            final long millisTotal =
184                    TimeUnit.NANOSECONDS.toMillis(ts_end - ts_start);
185            final long millisNetwork =
186                    TimeUnit.NANOSECONDS.toMillis(ts_parsing - ts_start);
187            final long millisParsing =
188                    TimeUnit.NANOSECONDS.toMillis(ts_end - ts_parsing);
189            logger.debug("{} byte(s) in {} milli(s) ({} milli(s) network / {} milli(s) parsing)",
190                    new Object[] { reader.getByteCount(),
191                            millisTotal, millisNetwork, millisParsing });
192            handler.onRequestStatistics((int) reader.getByteCount(),
193                    millisTotal, millisNetwork, millisParsing);
194        } catch (IllegalStateException e) {
195            throw new SRUClientException("error reading response", e);
196        } catch (IOException e) {
197            throw new SRUClientException("error reading response", e);
198        } catch (XMLStreamException e) {
199            throw new SRUClientException("error reading response", e);
200        } finally {
201            if (reader != null) {
202                try {
203                    reader.close();
204                } catch (XMLStreamException e) {
205                    /* IGNORE */
206                }
207            }
208            if (stream != null) {
209                try {
210                    stream.close();
211                } catch (IOException e) {
212                    /* IGNORE */
213                }
214            }
215        }
216    }
217
218
219    public void searchRetrieve(SRUSearchRetrieveRequest request,
220            SRUSearchRetrieveHandler handler) throws SRUClientException {
221        if (request == null) {
222            throw new NullPointerException("request == null");
223        }
224        if (handler == null) {
225            throw new NullArgumentException("handler == null");
226        }
227        logger.debug("searchRetrieve: query = {}", request.getQuery());
228
229        final long ts_start = System.nanoTime();
230
231        // create URI and perform request
232        final URI uri = request.makeURI(defaultVersion);
233        HttpResponse response = executeRequest(uri);
234        HttpEntity entity = response.getEntity();
235        if (entity == null) {
236            throw new SRUClientException("cannot get entity");
237        }
238
239        InputStream stream = null;
240        SRUXMLStreamReader reader = null;
241        try {
242            stream = entity.getContent();
243
244            final long ts_parsing = System.nanoTime();
245            reader = createReader(stream, true);
246            parseSearchRetrieveResponse(reader, request, handler);
247            final long ts_end = System.nanoTime();
248
249            final long millisTotal =
250                    TimeUnit.NANOSECONDS.toMillis(ts_end - ts_start);
251            final long millisNetwork =
252                    TimeUnit.NANOSECONDS.toMillis(ts_parsing - ts_start);
253            final long millisParsing =
254                    TimeUnit.NANOSECONDS.toMillis(ts_end - ts_parsing);
255            logger.debug("{} byte(s) in {} milli(s) ({} milli(s) network / {} milli(s) parsing)",
256                    new Object[] { reader.getByteCount(),
257                            millisTotal, millisNetwork, millisParsing });
258            handler.onRequestStatistics((int) reader.getByteCount(),
259                    millisTotal, millisNetwork, millisParsing);
260        } catch (IllegalStateException e) {
261            throw new SRUClientException("error reading response", e);
262        } catch (IOException e) {
263            throw new SRUClientException("error reading response", e);
264        } catch (XMLStreamException e) {
265            throw new SRUClientException("error reading response", e);
266        } finally {
267            if (reader != null) {
268                try {
269                    reader.close();
270                } catch (XMLStreamException e) {
271                    /* IGNORE */
272                }
273            }
274            if (stream != null) {
275                try {
276                    stream.close();
277                } catch (IOException e) {
278                    /* IGNORE */
279                }
280            }
281        }
282    }
283
284
285    private HttpResponse executeRequest(URI uri) throws SRUClientException {
286        HttpGet request = null;
287        HttpResponse response = null;
288        try {
289            logger.debug("executing HTTP request: {}", uri.toString());
290            try {
291                request = new HttpGet(uri);
292                response = httpClient.execute(request);
293                StatusLine status = response.getStatusLine();
294                if (status.getStatusCode() != HttpStatus.SC_OK) {
295                    if (status.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
296                        throw new SRUClientException("not found: " + uri);
297                    } else {
298                        throw new SRUClientException("unexpected status: " +
299                                status.getStatusCode());
300                    }
301                }
302                return response;
303            } catch (ClientProtocolException e) {
304                throw new SRUClientException("client protocol exception", e);
305            } catch (UnknownHostException e) {
306                throw new SRUClientException("unknown host: " + uri.getHost(),
307                        e);
308            } catch (IOException e) {
309                throw new SRUClientException("input/output error", e);
310            }
311        } catch (SRUClientException e) {
312            /*
313             * if an error occurred, make sure we are freeing up the resources
314             * we've used
315             */
316            if (response != null) {
317                try {
318                    EntityUtils.consume(response.getEntity());
319                } catch (IOException ex) {
320                    /* IGNORE */
321                }
322            }
323            if (request != null) {
324                request.abort();
325            }
326            throw e;
327        }
328    }
329
330
331    private void parseExplainResponse(final SRUXMLStreamReader reader,
332            final SRUAbstractRequest request, final SRUExplainHandler handler)
333            throws SRUClientException {
334        logger.debug("parsing 'explain' response");
335        try {
336            // explainResponse
337            reader.readStart(SRU_NS, "explainResponse", true);
338
339            // explainResponse/version
340            SRUVersion version = parseVersion(reader);
341            logger.debug("version = {}, requested = {}",
342                    version, request.getVersionPerformed());
343
344            // explainResponse/record
345            reader.readStart(SRU_NS, "record", true);
346
347            String schema = reader.readContent(SRU_NS, "recordSchema", true);
348
349            SRURecordPacking packing = parseRecordPacking(reader);
350
351            logger.debug("schema = {}, packing = {}", schema, packing);
352
353            // explainResponse/record/recordData
354            reader.readStart(SRU_NS, "recordData", true);
355            reader.readEnd(SRU_NS, "recordData", true);
356
357            // explainResponse/record/recordPosition
358            if (reader.readStart(SRU_NS, "recordPosition", false)) {
359                reader.readEnd(SRU_NS, "recordPosition", true);
360            }
361
362            // explainResponse/record/extraRecordData
363            if (reader.readStart(SRU_NS, "extraRecordData", false)) {
364                reader.readEnd(SRU_NS, "extraRecordData", true);
365            }
366
367            reader.readEnd(SRU_NS, "record");
368
369            // explainResponse/echoedExplainRequest
370            if (reader.readStart(SRU_NS, "echoedExplainRequest", false)) {
371                reader.readEnd(SRU_NS, "echoedExplainRequest", true);
372            }
373
374            // explainResponse/diagnostics
375            final List<SRUDiagnostic> diagnostics = parseDiagnostics(reader);
376            if (diagnostics != null) {
377                handler.onDiagnostics(diagnostics);
378            }
379
380            // explainResponse/extraResponseData
381            if (reader.readStart(SRU_NS, "extraResponseData", false)) {
382                reader.consumeWhitespace();
383                proxy.reset(reader);
384                try {
385                    handler.onExtraResponseData(proxy);
386                } catch (XMLStreamException e) {
387                    throw new SRUClientException("handler triggered "
388                            + "error while parsing 'extraResponseData'", e);
389                }
390                reader.consumeWhitespace();
391                reader.readEnd(SRU_NS, "extraResponseData", true);
392            }
393
394            reader.readEnd(SRU_NS, "explainResponse");
395        } catch (XMLStreamException e) {
396            throw new SRUClientException(e.getMessage(), e);
397        }
398    }
399
400
401    private void parseScanResponse(final SRUXMLStreamReader reader,
402            final SRUScanRequest request, final SRUScanHandler handler)
403            throws SRUClientException {
404        try {
405            /*
406             * if the endpoint cannot determine the operation, it should create
407             * a explain response.
408             */
409            if (reader.peekStart(SRU_NS, "explainResponse")) {
410                parseExplainResponse(reader, request, new SRUExplainHandler() {
411                    @Override
412                    public void onRequestStatistics(int bytes, long millisTotal,
413                            long millisNetwork, long millisParsing) {
414                    }
415
416
417                    @Override
418                    public void onExtraResponseData(XMLStreamReader reader)
419                            throws XMLStreamException, SRUClientException {
420                    }
421
422
423                    @Override
424                    public void onDiagnostics(List<SRUDiagnostic> diagnostics)
425                            throws SRUClientException {
426                        handler.onDiagnostics(diagnostics);
427                    }
428                });
429            } else {
430                logger.debug("parsing 'scanResponse' response");
431
432                // scanResponse
433                reader.readStart(SRU_NS, "scanResponse", true);
434
435                // scanResponse/version
436                SRUVersion version = parseVersion(reader);
437                logger.debug("version = {}, requested = {}", version,
438                        request.getVersionPerformed());
439
440                // scanResponse/terms
441                if (reader.readStart(SRU_NS, "terms", false)) {
442                    boolean first = true;
443                    while (reader.readStart(SRU_NS, "term", first)) {
444                        if (first) {
445                            first = false;
446                            handler.onStartTerms();
447                        }
448
449                        // scanResponse/terms/value
450                        String value = reader
451                                .readContent(SRU_NS, "value", true);
452
453                        // scanResponse/terms/numberOfRecords
454                        int numberOfRecords = reader.readContent(SRU_NS,
455                                "numberOfRecords", false, -1);
456
457                        // scanResponse/terms/displayTerm
458                        String displayTerm = reader.readContent(SRU_NS,
459                                "displayTerm", false);
460
461                        // scanResponse/terms/whereInList
462                        String s = reader.readContent(SRU_NS,
463                                "whereInList", false);
464                        WhereInList whereInList = null;
465                        if (s != null) {
466                            if ("first".equals(s)) {
467                                whereInList = WhereInList.FIRST;
468                            } else if ("last".equals(s)) {
469                                whereInList = WhereInList.LAST;
470                            } else if ("only".equals(s)) {
471                                whereInList = WhereInList.ONLY;
472                            } else if ("inner".equals(s)) {
473                                whereInList = WhereInList.INNER;
474                            } else {
475                                throw new SRUClientException(
476                                        "invalid value for 'whereInList': " + s);
477                            }
478                        }
479                        logger.debug("value = {}, numberOfRecords = {}, "
480                                + "displayTerm = {}, whereInList = {}",
481                                new Object[] { value, numberOfRecords,
482                                        displayTerm, whereInList });
483                        handler.onTerm(value, numberOfRecords, displayTerm,
484                                whereInList);
485
486                        // scanResponse/terms/extraTermData
487                        if (reader.readStart(SRU_NS, "extraTermData", first)) {
488                            reader.consumeWhitespace();
489                            proxy.reset(reader);
490                            try {
491                                handler.onExtraTermData(value, proxy);
492                            } catch (XMLStreamException e) {
493                                throw new SRUClientException("handler "
494                                        + "triggered error while parsing "
495                                        + "'extraTermData'", e);
496                            }
497                            reader.consumeWhitespace();
498                            reader.readEnd(SRU_NS, "extraTermData", true);
499                        }
500                        reader.readEnd(SRU_NS, "term", true);
501
502                    } // while
503                    reader.readEnd(SRU_NS, "terms");
504                    handler.onFinishTerms();
505                }
506
507                // scanResponse/echoedScanRequest
508                if (reader.readStart(SRU_NS, "echoedScanRequest", false)) {
509                    reader.readEnd(SRU_NS, "echoedScanRequest", true);
510                }
511
512                // scanResponse/diagnostics
513                final List<SRUDiagnostic> diagnostics = parseDiagnostics(reader);
514                if (diagnostics != null) {
515                    handler.onDiagnostics(diagnostics);
516                }
517
518                // scanResponse/extraResponseData
519                if (reader.readStart(SRU_NS, "extraResponseData", false)) {
520                    reader.consumeWhitespace();
521                    proxy.reset(reader);
522                    try {
523                        handler.onExtraResponseData(proxy);
524                    } catch (XMLStreamException e) {
525                        throw new SRUClientException("handler triggered "
526                                + "error while parsing 'extraResponseData'", e);
527                    }
528                    reader.consumeWhitespace();
529                    reader.readEnd(SRU_NS, "extraResponseData", true);
530                }
531
532                reader.readEnd(SRU_NS, "scanResponse");
533            }
534        } catch (XMLStreamException e) {
535            throw new SRUClientException(e.getMessage(), e);
536        }
537    }
538
539
540    private void parseSearchRetrieveResponse(final SRUXMLStreamReader reader,
541            final SRUSearchRetrieveRequest request,
542            final SRUSearchRetrieveHandler handler) throws SRUClientException {
543        try {
544            /*
545             * if the endpoint cannot determine the operation, it should create
546             * a explain response.
547             */
548            if (reader.peekStart(SRU_NS, "explainResponse")) {
549                parseExplainResponse(reader, request, new SRUExplainHandler() {
550                    @Override
551                    public void onRequestStatistics(int bytes, long millisTotal,
552                            long millisNetwork, long millisParsing) {
553                    }
554
555
556                    @Override
557                    public void onExtraResponseData(XMLStreamReader reader)
558                            throws XMLStreamException, SRUClientException {
559                    }
560
561
562                    @Override
563                    public void onDiagnostics(List<SRUDiagnostic> diagnostics)
564                            throws SRUClientException {
565                        handler.onDiagnostics(diagnostics);
566                    }
567                });
568            } else {
569                logger.debug("parsing 'serarchRetrieve' response");
570
571                // searchRetrieveResponse
572                reader.readStart(SRU_NS, "searchRetrieveResponse", true);
573
574                // searchRetrieveResponse/version
575                SRUVersion version = parseVersion(reader);
576                logger.debug("version = {}, requested = {}", version,
577                        request.getVersionPerformed());
578
579                // searchRetrieveResponse/numberOfRecords
580                int numberOfRecords = reader.readContent(SRU_NS,
581                        "numberOfRecords", true, -1);
582
583                // searchRetrieveResponse/resultSetId
584                int resultSetId = reader.readContent(SRU_NS,
585                        "resultSetId", false, -1);
586
587                // searchRetrieveResponse/resultSetIdleTime
588                int resultSetIdleTime = reader.readContent(SRU_NS,
589                        "resultSetIdleTime", false, -1);
590
591                logger.debug("numberOfRecords = {}, resultSetId = {}, "
592                        + "resultSetIdleTime = {}", new Object[] {
593                        numberOfRecords, resultSetId, resultSetIdleTime });
594
595                // searchRetrieveResponse/results
596                if (numberOfRecords > 0) {
597                    reader.readStart(SRU_NS, "records", true);
598
599                    // searchRetrieveResponse/records/record
600                    boolean first = true;
601                    while (reader.readStart(SRU_NS, "record", first)) {
602                        if (first) {
603                            first = false;
604                            handler.onStartRecords(numberOfRecords,
605                                    resultSetId, resultSetIdleTime);
606                        }
607
608                        String schema = reader.readContent(SRU_NS,
609                                "recordSchema", true);
610
611                        SRURecordPacking packing = parseRecordPacking(reader);
612
613                        logger.debug("schema = {}, packing = {}, requested packing = {}",
614                                new Object[] { schema, packing,
615                                        request.getRecordPacking() });
616
617                        if ((request.getRecordPacking() != null) &&
618                                (packing != request.getRecordPacking())) {
619                            logger.warn("requested '{}' record packing, but server responded with '{}' record packing",
620                                    request.getRecordPacking()
621                                            .toProtocolString(), packing
622                                            .toProtocolString());
623                            // XXX: only throw if client is pedantic?
624                            throw new SRUClientException(
625                                    "requested '" +
626                                            request.getRecordPacking()
627                                                    .toProtocolString() +
628                                            "' record packing, but server responded with '" +
629                                            packing.toProtocolString() +
630                                            "' record packing");
631                        }
632
633                        // searchRetrieveResponse/record/recordData
634                        reader.readStart(SRU_NS, "recordData", true);
635                        reader.consumeWhitespace();
636
637                        SRURecordData recordData = null;
638                        SRUDiagnostic surrogate = null;
639                        SRUXMLStreamReader recordReader = null;
640
641                        if (packing == SRURecordPacking.STRING) {
642                            /*
643                             * read content into temporary buffer and then use
644                             * a new XML reader to parse record data
645                             */
646                            final String data = reader.readString(true);
647                            InputStream in =
648                                    new ByteArrayInputStream(data.getBytes());
649                            // FIXME: namespace context?
650                            recordReader = createReader(in, false);
651                        } else {
652                            recordReader = reader;
653                        }
654
655                        if (SRU_DIAGNOSTIC_RECORD_SCHEMA.equals(schema)) {
656                            surrogate = parseDiagnostic(recordReader, true);
657                        } else {
658                            SRURecordDataParser parser = parsers.get(schema);
659                            if (parser != null) {
660                                try {
661                                    proxy.reset(recordReader);
662                                    recordData = parser.parse(proxy);
663                                } catch (XMLStreamException e) {
664                                    throw new SRUClientException(
665                                            "error parsing record", e);
666                                }
667                            } else {
668                                // FIXME: handle this better?
669                                logger.debug("no record parser found for schema '{}'",
670                                        schema);
671                            }
672                        }
673
674                        if (packing == SRURecordPacking.STRING) {
675                            recordReader.closeCompletly();
676                        }
677
678                        reader.consumeWhitespace();
679                        reader.readEnd(SRU_NS, "recordData", true);
680
681                        String identifier = null;
682                        if (version == SRUVersion.VERSION_1_2) {
683                            identifier = reader.readContent(SRU_NS,
684                                    "recordIdentifier", false);
685                        }
686
687                        int position = reader.readContent(SRU_NS,
688                                "recordPosition", false, -1);
689
690                        logger.debug("recordIdentifier = {}, recordPosition = {}",
691                                identifier, position);
692
693                        // notify handler
694                        if (surrogate != null) {
695                            handler.onSurrogateRecord(identifier,
696                                    position, surrogate);
697                        } else {
698                            if (recordData != null) {
699                                handler.onRecord(identifier,
700                                        position, recordData);
701                            }
702                        }
703
704                        if (reader.readStart(SRU_NS, "extraRecordData", false)) {
705                            reader.consumeWhitespace();
706                            proxy.reset(reader);
707                            try {
708                                handler.onExtraRecordData(identifier,
709                                        position, proxy);
710                            } catch (XMLStreamException e) {
711                                throw new SRUClientException("handler "
712                                        + "triggered error while parsing "
713                                        + "'extraRecordData'", e);
714                            }
715                            reader.consumeWhitespace();
716                            reader.readEnd(SRU_NS, "extraRecordData", true);
717                        }
718
719                        reader.readEnd(SRU_NS, "record");
720                    } // while
721                    reader.readEnd(SRU_NS, "records");
722                }
723
724                int nextRecordPosition = reader.readContent(SRU_NS,
725                        "nextRecordPosition", false, -1);
726                logger.debug("nextRecordPosition = {}", nextRecordPosition);
727                handler.onFinishRecords(nextRecordPosition);
728
729                // searchRetrieveResponse/echoedSearchRetrieveResponse
730                if (reader.readStart(SRU_NS,
731                        "echoedSearchRetrieveRequest", false)) {
732                    reader.readEnd(SRU_NS, "echoedSearchRetrieveRequest", true);
733                }
734
735                // searchRetrieveResponse/diagnostics
736                final List<SRUDiagnostic> diagnostics = parseDiagnostics(reader);
737                if (diagnostics != null) {
738                    handler.onDiagnostics(diagnostics);
739                }
740
741                // explainResponse/extraResponseData
742                if (reader.readStart(SRU_NS, "extraResponseData", false)) {
743                    reader.consumeWhitespace();
744                    proxy.reset(reader);
745                    try {
746                        handler.onExtraResponseData(proxy);
747                    } catch (XMLStreamException e) {
748                        throw new SRUClientException("handler triggered "
749                                + "error while parsing 'extraResponseData'", e);
750                    }
751                    reader.consumeWhitespace();
752                    reader.readEnd(SRU_NS, "extraResponseData", true);
753                }
754
755                reader.readEnd(SRU_NS, "searchRetrieveResponse");
756            }
757        } catch (XMLStreamException e) {
758            throw new SRUClientException(e.getMessage(), e);
759        }
760    }
761
762
763    private static SRUVersion parseVersion(SRUXMLStreamReader reader)
764        throws XMLStreamException, SRUClientException {
765        final String v = reader.readContent(SRU_NS, "version", true);
766        if (VERSION_1_1.equals(v)) {
767            return SRUVersion.VERSION_1_1;
768        } else if (VERSION_1_2.equals(v)) {
769            return SRUVersion.VERSION_1_2;
770        } else {
771            throw new SRUClientException("invalid value '" + v +
772                    "' for version (valid values are: '" + VERSION_1_1 +
773                    "' and '" + VERSION_1_2 + "')");
774        }
775    }
776
777
778    private static List<SRUDiagnostic> parseDiagnostics(
779            SRUXMLStreamReader reader) throws XMLStreamException,
780            SRUClientException {
781        if (reader.readStart(SRU_NS, "diagnostics", false)) {
782            List<SRUDiagnostic> diagnostics = null;
783
784            SRUDiagnostic diagnostic = null;
785            while ((diagnostic = parseDiagnostic(reader,
786                    (diagnostics == null))) != null) {
787                if (diagnostics == null) {
788                    diagnostics = new ArrayList<SRUDiagnostic>();
789                }
790                diagnostics.add(diagnostic);
791            } // while
792            reader.readEnd(SRU_NS, "diagnostics");
793            return diagnostics;
794        } else {
795            return null;
796        }
797    }
798
799
800    private static SRUDiagnostic parseDiagnostic(SRUXMLStreamReader reader,
801            boolean required) throws XMLStreamException, SRUClientException {
802        if (reader.readStart(SRU_DIAGNOSIC_NS, "diagnostic", required)) {
803
804            // diagnostic/uri
805            String uri = reader.readContent(SRU_DIAGNOSIC_NS, "uri", true);
806
807            // diagnostic/details
808            String details =
809                    reader.readContent(SRU_DIAGNOSIC_NS, "details", false);
810
811            // diagnostic/message
812            String message =
813                    reader.readContent(SRU_DIAGNOSIC_NS, "message", false);
814
815            reader.readEnd(SRU_DIAGNOSIC_NS, "diagnostic");
816
817            logger.debug("diagostic: uri={}, detail={}, message={}",
818                    new Object[] { uri, details, message });
819            return new SRUDiagnostic(uri, details, message);
820        } else {
821            return null;
822        }
823    }
824
825
826    private static SRURecordPacking parseRecordPacking(SRUXMLStreamReader reader)
827            throws XMLStreamException, SRUClientException {
828        final String v = reader.readContent(SRU_NS, "recordPacking", true);
829
830        if (RECORD_PACKING_XML.equals(v)) {
831            return SRURecordPacking.XML;
832        } else if (RECORD_PACKING_STRING.equals(v)) {
833            return SRURecordPacking.STRING;
834        } else {
835            throw new SRUClientException("invalid value '" + v +
836                    "' for record packing (valid values are: '" +
837                    RECORD_PACKING_XML + "' and '" + RECORD_PACKING_STRING +
838                    "')");
839        }
840    }
841
842
843    private SRUXMLStreamReader createReader(InputStream in, boolean wrap)
844            throws XMLStreamException {
845        return new SRUXMLStreamReader(in, wrap);
846    }
847
848} // class SRUClient
Note: See TracBrowser for help on using the repository browser.