source: main/trunk/greenstone2/runtime-src/src/oaiservr/abstractlistaction.cpp@ 24874

Last change on this file since 24874 was 24109, checked in by ak19, 13 years ago

Still on changes for OAIserver: oailastmodified date is now used instead of lastmodified, making it similar to GS3's more correct approach.

  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
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 oailastmodified value for this document
228 text_tset metadata;
229 metadata.insert("oailastmodified");
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 repository browser.