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

Last change on this file since 18895 was 16717, checked in by mdewsnip, 16 years ago

Tidied up the validateAction() function to be consistently structured.

  • Property svn:keywords set to Author Date Id Revision
File size: 8.7 KB
Line 
1#include "listsetsaction.h"
2
3#if defined(GSDL_USE_STL_H)
4#include <fstream.h>
5#else
6#include <fstream>
7#endif
8
9#include "recptprototools.h"
10#include "oaitools.h"
11
12bool listsetsaction::validateAction(recptproto *protocol, oaiargs &params)
13{
14 // ----------------------------------------------------------------------------
15 // 1. Check for invalid arguments
16 // ----------------------------------------------------------------------------
17 bool invalid_argument_supplied = false;
18 text_tmap::const_iterator param_iterator = params.begin();
19 while (param_iterator != params.end())
20 {
21 // Check for arguments that aren't valid for this action
22 if (param_iterator->first != "verb" &&
23 param_iterator->first != "resumptionToken")
24 {
25 // We've found an invalid argument
26 invalid_argument_supplied = true;
27
28 // Delete the invalid argument from the list so it doesn't end up in the <request> tag that is returned
29 params.erase(param_iterator->first);
30 }
31
32 param_iterator++;
33 }
34
35 // If we found an invalid argument it's an error, so don't go any further
36 if (invalid_argument_supplied)
37 {
38 this->errorType = "badArgument";
39 return false;
40 }
41
42 // ----------------------------------------------------------------------------
43 // 2. Handle any exclusive arguments
44 // ----------------------------------------------------------------------------
45
46 // The resumptionToken argument is exclusive
47 if (params["resumptionToken"] != "")
48 {
49 // This argument is exclusive, so no other arguments are allowed (except "verb" of course)
50 if (params.getSize() != 2)
51 {
52 this->errorType = "badArgument";
53 return false;
54 }
55
56 // Check the resumption token is valid
57 ResumptionToken token(params["resumptionToken"]);
58 if (true) // TO DO: Fix this (the token.isValid() function is useless for ListSets)
59 {
60 // Everything is fine, and we don't continue further because this is an exclusive argument
61 this->errorType = "";
62 return true;
63 }
64 else
65 {
66 // There was an error with the resumption token
67 this->errorType = "badResumptionToken";
68 return false;
69 }
70 }
71
72 // ----------------------------------------------------------------------------
73 // 3. Handle any required arguments
74 // ----------------------------------------------------------------------------
75
76 // None!
77
78 // ----------------------------------------------------------------------------
79 // 4. Check any remaining arguments
80 // ----------------------------------------------------------------------------
81
82 // None!
83
84 // If we've reached here everything must be fine
85 this->errorType = "";
86 return true;
87}
88
89bool listsetsaction::output_content(ostream &output, recptproto *protocol, text_tset &collections, oaiargs &params)
90{
91 text_tset::iterator here = collections.begin();
92 text_tset::iterator end = collections.end();
93 while (here != end) {
94 text_t collect = *here;
95 this->output_content(output, protocol, params);
96 ++here;
97 }
98 return true;
99}
100
101bool listsetsaction::output_content(ostream &output, recptproto *protocol, oaiargs &params)
102{
103 // output the total list of classifier points
104
105 // variables required
106 text_t browseOID = "browse";
107 FilterResponse_t response;
108 comerror_t err;
109 text_tarray & collections = this->configuration->getCollectionsList();
110 text_tset metadata;
111 ofstream logout("oai.log", ios::app);
112
113 // get a list of the collections available
114 // protocol->get_collection_list(collections, err, output);
115 if (collections.size() == 0) {
116 logout << "Found *no* OAI collections - check main.cfg for oaicollection items and read the OAI documentation.\n";
117 }
118
119 // check resumption token
120 int startSet = 0;
121 if (params["resumptionToken"] != "") {
122 ResumptionToken token(params["resumptionToken"]);
123 startSet = token.getPosition() - 1; // first document is said to be 1..
124 }
125 this->replyToken = NULL;
126
127 this->setNumber = 0;
128 this->setsOutput = 0;
129 for(int current_col = 0; current_col < collections.size(); ++current_col) {
130 // output the collection as a set, first, then its children
131 text_t gsdlCollect = collections[current_col];
132
133 if (this->setsOutput == this->configuration->resumeAfter())
134 {
135 this->replyToken = new ResumptionToken("", "", "");
136 this->replyToken->setPosition("", this->setNumber+1);
137 break;
138 }
139
140 if (this->setNumber >= startSet)
141 {
142 output << " <set>" << endl;
143 output << " <setSpec>" << gsdlCollect << "</setSpec>" << endl;;
144 output << " <setName>" << gsdlCollect << "</setName>" << endl;
145 output << " </set>" << endl;
146 this->setsOutput++;
147 }
148 setNumber++;
149
150 // get all the children of the (relevant) classifier data structures
151 get_children(browseOID, gsdlCollect, "", metadata, false, protocol, response, logout);
152 // and send them to the "recurse_content" list
153 for (int c = 0; c < response.numDocs; ++c) {
154 this->recurse_content(output, protocol, gsdlCollect, response.docInfo[c].OID, gsdlCollect, startSet);
155 }
156 }
157
158 // do a resumption token if required; errors cancel a token...
159 if (this->replyToken != NULL && this->errorType == "") {
160 // Don't add any whitespace around the resumption token as it can confuse harvesters/validators
161 output << " <resumptionToken>" << this->replyToken->getToken() << "</resumptionToken>" << endl;
162 }
163
164 return true;
165}
166
167void listsetsaction::recurse_content(ostream &output, recptproto *protocol, text_t &collection,
168 const text_t &classifier, text_t setHierarchy, int startSet)
169{
170 // metadata for this call
171 FilterResponse_t response;
172 text_tset metadata;
173 ofstream logout("oai.log", ios::app);
174
175 if (this->setsOutput == this->configuration->resumeAfter())
176 {
177 this->replyToken = new ResumptionToken("", "", "");
178 this->replyToken->setPosition("", this->setNumber+1);
179 return;
180 }
181
182 metadata.insert("contains");
183 metadata.insert("Title");
184 metadata.insert("supportsmemberof");
185
186 // get the document information
187 if (!get_info(classifier, collection, "", metadata, false, protocol, response, logout)) {
188 //cerr << "recurse content: Bad identifier or protocol " << classifier << endl;
189 return;
190 }
191
192 // check for top-level classifiers, check if the set name includes a '.'; if
193 // not, it is a top-level classifier: check for memberof support. Those without
194 // memberof support will not be supported on OAI
195 if (findchar(classifier.begin(), classifier.end(), '.') == classifier.end()) {
196 if (response.docInfo[0].metadata["supportsmemberof"].values.size() > 0) {
197 text_t memberOf = response.docInfo[0].metadata["supportsmemberof"].values[0];
198 if (memberOf != "true") {
199 return;
200 }
201 }
202 else {
203 return;
204 }
205 }
206
207 MetadataInfo_tmap::iterator here = response.docInfo[0].metadata.begin();
208 MetadataInfo_tmap::iterator end = response.docInfo[0].metadata.end();
209 text_t title;
210
211 while (here != end)
212 {
213 // Each set should only have one title - hence we only output one title here
214 // (it is a set title, not a collection)
215 if (here->first == "Title" && here->second.values.size() > 0) {
216 title = here->second.values[0];
217 }
218
219 ++here;
220 }
221
222 // output the xml for this set; use the classifier id for the name
223 // if the title is blank
224 // curSet holds the colon-separated sequence of parent sets of the current set
225 text_t curSet;
226 if (this->setNumber >= startSet)
227 {
228 output << " <set>" << endl;
229 text_t oai_classifier = classifier;
230 oaiclassifier::toOAI(collection, oai_classifier);
231 output << " <setSpec>" << oai_classifier << "</setSpec>" << endl;
232 output << " <setName>";
233 if (!title.empty()) {
234 curSet = setHierarchy + ":" + title;
235 }
236 else {
237 curSet = classifier; // Pretty much never gets here (shouldn't, at least)
238 }
239 output << curSet;
240 output << "</setName>" << endl;
241 output << " </set>" << endl;
242 this->setsOutput++;
243 }
244 this->setNumber++;
245
246 // get the children of this classifier and iterate them
247 get_children(classifier, collection, "", metadata, false, protocol, response, logout);
248 for (int c = 0; c < response.numDocs; ++c) {
249 text_t child = response.docInfo[c].OID;
250
251 if (child == classifier)
252 continue;
253
254 // check for non classifier items and exclude them
255 text_t childHead;
256 text_t::const_iterator start = child.begin();
257 text_t::const_iterator here = child.begin();
258 here += 2;
259 childHead = substr(start, here);
260
261 if (childHead != "CL")
262 continue;
263
264 // Recurse for "proper" classifier children. Pass curSet, the colon-separated list of
265 // parent sets. curSet is pass-by-value, so that as we step out of recursion we remember
266 // old set hierarchies.
267 this->recurse_content(output, protocol, collection, child, curSet, startSet);
268 }
269
270 return;
271}
Note: See TracBrowser for help on using the repository browser.