source: gsdl/trunk/runtime-src/src/oaiservr/listsetsaction.cpp@ 20590

Last change on this file since 20590 was 20590, checked in by mdewsnip, 15 years ago

Completely rewrote the resumption token support, as its buginess finally tipped the "I can't stand it any more" scale...

  • Property svn:keywords set to Author Date Id Revision
File size: 7.4 KB
Line 
1#include "listsetsaction.h"
2
3#include "resumptiontoken.h"
4#include "recptprototools.h"
5#include "oaitools.h"
6
7
8bool listsetsaction::validateAction(recptproto *protocol, oaiargs &params)
9{
10 // ----------------------------------------------------------------------------
11 // 1. Check for invalid arguments
12 // ----------------------------------------------------------------------------
13 bool invalid_argument_supplied = false;
14 text_tmap::const_iterator param_iterator = params.begin();
15 while (param_iterator != params.end())
16 {
17 // Check for arguments that aren't valid for this action
18 if (param_iterator->first != "verb" &&
19 param_iterator->first != "resumptionToken")
20 {
21 // We've found an invalid argument
22 invalid_argument_supplied = true;
23
24 // Delete the invalid argument from the list so it doesn't end up in the <request> tag that is returned
25 params.erase(param_iterator->first);
26 }
27
28 param_iterator++;
29 }
30
31 // If we found an invalid argument it's an error, so don't go any further
32 if (invalid_argument_supplied)
33 {
34 this->errorType = "badArgument";
35 return false;
36 }
37
38 // ----------------------------------------------------------------------------
39 // 2. Handle any exclusive arguments
40 // ----------------------------------------------------------------------------
41
42 // The resumptionToken argument is exclusive
43 if (params["resumptionToken"] != "")
44 {
45 // This argument is exclusive, so no other arguments are allowed (except "verb" of course)
46 if (params.getSize() != 2)
47 {
48 this->errorType = "badArgument";
49 return false;
50 }
51
52 // Check the resumption token is valid
53 ResumptionToken token(params["resumptionToken"]);
54 if (token.isValid())
55 {
56 // Everything is fine, and we don't continue further because this is an exclusive argument
57 this->errorType = "";
58 return true;
59 }
60 else
61 {
62 // There was an error with the resumption token
63 this->errorType = "badResumptionToken";
64 return false;
65 }
66 }
67
68 // ----------------------------------------------------------------------------
69 // 3. Handle any required arguments
70 // ----------------------------------------------------------------------------
71
72 // None!
73
74 // ----------------------------------------------------------------------------
75 // 4. Check any remaining arguments
76 // ----------------------------------------------------------------------------
77
78 // None!
79
80 // If we've reached here everything must be fine
81 this->errorType = "";
82 return true;
83}
84
85
86bool listsetsaction::output_content(ostream &output, recptproto *protocol, oaiargs &params)
87{
88 // Reset variables
89 this->setsOutput = 0;
90
91 text_t collection = "";
92
93 // Process the resumptionToken if there is one
94 if (params["resumptionToken"] != "")
95 {
96 ResumptionToken resumption_token(params["resumptionToken"]);
97 collection = resumption_token.getSet();
98 }
99
100 // Get a list of the collections available
101 text_tarray& collections = this->configuration->getCollectionsList();
102 if (collections.size() == 0)
103 {
104 return false;
105 }
106
107 // Find the starting collection
108 text_tarray::iterator collection_iterator = collections.begin();
109 while (collection_iterator != collections.end())
110 {
111 if (collection == "" || collection == *collection_iterator)
112 {
113 break;
114 }
115
116 collection_iterator++;
117 }
118
119 // Now loop through the remaining collections
120 while (collection_iterator != collections.end())
121 {
122 collection = (*collection_iterator);
123
124 // If we've output the desired number of records return a resumptionToken and we're done
125 if (this->setsOutput == this->configuration->resumeAfter())
126 {
127 // Get the buildDate from the build.cfg file
128 ColInfoResponse_t cinfo;
129 comerror_t err;
130 protocol->get_collectinfo(collection, cinfo, err, cerr);
131
132 ResumptionToken resumption_token(cinfo.buildDate, collection, "", "", "", "");
133
134 // Don't add any whitespace around the resumption token as it can confuse harvesters/validators
135 output << " <resumptionToken>" << resumption_token.getResumptionTokenString() << "</resumptionToken>" << endl;
136 return true;
137 }
138
139 // If output_content_for_col() returns false a resumption token has been output, so it's time to stop
140 if (output_content_for_col(output, protocol, params, collection) == false)
141 {
142 return true;
143 }
144
145 collection_iterator++;
146 }
147
148 return true;
149}
150
151
152bool listsetsaction::output_content_for_col(ostream &output, recptproto *protocol, oaiargs &params, text_t collection)
153{
154 text_t position = "";
155
156 // Process the resumptionToken if there is one
157 if (params["resumptionToken"] != "")
158 {
159 ResumptionToken resumption_token(params["resumptionToken"]);
160 position = resumption_token.getPosition();
161 }
162
163 // Get the list of sets in this collection
164 // Collections should not contain too many sets otherwise this will use a lot of time and memory
165 text_tset metadata; // Must be empty for efficiency
166 FilterResponse_t sets_response;
167 get_children("browse", collection, "", metadata, false, protocol, sets_response, *this->logout);
168
169 // Find the starting position, if necessary
170 ResultDocInfo_tarray::iterator set_iterator = sets_response.docInfo.begin();
171 if (this->setsOutput == 0)
172 {
173 while (set_iterator != sets_response.docInfo.end())
174 {
175 if (position == "" || position == (*set_iterator).OID)
176 {
177 break;
178 }
179
180 set_iterator++;
181 }
182 }
183
184 // Output the collection as a set
185 if (position == "")
186 {
187 output << " <set>" << endl;
188 output << " <setSpec>" << collection << "</setSpec>" << endl;
189 output << " <setName>" << collection << "</setName>" << endl;
190 output << " </set>" << endl;
191 this->setsOutput++;
192 }
193
194 // Now loop through displaying the next matching records
195 while (set_iterator != sets_response.docInfo.end())
196 {
197 text_t set = (*set_iterator).OID;
198
199 // Only classifiers with supportsmemberof become OAI sets, for reasons I don't really understand
200 text_tset set_metadata;
201 set_metadata.insert("supportsmemberof");
202 set_metadata.insert("Title");
203 FilterResponse_t set_response;
204 get_info(set, collection, "", set_metadata, false, protocol, set_response, *this->logout);
205
206 if (set_response.docInfo[0].metadata["supportsmemberof"].values.size() > 0 && set_response.docInfo[0].metadata["supportsmemberof"].values[0] == "true")
207 {
208 // If we've output the desired number of records return a resumptionToken and we're done
209 if (this->setsOutput == this->configuration->resumeAfter())
210 {
211 // Get the buildDate from the build.cfg file
212 ColInfoResponse_t cinfo;
213 comerror_t err;
214 protocol->get_collectinfo(collection, cinfo, err, cerr);
215
216 ResumptionToken resumption_token(cinfo.buildDate, collection, "", "", "", set);
217
218 // Don't add any whitespace around the resumption token as it can confuse harvesters/validators
219 output << " <resumptionToken>" << resumption_token.getResumptionTokenString() << "</resumptionToken>" << endl;
220 return false;
221 }
222
223 // Otherwise output this set and increment the count
224 text_t set_title = set_response.docInfo[0].metadata["Title"].values[0];
225 output << " <set>" << endl;
226 output << " <setSpec>" << collection << ":" << set << "</setSpec>" << endl;
227 output << " <setName>" << collection << ":" << set_title << "</setName>" << endl;
228 output << " </set>" << endl;
229 this->setsOutput++;
230 }
231
232 set_iterator++;
233 }
234
235 return true;
236}
Note: See TracBrowser for help on using the repository browser.