Changeset 1990


Ignore:
Timestamp:
06/16/12 17:12:37 (12 years ago)
Author:
oschonef
Message:
  • add SRUServerServlet and SRUSearchEngineBase
  • add close() method to response objects
  • remove hasMore*() methods and modify next*() to return boolean from SRUScanResponse and SRUSearchResponse

HEADS UP:
This commit breaks existing API and requires changes to your SRUScanResponse and SRUSearchResponse implementations

Location:
SRUServer/trunk
Files:
3 added
8 edited

Legend:

Unmodified
Added
Removed
  • SRUServer/trunk/README.txt

    r1889 r1990  
    22---------
    33This package implements the server-side part of the SRU/CQL protocol (SRU/S)
    4 and conforms to SRU versin 1.1 and 1.2. The library will handle most of the
     4and conforms to SRU version 1.1 and 1.2. The library will handle most of the
    55protocol related tasks for you and you'll only need to implement a few classes
    66to connect you search engine. However, the library will not save you from
    77doing your SRU/CQL homework (i.e. you'll need to have at least some
    8 understanding of the protocol and adhere to the protocol sementics).
     8understanding of the protocol and adhere to the protocol semantics).
     9Furthermore, you need to have at least some basic understanding of Java web
     10application development (Servlets in particular) to use this library.
    911
    1012More Information about SRU/CQL:
     
    1618HOW TO USE:
    1719-----------
    18 You'll need to provide your own Servlet to initialize the SRUServer class
    19 with a SRUServerConfig instance and dispatch the appropriate HTTP requets
    20 to it. The SRUServerConfig requires an XML document which contains the
    21 end-point configuration. It must conform to the "sru-server-config.xsd" schema
    22 in the "src/main/resources/META-INF" directory.
    23 Furthermore, you need to provide an implementation of the SRUSearchEngine
    24 interface. This interface is the bridge between the SRU/CQL end-point and
    25 your search engine. You'll need to implement at least the search() method.
    26 Check the Java API docs for details.
     20The implementation is designed to make very minimal assumptions about the
     21environment it's deployed in. For interfacing with your search engine, you
     22need to implement the SRUSearchEngine interface. At minimum, you'll need
     23to implement at least the search() method. Please check the Java API
     24documentation for further details about this interface.
     25The SRUServer implements the SRU protocol an used your supplied search engine
     26implementation to talk to your search engine. The SRUServer is configured
     27using a SRUServerConfig instance. The SRUServerConfig reads an XML document,
     28which contains the (static) server configuration. It must conform to the
     29"sru-server-config.xsd" schema in the "src/main/resources/META-INF" directory.
     30You can either write your own Servlet implementation to drive the SRUServer or
     31can use supplied SRUServerServlet from the "de.clarin.sru.server.utils"
     32package. If you do so, your search engine needs to inherit from the abstract
     33class SRUSearchEngineBase. Check the Java API docs (and the code) of these
     34classes for more information.
     35Of couse, you can use frameworks like Spring or similar to assemble your
     36web application.
    2737
    2838
  • SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUAbstractResult.java

    r1881 r1990  
    105105    }
    106106
     107
     108    /**
     109     * Release this result and free any associated resources.
     110     * <p>
     111     * This method <strong>must not</strong> throw any exceptions
     112     * </p>
     113     * <p>
     114     * Calling the method <code>close</code> on a result object that is already
     115     * closed is a no-op.
     116     * </p>
     117     */
     118    public void close() {
     119    }
     120
    107121} // abstract class SRUAbstractResult
  • SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUConstants.java

    r1881 r1990  
    1919/**
    2020 * Constants for SRU diagnostics.
    21  * 
     21 *
    2222 * @see <a href="http://www.loc.gov/standards/sru/specs/diagnostics.html"> SRU
    2323 *      Diagnostics</a>
  • SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUExplainResult.java

    r1881 r1990  
    2121 * use it implement extensions to the SRU protocol, i.e. providing
    2222 * extraResponseData.
    23  * 
     23 *
    2424 * <p>This class needs to be implemented for the target data source.</p>
    25  * 
     25 *
    2626 * @see <a href="http://www.loc.gov/standards/sru/specs/explain.html">SRU
    2727 *      Explain Operation </a>
  • SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUScanResultSet.java

    r1881 r1990  
    2424
    2525/**
    26  * A result set of a <em>scan</em> operation. It allows to iterate over the term
    27  * set and provides a method to serialize the terms. <br />
     26 * A result set of a <em>scan</em> operation. It is used to iterate over the
     27 * term set and provides a method to serialize the terms.
    2828 *
    29  * <p>This class needs to be implemented for the target data source.</p>
     29 * <p>
     30 * A <code>SRUScanResultSet</code> object maintains a cursor pointing to its
     31 * current term. Initially the cursor is positioned before the first term. The
     32 * <code>next</code> method moves the cursor to the next term, and because it
     33 * returns <code>false</code> when there are no more terms in the
     34 * <code>SRUScanResultSet</code> object, it can be used in a <code>while</code>
     35 * loop to iterate through the term set.
     36 * </p>
     37 * <p>
     38 * This class needs to be implemented for the target search engine.
     39 * </p>
    3040 *
    31  * @see <a href="http://www.loc.gov/standards/sru/specs/scan.html">
    32  *      SRU Scan Operation</a>
     41 * @see <a href="http://www.loc.gov/standards/sru/specs/scan.html"> SRU Scan
     42 *      Operation</a>
    3343 */
    3444public abstract class SRUScanResultSet extends SRUAbstractResult {
     
    7383
    7484    /**
    75      * Returns true if the term set has more terms. (In other words, returns
    76      * <code>true</code> if <code>nextTerm()</code> would move the internal
    77      * result pointer to a new term instead of throwing an exception.)
     85     * Moves the cursor forward one term from its current position. A result
     86     * set cursor is initially positioned before the first record; the first
     87     * call to the method <code>next</code> makes the first term the current
     88     * term; the second call makes the second term the current term, and
     89     * so on.
     90     * <p>
     91     * When a call to the <code>next</code> method returns <code>false</code>,
     92     * the cursor is positioned after the last term.
     93     * </p>
    7894     *
    79      * @return <code>true</code> if the term set has more terms,
    80      *         <code>false</code> otherwise
     95     * @return <code>true</code> if the new current term is valid;
     96     *         <code>false</code> if there are no more terms
    8197     */
    82     public abstract boolean hasMoreTerms();
    83 
    84 
    85     /**
    86      * Move to the next term.
    87      *
    88      * @throws NoSuchElementException
    89      *             term set has no more terms
    90      */
    91     public abstract void nextTerm();
     98    public abstract boolean nextTerm();
    9299
    93100
  • SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUSearchEngine.java

    r1889 r1990  
    4545     *            non-fatal diagnostics
    4646     * @return a <code>SRUExplainResult</code> object or <code>null</code> if
    47      *         the database does not want to provide
     47     *         the search engine does not want to provide
    4848     *         <em>writeExtraResponseData</em>
    4949     * @throws SRUException
     
    5858    /**
    5959     * Handle a <em>searchRetrieve</em> operation. Implementing this method is
    60      * mandatory. The query arguments are availavle trough the request object.
     60     * mandatory. The query arguments are available trough the request object.
    6161     *
    6262     * @param config
     
    9292     *            non-fatal diagnostics
    9393     * @return a <code>SRUScanResultSet</code> object or <code>null</code> if
    94      *         this operation is not supported by this database
     94     *         this operation is not supported by this serach engine
    9595     * @throws SRUException
    9696     *             if an fatal error occurred
  • SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUSearchResultSet.java

    r1881 r1990  
    2424
    2525/**
    26  * A result set of a <em>searchRetrieve</em> operation. It allows to iterate
     26 * A result set of a <em>searchRetrieve</em> operation. It it used to iterate
    2727 * over the result set and provides a method to serialize the record in the
    2828 * requested format.
    29  *
    30  * <p>This class needs to be implemented for the target data source.</p>
    31  *
     29 * <p>
     30 * A <code>SRUSearchResultSet</code> object maintains a cursor pointing to its
     31 * current record. Initially the cursor is positioned before the first record.
     32 * The <code>next</code> method moves the cursor to the next record, and because
     33 * it returns <code>false</code> when there are no more records in the
     34 * <code>SRUSearchResultSet</code> object, it can be used in a
     35 * <code>while</code> loop to iterate through the result set.
     36 * </p>
     37 * <p>
     38 * This class needs to be implemented for the target search engine.
     39 * </p>
     40 *
    3241 * @see <a href="http://www.loc.gov/standards/sru/specs/search-retrieve.html">
    3342 *      SRU Search Retrieve Operation</a>
     
    100109
    101110    /**
    102      * Returns true if the search result set has more records. (In other words,
    103      * returns <code>true</code> if <code>nextRecord()</code> would move the
    104      * internal result pointer to a new record instead of throwing an
    105      * exception.)
     111     * Moves the cursor forward one record from its current position. A
     112     * <code>SRUSearchResultSet</code> cursor is initially positioned before the
     113     * first record; the first call to the method <code>next</code> makes the
     114     * first record the current record; the second call makes the second record
     115     * the current record, and so on.
     116     * <p>
     117     * When a call to the <code>next</code> method returns <code>false</code>,
     118     * the cursor is positioned after the last record.
     119     * </p>
    106120     *
    107      * @return <code>true</code> if the search result set has more records,
    108      *         <code>false</code> otherwise
     121     * @return <code>true</code> if the new current record is valid;
     122     *         <code>false</code> if there are no more records
    109123     */
    110     public abstract boolean hasMoreRecords();
    111 
    112 
    113     /**
    114      * Move to the next record.
    115      *
    116      * @throws NoSuchElementException
    117      *             result set has no more records
    118      */
    119     public abstract void nextRecord();
     124    public abstract boolean nextRecord();
    120125
    121126
  • SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUServer.java

    r1989 r1990  
    3737import eu.clarin.sru.server.SRUServerConfig.LocalizedString;
    3838import eu.clarin.sru.server.SRUServerConfig.SchemaInfo;
     39import eu.clarin.sru.server.utils.SRUServerServlet;
    3940
    4041
     
    4243 * SRU/CQL protocol implementation for the server-side (SRU/S). This class
    4344 * implements SRU/CQL version 1.1 and and 1.2.
    44  * <p>
    45  * An example servlet using this class:
    46  * </p>
    47  * <pre>
    48  * public class MySRUServlet extends HttpServlet {
    49  *     private transient SRUServer sruServer;
    50  *
    51  *
    52  *     public void init() throws ServletException {
    53  *         final ServletContext ctx = getServletContext();
    54  *         try {
    55  *             URL url = MySRUServlet.class.getClassLoader().getResource(
    56  *                     &quot;META-INF/endpoint-config.xml&quot;);
    57  *             if (url == null) {
    58  *                 throw new ServletException(&quot;not found, url == null&quot;);
    59  *             }
    60  *
    61  *             // get additional runtime configuration from Servlet context
    62  *             HashMap&lt;String, String&gt; params = new HashMap&lt;String, String&gt;();
    63  *             for (Enumeration&lt;?&gt; i = ctx.getInitParameterNames(); i
    64  *                     .hasMoreElements();) {
    65  *                 String key = (String) i.nextElement();
    66  *                 String value = ctx.getInitParameter(key);
    67  *                 if ((value != null) &amp;&amp; !value.isEmpty()) {
    68  *                     params.put(key, value);
    69  *                 }
    70  *             }
    71  *
    72  *             SRUServerConfig config = SRUServerConfig.parse(params,
    73  *                     url.openStream());
    74  *             SRUSearchEngine searchEngine = new MySRUSearchEngine(config, params);
    75  *             sruServer = new SRUServer(config, searchEngine);
    76  *         } catch (Exception e) {
    77  *             throw new ServletException(&quot;error initializing endpoint&quot;, e);
    78  *         }
    79  *     }
    80  *
    81  *
    82  *     protected void doGet(HttpServletRequest request,
    83  *             HttpServletResponse response) throws ServletException, IOException {
    84  *         sruServer.handleRequest(request, response);
    85  *     }
    86  *
    87  *
    88  *     protected void doPost(HttpServletRequest request,
    89  *             HttpServletResponse response) throws ServletException, IOException {
    90  *         sruServer.handleRequest(request, response);
    91  *     }
    92  * }
    93  * </pre>
    9445 *
    9546 * @see SRUServerConfig
    9647 * @see SRUSearchEngine
     48 * @see SRUServerServlet
    9749 * @see <a href="http://www.loc.gov/standards/sru/">SRU/CQL protocol 1.2</a>
    9850 */
    99 public class SRUServer {
     51public final class SRUServer {
    10052    private static final String SRU_NS =
    10153            "http://www.loc.gov/zing/srw/";
     
    228180
    229181        // commence explain ...
    230         SRUExplainResult result = searchEngine.explain(config,
    231                 request, request);
    232 
    233         // send results
    234         SRUXMLStreamWriter out =
    235                 createXMLStreamWriter(response.getOutputStream(),
    236                                       request.getRecordPacking(),
    237                                       request.getIndentResponse());
    238 
    239         beginResponse(out, request);
    240 
    241         // write the explain record
    242         writeExplainRecord(out, request);
    243 
    244         if (config.getEchoRequests()) {
    245             writeEchoedExplainRequest(out, request);
    246         }
    247 
    248         // diagnostics
    249         writeDiagnosticList(out, request.getDiagnostics());
    250 
    251         // extraResponseData
    252         if (result != null) {
     182        final SRUExplainResult result =
     183                searchEngine.explain(config, request, request);
     184
     185        try {
     186            // send results
     187            SRUXMLStreamWriter out =
     188                    createXMLStreamWriter(response.getOutputStream(),
     189                                          request.getRecordPacking(),
     190                                          request.getIndentResponse());
     191
     192            beginResponse(out, request);
     193
     194            // write the explain record
     195            writeExplainRecord(out, request);
     196
     197            if (config.getEchoRequests()) {
     198                writeEchoedExplainRequest(out, request);
     199            }
     200
     201            // diagnostics
     202            writeDiagnosticList(out, request.getDiagnostics());
     203
     204            // extraResponseData
     205            if (result != null) {
     206                if (result.hasExtraResponseData()) {
     207                    out.writeStartElement(SRU_NS, "extraResponseData");
     208                    result.writeExtraResponseData(out);
     209                    out.writeEndElement(); // "extraResponseData" element
     210                }
     211            }
     212
     213            endResponse(out);
     214        } finally {
     215            if (result != null) {
     216                result.close();
     217            }
     218        }
     219    }
     220
     221
     222    private void scan(SRURequestImpl request, HttpServletResponse response)
     223            throws IOException, XMLStreamException, SRUException {
     224        logger.info("scan: scanClause = \"{}\"",
     225                new Object[] { request.getRawScanClause() });
     226
     227        // commence scan
     228        final SRUScanResultSet result =
     229                searchEngine.scan(config, request, request);
     230        if (result == null) {
     231            throw new SRUException(SRUConstants.SRU_UNSUPPORTED_OPERATION,
     232                    "The 'scan' operation is not supported by this endpoint.");
     233        }
     234
     235        try {
     236            // send results
     237            SRUXMLStreamWriter out =
     238                    createXMLStreamWriter(response.getOutputStream(),
     239                                          request.getRecordPacking(),
     240                                          request.getIndentResponse());
     241
     242            beginResponse(out, request);
     243
     244            try {
     245                out.writeStartElement(SRU_NS, "terms");
     246                while (result.nextTerm()) {
     247                    out.writeStartElement(SRU_NS, "term");
     248
     249                    out.writeStartElement(SRU_NS, "value");
     250                    out.writeCharacters(result.getValue());
     251                    out.writeEndElement(); // "value" element
     252
     253                    if (result.getNumberOfRecords() > -1) {
     254                        out.writeStartElement(SRU_NS, "numberOfRecords");
     255                        out.writeCharacters(
     256                                Integer.toString(result.getNumberOfRecords()));
     257                        out.writeEndElement(); // "numberOfRecords" element
     258                    }
     259
     260                    if (result.getDisplayTerm() != null) {
     261                        out.writeStartElement(SRU_NS, "displayTerm");
     262                        out.writeCharacters(result.getDisplayTerm());
     263                        out.writeEndElement(); // "displayTerm" element
     264                    }
     265
     266                    if (result.getWhereInList() != null) {
     267                        out.writeStartElement(SRU_NS, "whereInList");
     268                        switch (result.getWhereInList()) {
     269                        case FIRST:
     270                            out.writeCharacters("first");
     271                            break;
     272                        case LAST:
     273                            out.writeCharacters("last");
     274                            break;
     275                        case ONLY:
     276                            out.writeCharacters("only");
     277                            break;
     278                        case INNER:
     279                            out.writeCharacters("inner");
     280                            break;
     281                        } // switch
     282                        out.writeEndElement(); // "whereInList" element
     283                    }
     284
     285                    if (result.hasExtraTermData()) {
     286                        out.writeStartElement(SRU_NS, "extraTermData");
     287                        result.writeExtraTermData(out);
     288                        out.writeEndElement(); // "extraTermData" element
     289                    }
     290
     291                    out.writeEndElement(); // "term" element
     292                } // while
     293                out.writeEndElement(); // "terms" element
     294            } catch (NoSuchElementException e) {
     295                throw new SRUException(SRUConstants.SRU_GENERAL_SYSTEM_ERROR,
     296                        "An internal error occurred while "
     297                                + "serializing scan results.");
     298            }
     299
     300            // echoedScanRequest
     301            if (config.getEchoRequests()) {
     302                writeEchoedScanRequest(out, request, request.getScanClause());
     303            }
     304
     305            // diagnostics
     306            writeDiagnosticList(out, request.getDiagnostics());
     307
     308            // extraResponseData
    253309            if (result.hasExtraResponseData()) {
    254310                out.writeStartElement(SRU_NS, "extraResponseData");
     
    256312                out.writeEndElement(); // "extraResponseData" element
    257313            }
    258         }
    259 
    260         endResponse(out);
    261     }
    262 
    263 
    264     private void scan(SRURequestImpl request, HttpServletResponse response)
    265             throws IOException, XMLStreamException, SRUException {
    266         logger.info("scan: scanClause = \"{}\"",
    267                 new Object[] { request.getRawScanClause() });
    268 
    269         // commence scan
    270         final SRUScanResultSet result = searchEngine.scan(config,
    271                 request, request);
    272         if (result == null) {
    273             throw new SRUException(SRUConstants.SRU_UNSUPPORTED_OPERATION,
    274                     "The 'scan' operation is not supported by this endpoint.");
    275         }
    276 
    277         // send results
    278         SRUXMLStreamWriter out =
    279                 createXMLStreamWriter(response.getOutputStream(),
    280                                       request.getRecordPacking(),
    281                                       request.getIndentResponse());
    282 
    283         beginResponse(out, request);
    284 
    285         try {
    286             out.writeStartElement(SRU_NS, "terms");
    287             while (result.hasMoreTerms()) {
    288                 out.writeStartElement(SRU_NS, "term");
    289 
    290                 out.writeStartElement(SRU_NS, "value");
    291                 out.writeCharacters(result.getValue());
    292                 out.writeEndElement(); // "value" element
    293 
    294                 if (result.getNumberOfRecords() > -1) {
    295                     out.writeStartElement(SRU_NS, "numberOfRecords");
    296                     out.writeCharacters(
    297                             Integer.toString(result.getNumberOfRecords()));
    298                     out.writeEndElement(); // "numberOfRecords" element
    299                 }
    300 
    301                 if (result.getDisplayTerm() != null) {
    302                     out.writeStartElement(SRU_NS, "displayTerm");
    303                     out.writeCharacters(result.getDisplayTerm());
    304                     out.writeEndElement(); // "displayTerm" element
    305                 }
    306 
    307                 if (result.getWhereInList() != null) {
    308                     out.writeStartElement(SRU_NS, "whereInList");
    309                     switch (result.getWhereInList()) {
    310                     case FIRST:
    311                         out.writeCharacters("first");
    312                         break;
    313                     case LAST:
    314                         out.writeCharacters("last");
    315                         break;
    316                     case ONLY:
    317                         out.writeCharacters("only");
    318                         break;
    319                     case INNER:
    320                         out.writeCharacters("inner");
    321                         break;
    322                     } // switch
    323                     out.writeEndElement(); // "whereInList" element
    324                 }
    325 
    326                 if (result.hasExtraTermData()) {
    327                     out.writeStartElement(SRU_NS, "extraTermData");
    328                     result.writeExtraTermData(out);
    329                     out.writeEndElement(); // "extraTermData" element
    330                 }
    331 
    332                 out.writeEndElement(); // "term" element
    333 
    334                 result.nextTerm();
    335             }
    336             out.writeEndElement(); // "terms" element
    337         } catch (NoSuchElementException e) {
    338             throw new SRUException(SRUConstants.SRU_GENERAL_SYSTEM_ERROR,
    339                     "An internal error occurred while " +
    340                     "serializing scan results.");
    341         }
    342 
    343         // echoedScanRequest
    344         if (config.getEchoRequests()) {
    345             writeEchoedScanRequest(out, request, request.getScanClause());
    346         }
    347 
    348         // diagnostics
    349         writeDiagnosticList(out, request.getDiagnostics());
    350 
    351         // extraResponseData
    352         if (result.hasExtraResponseData()) {
    353             out.writeStartElement(SRU_NS, "extraResponseData");
    354             result.writeExtraResponseData(out);
    355             out.writeEndElement(); // "extraResponseData" element
    356         }
    357 
    358         endResponse(out);
     314
     315            endResponse(out);
     316        } finally {
     317            if (result != null) {
     318                result.close();
     319            }
     320        }
    359321    }
    360322
     
    370332
    371333        // commence search ...
    372         final SRUSearchResultSet result = searchEngine.search(config,
    373                 request, request);
     334        final SRUSearchResultSet result =
     335                searchEngine.search(config, request, request);
    374336        if (result == null) {
    375337            throw new SRUException(SRUConstants.SRU_GENERAL_SYSTEM_ERROR,
    376                     "Database implementation returned invalid result (null).");
    377         }
    378 
    379         // send results
    380         SRUXMLStreamWriter out =
    381                 createXMLStreamWriter(response.getOutputStream(),
    382                                       request.getRecordPacking(),
    383                                       request.getIndentResponse());
    384 
    385         beginResponse(out, request);
    386 
    387         // numberOfRecords
    388         out.writeStartElement(SRU_NS, "numberOfRecords");
    389         out.writeCharacters(Integer.toString(result.getTotalRecordCount()));
    390         out.writeEndElement(); // "numberOfRecords" element
    391 
    392         // resultSetId
    393         if (result.getResultSetId() != null) {
    394             out.writeStartElement(SRU_NS, "resultSetId");
    395             out.writeCharacters(result.getResultSetId());
    396             out.writeEndElement(); // "resultSetId" element
    397         }
    398 
    399         // resultSetIdleTime
    400         if (result.getResultSetIdleTime() > 0) {
    401             out.writeStartElement(SRU_NS, "resultSetIdleTime");
     338                    "SRUSearchEngine implementation returned invalid result (null).");
     339        }
     340
     341        try {
     342            // send results
     343            SRUXMLStreamWriter out =
     344                    createXMLStreamWriter(response.getOutputStream(),
     345                                          request.getRecordPacking(),
     346                                          request.getIndentResponse());
     347
     348            beginResponse(out, request);
     349
     350            // numberOfRecords
     351            out.writeStartElement(SRU_NS, "numberOfRecords");
    402352            out.writeCharacters(
    403                     Integer.toString(result.getResultSetIdleTime()));
    404             out.writeEndElement();  // "resultSetIdleTime" element
    405         }
    406 
    407         int position = (request.getStartRecord() > 0)
    408                      ? request.getStartRecord() : 1;
    409         if (result.getRecordCount() > 0) {
    410             final int maxPositionOffset =
    411                     (request.getMaximumRecords() != -1)
    412                     ? (position + request.getMaximumRecords() - 1) : - 1;
    413             try {
    414                 out.writeStartElement(SRU_NS, "records");
    415                 while (result.hasMoreRecords()) {
    416                     /*
    417                      * Sanity check: do not return more then the maximum
    418                      * requested records. If database implementation does
    419                      * not honor limit truncate the result set.
    420                      */
    421                     if ((maxPositionOffset != -1) &&
    422                             (position > maxPositionOffset)) {
    423                         logger.error("SRUSearchEngine implementation did not " +
    424                                 "honor limit for the amount of requsted " +
    425                                 "records. Result set truncated!");
    426                         break;
    427                     }
    428 
    429                     out.writeStartElement(SRU_NS, "record");
    430 
    431                     /*
    432                      *  We need to output either the record or a
    433                      *  surrogate diagnostic. In case of the latter, we need
    434                      *  to output the appropriate record schema ...
    435                      */
    436                     SRUDiagnostic diagnostic = result.getSurrogateDiagnostic();
    437 
    438                     out.writeStartElement(SRU_NS, "recordSchema");
    439                     if (diagnostic == null) {
    440                         out.writeCharacters(result.getRecordSchemaIdentifier());
    441                     } else {
    442                         out.writeCharacters(SRU_DIAGNOSTIC_RECORD_SCHEMA);
    443                     }
    444                     out.writeEndElement(); // "recordSchema" element
    445 
    446                     // recordPacking
    447                     writeRecordPacking(out, request.getRecordPacking());
    448 
    449                     /*
    450                      * Output either record data or surrogate diagnostic ...
    451                      */
    452                     out.writeStartElement(SRU_NS, "recordData");
    453                     out.startRecord();
    454                     if (diagnostic == null) {
    455                         result.writeRecord(out);
    456                     } else {
    457                         // write a surrogate diagnostic
    458                         writeDiagnostic(out, diagnostic, true);
    459                     }
    460                     out.endRecord();
    461                     out.writeEndElement(); // "recordData" element
    462 
    463                     /*
    464                      * recordIdentifier is version 1.2 only
    465                      */
    466                     if (request.isVersion(SRUVersion.VERSION_1_2)) {
    467                         final String identifier = result.getRecordIdentifier();
    468                         if (identifier != null) {
    469                             out.writeStartElement(SRU_NS, "recordIdentifier");
    470                             out.writeCharacters(identifier);
    471                             out.writeEndElement(); // "recordIdentifier" element
     353                    Integer.toString(result.getTotalRecordCount()));
     354            out.writeEndElement(); // "numberOfRecords" element
     355
     356            // resultSetId
     357            if (result.getResultSetId() != null) {
     358                out.writeStartElement(SRU_NS, "resultSetId");
     359                out.writeCharacters(result.getResultSetId());
     360                out.writeEndElement(); // "resultSetId" element
     361            }
     362
     363            // resultSetIdleTime
     364            if (result.getResultSetIdleTime() > 0) {
     365                out.writeStartElement(SRU_NS, "resultSetIdleTime");
     366                out.writeCharacters(Integer.toString(result
     367                        .getResultSetIdleTime()));
     368                out.writeEndElement(); // "resultSetIdleTime" element
     369            }
     370
     371            int position = (request.getStartRecord() > 0)
     372                    ? request.getStartRecord() : 1;
     373            if (result.getRecordCount() > 0) {
     374                final int maxPositionOffset =
     375                        (request.getMaximumRecords() != -1)
     376                        ? (position + request.getMaximumRecords() - 1)
     377                        : -1;
     378                try {
     379                    out.writeStartElement(SRU_NS, "records");
     380                    while (result.nextRecord()) {
     381                        /*
     382                         * Sanity check: do not return more then the maximum
     383                         * requested records. If the search engine
     384                         * implementation does not honor limit truncate the
     385                         * result set.
     386                         */
     387                        if ((maxPositionOffset != -1) &&
     388                                (position > maxPositionOffset)) {
     389                            logger.error("SRUSearchEngine implementation did " +
     390                                    "not honor limit for the amount of " +
     391                                    "requsted records. Result set truncated!");
     392                            break;
    472393                        }
    473                     }
    474 
    475                     out.writeStartElement(SRU_NS, "recordPosition");
    476                     out.writeCharacters(Integer.toString(position));
    477                     out.writeEndElement(); // "recordPosition" element
    478 
    479                     if (result.hasExtraRecordData()) {
    480                         out.writeStartElement(SRU_NS, "extraRecordData");
    481                         result.writeExtraRecordData(out);
    482                         out.writeEndElement(); // "extraRecordData"
    483                     }
    484 
    485                     out.writeEndElement(); // "record" element
    486 
    487                     result.nextRecord();
    488                     position++;
     394
     395                        out.writeStartElement(SRU_NS, "record");
     396
     397                        /*
     398                         * We need to output either the record or a surrogate
     399                         * diagnostic. In case of the latter, we need to output
     400                         * the appropriate record schema ...
     401                         */
     402                        final SRUDiagnostic diagnostic =
     403                                result.getSurrogateDiagnostic();
     404
     405                        out.writeStartElement(SRU_NS, "recordSchema");
     406                        if (diagnostic == null) {
     407                            out.writeCharacters(
     408                                    result.getRecordSchemaIdentifier());
     409                        } else {
     410                            out.writeCharacters(SRU_DIAGNOSTIC_RECORD_SCHEMA);
     411                        }
     412                        out.writeEndElement(); // "recordSchema" element
     413
     414                        // recordPacking
     415                        writeRecordPacking(out, request.getRecordPacking());
     416
     417                        /*
     418                         * Output either record data or surrogate diagnostic ...
     419                         */
     420                        out.writeStartElement(SRU_NS, "recordData");
     421                        out.startRecord();
     422                        if (diagnostic == null) {
     423                            result.writeRecord(out);
     424                        } else {
     425                            // write a surrogate diagnostic
     426                            writeDiagnostic(out, diagnostic, true);
     427                        }
     428                        out.endRecord();
     429                        out.writeEndElement(); // "recordData" element
     430
     431                        /*
     432                         * recordIdentifier is version 1.2 only
     433                         */
     434                        if (request.isVersion(SRUVersion.VERSION_1_2)) {
     435                            final String identifier =
     436                                    result.getRecordIdentifier();
     437                            if (identifier != null) {
     438                                out.writeStartElement(SRU_NS,
     439                                                      "recordIdentifier");
     440                                out.writeCharacters(identifier);
     441                                out.writeEndElement(); // "recordIdentifier" element
     442                            }
     443                        }
     444
     445                        out.writeStartElement(SRU_NS, "recordPosition");
     446                        out.writeCharacters(Integer.toString(position));
     447                        out.writeEndElement(); // "recordPosition" element
     448
     449                        if (result.hasExtraRecordData()) {
     450                            out.writeStartElement(SRU_NS, "extraRecordData");
     451                            result.writeExtraRecordData(out);
     452                            out.writeEndElement(); // "extraRecordData"
     453                        }
     454
     455                        out.writeEndElement(); // "record" element
     456
     457                        position++;
     458                    } // while
     459                    out.writeEndElement(); // "records" element
     460                } catch (NoSuchElementException e) {
     461                    throw new SRUException(
     462                            SRUConstants.SRU_GENERAL_SYSTEM_ERROR,
     463                            "An internal error occurred while " +
     464                            "serializing search result set.");
    489465                }
    490                 out.writeEndElement(); // "records" element
    491             } catch (NoSuchElementException e) {
    492                 throw new SRUException(SRUConstants.SRU_GENERAL_SYSTEM_ERROR,
    493                         "An internal error occurred while " +
    494                         "serializing search result set.");
    495             }
    496         }
    497 
    498         // nextRecordPosition
    499         if (position <= result.getTotalRecordCount()) {
    500             out.writeStartElement(SRU_NS, "nextRecordPosition");
    501             out.writeCharacters(Integer.toString(position));
    502             out.writeEndElement();
    503         }
    504 
    505         // echoedSearchRetrieveRequest
    506         if (config.getEchoRequests()) {
    507             writeEchoedSearchRetrieveRequest(out, request, request.getQuery());
    508         }
    509 
    510         // diagnostics
    511         writeDiagnosticList(out, request.getDiagnostics());
    512 
    513         // extraResponseData
    514         if (result.hasExtraResponseData()) {
    515             out.writeStartElement(SRU_NS, "extraResponseData");
    516             result.writeExtraResponseData(out);
    517             out.writeEndElement(); // "extraResponseData" element
    518         }
    519 
    520         endResponse(out);
     466            }
     467
     468            // nextRecordPosition
     469            if (position <= result.getTotalRecordCount()) {
     470                out.writeStartElement(SRU_NS, "nextRecordPosition");
     471                out.writeCharacters(Integer.toString(position));
     472                out.writeEndElement();
     473            }
     474
     475            // echoedSearchRetrieveRequest
     476            if (config.getEchoRequests()) {
     477                writeEchoedSearchRetrieveRequest(out, request,
     478                                                 request.getQuery());
     479            }
     480
     481            // diagnostics
     482            writeDiagnosticList(out, request.getDiagnostics());
     483
     484            // extraResponseData
     485            if (result.hasExtraResponseData()) {
     486                out.writeStartElement(SRU_NS, "extraResponseData");
     487                result.writeExtraResponseData(out);
     488                out.writeEndElement(); // "extraResponseData" element
     489            }
     490
     491            endResponse(out);
     492        } finally {
     493            result.close();
     494        }
    521495    }
    522496
Note: See TracChangeset for help on using the changeset viewer.