root/main/trunk/greenstone2/runtime-src/src/oaiservr/abstractlistaction.cpp @ 22739

Revision 22739, 8.1 KB (checked in by mdewsnip, 9 years ago)

Added copyright header to runtime-src/src/oaiserver/*.cpp and runtime-src/src/oaiserver/*.h.

  • Property svn:keywords set to Author Date Id Revision
Line 
1/**********************************************************************
2 *
3 * abstractlistaction.cpp --
4 *
5 * Copyright (C) 2004-2010  The New Zealand Digital Library Project
6 *
7 * A component of the Greenstone digital library software
8 * from the New Zealand Digital Library Project at the
9 * University of Waikato, New Zealand.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 *********************************************************************/
26
27#include "abstractlistaction.h"
28#include "OIDtools.h"
29#include "recptprototools.h"
30
31#include "oaitools.h"
32
33
34bool abstractlistaction::check_classifier(recptproto *protocol, const text_t &collection, const text_t &set_name)
35{
36  text_tset metadata;
37  FilterResponse_t response;
38  return get_info(set_name, collection, "", metadata, false, protocol, response, *this->logout);
39}
40
41
42bool abstractlistaction::output_content(ostream &output, recptproto *protocol, oaiargs &params)
43{
44  // Reset variables
45  this->output_docs = 0;
46
47  text_t set_name = params["set"];
48  text_t position = "";
49
50  // Process the resumptionToken if there is one
51  if (params["resumptionToken"] != "")
52  {
53    ResumptionToken resumption_token(params["resumptionToken"]);
54    set_name = resumption_token.getSet();
55    position = resumption_token.getPosition();
56  }
57
58  // Case for "set" argument present -- output just the records in the specified set
59  if (set_name != "")
60  {
61    // Separate the collection name and Greenstone classifier OID from the set name
62    text_t collection_name = "";
63    text_t gsdl_classifier_OID = set_name;
64    oaiclassifier::toGSDL(collection_name, gsdl_classifier_OID);
65
66    // If output_content_for_set() returns false a resumption token has been output, so it's time to stop
67    if (output_content_for_set(output, protocol, params, collection_name, gsdl_classifier_OID, set_name) == false)
68    {
69      return true;
70    }
71  }
72
73  // Case for no "set" argument present -- output all records in all collections
74  else
75  {
76    // Get a list of the collections available
77    text_tarray& collections = this->configuration->getCollectionsList();
78    if (collections.size() == 0)
79    {
80      return false;
81    }
82
83    // Get the current collection from the position value
84    text_t collection_name = "";
85    oaiclassifier::toGSDL(collection_name, position);
86
87    // Find the starting collection
88    text_tarray::iterator collection_iterator = collections.begin();
89    while (collection_iterator != collections.end())
90    {
91      if (collection_name == "" || collection_name == *collection_iterator)
92      {
93    break;
94      }
95
96      collection_iterator++;
97    }
98
99    // Now loop through the remaining collections
100    while (collection_iterator != collections.end())
101    {
102      // If output_content_for_set() returns false a resumption token has been output, so it's time to stop
103      if (output_content_for_set(output, protocol, params, *collection_iterator, "", "") == false)
104      {
105    return true;
106      }
107
108      collection_iterator++;
109    }
110  }
111
112  // If no records were output throw an error
113  if (this->configuration->getOAIVersion() >= 200 && this->output_docs == 0)
114  {
115    errorType = "noRecordsMatch";
116    this->output_error(output, errorType);
117    return false;
118  }
119
120  return true;
121}
122
123
124bool abstractlistaction::output_content_for_set(ostream &output, recptproto *protocol, oaiargs &params, text_t collection_name, text_t gsdl_classifier_OID, text_t set_name)
125{
126  // Check if the set is actually a collection
127  if (gsdl_classifier_OID == "")
128  {
129    gsdl_classifier_OID = "oai";
130  }
131
132  text_t metadata_prefix = params["metadataPrefix"];
133  text_t from = params["from"];
134  text_t until = params["until"];
135  text_t position = "";
136
137  // Process the resumptionToken if there is one
138  if (params["resumptionToken"] != "")
139  {
140    ResumptionToken resumption_token(params["resumptionToken"]);
141    metadata_prefix = resumption_token.getMetadataPrefix();
142    from = resumption_token.getFrom();
143    until = resumption_token.getUntil();
144    position = resumption_token.getPosition();
145  }
146
147  // Get the list of identifiers in this collection
148  // Collections should not contain too many identifiers otherwise this will use a lot of time and memory
149  text_tset metadata;  // Must be empty for efficiency
150  FilterResponse_t identifiers_response;
151  get_children(gsdl_classifier_OID, collection_name, "", metadata, false, protocol, identifiers_response, *this->logout);
152
153  // Find the starting position, if necessary
154  ResultDocInfo_tarray::iterator identifier_iterator = identifiers_response.docInfo.begin();
155  if (output_docs == 0)
156  {
157    while (identifier_iterator != identifiers_response.docInfo.end())
158    {
159      if (position == "" || position == (collection_name + ":" + (*identifier_iterator).OID))
160      {
161    break;
162      }
163
164      identifier_iterator++;
165    }
166  }
167
168  // Now loop through displaying the next matching records
169  while (identifier_iterator != identifiers_response.docInfo.end())
170  {
171    position = (*identifier_iterator).OID;
172
173    text_t document_OID = position;
174    if (starts_with(document_OID, "oai."))
175    {
176      document_OID = oaiclassifier::getGSDL_OID(collection_name, document_OID, protocol, *this->logout);
177    }
178
179    // Check this OID is in the (optional) date range specified
180    if (this->in_date_range(output, protocol, params, collection_name, document_OID, from, until))
181    {
182      // If we've output the desired number of records return a resumptionToken and we're done
183      if (this->output_docs == this->configuration->resumeAfter())
184      {
185    // If a set has been specified, we can use the collection's buildDate in the resumption token
186    text_t date_stamp = "";
187    if (set_name != "")
188    {
189      ColInfoResponse_t cinfo;
190      comerror_t err;
191      protocol->get_collectinfo(collection_name, cinfo, err, cerr);
192      date_stamp = cinfo.buildDate;
193    }
194
195    ResumptionToken resumption_token(date_stamp, set_name, metadata_prefix, from, until, collection_name + ":" + position);
196
197    // Don't add any whitespace around the resumption token as it can confuse harvesters/validators
198    output << "  <resumptionToken>" << resumption_token.getResumptionTokenString() << "</resumptionToken>" << endl;
199    return false;
200      }
201
202      // Otherwise output this record and increment the count
203      this->output_document(output, protocol, collection_name, document_OID, metadata_prefix);
204      this->output_docs++;
205    }
206
207    identifier_iterator++;
208  }
209
210  return true;
211}
212
213
214bool abstractlistaction::in_date_range(ostream &output, recptproto *protocol, oaiargs &params,
215                       text_t& collection, text_t oai_OID, text_t from, text_t until)
216{
217  // If no "from" or "until" value is specified every record matches, so we don't need to go any further
218  if (from == "" && until == "")
219  {
220    return true;
221  }
222
223  // Get the datestamp from the document as sections do not have this metadata
224  text_t document_OID;
225  get_top(oai_OID, document_OID);
226
227  // Request the lastmodified value for this document
228  text_tset metadata;
229  metadata.insert("lastmodified");
230  metadata.insert("gs.OAIDateStamp");
231  FilterResponse_t response;
232  if (!get_info(document_OID, collection, "", metadata, false, protocol, response, *this->logout))
233  {
234    return false;
235  }
236
237  text_t last_modified_date;
238  this->getLastModifiedDate(response.docInfo[0], last_modified_date);
239
240  // Check this record is not before the "from" value, if it exists
241  if (from != "" && last_modified_date < from)
242  {
243    // Too early
244    return false;
245  }
246
247  // Check this record is not after the "until" value, if it exists
248  if (until != "" && last_modified_date > until)
249  {
250    // Too late
251    return false;
252  }
253
254  // Just right
255  return true;
256}
Note: See TracBrowser for help on using the browser.