39 using std::ostringstream;
41 #include <curl/curl.h>
45 #define TP_TEMPLATE_LOCATION "http://openmodeller.cria.org.br/xml/tapir/1.0/st_v3.xml"
46 #define TP_TEMPLATE_STRSIZE 55
47 #define TP_OUTPUT_MODEL_LOCATION "http://openmodeller.cria.org.br/xml/tapir/1.0/om.xml"
48 #define TP_OUTPUT_MODEL_STRSIZE 52
63 if ( stream == NULL ) {
69 std::string& str = *(
reinterpret_cast<std::string*
>( stream ) );
71 str.append( reinterpret_cast<const char*>(ptr), size*nmemb );
81 if ( stream == NULL ) {
87 std::string& str = *(
reinterpret_cast<std::string*
>( stream ) );
89 str.append( reinterpret_cast<const char*>(ptr), size*nmemb );
98 if ( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK ) {
117 curl_global_cleanup();
136 CURL * curl_handle = curl_easy_init();
138 if ( curl_handle == NULL ) {
140 Log::instance()->
error(
"TapirOccurrences::load - Could not initialize curl handle\n" );
145 std::string capabilities_url(
_source );
147 if ( capabilities_url.find(
"?" ) != string::npos ) {
149 capabilities_url.append(
"&" );
153 capabilities_url.append(
"?" );
156 capabilities_url.append(
"op=c" );
159 if ( curl_easy_setopt( curl_handle, CURLOPT_URL, capabilities_url.c_str() ) != CURLE_OK ) {
162 curl_easy_cleanup( curl_handle );
168 Log::instance()->
error(
"TapirOccurrences::load - Failed to set CURLOPT_HEADERFUNCTION\n" );
169 curl_easy_cleanup( curl_handle );
175 if ( curl_easy_setopt( curl_handle, CURLOPT_WRITEHEADER, &header ) != CURLE_OK ) {
177 Log::instance()->
error(
"TapirOccurrences::load - Failed to set CURLOPT_WRITEHEADER\n" );
178 curl_easy_cleanup( curl_handle );
184 Log::instance()->
error(
"TapirOccurrences::load - Failed to set CURLOPT_WRITEFUNCTION\n" );
185 curl_easy_cleanup( curl_handle );
189 std::string capabilities_response;
191 if ( curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, &capabilities_response ) != CURLE_OK ) {
193 Log::instance()->
error(
"TapirOccurrences::load - Failed to set CURLOPT_WRITEDATA\n" );
194 curl_easy_cleanup( curl_handle );
198 Log::instance()->
info(
"Getting capabilities using %s\n", capabilities_url.c_str() );
201 CURLcode curl_code = curl_easy_perform( curl_handle );
203 if ( curl_code != CURLE_OK )
205 Log::instance()->
error(
"TapirOccurrences::load - Could not get service capabilities from the specified endpoint (CURL code error: %d)\n", curl_code );
206 curl_easy_cleanup( curl_handle );
210 curl_easy_cleanup( curl_handle );
213 if ( header.find(
"Content-Type: text/xml" ) == string::npos )
215 Log::instance()->
warn(
"TapirOccurrences::load - URL does not seem to be a TAPIR endpoint (HTTP Content-Type header is not text/xml)\n" );
232 Log::instance()->
warn(
"TapirOccurrences::load - URL does not seem to be a TAPIR endpoint (no TAPIR response element detected)\n" );
237 Log::instance()->
error(
"TapirOccurrences::load - Provider did not map the DarwinCore GlobalUniqueIdentifier concept\n" );
242 Log::instance()->
error(
"TapirOccurrences::load - Provider did not map the DarwinCore ScientificName concept\n" );
247 Log::instance()->
error(
"TapirOccurrences::load - Provider did not map the DarwinCore DecimalLongitude concept from the geospatial extension\n" );
252 Log::instance()->
error(
"TapirOccurrences::load - Provider did not map the DarwinCore DecimalLatitude concept from the geospatial extension\n" );
257 Log::instance()->
error(
"TapirOccurrences::load - Provider must accept searches with the openModeller query template or searches with the openModeller output model or searches with any output model\n" );
274 XML_Parser parser = XML_ParserCreateNS( NULL,
'/' );
278 Log::instance()->
error(
"Unable to allocate memory for capabilities response parser" );
286 XML_SetUserData( parser, info );
288 if ( ! XML_Parse( parser, xml->c_str(), xml->size(), 1 ) ) {
290 XML_Error error_code = XML_GetErrorCode( parser );
291 std::ostringstream errormsg;
292 errormsg << XML_ErrorString( error_code )
294 << XML_GetCurrentLineNumber( parser )
296 << XML_GetCurrentColumnNumber( parser )
299 Log::instance()->
error(
"XML Parser fatal error for capabilities response: %s\n", errormsg.str().c_str() );
300 XML_ParserFree( parser );
304 XML_ParserFree( parser );
320 if ( strncmp( el,
"http://rs.tdwg.org/tapir/1.0/response", 37 ) == 0 ) {
325 else if ( strncmp( el,
"http://rs.tdwg.org/tapir/1.0/mappedConcept", 42 ) == 0 ) {
327 for (
int i = 0; attr[i]; i += 2 ) {
330 if ( strncmp( attr[i],
"id", 2 ) == 0 ) {
332 if ( strncmp( attr[i+1],
"http://rs.tdwg.org/dwc/dwcore/GlobalUniqueIdentifier", 52 ) == 0 ) {
335 else if ( strncmp( attr[i+1],
"http://rs.tdwg.org/dwc/dwcore/ScientificName", 44 ) == 0 ) {
339 else if ( strncmp( attr[i+1],
"http://rs.tdwg.org/dwc/geospatial/DecimalLongitude", 50 ) == 0 ) {
343 else if ( strncmp( attr[i+1],
"http://rs.tdwg.org/dwc/geospatial/DecimalLatitude/", 49 ) == 0 ) {
351 else if ( strncmp( el,
"http://rs.tdwg.org/tapir/1.0/template", 37 ) == 0 ) {
353 for (
int i = 0; attr[i]; i += 2 ) {
356 if ( strncmp( attr[i],
"location", 8 ) == 0 &&
364 else if ( strncmp( el,
"http://rs.tdwg.org/tapir/1.0/outputModel", 40 ) == 0 ) {
366 for (
int i = 0; attr[i]; i += 2 ) {
369 if ( strncmp( attr[i],
"location", 8 ) == 0 &&
377 else if ( strncmp( el,
"http://rs.tdwg.org/tapir/1.0/anyOutputModels", 44 ) == 0 ) {
382 else if ( strncmp( el,
"http://rs.tdwg.org/tapir/1.0/maxElementRepetitions", 50 ) == 0 ) {
408 if ( strncmp( el,
"http://rs.tdwg.org/tapir/1.0/maxElementRepetitions", 50 ) == 0 ) {
412 XML_SetCharacterDataHandler( info.
_parser, NULL );
429 LstOccurrences::iterator ocs =
_presences.begin();
430 LstOccurrences::iterator end =
_presences.end();
432 while ( ocs != end ) {
436 if ( ! strcasecmp( groupId, oc->label() ) ) {
453 search_data.
_next = 0;
462 while ( search_data.
_next >= 0 ) {
484 CURL * curl_handle = curl_easy_init();
486 if ( curl_handle == NULL ) {
488 Log::instance()->
error(
"TapirOccurrences::_retrieveRecords - Could not initialize curl handle\n" );
495 std::ostringstream search_url;
497 search_url << source.c_str();
499 if ( source.find(
"?" ) != string::npos ) {
508 search_url <<
"op=s&s=" << data->
_next;
510 search_url <<
"&l=" << limit;
513 #if LIBCURL_VERSION_NUM >= 0x070f04
514 search_url <<
"&sciname=" << curl_easy_escape( curl_handle, data->
_occurrences->label(), 0 );
517 search_url <<
"&sciname=" << curl_escape( data->
_occurrences->label(), 0 );
526 if ( curl_easy_setopt( curl_handle, CURLOPT_URL, search_url.str().c_str() ) != CURLE_OK ) {
528 Log::instance()->
error(
"TapirOccurrences::_retrieveRecords - Failed to set CURLOPT_URL\n" );
529 curl_easy_cleanup( curl_handle );
535 Log::instance()->
error(
"TapirOccurrences::_retrieveRecords - Failed to set CURLOPT_HEADERFUNCTION\n" );
536 curl_easy_cleanup( curl_handle );
542 if ( curl_easy_setopt( curl_handle, CURLOPT_WRITEHEADER, &header ) != CURLE_OK ) {
544 Log::instance()->
error(
"TapirOccurrences::_retrieveRecords - Failed to set CURLOPT_WRITEHEADER\n" );
545 curl_easy_cleanup( curl_handle );
551 Log::instance()->
error(
"TapirOccurrences::_retrieveRecords - Failed to set CURLOPT_WRITEFUNCTION\n" );
552 curl_easy_cleanup( curl_handle );
556 std::string search_response;
558 if ( curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, &search_response ) != CURLE_OK ) {
560 Log::instance()->
error(
"TapirOccurrences::_retrieveRecords - Failed to set CURLOPT_WRITEDATA\n" );
561 curl_easy_cleanup( curl_handle );
565 Log::instance()->
info(
"Searching records using %s\n", search_url.str().c_str() );
568 CURLcode curl_code = curl_easy_perform( curl_handle );
570 if ( curl_code != CURLE_OK )
572 const char * error_msg = curl_easy_strerror( curl_code );
574 Log::instance()->
error(
"TapirOccurrences::_retrieveRecords - Could not search records from the specified TAPIR endpoint (CURL error: %s)\n", error_msg );
576 curl_easy_cleanup( curl_handle );
580 curl_easy_cleanup( curl_handle );
583 if ( header.find(
"Content-Type: text/xml" ) == string::npos )
585 Log::instance()->
error(
"TapirOccurrences::_retrieveRecords - URL does not seem to be a TAPIR endpoint (HTTP Content-Type header is not text/xml)\n" );
590 XML_Parser parser = XML_ParserCreateNS( NULL,
'/' );
600 XML_SetUserData( parser, data );
602 if ( ! XML_Parse( parser, search_response.c_str(), search_response.size(), 1 ) ) {
604 XML_Error error_code = XML_GetErrorCode( parser );
605 std::ostringstream errormsg;
606 errormsg << XML_ErrorString( error_code )
608 << XML_GetCurrentLineNumber( parser )
610 << XML_GetCurrentColumnNumber( parser )
613 Log::instance()->
error(
"XML Parser fatal error for search response: %s\n", errormsg.str().c_str() );
614 XML_ParserFree( parser );
618 XML_ParserFree( parser );
632 if ( strlen( el ) == 49 &&
633 strncmp( el,
"http://openmodeller.cria.org.br/xml/tapir/1.0/occ", 49 ) == 0 ) {
635 std::string guid(
"");
640 for (
int i = 0; attr[i]; i += 2 ) {
643 if ( strncmp( attr[i],
"guid", 4 ) == 0 ) {
648 else if ( strncmp( attr[i],
"long", 4 ) == 0 ) {
650 lg =
Coord( atof( attr[i+1] ) );
653 else if ( strncmp( attr[i],
"lat", 3 ) == 0 ) {
655 lt =
Coord( atof( attr[i+1] ) );
660 search_data.
_occurrences->createOccurrence( guid.c_str(), lg, lt, 0.0, 1, 0, 0 );
663 if ( strncmp( el,
"http://rs.tdwg.org/tapir/1.0/summary", 36 ) == 0 ) {
665 for (
int i = 0; attr[i]; i += 2 ) {
668 if ( strncmp( attr[i],
"next", 4 ) == 0 ) {
670 search_data.
_next = atoi( attr[i+1] );
LstOccurrences _presences
void warn(const char *format,...)
'Warn' level.
static OccurrencesReader * CreateOccurrencesReaderCallback(const char *source, const char *coordSystem)
bool _accepts_om_template
static size_t _curl_header_writer(void *ptr, size_t size, size_t nmemb, void *stream)
#define TP_TEMPLATE_STRSIZE
static void _endCapabilitiesElement(void *data, const char *el)
static Log * instance()
Returns the instance pointer, creating the object on the first call.
OccurrencesPtr _occurrences
void error(const char *format,...)
'Error' level.
bool _parseCapabilities(const std::string *xml, CapabilitiesInfo *info)
static size_t _curl_body_writer(void *ptr, size_t size, size_t nmemb, void *stream)
#define TP_OUTPUT_MODEL_STRSIZE
#define TP_OUTPUT_MODEL_LOCATION
bool _retrieveRecords(TapirRecordData *data, int limit)
static void _startCapabilitiesElement(void *data, const char *el, const char **attr)
static void _maxRecordsDataHandler(void *data, const char *value, int len)
static void _startSearchElement(void *data, const char *el, const char **attr)
void info(const char *format,...)
'Info' level.
TapirOccurrences(const char *url, const char *coordSystem)
OccurrencesPtr getPresences(const char *groupId)
double Coord
Type of map coordinates.
#define TP_TEMPLATE_LOCATION