Project

Profile

Help

Bug #4274 » SaxonProcessor.h

O'Neil Delpratt, 2019-08-14 00:15

 
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright (c) 2019 Saxonica Limited.
3
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
6
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7

    
8
#ifndef SAXON_PROCESSOR_H
9
#define SAXON_PROCESSOR_H
10
        
11
#if defined __linux__ || defined __APPLE__
12
        #include <stdlib.h>
13
        #include <string.h>
14
        #include <dlfcn.h>
15

    
16
        #define HANDLE void*
17
        #define LoadLibrary(x) dlopen(x, RTLD_LAZY)
18
        #define GetProcAddress(x,y) dlsym(x,y)
19
#else
20
    #include <windows.h>
21
#endif
22

    
23
//#define DEBUG //remove
24
#define CVERSION "1.1.2"
25
#include <string>
26
#include <iostream>
27
#include <sstream>  
28
#include <map>        
29
#include <vector>
30
#include <stdexcept>      // std::logic_error
31

    
32
#include "SaxonCGlue.h"
33
#include "SaxonCXPath.h"
34
#include "XsltProcessor.h"
35
#include "XQueryProcessor.h"
36
#include "XPathProcessor.h"
37
#include "SchemaValidator.h"
38
//#include "com_saxonica_functions_extfn_PhpCall.h"
39
//#include "com_saxonica_functions_extfn_PhpCall_PhpFunctionCall.h"
40

    
41
class XsltProcessor;
42
class XQueryProcessor;
43
class XPathProcessor;
44
class SchemaValidator;
45
class XdmValue;
46
class XdmNode;
47
class XdmItem;
48
class XdmAtomicValue;
49

    
50

    
51

    
52
// The Saxon XSLT interface class
53

    
54
//std::mutex mtx;
55
/*! <code>MyException</code>. This struct captures details of the Java exception thrown from Saxon s9api API (Java).
56
 * <p/>
57
 */
58
typedef struct {
59
                std::string errorCode;
60
                std::string errorMessage;
61
                int linenumber;
62
                    bool isType;
63
                    bool isStatic;
64
                    bool isGlobal;
65
        }MyException;
66

    
67

    
68

    
69

    
70
/*! <code>SaxonApiException</code>. An exception thrown by the Saxon s9api API (Java). This is always a C++ wrapper for some other underlying exception in Java
71
 * <p/>
72
 */
73
class SaxonApiException {
74

    
75
public:
76

    
77
    /**
78
     * A default Constructor. Create a SaxonApiException
79
     */
80
     SaxonApiException(){
81
        exceptions = std::vector<MyException>(0);
82
    }
83

    
84
    /**
85
     * A Copy constructor. Create a SaxonApiException
86
     * @param ex - The exception object to copy
87
     */
88
        SaxonApiException(const SaxonApiException &ex){
89
                exceptions = ex.exceptions;
90
        }
91

    
92
    /**
93
     * A constructor. Create a SaxonApiException
94
     * @param ec - The error code of the underlying exception thrown, if known
95
     * @param exM - The error message of the underlying exception thrown, if known
96
     */
97
        SaxonApiException(const char * ec, const char * exM){
98
                exceptions = std::vector<MyException>(0);
99
                MyException newEx;        
100
                if(ec != NULL){
101
                        newEx.errorCode =   std::string(ec);
102
                } else {
103
                        newEx.errorCode ="Unknown";        
104
                }
105
                if(exM != NULL){
106
                        newEx.errorMessage =  std::string(exM);
107
                } else {
108
                        newEx.errorMessage="Unkown";                
109
                }
110
                newEx.isType = false;
111
                    newEx.isStatic = false;
112
                    newEx.isGlobal = false;
113
                newEx.linenumber = 0;
114
                exceptions.push_back(newEx);
115
        }
116

    
117
    /**
118
     * A constructor. Create a SaxonApiException
119
     * @param ec - The error code of the underlying exception thrown, if known
120
     * @param exM - The error message of the underlying exception thrown, if known
121
     * @param typeErr - Flag indicating if the error is a type error
122
     * @param stat - Flag indicating a static error
123
     * @param glob - Flag for if the error is global
124
     * @param l - Line number information of where the error occurred
125
     */
126
        SaxonApiException(const char * ec, const char * exM, bool typeErr, bool stat, bool glob, int l){
127
                exceptions = std::vector<MyException>(20);
128
                MyException newEx;
129
                if(ec != NULL){
130
                        newEx.errorCode =   std::string(ec);
131
                } else {
132
                        newEx.errorCode ="ERROR1";        
133
                }
134
                if(exM != NULL){
135
                        newEx.errorMessage =  std::string(exM);
136
                } else {
137
                        newEx.errorMessage="ERROR2";                
138
                }
139
                newEx.isType = typeErr;
140
                    newEx.isStatic = stat;
141
                    newEx.isGlobal = glob;
142
                newEx.linenumber = l;
143
                exceptions.push_back(newEx);
144
        }
145

    
146
    /**
147
     * Creates a SaxonApiException and adds it to a vector of exceptions
148
     * @param ec - The error code of the underlying exception thrown, if known
149
     * @param exM - The error message of the underlying exception thrown, if known
150
     * @param typeErr - Flag indicating if the error is a type error
151
     * @param stat - Flag indicating a static error
152
     * @param glob - Flag for if the error is global
153
     * @param l - Line number information of where the error occurred
154
     */
155
        void add(const char * ec, const char * exM, bool typeErr, bool stat, bool glob, int l){
156
                MyException newEx;
157
                if(ec != NULL){
158
                        newEx.errorCode =   std::string(ec);
159
                } else {
160
                        newEx.errorCode ="ERROR1";        
161
                }
162
                if(exM != NULL){
163
                        newEx.errorMessage =  std::string(exM);
164
                } else {
165
                        newEx.errorMessage="ERROR2";                
166
                }
167
                newEx.isType = typeErr;
168
                    newEx.isStatic = stat;
169
                    newEx.isGlobal = glob;
170
                newEx.linenumber = l;
171
                exceptions.push_back(newEx);
172
        }
173

    
174

    
175
    /**
176
     * A destructor.
177
     */
178
        ~SaxonApiException(){ 
179
          clear();
180
        }
181

    
182
    /**
183
     * Get the error code associated with the ith exception in the vector, if there is one
184
     * @param i - ith exception in the vector
185
     * @return the associated error code, or null if no error code is available
186
     */
187
        const char * getErrorCode(int i){
188
                if((size_t)i <= exceptions.size()){
189
                        return exceptions[i].errorCode.c_str();
190
                }
191
                return NULL;
192
        }
193

    
194

    
195
        int getLineNumber(int i){
196
                if((size_t)i <= exceptions.size()){
197
                        return exceptions[i].linenumber;        
198
                }
199
                return 0;
200
        }
201

    
202
        bool isGlobalError(int i){
203
                if((size_t)i <= exceptions.size()){
204
                        return exceptions[i].isGlobal;
205
                }
206
                return false;
207
        }
208

    
209
        bool isStaticError(int i){
210
                if((size_t)i <= exceptions.size()){
211
                        return exceptions[i].isStatic;
212
                }
213
                return false;
214
        }
215

    
216
        bool isTypeError(int i){
217
                if((size_t) i <= exceptions.size()){
218
                        return exceptions[i].isType;
219
                }
220
                return false;
221
        }
222

    
223
        void clear(){
224
          for(size_t i =0; i< exceptions.size();i++) {
225
                exceptions[i].errorCode.clear();
226
                exceptions[i].errorMessage.clear();        
227
          }
228
          exceptions.clear();
229
        }
230

    
231
        int count(){
232
                return (int)exceptions.size();        
233
        }
234

    
235
    /**
236
     * Returns the detail message string of the ith throwable, if there is one
237
     * @param i - ith exception in the vector
238
     * @return the detail message string of this <tt>Throwable</tt> instance
239
     *         (which may be <tt>null</tt>).
240
     */
241
        const char * getErrorMessage(int i){
242
                if((size_t)i <= exceptions.size()){
243
                        return exceptions[i].errorMessage.c_str();
244
                }
245
                return NULL;
246
        }
247

    
248
        const char * getErrorMessages(){
249
                std::string result;
250
                for(size_t i = 0;i<exceptions.size();i++) {
251
                        result += getErrorMessage(i);
252
                }
253
                if(result.empty()) { return NULL;}
254
                return result.c_str();
255
        }
256

    
257
    /**
258
     * Returns the ith Exception added, if there is one
259
     * @param i - ith exception in the vector
260
     * @return MyException
261
     */
262
        MyException getException(int i){
263
                if((size_t)i <= exceptions.size()){
264
                        return exceptions[i];        
265
                }
266
                throw 0;
267
        }
268

    
269
        
270

    
271
private:
272
        std::vector<MyException> exceptions; /*!< Capture exceptions in a std:vector */
273
};
274

    
275

    
276

    
277

    
278

    
279

    
280

    
281

    
282
//==========================================
283

    
284

    
285

    
286
/*! An <code>SaxonProcessor</code> acts as a factory for generating XQuery, XPath, Schema and XSLT compilers
287
 * In this alpha release only the XSLT compiler is available
288
 * <p/>
289
 */
290
class SaxonProcessor {
291
friend  class XsltProcessor;
292
friend  class XQueryProcessor;
293
friend class SchemaValidator;
294
friend class XPathProcessor;
295
friend class XdmValue;
296
friend class XdmAtomicValue;
297
public:
298

    
299
   //! A default constructor.
300
    /*!
301
      * Create Saxon Processor.
302
    */
303

    
304
    SaxonProcessor();
305

    
306
   //! constructor based upon a Saxon configuration file.
307
    /*!
308
      * Create Saxon Processor.
309
    */
310

    
311
    SaxonProcessor(const char * configFile);
312

    
313

    
314
   //! A constructor.
315
    /*!
316
      * Create Saxon Processor.
317
      * @param l - Flag that a license is to be used. Default is false.        
318
    */
319
    SaxonProcessor(bool l);
320

    
321
    SaxonProcessor& operator=( const SaxonProcessor& other );
322

    
323
   /*!
324

325
      * Destructor
326
    */
327
    ~SaxonProcessor();
328
        
329
   /*!
330

331
      * Create an XsltProcessor. An XsltProcessor is used to compile XSLT stylesheets.
332
      * @return a newly created XsltProcessor        
333
    */        
334
    XsltProcessor * newXsltProcessor();
335

    
336
    /*!
337
     * Create an XQueryProcessor. An XQueryProcessor is used to compile XQuery queries.
338
     *
339
     * @return a newly created XQueryProcessor
340
     */
341
    XQueryProcessor * newXQueryProcessor();
342

    
343

    
344
    /*!
345
     * Create an XPathProcessor. An XPathProcessor is used to compile XPath expressions.
346
     *
347
     * @return a newly created XPathProcessor
348
     */
349
    XPathProcessor * newXPathProcessor();
350

    
351
    /*!
352
     * Create a SchemaValidator which can be used to validate instance documents against the schema held by this
353
     * SchemaManager
354
     *
355
     * @return a new SchemaValidator
356
     */
357
    SchemaValidator * newSchemaValidator();
358

    
359

    
360
    /*!
361
     * Factory method. Unlike the constructor, this avoids creating a new StringValue in the case
362
     * of a zero-length string (and potentially other strings, in future)
363
     *
364
     * @param value the String value. Null is taken as equivalent to "".
365
     * @return the corresponding StringValue
366
     */
367
    XdmAtomicValue * makeStringValue(std::string str);
368

    
369
    /*!
370
     * Factory method. Unlike the constructor, this avoids creating a new StringValue in the case
371
     * of a zero-length string (and potentially other strings, in future)
372
     *
373
     * @param value the char pointer array. Null is taken as equivalent to "".
374
     * @return the corresponding StringValue
375
     */
376
    XdmAtomicValue * makeStringValue(const char * str);
377

    
378
    /*!
379
     * Factory method: makes either an Int64Value or a BigIntegerValue depending on the value supplied
380
     *
381
     * @param i the supplied primitive integer value
382
     * @return the value as a XdmAtomicValue which is a BigIntegerValue or Int64Value as appropriate
383
     */
384
    XdmAtomicValue * makeIntegerValue(int i);
385

    
386

    
387
    /*!
388
     * Factory method (for convenience in compiled bytecode)
389
     *
390
     * @param d the value of the double
391
     * @return a new XdmAtomicValue
392
     */
393
    XdmAtomicValue * makeDoubleValue(double d);
394

    
395
    /*!
396
     * Factory method (for convenience in compiled bytecode)
397
     *
398
     * @param f the value of the foat
399
     * @return a new XdmAtomicValue
400
     */
401
    XdmAtomicValue * makeFloatValue(float);
402

    
403
    /*!
404
     * Factory method: makes either an Int64Value or a BigIntegerValue depending on the value supplied
405
     *
406
     * @param l the supplied primitive long value
407
     * @return the value as a XdmAtomicValue which is a BigIntegerValue or Int64Value as appropriate
408
     */
409
    XdmAtomicValue * makeLongValue(long l);
410

    
411
    /*!
412
     * Factory method: makes a XdmAtomicValue representing a boolean Value
413
     *
414
     * @param b true or false, to determine which boolean value is
415
     *              required
416
     * @return the XdmAtomicValue requested
417
     */
418
    XdmAtomicValue * makeBooleanValue(bool b);
419

    
420
    /**
421
     * Create an QName Xdm value from string representation in clark notation
422
     * @param valueStr - The value given in a string form in clark notation. {uri}local
423
     * @return XdmAtomicValue - value
424
    */
425
    XdmAtomicValue * makeQNameValue(std::string str);
426

    
427
    /*!
428
     * Create an Xdm Atomic value from string representation
429
     * @param type    - Local name of a type in the XML Schema namespace.
430
     * @param value - The value given in a string form.
431
     * In the case of a QName the value supplied must be in clark notation. {uri}local
432
     * @return XdmValue - value
433
    */
434
    XdmAtomicValue * makeAtomicValue(std::string type, std::string value);
435

    
436
     /**
437
     * Get the string representation of the XdmValue.
438
     * @return char array
439
     */
440
    const char * getStringValue(XdmItem * item);
441

    
442
    /**
443
     * Parse a lexical representation of the source document and return it as an XdmNode
444
    */
445
    XdmNode * parseXmlFromString(const char* source);
446

    
447
    /**
448
     * Parse a source document file and return it as an XdmNode.
449
    */
450
    XdmNode * parseXmlFromFile(const char* source);
451

    
452
    /**
453
     * Parse a source document available by URI and return it as an XdmNode.
454
    */
455
    XdmNode * parseXmlFromUri(const char* source);
456

    
457
    int getNodeKind(jobject);
458

    
459
    bool isSchemaAware();
460
 
461

    
462
    /**
463
     * Checks for pending exceptions without creating a local reference to the exception object
464
     * @return bool - true when there is a pending exception; otherwise return false
465
    */
466
    bool exceptionOccurred();
467

    
468
    /**
469

470
     * Clears any exception that is currently being thrown. If no exception is currently being thrown, this routine has no effect.
471
    */
472
    void exceptionClear(bool clearCPPException=true);
473

    
474
    /**
475
     * Checks for pending exceptions and creates a SaxonApiException object, which handles one or more local exceptions objects
476
     * @param env
477
     * @param callingClass
478
     * @param callingObject
479
     * @return SaxonApiException
480
    */
481
    SaxonApiException * checkForExceptionCPP(JNIEnv* env, jclass callingClass,  jobject callingObject);
482

    
483
    SaxonApiException * getException();
484

    
485
    /*
486
      * Clean up and destroy Java VM to release memory used. 
487
     */
488
    static void release();
489

    
490
    /**
491
     * set the current working directory
492
    */
493
   void setcwd(const char* cwd);
494

    
495

    
496
    /**
497
     * set saxon resources directory
498
    */
499
   void setResourcesDirectory(const char* dir);
500

    
501
        
502
    /**
503
     * set catalog to be used in Saxon
504
    */
505
   void setCatalog(const char* catalogFile, bool isTracing);        
506

    
507
    /**
508
     * get saxon resources directory
509
    */
510
   const char * getResourcesDirectory();
511

    
512
    /**
513
     * Set a configuration property specific to the processor in use. 
514
     * Properties specified here are common across all the processors.
515
     * Example 'l':enable line number has the value 'on' or 'off'
516
     * @param name of the property
517
     * @param value of the property
518
     */
519
    void setConfigurationProperty(const char * name, const char * value);
520

    
521
    /**
522
     * Clear configuration properties specific to the processor in use. 
523
     */
524
     void clearConfigurationProperties();
525

    
526

    
527
    /**
528
     * Get the Saxon version
529
     * @return char array
530
     */
531
    const char * version();
532

    
533
/*
534
     * Add a native method.
535
     * @param name of the native method
536
     * @param signature of the native method
537
     * @param fnPtr Pointer to the native method
538
 */
539
void addNativeMethod(char *name, char* signature, void * fnPtr){
540

    
541
        JNINativeMethod method;
542
        method.name = name;
543
        method.signature = signature;
544
        method.fnPtr = fnPtr;
545

    
546
        nativeMethodVect.push_back(method);
547

    
548
        
549

    
550
}
551

    
552
/*
553
     * Register several native methods for one class.
554
     * @param libName name of the library which contains the function(s). Loads the library
555
     * @param gMethods Register native methods. Default is NULL, also NULL allowed in which cause assumption is made the user has added native methods using the method addNativeMethod .
556
 * @return bool success of registered native method
557
 */
558
bool registerCPPFunction(char * libName, JNINativeMethod * gMethods=NULL){
559
        if(libName != NULL) {
560
                setConfigurationProperty("extc", libName);
561
                        
562
        }
563

    
564
        if(gMethods == NULL && nativeMethodVect.size()==0) {
565
        return false;
566
        } else {
567
                if(gMethods == NULL) {
568
                        //copy vector to gMethods
569
                        gMethods = new JNINativeMethod[nativeMethodVect.size()];
570
                } 
571
                return registerNativeMethods(sxn_environ->env, "com/saxonica/functions/extfn/CppCall$PhpFunctionCall",
572
    gMethods, sizeof(gMethods) / sizeof(gMethods[0]));
573
        
574

    
575
        }
576
        return false;
577
}
578

    
579
/*
580
 * Register several native methods for one class.
581
 * @return bool success of registered native method
582
 */
583
static bool registerNativeMethods(JNIEnv* env, const char* className,
584
    JNINativeMethod* gMethods, int numMethods)
585
{
586
    jclass clazz;
587
    clazz = env->FindClass(className);
588
    if (clazz == NULL) {
589
       // std::cerr<<"Native registration unable to find class "<< className<<std::endl;
590
        return false;
591
    }
592
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
593
       // std::cerr<<"RegisterNatives failed for "<< className<<std::endl;
594
        return false;
595
    }
596
    return true;
597
}
598

    
599
        /* TODO: Remove use of this method.*/
600
        const char* checkException(jobject cpp);
601

    
602
        /* Internal use*/
603
        void checkAndCreateException(jclass cppClass);
604

    
605

    
606

    
607
//        XPathEngine
608
//        XQueryEngine
609
//        SchemaManager
610

    
611
   // static JNIEnv *env;
612
    static int jvmCreatedCPP;
613
    static sxnc_environment * sxn_environ;
614
    static int refCount;
615
    std::string cwd; /*!< current working directory */
616
    jobject proc; /*!< Java Processor object */
617
    
618
    /*static JavaVM *jvm;*/
619
    
620
protected:
621
        jclass xdmAtomicClass;
622
        jclass  versionClass;
623
        jclass  procClass;
624
        jclass  saxonCAPIClass;
625
        std::string cwdV; /*!< current working directory */
626
        //std::string resources_dir; /*!< current Saxon resources directory */
627
        char * versionStr;
628
        std::map<std::string,XdmValue*> parameters; /*!< map of parameters used for the transformation as (string, value) pairs */
629
        std::map<std::string,std::string> configProperties; /*!< map of properties used for the transformation as (string, string) pairs */         
630
        bool licensei; /*!< indicates whether the Processor requires a Saxon that needs a license file (i.e. Saxon-EE) other a Saxon-HE Processor is created  */
631
        bool closed;
632
        SaxonApiException* exception; /*!< Pointer to any potential exception thrown */
633

    
634
        JNINativeMethod * nativeMethods;
635
        std::vector<JNINativeMethod> nativeMethodVect; /*!< Vector of native methods defined by user */
636

    
637
private:
638

    
639
        void applyConfigurationProperties();
640
};
641

    
642
//===============================================================================================
643

    
644
#endif /* SAXON_PROCESSOR_H */
(1-1/4)