diff options
author | tradke <tradke@83718e91-0e4f-0410-abf4-91180603181f> | 2007-08-29 12:34:48 +0000 |
---|---|---|
committer | tradke <tradke@83718e91-0e4f-0410-abf4-91180603181f> | 2007-08-29 12:34:48 +0000 |
commit | fd620c91b16ec633407d347b40315546464a45d4 (patch) | |
tree | 29182b72fe9301397439b2a32850d6281969e34d | |
parent | f087ca19300df86166e298c305d42143ad67704d (diff) |
- register callbacks for the Publish API
these callbacks collect published information and send it to an external
RDF information service
- use the Publish API to periodically announce simulation metadata runtime
information
git-svn-id: http://svn.cactuscode.org/arrangements/CactusUtils/Formaline/trunk@132 83718e91-0e4f-0410-abf4-91180603181f
-rw-r--r-- | interface.ccl | 104 | ||||
-rw-r--r-- | param.ccl | 5 | ||||
-rw-r--r-- | schedule.ccl | 14 | ||||
-rw-r--r-- | src/make.code.defn | 2 | ||||
-rw-r--r-- | src/rdf.cc | 271 | ||||
-rw-r--r-- | src/rdf.hh | 47 | ||||
-rw-r--r-- | src/rdf_publisher.cc | 309 |
7 files changed, 640 insertions, 112 deletions
diff --git a/interface.ccl b/interface.ccl index fa8779b..71e356e 100644 --- a/interface.ccl +++ b/interface.ccl @@ -6,7 +6,7 @@ IMPLEMENTS: Formaline # for HTTP_Port() USES INCLUDE HEADER: http_Content.h -USES INCLUDE HEADER: Announce.h +USES INCLUDE HEADER: Publish.h @@ -31,6 +31,108 @@ PROVIDES FUNCTION UniqueSimulationID \ LANGUAGE C +############# +# Publish API +############# +CCTK_INT FUNCTION PublishBoolean (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_INT IN level, \ + CCTK_INT IN value, \ + CCTK_STRING IN key, \ + CCTK_STRING IN name) +CCTK_INT FUNCTION PublishInt (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_INT IN level, \ + CCTK_INT IN value, \ + CCTK_STRING IN key, \ + CCTK_STRING IN name) +CCTK_INT FUNCTION PublishReal (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_INT IN level, \ + CCTK_REAL IN value, \ + CCTK_STRING IN key, \ + CCTK_STRING IN name) +CCTK_INT FUNCTION PublishString (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_INT IN level, \ + CCTK_STRING IN value, \ + CCTK_STRING IN key, \ + CCTK_STRING IN name) +CCTK_INT FUNCTION PublishTable (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_INT IN level, \ + CCTK_INT IN table, \ + CCTK_STRING IN key, \ + CCTK_STRING IN name) +USES FUNCTION PublishBoolean +USES FUNCTION PublishInt +USES FUNCTION PublishReal +USES FUNCTION PublishString +USES FUNCTION PublishTable + +########################## +# Publish registration API +########################## +CCTK_INT FUNCTION PublishBoolean_Register( \ + CCTK_INT CCTK_FPOINTER IN publish_cb (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_POINTER IN cb_data, \ + CCTK_INT IN level, \ + CCTK_INT IN value, \ + CCTK_STRING IN key, \ + CCTK_STRING IN thorn), \ + CCTK_POINTER IN cb_data, \ + CCTK_STRING IN name) +CCTK_INT FUNCTION PublishInt_Register( \ + CCTK_INT CCTK_FPOINTER IN publish_cb (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_POINTER IN cb_data, \ + CCTK_INT IN level, \ + CCTK_INT IN value, \ + CCTK_STRING IN key, \ + CCTK_STRING IN thorn), \ + CCTK_POINTER IN cb_data, \ + CCTK_STRING IN name) +CCTK_INT FUNCTION PublishReal_Register( \ + CCTK_INT CCTK_FPOINTER IN publish_cb (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_POINTER IN cb_data, \ + CCTK_INT IN level, \ + CCTK_REAL IN value, \ + CCTK_STRING IN key, \ + CCTK_STRING IN thorn), \ + CCTK_POINTER IN cb_data, \ + CCTK_STRING IN name) +CCTK_INT FUNCTION PublishString_Register( \ + CCTK_INT CCTK_FPOINTER IN publish_cb (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_POINTER IN cb_data, \ + CCTK_INT IN level, \ + CCTK_STRING IN value, \ + CCTK_STRING IN key, \ + CCTK_STRING IN thorn), \ + CCTK_POINTER IN cb_data, \ + CCTK_STRING IN name) +CCTK_INT FUNCTION PublishTable_Register( \ + CCTK_INT CCTK_FPOINTER IN publish_cb (CCTK_POINTER_TO_CONST IN cctkGH, \ + CCTK_POINTER IN cb_data, \ + CCTK_INT IN level, \ + CCTK_INT IN table, \ + CCTK_STRING IN key, \ + CCTK_STRING IN thorn), \ + CCTK_POINTER IN cb_data, \ + CCTK_STRING IN name) + +USES FUNCTION PublishBoolean_Register +USES FUNCTION PublishInt_Register +USES FUNCTION PublishReal_Register +USES FUNCTION PublishString_Register +USES FUNCTION PublishTable_Register + +CCTK_INT FUNCTION PublishBoolean_Unregister (CCTK_STRING IN name) +CCTK_INT FUNCTION PublishInt_Unregister (CCTK_STRING IN name) +CCTK_INT FUNCTION PublishReal_Unregister (CCTK_STRING IN name) +CCTK_INT FUNCTION PublishString_Unregister (CCTK_STRING IN name) +CCTK_INT FUNCTION PublishTable_Unregister (CCTK_STRING IN name) + +USES FUNCTION PublishBoolean_Unregister +USES FUNCTION PublishInt_Unregister +USES FUNCTION PublishReal_Unregister +USES FUNCTION PublishString_Unregister +USES FUNCTION PublishTable_Unregister + + # Return a pointer to an unmodifiable C string # which contains a unique ID for this run @@ -14,6 +14,11 @@ REAL update_interval "Update interval for the meta information (in seconds)" STE 0:* :: "" } 600.0 +INT publish_level "Importance level for meta data to be published via the Publish API" STEERABLE=always +{ + 0:10 :: "the lower the level the more important the meta data to be published" +} 1 + INT timeout "Timeout for sending meta information to a server (in seconds)" STEERABLE=always { 1:* :: "a positive value" diff --git a/schedule.ccl b/schedule.ccl index a9f84fb..5b897eb 100644 --- a/schedule.ccl +++ b/schedule.ccl @@ -19,8 +19,12 @@ if (collect_metadata) OPTIONS: meta } "Print the build and simulation ids" - - + SCHEDULE Formaline_RegisterPublishRDF_Callbacks IN RegisterPublishCallbacks + { + LANG: C + OPTIONS: meta + } "Register RDF callbacks for the Publish API" + SCHEDULE Formaline_RegisterWarnings AT wragh { LANG: C @@ -45,4 +49,10 @@ if (collect_metadata) OPTIONS: global } "Put some meta information about the current run into permanent storage" + SCHEDULE Formaline_UnregisterPublishRDF_Callbacks IN UnregisterPublishCallbacks + { + LANG: C + OPTIONS: meta + } "Unregister RDF callbacks for the Publish API" + } diff --git a/src/make.code.defn b/src/make.code.defn index a195bbc..f00f745 100644 --- a/src/make.code.defn +++ b/src/make.code.defn @@ -2,7 +2,7 @@ # $Header$ # Source files in this directory -SRCS = announce.cc file.cc id.cc multistorage.cc output_source.c portal.cc rdf.cc senddata.cc storage.cc thornlist.cc +SRCS = announce.cc file.cc id.cc multistorage.cc output_source.c portal.cc rdf.cc rdf_publisher.cc senddata.cc storage.cc thornlist.cc # Subdirectories containing source files SUBDIRS = @@ -21,8 +21,10 @@ #include "cctk.h" #include "cctk_Parameters.h" #include "cctk_Version.h" -#include "util_String.h" #include "util_Network.h" +#include "util_String.h" + +#include "Publish.h" #include "rdf.hh" #include "senddata.hh" @@ -31,17 +33,19 @@ namespace Formaline { - using namespace std; - + // the jobID is shared between this source file and PublishAsRDF.cc + string jobID; + + // NUM_RDF_ENTRIES must match the size of the // Formaline::rdf_hostname and Formaline::rdf_port parameter arrays int const NUM_RDF_ENTRIES = 5; // Number of space chars for indentation - int const NUM_INDENT_SPACES = 2; + // int const NUM_INDENT_SPACES = 2; @@ -57,52 +61,6 @@ namespace Formaline cGH const * const cctkGH) : storage (st) { - // - // RDF/XML document header with some namespace definitions - // - msgbuf - << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl - << "<!DOCTYPE owl [" << endl - << "\t<!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" << endl - << "\t<!ENTITY xsd 'http://www.w3.org/2001/XMLSchema#'>" << endl - << "\t<!ENTITY cctk 'http://www.gac-grid.org/project-products/Software/InformationService/InformationProducer/CactusRDFProducer/2006/08/cctk-schema#'>" << endl -#if 0 - << "\t<!ENTITY cctk 'http://www.aei.mpg.de/~tradke/cctk-schema#'>" << endl - << "\t<!ENTITY cctk 'http://www.cct.lsu.edu/~dstark/cctk/0.1/'>" << endl - << "<!--" << endl - << "\t<!ENTITY dc 'http://purl.org/dc/elements/1.1/'>" << endl - << "\t<!ENTITY doap 'http://usefulinc.com/ns/doap#'>" << endl - << "\t<!ENTITY foaf 'http://xmlns.com/foaf/0.1/'>" << endl - << "\t<!ENTITY rdfs 'http://www.w3.org/2000/01/rdf-schema#'>" << endl - << "\t<!ENTITY form 'http://www.aei.mpg.de/form#'>" << endl - << "-->" << endl -#endif - << "]>" << endl - << "<rdf:RDF xmlns:rdf=\"&rdf;\"" << endl - << "\txmlns:xsd=\"&xsd;\"" << endl - << "\txmlns:cctk=\"&cctk;\"" << endl - << ">" << endl -#if 0 - << "<!--" << endl - << "\txmlns:dc=\"&dc;\"" << endl - << "\txmlns:doap=\"&doap;\"" << endl - << "\txmlns:foaf=\"&foaf;\"" << endl - << "\txmlns:rdfs=\"&rdfs;\"" << endl - << "\txmlns:form=\"&form;\"" << endl - << "-->" << endl - << "" << endl - << "<!-- lessons learned so far" << endl - << " " << endl - << " * although it would be better to use rdf:ID as relative URIs for objects" << endl - << " (because they are enforced to be unique), rdf:about must be used instead" << endl - << " because the value of a relative rdf:about URI may contain special" << endl - << " characters (such as '/') whereas rdf:ID must not" << endl - << "-->" << endl -#endif - << endl - << endl; - - // set the unique ID for this simulation jobID = clean (string (id)); @@ -113,13 +71,8 @@ namespace Formaline case initial: Initial (); break; case update: case final: Update (cctkGH); break; - default: assert (0 && "invalid state"); + default: assert (0); // invalid state } - - // - // close the RDF/XML document - // - msgbuf << endl << "</rdf:RDF>" << endl; } void rdf::Initial (void) @@ -173,10 +126,27 @@ namespace Formaline if (pbsJobname) { msgbuf << "\tcctk:pbsJobname=\"" << clean (pbsJobname) << "\"" << endl; } + const char* pbsHost = getenv ("PBS_O_HOST"); + if (pbsHost) { + // fix incomplete and/or strange PBS headnode hostnames + if (strncmp(pbsHost, "peyote", 6) == 0) { + pbsHost = "peyote.aei.mpg.de"; + } else if (strcmp(pbsHost, "master.ic") == 0) { + pbsHost = "belladonna.aei.mpg.de"; + } else if (strcmp(pbsHost, "damiana.damiana.admin") == 0) { + pbsHost = "damiana.aei.mpg.de"; + } + msgbuf << "\tcctk:pbsHost=\"" << clean (pbsHost) << "\"" << endl; + } msgbuf << "\tcctk:cwd=\"" << cwd << "\">" << endl - << "\t<cctk:nProcs rdf:datatype=\"&xsd;integer\">" << nprocs << "</cctk:nProcs>" << endl - << "\t<cctk:compiledAt rdf:datatype=\"&xsd;datetime\">" << compiled_at << "</cctk:compiledAt>" << endl - << "\t<cctk:startedAt rdf:datatype=\"&xsd;datetime\">" << started_at << "</cctk:startedAt>" << endl; + << "\t<cctk:nProcs rdf:datatype=\"&xsd;integer\">" + << nprocs << "</cctk:nProcs>" << endl + << "\t<cctk:compiledAt rdf:datatype=\"&xsd;datetime\">" + << compiled_at << "</cctk:compiledAt>" << endl + << "\t<cctk:startedAt rdf:datatype=\"&xsd;datetime\">" + << started_at << "</cctk:startedAt>" << endl + << "\t<cctk:lastModified rdf:datatype=\"&xsd;datetime\">" + << started_at << "</cctk:lastModified>" << endl; // // metadata as references to other nodes @@ -235,7 +205,8 @@ namespace Formaline // skip parameters that belong to inactive thorns const bool is_active = CCTK_IsThornActive (thornname); - msgbuf << "\t<cctk:active rdf:datatype=\"&xsd;boolean\">" << (is_active ? "true" : "false") << "</cctk:active>" << endl; + msgbuf << "\t<cctk:active rdf:datatype=\"&xsd;boolean\">" + << (is_active ? "true" : "false") << "</cctk:active>" << endl; // loop over all parameters of this thorn (if it is active) if (is_active) { @@ -244,7 +215,8 @@ namespace Formaline const cParamData* pdata = NULL; // get the first/next parameter - const int ierr = CCTK_ParameterWalk (first, thornname,&fullname,&pdata); + const int ierr = CCTK_ParameterWalk (first, thornname, + &fullname, &pdata); assert (ierr >= 0); if (ierr > 0) break; @@ -309,7 +281,7 @@ namespace Formaline } break; - default: assert (0 and "invalid parameter type"); + default: assert (0); // invalid parameter type } // switch (pdata->type) @@ -318,7 +290,8 @@ namespace Formaline << pdata->thorn << "/" << cleanURI (pdata->name) << "\"" << endl << "\tcctk:name=\"" << fullname <<"\">" << endl - << "\t<cctk:value rdf:datatype=\"&xsd;" << paramdatatype <<"\">" << paramvaluebuf.str() << "</cctk:value>" << endl + << "\t<cctk:value rdf:datatype=\"&xsd;" << paramdatatype + << "\">" << paramvaluebuf.str() << "</cctk:value>" << endl << "</cctk:" << paramtype << ">" << endl; } // if (pdata->n_set or list_all_parameters) @@ -347,27 +320,78 @@ namespace Formaline } } - char* currentdatebuf = Util_CurrentDateTime (); - const string currentdate (clean (currentdatebuf)); - free (currentdatebuf); + if (CCTK_IsFunctionAliased ("PublishBoolean")) { +#ifndef PUBLISH_LEVEL_NOTICE +#define PUBLISH_LEVEL_NOTICE 2 +#endif + const int retval = PublishBoolean (cctkGH, PUBLISH_LEVEL_NOTICE, + get_state() == final ? 1 : 0, + "Finished", "Runtime Info"); + if (retval < 0) { + CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, + "Failed to publish runtime information (error code %d)", + retval); + } + } + + // check if there was anything published + if (rdfPublishList.empty()) return; - // update counter which is incremented for each Update() call - static int update_counter = 0; - update_counter++; + char* rundatebuf = Util_CurrentDateTime (); + const string started_at (clean (rundatebuf)); - msgbuf -<< "<cctk:Simulation rdf:about=\"#" << jobID << "\">" << endl -<< "\t<cctk:updateInfo rdf:resource=\"#UpdateInfo/" << update_counter << "\"/>" << endl -<< "</cctk:Simulation>" << endl << endl -<< "<cctk:UpdateInfo rdf:about=\"#UpdateInfo/" << update_counter << "\">" << endl -<< "\t<cctk:iteration rdf:datatype=\"&xsd;integer\">" << cctkGH->cctk_iteration << "</cctk:iteration>" << endl -<< "\t<cctk:time rdf:datatype=\"&xsd;double\">" << cctkGH->cctk_time << "</cctk:time>" << endl -<< "\t<cctk:datetime rdf:datatype=\"&xsd;datetime\">" << currentdate << "</cctk:datetime>" << endl; - - if (get_state() == final) { - msgbuf << "\t<cctk:terminated rdf:datatype=\"&xsd;boolean\">yes</cctk:terminated>" << endl; + static int publishedItems = 0; + msgbuf << "<cctk:Simulation rdf:about=\"#" << jobID << "\">" << endl + << "\t<cctk:lastModified rdf:datatype=\"&xsd;datetime\">" + << started_at << "</cctk:lastModified>" << endl; + for (size_t i = 0; i < rdfPublishList.size(); i++) { + msgbuf << "\t<cctk:publish rdf:resource=\"#Publish/" + << (publishedItems + i) << "\"/>" << endl; + } + msgbuf << "</cctk:Simulation>" << endl << endl; + for (size_t i = 0; i < rdfPublishList.size(); i++, publishedItems++) { + const rdfPublishItem& item = rdfPublishList[i]; + msgbuf << "<cctk:Publish rdf:about=\"#Publish/" + << publishedItems << "\">" << endl + << "\t<cctk:datetime rdf:datatype=\"&xsd;datetime\">" + << item.datetime << "</cctk:datetime>" << endl + << "\t<cctk:key>" << item.key << "</cctk:key>" << endl; + if (not item.name.empty()) { + msgbuf << "\t<cctk:name>" << item.name << "</cctk:name>" << endl; + } + if (item.hasCCTKinfo) { + msgbuf << "\t<cctk:time>" << item.cctk_time << "</cctk:time>" << endl; + msgbuf << "\t<cctk:iteration>" << item.cctk_iteration + << "</cctk:iteration>" << endl; + } + ostringstream tablebuf; + if (item.isTable) { + for (size_t j = 0; j < item.table.size(); j++) { + const rdfTableEntry& entry = item.table[j]; + msgbuf << "\t<cctk:tableEntry rdf:resource=\"#Publish/" + << publishedItems << "/" << j << "\"/>" << endl; + tablebuf << "<cctk:TableEntry rdf:about=\"#Publish/" + << publishedItems << "/" << j << "\">" << endl + << "\t<cctk:key>" << entry.key << "</cctk:key>" << endl + << "\t<cctk:value"; + if (not entry.value.type.empty()) { + tablebuf << " rdf:datatype=\"&xsd;" << entry.value.type << "\""; + } + tablebuf << ">" << entry.value.value << "</cctk:value>" << endl + << "</cctk:TableEntry>" << endl; + } + } else { + msgbuf << "\t<cctk:value"; + if (not item.scalar.type.empty()) { + msgbuf << " rdf:datatype=\"&xsd;" << item.scalar.type << "\""; + } + msgbuf << ">" << item.scalar.value << "</cctk:value>" << endl; + } + msgbuf << "</cctk:Publish>" << endl; + msgbuf << tablebuf.str(); } - msgbuf << "</cctk:UpdateInfo>" << endl; + + rdfPublishList.clear(); } @@ -375,9 +399,57 @@ namespace Formaline ~ rdf () { DECLARE_CCTK_PARAMETERS; - - // Create the data string - string const msgstr = msgbuf.str(); + + // check if anything needs to be done + if (msgbuf.str().empty()) return; + + // RDF/XML document header with some namespace definitions + const string header = +"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +"<!DOCTYPE owl [\n" +"\t<!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n" +"\t<!ENTITY xsd 'http://www.w3.org/2001/XMLSchema#'>\n" +"\t<!ENTITY cctk 'http://www.gac-grid.org/project-products/Software/InformationService/InformationProducer/CactusRDFProducer/2006/08/cctk-schema#'>\n" + +#if 0 + << "\t<!ENTITY cctk 'http://www.aei.mpg.de/~tradke/cctk-schema#'>" << endl + << "\t<!ENTITY cctk 'http://www.cct.lsu.edu/~dstark/cctk/0.1/'>" << endl + << "<!--" << endl + << "\t<!ENTITY dc 'http://purl.org/dc/elements/1.1/'>" << endl + << "\t<!ENTITY doap 'http://usefulinc.com/ns/doap#'>" << endl + << "\t<!ENTITY foaf 'http://xmlns.com/foaf/0.1/'>" << endl + << "\t<!ENTITY rdfs 'http://www.w3.org/2000/01/rdf-schema#'>" << endl + << "\t<!ENTITY form 'http://www.aei.mpg.de/form#'>" << endl + << "-->" << endl +#endif +"]>\n" +"<rdf:RDF xmlns:rdf=\"&rdf;\"\n" +"\txmlns:xsd=\"&xsd;\"\n" +"\txmlns:cctk=\"&cctk;\"\n" +">\n" +#if 0 + << "<!--" << endl + << "\txmlns:dc=\"&dc;\"" << endl + << "\txmlns:doap=\"&doap;\"" << endl + << "\txmlns:foaf=\"&foaf;\"" << endl + << "\txmlns:rdfs=\"&rdfs;\"" << endl + << "\txmlns:form=\"&form;\"" << endl + << "-->" << endl + << "" << endl + << "<!-- lessons learned so far" << endl + << " " << endl + << " * although it would be better to use rdf:ID as relative URIs for objects" << endl + << " (because they are enforced to be unique), rdf:about must be used instead" << endl + << " because the value of a relative rdf:about URI may contain special" << endl + << " characters (such as '/') whereas rdf:ID must not" << endl + << "-->" << endl +#endif +"\n\n"; + + // RDF/XML document footer + const string footer = "\n</rdf:RDF>\n"; + + const int len = header.length() + msgbuf.str().length() + footer.length(); // Loop over all destinations for (int i = 0; i < NUM_RDF_ENTRIES; i++) { @@ -389,19 +461,17 @@ namespace Formaline ostringstream databuf; databuf << (get_state() == initial ? "PUT" : "POST") -<< " /context/CactusSimulations/" << jobID << " HTTP/1.0\r\n" +<< " /context/CactusSimulations/" << jobID; +// if (get_state() != initial) databuf << "?action=update"; + databuf << " HTTP/1.0\r\n" << "Host: " << rdf_hostname[i] << "\r\n" << "Content-Type: application/rdf+xml\r\n" -<< "Content-Length: " << msgstr.length() << "\r\n" -<< "\r\n" -<< msgstr -<< "\r\n" -<< "\r\n"; - string const datastr = databuf.str(); +<< "Content-Length: " << len << "\r\n\r\n" +<< header << msgbuf.str() << footer << "\r\n\r\n"; // Send the data - SendData (rdf_hostname[i], rdf_port[i], datastr); - + SendData (rdf_hostname[i], rdf_port[i], databuf.str()); + } } // loop over all destinations } @@ -412,6 +482,8 @@ namespace Formaline store (char const * const key, bool const value) { + const void* dummy = &dummy; + dummy = &key; dummy = &value; #if 0 ostringstream valuebuf; valuebuf << (value ? "true" : "false"); @@ -447,6 +519,8 @@ namespace Formaline store (char const * const key, CCTK_INT const value) { + const void* dummy = &dummy; + dummy = &key; dummy = &value; #if 0 ostringstream valuebuf; valuebuf << value; @@ -482,6 +556,8 @@ namespace Formaline store (char const * const key, CCTK_REAL const value) { + const void* dummy = &dummy; + dummy = &key; dummy = &value; #if 0 int const prec = numeric_limits<CCTK_REAL>::digits10; ostringstream valuebuf; @@ -518,6 +594,8 @@ namespace Formaline store (char const * const key, char const * const value) { + const void* dummy = &dummy; + dummy = &key; dummy = &value; #if 0 // don't store keys with empty string values if (not *value) return; @@ -552,10 +630,8 @@ namespace Formaline } - - string rdf:: + string clean (string const & txt) - const { ostringstream buf; @@ -573,9 +649,8 @@ namespace Formaline } - string rdf:: + string cleanURI (string const & uri) - const { const string allowed_charset ("-_.!~*'()/"); ostringstream buf; @@ -7,6 +7,7 @@ #include <sstream> #include <string> +#include <vector> #include "storage.hh" @@ -15,6 +16,41 @@ namespace Formaline { + typedef struct { + std::string type; + std::string value; + } rdfScalarValue; + + typedef struct { + std::string key; + rdfScalarValue value; + } rdfTableEntry; + + typedef struct { + std::string datetime; + bool hasCCTKinfo; + CCTK_REAL cctk_time; + int cctk_iteration; + std::string name; + std::string key; +// classes (with constructors) are not allowed as members of a union +// union value { + rdfScalarValue scalar; + std::vector<rdfTableEntry> table; +// } + bool isTable; + } rdfPublishItem; + + // buffer to keep RDF metadata until the next Update() call + extern std::vector<rdfPublishItem> rdfPublishList; + + // the jobID string + extern std::string jobID; + + std::string clean (std::string const & txt); + + std::string cleanURI (std::string const & uri); + class rdf : public storage @@ -49,18 +85,9 @@ namespace Formaline private: - std::string jobID; - - std::string - clean (std::string const & txt) - const; - - std::string - cleanURI (std::string const & uri) - const; - void Initial (void); void Update (cGH const * cctkGH); + }; diff --git a/src/rdf_publisher.cc b/src/rdf_publisher.cc new file mode 100644 index 0000000..fd17707 --- /dev/null +++ b/src/rdf_publisher.cc @@ -0,0 +1,309 @@ +// $Header$ + +#include <cassert> +#include <string> +#include <iostream> + +#include "util_Table.h" +#include "cctk.h" +#include "cctk_Arguments.h" +#include "cctk_Parameters.h" + +#include "Publish.h" + +#include "rdf.hh" + + +using std::endl; + +namespace Formaline +{ + +// buffer of published RDF metadata since the last Update() call +std::vector<rdfPublishItem> rdfPublishList; + + +static rdfPublishItem* CreateNewItem (CCTK_POINTER_TO_CONST cctkGH, + CCTK_POINTER data, + CCTK_INT level, + CCTK_STRING name, + CCTK_STRING key, + bool isTable) +{ + DECLARE_CCTK_PARAMETERS; + + // prevent compiler warnings about unused parameters + data = &data; + + assert (key and *key); + assert (level >= 0); + rdfPublishItem* item = NULL; + if (level <= publish_level) { + rdfPublishItem newItem; + rdfPublishList.push_back (newItem); + item = &rdfPublishList.back(); + char* currentdate = Util_CurrentDateTime (); + item->datetime = clean (currentdate); + free (currentdate); + item->hasCCTKinfo = cctkGH != NULL; + if (item->hasCCTKinfo) { + const cGH* _cctkGH = (const cGH*) cctkGH; + item->cctk_time = _cctkGH->cctk_time; + item->cctk_iteration = _cctkGH->cctk_iteration; + } + if (name and *name) item->name = clean (name); + item->key = clean (key); + item->isTable = isTable; + } + return item; +} + +static CCTK_INT PublishBooleanAsRDF (CCTK_POINTER_TO_CONST cctkGH, + CCTK_POINTER data, + CCTK_INT level, + CCTK_INT value, + CCTK_STRING key, + CCTK_STRING name) +{ + rdfPublishItem* item = CreateNewItem (cctkGH, data, level, name, key, false); + if (item) { + item->scalar.value = value ? "true" : "false"; + item->scalar.type = "boolean"; + } + + return (item ? 1 : 0); +} + + +static CCTK_INT PublishIntAsRDF (CCTK_POINTER_TO_CONST cctkGH, + CCTK_POINTER data, + CCTK_INT level, + CCTK_INT value, + CCTK_STRING key, + CCTK_STRING name) +{ + rdfPublishItem* item = CreateNewItem (cctkGH, data, level, name, key, false); + if (item) { + std::ostringstream buf; + buf << value; + item->scalar.value = buf.str(); + item->scalar.type = "int"; + } + + return (item ? 1 : 0); +} + + +static CCTK_INT PublishRealAsRDF (CCTK_POINTER_TO_CONST cctkGH, + CCTK_POINTER data, + CCTK_INT level, + CCTK_REAL value, + CCTK_STRING key, + CCTK_STRING name) +{ + rdfPublishItem* item = CreateNewItem (cctkGH, data, level, name, key, false); + if (item) { + std::ostringstream buf; + buf << value; + item->scalar.value = buf.str(); + item->scalar.type = "double"; + } + + return (item ? 1 : 0); +} + + +static CCTK_INT PublishStringAsRDF (CCTK_POINTER_TO_CONST cctkGH, + CCTK_POINTER data, + CCTK_INT level, + CCTK_STRING value, + CCTK_STRING key, + CCTK_STRING name) +{ + rdfPublishItem* item = CreateNewItem (cctkGH, data, level, name, key, false); + if (item) { + item->scalar.value = clean (value); + item->scalar.type = "string"; + } + + return (item ? 1 : 0); +} + + +static CCTK_INT PublishTableAsRDF (CCTK_POINTER_TO_CONST cctkGH, + CCTK_POINTER data, + CCTK_INT level, + CCTK_INT table, + CCTK_STRING key, + CCTK_STRING name) +{ + rdfPublishItem* item = CreateNewItem (cctkGH, data, level, name, key, true); + if (not item) return 0; + + const int maxkeylen = Util_TableQueryMaxKeyLength (table); + if (maxkeylen <= 0) return (-1); + char* userkey = new char[maxkeylen + 1]; + + int iterator; + for (iterator = Util_TableItCreate (table); + Util_TableItQueryIsNonNull (iterator) > 0; + Util_TableItAdvance (iterator)) { + CCTK_INT typecode, n_elements = -1; + + Util_TableItQueryKeyValueInfo (iterator, maxkeylen + 1, userkey, + &typecode, &n_elements); + if (n_elements <= 0) { + CCTK_VWarn (3, __LINE__, __FILE__, CCTK_THORNSTRING, + "No value provided for user key '%s' in table to be " + "published with key '%s'", userkey, key); + continue; + } + if (n_elements > 1 and + (typecode == CCTK_VARIABLE_INT or typecode == CCTK_VARIABLE_REAL)) { + CCTK_VWarn (3, __LINE__, __FILE__, CCTK_THORNSTRING, + "Array value not supported for user key '%s' in table to " + "be published with key '%s'", userkey, key); + continue; + } else if (typecode != CCTK_VARIABLE_CHAR and + typecode != CCTK_VARIABLE_INT and + typecode != CCTK_VARIABLE_REAL) { + CCTK_VWarn (3, __LINE__, __FILE__, CCTK_THORNSTRING, + "Unsupported datatype '%s' for value with user key '%s' " + "in table to be published with key '%s'", + CCTK_VarTypeName (typecode), userkey, key); + continue; + } + + rdfTableEntry newEntry; + item->table.push_back (newEntry); + rdfTableEntry* entry = &item->table.back(); + entry->key = clean (userkey); + std::ostringstream buf; + if (typecode == CCTK_VARIABLE_CHAR) { + char *buffer = new char[n_elements + 1]; + Util_TableGetString (table, n_elements + 1, buffer, userkey); + entry->value.value = buffer; + delete[] buffer; + } else if (typecode == CCTK_VARIABLE_INT) { + CCTK_INT int_value; + Util_TableGetInt (table, &int_value, userkey); + buf << int_value; + entry->value.value = buf.str(); + entry->value.type = "int"; + } else if (typecode == CCTK_VARIABLE_REAL) { + CCTK_REAL real_value; + Util_TableGetReal (table, &real_value, userkey); + buf << real_value; + entry->value.value = buf.str(); + entry->value.type = "double"; + } else { + assert (0); + } + } + Util_TableItDestroy (iterator); + delete[] userkey; + + return 1; +} + + +static void ParameterSetNotify (void *unused, + const char *thorn, + const char *parameter, + const char *new_value) +{ + unused = &unused; + + const char *name = "Set Parameter"; + std::string key(thorn); key.append ("::"); key.append (parameter); + + int type; + const void* data = CCTK_ParameterGet (parameter, thorn, &type); + + if (type == PARAMETER_KEYWORD || type == PARAMETER_STRING || + type == PARAMETER_SENTENCE) + { + if (CCTK_IsFunctionAliased ("PublishString")) + { + PublishString (NULL, 0, *(const char *const *) data, key.c_str(), name); + } + } + else if (type == PARAMETER_BOOLEAN) + { + if (CCTK_IsFunctionAliased ("PublishBoolean")) + { + PublishBoolean (NULL, 0, *(const CCTK_INT *) data, key.c_str(), name); + } + } + else if (type == PARAMETER_INT) + { + if (CCTK_IsFunctionAliased ("PublishInt")) + { + PublishInt (NULL, 0, *(const CCTK_INT *) data, key.c_str(), name); + } + } + else if (type == PARAMETER_REAL) + { + if (CCTK_IsFunctionAliased ("PublishReal")) + { + PublishReal (NULL, 0, *(const CCTK_REAL *) data, key.c_str(), name); + } + } else { + assert (0 and "invalid parameter type"); + } +} + + +extern "C" +void Formaline_RegisterPublishRDF_Callbacks (void) +{ + int registered = 0; + +#define REGISTER_RDF_CALLBACKS(type) \ + if (CCTK_IsFunctionAliased ("Publish" #type "_Register")) { \ + if (Publish##type##_Register (Publish##type##AsRDF, NULL, \ + "Publish as RDF")) { \ + CCTK_WARN (0, "Failed to register Publish" #type " callback"); \ + } \ + registered++; \ + } + // we don't have a valid cctkGH yet + if (CCTK_MyProc (NULL) == 0) { + REGISTER_RDF_CALLBACKS (Boolean); + REGISTER_RDF_CALLBACKS (Int); + REGISTER_RDF_CALLBACKS (Real); + REGISTER_RDF_CALLBACKS (String); + REGISTER_RDF_CALLBACKS (Table); + if (registered) { + if (CCTK_ParameterSetNotifyRegister (ParameterSetNotify, NULL, + CCTK_THORNSTRING, NULL, NULL)) { + CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING, + "Couldn't register parameter set notify callback"); + } + } else { + CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, + "Couldn't register Publish RDF callbacks because no thorn " + "provides Publish register API aliases functions"); + } + } +} + +extern "C" +void Formaline_UnregisterPublishRDF_Callbacks (CCTK_ARGUMENTS) +{ +#define UNREGISTER_RDF_CALLBACKS(type) \ + if (CCTK_IsFunctionAliased ("Publish" #type "_Unregister")) { \ + Publish##type##_Unregister ("Publish as RDF"); \ + } + if (CCTK_MyProc (cctkGH) == 0) { + CCTK_ParameterSetNotifyUnregister (CCTK_THORNSTRING); + UNREGISTER_RDF_CALLBACKS (Boolean); + UNREGISTER_RDF_CALLBACKS (Int); + UNREGISTER_RDF_CALLBACKS (Real); + UNREGISTER_RDF_CALLBACKS (String); + UNREGISTER_RDF_CALLBACKS (Table); + } +} + + +} // namespace Formaline |