1 /**
2 * @file    rngvalidator.cpp
3 * @brief   Example creating a rng validator to be called during validation
4 * @author  Frank T. Bergmann
5 *
6  * <!--------------------------------------------------------------------------
7  * This sample program is distributed under a different license than the rest
8  * of libSBML.  This program uses the open-source MIT license, as follows:
9  *
10  * Copyright (c) 2013-2018 by the California Institute of Technology
11  * (California, USA), the European Bioinformatics Institute (EMBL-EBI, UK)
12  * and the University of Heidelberg (Germany), with support from the National
13  * Institutes of Health (USA) under grant R01GM070923.  All rights reserved.
14  *
15  * Permission is hereby granted, free of charge, to any person obtaining a
16  * copy of this software and associated documentation files (the "Software"),
17  * to deal in the Software without restriction, including without limitation
18  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19  * and/or sell copies of the Software, and to permit persons to whom the
20  * Software is furnished to do so, subject to the following conditions:
21  *
22  * The above copyright notice and this permission notice shall be included in
23  * all copies or substantial portions of the Software.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31  * DEALINGS IN THE SOFTWARE.
32  *
33  * Neither the name of the California Institute of Technology (Caltech), nor
34  * of the European Bioinformatics Institute (EMBL-EBI), nor of the University
35  * of Heidelberg, nor the names of any contributors, may be used to endorse
36  * or promote products derived from this software without specific prior
37  * written permission.
38  * ------------------------------------------------------------------------ -->
39 */
40 
41 #include <iostream>
42 #include <sbml/SBMLTypes.h>
43 #include <sbml/SBMLError.h>
44 
45 #include <sbml/validator/SBMLValidator.h>
46 
47 #include <libxml/xmlmemory.h>
48 #include <libxml/parser.h>
49 #include <libxml/relaxng.h>
50 #include <stdarg.h>
51 #include <util.h>
52 
53 using namespace std;
54 LIBSBML_CPP_NAMESPACE_USE
55 
56 std::vector<std::string> warnings;
57 std::vector<std::string> errors;
58 
logWarning(void * ctx,const char * msg,...)59 void logWarning(void *ctx, const char *msg, ...)
60 {
61   char buffer[1000];
62   va_list args;
63   va_start (args, msg);
64   vsprintf (buffer,msg, args);
65   va_end (args);
66 
67   warnings.push_back(buffer);
68 }
logError(void * ctx,const char * msg,...)69 void logError(void *ctx, const char *msg, ...)
70 {
71   char buffer[1000];
72   va_list args;
73   va_start (args, msg);
74   vsprintf (buffer,msg, args);
75   va_end (args);
76 
77   errors.push_back(buffer);
78 }
79 
80   /**
81   * Declares a custom validator to be called. This allows you to validate
82   * any aspect of an SBML Model that you want to be notified about. You could
83   * use this to notify your application that a model contains an unsupported
84   * feature of SBML (either as warning).
85   *
86   * In this example the validator will go through the model and test for the
87   * presence of 'fast' reactions and algebraic rules. If either is used a
88   * warning will be added to the error log.
89   */
90 class RNGValidator : public SBMLValidator
91 {
92 private:
93   std::string mSchema;
94 
95 public:
96 
setSchema(const std::string & schemaFile)97   void setSchema(const std::string& schemaFile)
98   {
99     mSchema =schemaFile;
100   }
101 
getSchema() const102   const std::string& getSchema() const { return mSchema; }
103 
RNGValidator()104   RNGValidator() : SBMLValidator(), mSchema() {}
105 
RNGValidator(const std::string & schema)106   RNGValidator(const std::string& schema) : SBMLValidator(), mSchema(schema) {}
107 
RNGValidator(const RNGValidator & orig)108   RNGValidator(const RNGValidator& orig) : SBMLValidator(orig), mSchema(orig.mSchema) {
109   }
~RNGValidator()110   virtual ~RNGValidator() {}
111 
clone() const112   virtual SBMLValidator* clone() const { return new RNGValidator(*this); }
113 
validate()114   virtual unsigned int validate() {
115     // if we don't have a model we don't apply this validator.
116     if (getDocument() == NULL || getModel() == NULL)
117       return 0;
118 
119     // we dont' have a schema, so don't report
120     if (mSchema.empty())
121       return 0;
122 
123     // if we have no rules and reactions we don't apply this validator either
124     if (getModel()->getNumReactions() == 0 && getModel()->getNumRules() == 0)
125       return 0;
126 
127     // get document
128 
129     std::string sbmlDoc = writeSBMLToString(getDocument());
130     warnings.clear();
131     errors.clear();
132 
133     xmlDoc *doc;
134     xmlRelaxNGPtr schema;
135     xmlRelaxNGValidCtxtPtr validctxt;
136     xmlRelaxNGParserCtxtPtr rngparser;
137 
138     doc = xmlParseMemory(sbmlDoc.c_str(), (int)(sbmlDoc.length()));
139 
140     rngparser = xmlRelaxNGNewParserCtxt(mSchema.c_str());
141     schema = xmlRelaxNGParse(rngparser);
142     validctxt = xmlRelaxNGNewValidCtxt(schema);
143 
144 
145     xmlRelaxNGSetParserErrors	(rngparser,
146 					 &logError,
147 					 &logWarning,
148 					 (void *) getErrorLog());
149    xmlRelaxNGSetValidErrors	(validctxt,
150 					 &logError,
151 					 &logWarning,
152 					 (void *) getErrorLog());
153 
154     xmlRelaxNGValidateDoc(validctxt, doc);
155 
156     xmlRelaxNGFree(schema);
157     xmlRelaxNGFreeValidCtxt(validctxt);
158     xmlRelaxNGFreeParserCtxt(rngparser);
159     xmlFreeDoc(doc);
160 
161     unsigned int numErrors = 0;
162 
163     for (size_t i = 0; i < warnings.size(); ++i)
164     {
165 
166         getErrorLog()->add(SBMLError(99999, 3, 1,
167           warnings[i],
168           0, 0,
169           LIBSBML_SEV_WARNING, // or LIBSBML_SEV_ERROR if you want to stop
170           LIBSBML_CAT_SBML // or whatever category you prefer
171           ));
172     }
173 
174     for (size_t i = 0; i < errors.size(); ++i)
175     {
176 
177         getErrorLog()->add(SBMLError(99999, 3, 1,
178           errors[i],
179           0, 0,
180           LIBSBML_SEV_ERROR, // or LIBSBML_SEV_ERROR if you want to stop
181           LIBSBML_CAT_SBML // or whatever category you prefer
182           ));
183         numErrors ++;
184     }
185 
186     return numErrors;
187   }
188 
189 
190 };
191 
192 
193 int
main(int argc,char * argv[])194 main (int argc, char *argv[])
195 {
196   if (argc < 2)
197   {
198     cout << endl << "Usage: rngvalidator filename [schema]" << endl << endl;
199     return 1;
200   }
201 
202   const char* filename   = argv[1];
203 
204   const char* schema   = argc > 2 ? argv[2] : NULL;
205 
206   // read the file name
207   SBMLDocument* document = readSBML(filename);
208 
209   // add a custom validator if given
210   if (schema  != NULL)
211     document->addValidator(new RNGValidator(schema));
212 
213   unsigned long long start, stop;
214 
215   start    = getCurrentMillis();
216 
217   // check consistency like before
218   int numErrors = document->checkConsistency();
219 
220   stop     = getCurrentMillis();
221 
222   cout << "      validation time (ms): " << stop - start          << endl<< endl;
223 
224 
225   // print errors and warnings
226   document->printErrors();
227 
228   // return number of errors
229   return  numErrors;
230 
231 }
232