Project

Profile

Help

Bug #4274 » SaxonProcessor.h

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

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

#ifndef SAXON_PROCESSOR_H
#define SAXON_PROCESSOR_H
#if defined __linux__ || defined __APPLE__
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>

#define HANDLE void*
#define LoadLibrary(x) dlopen(x, RTLD_LAZY)
#define GetProcAddress(x,y) dlsym(x,y)
#else
#include <windows.h>
#endif

//#define DEBUG //remove
#define CVERSION "1.1.2"
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <vector>
#include <stdexcept> // std::logic_error

#include "SaxonCGlue.h"
#include "SaxonCXPath.h"
#include "XsltProcessor.h"
#include "XQueryProcessor.h"
#include "XPathProcessor.h"
#include "SchemaValidator.h"
//#include "com_saxonica_functions_extfn_PhpCall.h"
//#include "com_saxonica_functions_extfn_PhpCall_PhpFunctionCall.h"

class XsltProcessor;
class XQueryProcessor;
class XPathProcessor;
class SchemaValidator;
class XdmValue;
class XdmNode;
class XdmItem;
class XdmAtomicValue;



// The Saxon XSLT interface class

//std::mutex mtx;
/*! <code>MyException</code>. This struct captures details of the Java exception thrown from Saxon s9api API (Java).
* <p/>
*/
typedef struct {
std::string errorCode;
std::string errorMessage;
int linenumber;
bool isType;
bool isStatic;
bool isGlobal;
}MyException;




/*! <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
* <p/>
*/
class SaxonApiException {

public:

/**
* A default Constructor. Create a SaxonApiException
*/
SaxonApiException(){
exceptions = std::vector<MyException>(0);
}

/**
* A Copy constructor. Create a SaxonApiException
* @param ex - The exception object to copy
*/
SaxonApiException(const SaxonApiException &ex){
exceptions = ex.exceptions;
}

/**
* A constructor. Create a SaxonApiException
* @param ec - The error code of the underlying exception thrown, if known
* @param exM - The error message of the underlying exception thrown, if known
*/
SaxonApiException(const char * ec, const char * exM){
exceptions = std::vector<MyException>(0);
MyException newEx;
if(ec != NULL){
newEx.errorCode = std::string(ec);
} else {
newEx.errorCode ="Unknown";
}
if(exM != NULL){
newEx.errorMessage = std::string(exM);
} else {
newEx.errorMessage="Unkown";
}
newEx.isType = false;
newEx.isStatic = false;
newEx.isGlobal = false;
newEx.linenumber = 0;
exceptions.push_back(newEx);
}

/**
* A constructor. Create a SaxonApiException
* @param ec - The error code of the underlying exception thrown, if known
* @param exM - The error message of the underlying exception thrown, if known
* @param typeErr - Flag indicating if the error is a type error
* @param stat - Flag indicating a static error
* @param glob - Flag for if the error is global
* @param l - Line number information of where the error occurred
*/
SaxonApiException(const char * ec, const char * exM, bool typeErr, bool stat, bool glob, int l){
exceptions = std::vector<MyException>(20);
MyException newEx;
if(ec != NULL){
newEx.errorCode = std::string(ec);
} else {
newEx.errorCode ="ERROR1";
}
if(exM != NULL){
newEx.errorMessage = std::string(exM);
} else {
newEx.errorMessage="ERROR2";
}
newEx.isType = typeErr;
newEx.isStatic = stat;
newEx.isGlobal = glob;
newEx.linenumber = l;
exceptions.push_back(newEx);
}

/**
* Creates a SaxonApiException and adds it to a vector of exceptions
* @param ec - The error code of the underlying exception thrown, if known
* @param exM - The error message of the underlying exception thrown, if known
* @param typeErr - Flag indicating if the error is a type error
* @param stat - Flag indicating a static error
* @param glob - Flag for if the error is global
* @param l - Line number information of where the error occurred
*/
void add(const char * ec, const char * exM, bool typeErr, bool stat, bool glob, int l){
MyException newEx;
if(ec != NULL){
newEx.errorCode = std::string(ec);
} else {
newEx.errorCode ="ERROR1";
}
if(exM != NULL){
newEx.errorMessage = std::string(exM);
} else {
newEx.errorMessage="ERROR2";
}
newEx.isType = typeErr;
newEx.isStatic = stat;
newEx.isGlobal = glob;
newEx.linenumber = l;
exceptions.push_back(newEx);
}


/**
* A destructor.
*/
~SaxonApiException(){
clear();
}

/**
* Get the error code associated with the ith exception in the vector, if there is one
* @param i - ith exception in the vector
* @return the associated error code, or null if no error code is available
*/
const char * getErrorCode(int i){
if((size_t)i <= exceptions.size()){
return exceptions[i].errorCode.c_str();
}
return NULL;
}


int getLineNumber(int i){
if((size_t)i <= exceptions.size()){
return exceptions[i].linenumber;
}
return 0;
}

bool isGlobalError(int i){
if((size_t)i <= exceptions.size()){
return exceptions[i].isGlobal;
}
return false;
}

bool isStaticError(int i){
if((size_t)i <= exceptions.size()){
return exceptions[i].isStatic;
}
return false;
}

bool isTypeError(int i){
if((size_t) i <= exceptions.size()){
return exceptions[i].isType;
}
return false;
}

void clear(){
for(size_t i =0; i< exceptions.size();i++) {
exceptions[i].errorCode.clear();
exceptions[i].errorMessage.clear();
}
exceptions.clear();
}

int count(){
return (int)exceptions.size();
}

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

const char * getErrorMessages(){
std::string result;
for(size_t i = 0;i<exceptions.size();i++) {
result += getErrorMessage(i);
}
if(result.empty()) { return NULL;}
return result.c_str();
}

/**
* Returns the ith Exception added, if there is one
* @param i - ith exception in the vector
* @return MyException
*/
MyException getException(int i){
if((size_t)i <= exceptions.size()){
return exceptions[i];
}
throw 0;
}


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








//==========================================



/*! An <code>SaxonProcessor</code> acts as a factory for generating XQuery, XPath, Schema and XSLT compilers
* In this alpha release only the XSLT compiler is available
* <p/>
*/
class SaxonProcessor {
friend class XsltProcessor;
friend class XQueryProcessor;
friend class SchemaValidator;
friend class XPathProcessor;
friend class XdmValue;
friend class XdmAtomicValue;
public:

//! A default constructor.
/*!
* Create Saxon Processor.
*/

SaxonProcessor();

//! constructor based upon a Saxon configuration file.
/*!
* Create Saxon Processor.
*/

SaxonProcessor(const char * configFile);


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

SaxonProcessor& operator=( const SaxonProcessor& other );

/*!

* Destructor
*/
~SaxonProcessor();
/*!

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

/*!
* Create an XQueryProcessor. An XQueryProcessor is used to compile XQuery queries.
*
* @return a newly created XQueryProcessor
*/
XQueryProcessor * newXQueryProcessor();


/*!
* Create an XPathProcessor. An XPathProcessor is used to compile XPath expressions.
*
* @return a newly created XPathProcessor
*/
XPathProcessor * newXPathProcessor();

/*!
* Create a SchemaValidator which can be used to validate instance documents against the schema held by this
* SchemaManager
*
* @return a new SchemaValidator
*/
SchemaValidator * newSchemaValidator();


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

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

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


/*!
* Factory method (for convenience in compiled bytecode)
*
* @param d the value of the double
* @return a new XdmAtomicValue
*/
XdmAtomicValue * makeDoubleValue(double d);

/*!
* Factory method (for convenience in compiled bytecode)
*
* @param f the value of the foat
* @return a new XdmAtomicValue
*/
XdmAtomicValue * makeFloatValue(float);

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

/*!
* Factory method: makes a XdmAtomicValue representing a boolean Value
*
* @param b true or false, to determine which boolean value is
* required
* @return the XdmAtomicValue requested
*/
XdmAtomicValue * makeBooleanValue(bool b);

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

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

/**
* Get the string representation of the XdmValue.
* @return char array
*/
const char * getStringValue(XdmItem * item);

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

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

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

int getNodeKind(jobject);

bool isSchemaAware();

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

/**

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

/**
* Checks for pending exceptions and creates a SaxonApiException object, which handles one or more local exceptions objects
* @param env
* @param callingClass
* @param callingObject
* @return SaxonApiException
*/
SaxonApiException * checkForExceptionCPP(JNIEnv* env, jclass callingClass, jobject callingObject);

SaxonApiException * getException();

/*
* Clean up and destroy Java VM to release memory used.
*/
static void release();

/**
* set the current working directory
*/
void setcwd(const char* cwd);


/**
* set saxon resources directory
*/
void setResourcesDirectory(const char* dir);

/**
* set catalog to be used in Saxon
*/
void setCatalog(const char* catalogFile, bool isTracing);

/**
* get saxon resources directory
*/
const char * getResourcesDirectory();

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

/**
* Clear configuration properties specific to the processor in use.
*/
void clearConfigurationProperties();


/**
* Get the Saxon version
* @return char array
*/
const char * version();

/*
* Add a native method.
* @param name of the native method
* @param signature of the native method
* @param fnPtr Pointer to the native method
*/
void addNativeMethod(char *name, char* signature, void * fnPtr){

JNINativeMethod method;
method.name = name;
method.signature = signature;
method.fnPtr = fnPtr;

nativeMethodVect.push_back(method);


}

/*
* Register several native methods for one class.
* @param libName name of the library which contains the function(s). Loads the library
* @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 .
* @return bool success of registered native method
*/
bool registerCPPFunction(char * libName, JNINativeMethod * gMethods=NULL){
if(libName != NULL) {
setConfigurationProperty("extc", libName);
}

if(gMethods == NULL && nativeMethodVect.size()==0) {
return false;
} else {
if(gMethods == NULL) {
//copy vector to gMethods
gMethods = new JNINativeMethod[nativeMethodVect.size()];
}
return registerNativeMethods(sxn_environ->env, "com/saxonica/functions/extfn/CppCall$PhpFunctionCall",
gMethods, sizeof(gMethods) / sizeof(gMethods[0]));

}
return false;
}

/*
* Register several native methods for one class.
* @return bool success of registered native method
*/
static bool registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = env->FindClass(className);
if (clazz == NULL) {
// std::cerr<<"Native registration unable to find class "<< className<<std::endl;
return false;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
// std::cerr<<"RegisterNatives failed for "<< className<<std::endl;
return false;
}
return true;
}

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

/* Internal use*/
void checkAndCreateException(jclass cppClass);



// XPathEngine
// XQueryEngine
// SchemaManager

// static JNIEnv *env;
static int jvmCreatedCPP;
static sxnc_environment * sxn_environ;
static int refCount;
std::string cwd; /*!< current working directory */
jobject proc; /*!< Java Processor object */
/*static JavaVM *jvm;*/
protected:
jclass xdmAtomicClass;
jclass versionClass;
jclass procClass;
jclass saxonCAPIClass;
std::string cwdV; /*!< current working directory */
//std::string resources_dir; /*!< current Saxon resources directory */
char * versionStr;
std::map<std::string,XdmValue*> parameters; /*!< map of parameters used for the transformation as (string, value) pairs */
std::map<std::string,std::string> configProperties; /*!< map of properties used for the transformation as (string, string) pairs */
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 */
bool closed;
SaxonApiException* exception; /*!< Pointer to any potential exception thrown */

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

private:

void applyConfigurationProperties();
};

//===============================================================================================

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