Changeset 1990
- Timestamp:
- 06/16/12 17:12:37 (12 years ago)
- Location:
- SRUServer/trunk
- Files:
-
- 3 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
SRUServer/trunk/README.txt
r1889 r1990 2 2 --------- 3 3 This package implements the server-side part of the SRU/CQL protocol (SRU/S) 4 and conforms to SRU versi n 1.1 and 1.2. The library will handle most of the4 and conforms to SRU version 1.1 and 1.2. The library will handle most of the 5 5 protocol related tasks for you and you'll only need to implement a few classes 6 6 to connect you search engine. However, the library will not save you from 7 7 doing 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). 8 understanding of the protocol and adhere to the protocol semantics). 9 Furthermore, you need to have at least some basic understanding of Java web 10 application development (Servlets in particular) to use this library. 9 11 10 12 More Information about SRU/CQL: … … 16 18 HOW TO USE: 17 19 ----------- 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. 20 The implementation is designed to make very minimal assumptions about the 21 environment it's deployed in. For interfacing with your search engine, you 22 need to implement the SRUSearchEngine interface. At minimum, you'll need 23 to implement at least the search() method. Please check the Java API 24 documentation for further details about this interface. 25 The SRUServer implements the SRU protocol an used your supplied search engine 26 implementation to talk to your search engine. The SRUServer is configured 27 using a SRUServerConfig instance. The SRUServerConfig reads an XML document, 28 which contains the (static) server configuration. It must conform to the 29 "sru-server-config.xsd" schema in the "src/main/resources/META-INF" directory. 30 You can either write your own Servlet implementation to drive the SRUServer or 31 can use supplied SRUServerServlet from the "de.clarin.sru.server.utils" 32 package. If you do so, your search engine needs to inherit from the abstract 33 class SRUSearchEngineBase. Check the Java API docs (and the code) of these 34 classes for more information. 35 Of couse, you can use frameworks like Spring or similar to assemble your 36 web application. 27 37 28 38 -
SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUAbstractResult.java
r1881 r1990 105 105 } 106 106 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 107 121 } // abstract class SRUAbstractResult -
SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUConstants.java
r1881 r1990 19 19 /** 20 20 * Constants for SRU diagnostics. 21 * 21 * 22 22 * @see <a href="http://www.loc.gov/standards/sru/specs/diagnostics.html"> SRU 23 23 * Diagnostics</a> -
SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUExplainResult.java
r1881 r1990 21 21 * use it implement extensions to the SRU protocol, i.e. providing 22 22 * extraResponseData. 23 * 23 * 24 24 * <p>This class needs to be implemented for the target data source.</p> 25 * 25 * 26 26 * @see <a href="http://www.loc.gov/standards/sru/specs/explain.html">SRU 27 27 * Explain Operation </a> -
SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUScanResultSet.java
r1881 r1990 24 24 25 25 /** 26 * A result set of a <em>scan</em> operation. It allows to iterate over the term27 * 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. 28 28 * 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> 30 40 * 31 * @see <a href="http://www.loc.gov/standards/sru/specs/scan.html"> 32 * SRU ScanOperation</a>41 * @see <a href="http://www.loc.gov/standards/sru/specs/scan.html"> SRU Scan 42 * Operation</a> 33 43 */ 34 44 public abstract class SRUScanResultSet extends SRUAbstractResult { … … 73 83 74 84 /** 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> 78 94 * 79 * @return <code>true</code> if the term set has more terms,80 * <code>false</code> otherwise95 * @return <code>true</code> if the new current term is valid; 96 * <code>false</code> if there are no more terms 81 97 */ 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(); 92 99 93 100 -
SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUSearchEngine.java
r1889 r1990 45 45 * non-fatal diagnostics 46 46 * @return a <code>SRUExplainResult</code> object or <code>null</code> if 47 * the database does not want to provide47 * the search engine does not want to provide 48 48 * <em>writeExtraResponseData</em> 49 49 * @throws SRUException … … 58 58 /** 59 59 * Handle a <em>searchRetrieve</em> operation. Implementing this method is 60 * mandatory. The query arguments are availa vle trough the request object.60 * mandatory. The query arguments are available trough the request object. 61 61 * 62 62 * @param config … … 92 92 * non-fatal diagnostics 93 93 * @return a <code>SRUScanResultSet</code> object or <code>null</code> if 94 * this operation is not supported by this database94 * this operation is not supported by this serach engine 95 95 * @throws SRUException 96 96 * if an fatal error occurred -
SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUSearchResultSet.java
r1881 r1990 24 24 25 25 /** 26 * A result set of a <em>searchRetrieve</em> operation. It allowsto iterate26 * A result set of a <em>searchRetrieve</em> operation. It it used to iterate 27 27 * over the result set and provides a method to serialize the record in the 28 28 * 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 * 32 41 * @see <a href="http://www.loc.gov/standards/sru/specs/search-retrieve.html"> 33 42 * SRU Search Retrieve Operation</a> … … 100 109 101 110 /** 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> 106 120 * 107 * @return <code>true</code> if the search result set has more records,108 * <code>false</code> otherwise121 * @return <code>true</code> if the new current record is valid; 122 * <code>false</code> if there are no more records 109 123 */ 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(); 120 125 121 126 -
SRUServer/trunk/src/main/java/eu/clarin/sru/server/SRUServer.java
r1989 r1990 37 37 import eu.clarin.sru.server.SRUServerConfig.LocalizedString; 38 38 import eu.clarin.sru.server.SRUServerConfig.SchemaInfo; 39 import eu.clarin.sru.server.utils.SRUServerServlet; 39 40 40 41 … … 42 43 * SRU/CQL protocol implementation for the server-side (SRU/S). This class 43 44 * 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 * "META-INF/endpoint-config.xml");57 * if (url == null) {58 * throw new ServletException("not found, url == null");59 * }60 *61 * // get additional runtime configuration from Servlet context62 * HashMap<String, String> params = new HashMap<String, String>();63 * for (Enumeration<?> i = ctx.getInitParameterNames(); i64 * .hasMoreElements();) {65 * String key = (String) i.nextElement();66 * String value = ctx.getInitParameter(key);67 * if ((value != null) && !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("error initializing endpoint", 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>94 45 * 95 46 * @see SRUServerConfig 96 47 * @see SRUSearchEngine 48 * @see SRUServerServlet 97 49 * @see <a href="http://www.loc.gov/standards/sru/">SRU/CQL protocol 1.2</a> 98 50 */ 99 public class SRUServer {51 public final class SRUServer { 100 52 private static final String SRU_NS = 101 53 "http://www.loc.gov/zing/srw/"; … … 228 180 229 181 // 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 253 309 if (result.hasExtraResponseData()) { 254 310 out.writeStartElement(SRU_NS, "extraResponseData"); … … 256 312 out.writeEndElement(); // "extraResponseData" element 257 313 } 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 } 359 321 } 360 322 … … 370 332 371 333 // commence search ... 372 final SRUSearchResultSet result = searchEngine.search(config,373 request, request);334 final SRUSearchResultSet result = 335 searchEngine.search(config, request, request); 374 336 if (result == null) { 375 337 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"); 402 352 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; 472 393 } 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."); 489 465 } 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 } 521 495 } 522 496
Note: See TracChangeset
for help on using the changeset viewer.