root/gsdl/trunk/runtime-src/src/oaiservr/listsetsaction.cpp @ 16717

Revision 16717, 8.7 KB (checked in by mdewsnip, 11 years ago)

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

  • Property svn:keywords set to Author Date Id Revision
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 browser.