Project

Profile

Help

How to connect?
Download (19 KB) Statistics
| Branch: | Tag: | Revision:

he / latest9.9 / hec / Saxon.C.API / XQueryProcessor.cpp @ 1117bc69

1
#include "XQueryProcessor.h"
2
#include "XdmValue.h"
3
#include "XdmItem.h"
4
#include "XdmNode.h"
5
#include "XdmAtomicValue.h"
6

    
7
    XQueryProcessor::XQueryProcessor() {
8
        SaxonProcessor *p = new SaxonProcessor(false);
9
        XQueryProcessor(p, "");
10
     }
11

    
12
    XQueryProcessor::XQueryProcessor(SaxonProcessor *p, std::string curr) {
13
    proc = p;
14

    
15
  
16
     cppClass = lookForClass(SaxonProcessor::sxn_environ->env, "net/sf/saxon/option/cpp/XQueryEngine");
17

    
18

    
19
    cppXQ = createSaxonProcessor2 (SaxonProcessor::sxn_environ->env, cppClass, "(Lnet/sf/saxon/s9api/Processor;)V", proc->proc);
20
    
21
#ifdef DEBUG
22
        jmethodID debugMID = SaxonProcessor::sxn_environ->env->GetStaticMethodID(cppClass, "setDebugMode", "(Z)V");
23
        SaxonProcessor::sxn_environ->env->CallStaticVoidMethod(cppClass, debugMID, (jboolean)true);
24
#endif
25

    
26
    proc->exception = NULL;
27
   // outputfile1 = "";
28
        if(!(proc->cwd.empty()) && curr.empty()){
29
                cwdXQ = proc->cwd;
30
        } else {
31
                cwdXQ = curr;
32
        }
33
}
34

    
35

    
36

    
37
XQueryProcessor::XQueryProcessor(const XQueryProcessor &other) {
38
    cwdXQ = other.cwdXQ;
39
        proc = other.proc; //TODO check thread safety
40
        jclass  cppClass;
41
        jobject cppXQ;
42
        std::map<std::string,XdmValue*> parameters; /*!< map of parameters used for the transformation as (string, value) pairs */
43
        std::map<std::string,std::string> properties;
44

    
45

    
46
}
47

    
48

    
49
XQueryProcessor::XQueryProcessor * clone() {
50
      XQueryProcessor * proc = new XQueryProcessor(*this);
51
      return proc;
52

    
53

    
54
}
55

    
56

    
57
std::map<std::string,XdmValue*>& XQueryProcessor::getParameters(){
58
        std::map<std::string,XdmValue*>& ptr = parameters;
59
        return ptr;
60
}
61

    
62
std::map<std::string,std::string>& XQueryProcessor::getProperties(){
63
        std::map<std::string,std::string> &ptr = properties;
64
        return ptr;
65
}
66

    
67

    
68
    /**
69
     * Set the source document for the query
70
    */
71
    void XQueryProcessor::setContextItem(XdmItem * value){
72
            if(value != NULL){
73
         value->incrementRefCount();
74
              parameters["node"] = (XdmValue *)value;
75
            }
76
    }
77

    
78

    
79
     void XQueryProcessor::declareNamespace(const char *prefix, const char * uri){
80
        if (prefix == NULL || uri == NULL) {
81
                    return;
82
        }  else {
83
            //setProperty("ns-prefix", uri);
84
             int s = properties.size();
85
             std:string skey = std::string("ns-prefix:"+prefix);
86
             properties.insert(std::pair<std::string, std::string>(skey, std::string(uri)));
87

    
88
             if(s == properties.size()) {
89
                 std::map<std::string, std::string>::iterator it;
90
                 it = properties.find(skey);
91
                 if (it != properties.end()) {
92
                       properties.erase(skey);
93
                       properties[skey] = std::string(uri);
94
                 }
95
             }
96

    
97
        }
98
}
99

    
100

    
101
    /**
102
     * Set the source document for the query
103
    */
104
    void XQueryProcessor::setContextItemFromFile(const char * ifile){
105
        setProperty("s", ifile);
106
    }
107

    
108
    /**
109
     * Set the output file where the result is sent
110
    */
111
    void XQueryProcessor::setOutputFile(const char* ofile){
112
      // outputfile1 = std::string(ofile); 
113
       setProperty("o", ofile);
114
    }
115

    
116
    /**
117
     * Set a parameter value used in the query
118
     *
119
     * @param name  of the parameter, as a string
120
     * @param value of the query parameter, or null to clear a previously set value
121
     */
122
    void XQueryProcessor::setParameter(const char * name, XdmValue*value){
123
        if(value != NULL){
124
                value->incrementRefCount();
125
                int s = parameters.size();
126
                std::String skey = "param:"+std::string(name);
127
                parameters[skey] = value;
128
                if(s == parameters.size()) {
129
            std::map<std::string, XdmValue*>::iterator it;
130
            it = parameters.find(skey);
131
            if (it != parameters.end()) {
132
                XdmValue * valuei = it->second;
133
                valuei->decrementRefCount();
134
                if(valuei != NULL && valuei->getRefCount() < 1){
135
                    delete value;
136
                }
137
                parameters.erase(skey);
138
                parameters[skey] = value;
139
            }
140
                }
141
        } 
142
    }
143

    
144

    
145
    /**
146
     * Remove a parameter (name, value) pair
147
     *
148
     * @param namespacei currently not used
149
     * @param name  of the parameter
150
     * @return bool - outcome of the romoval
151
     */
152
    bool XQueryProcessor::removeParameter(const char * name){
153
        return (bool)(parameters.erase("param:"+std::string(name)));
154
    }
155
    /**
156
     * Set a property.
157
     *
158
     * @param name of the property
159
     * @param value of the property
160
     */
161
    void XQueryProcessor::setProperty(const char * name, const char * value){
162
#ifdef DEBUG        
163
        if(value == NULL) {
164
                std::cerr<<"XQueryProc setProperty is NULL"<<std::endl;
165
        }
166
#endif
167
            if(name != NULL) {
168
                int s = properties.size();
169
                    std:string skey = std::string(name);
170
                    properties.insert(std::pair<std::string, std::string>(skey, std::string((value == NULL ? "" : value))));
171

    
172
                    if(s == properties.size()) {
173
                std::map<std::string, std::string>::iterator it;
174
                it = properties.find(skey);
175
                if (it != properties.end()) {
176
                    properties.erase(skey);
177
                    properties[skey] = std::string((value == NULL ? "" : value));
178
                }
179
                    }
180
            }
181

    
182

    
183

    
184
    }
185

    
186
    void XQueryProcessor::clearParameters(bool delVal){
187
        if(delVal){
188
                       for(std::map<std::string, XdmValue*>::iterator itr = parameters.begin(); itr != parameters.end(); itr++){
189
                        XdmValue * value = itr->second;
190
                        value->decrementRefCount();
191
#ifdef DEBUG
192
                        std::cerr<<"XQueryProc.clearParameter() - XdmValue refCount="<<value->getRefCount()<<std::endl;
193
#endif
194
                        if(value != NULL && value->getRefCount() < 1){                
195
                                delete value;
196
                        }
197
                }
198
                
199
        } else {
200

    
201
                for(std::map<std::string, XdmValue*>::iterator itr = parameters.begin(); itr != parameters.end(); itr++){
202
                        XdmValue * value = itr->second;
203
                        value->decrementRefCount();
204

    
205
                }
206
        }
207

    
208
        parameters.clear();
209
    }
210

    
211
   void XQueryProcessor::clearProperties(){
212
        properties.clear();
213
        //outputfile1.clear();
214
   }
215

    
216

    
217
   void XQueryProcessor::setcwd(const char* dir){
218
    cwdXQ = std::string(dir);
219
   }
220

    
221
    void XQueryProcessor::setQueryBaseURI(const char * baseURI){
222
        setProperty("base", baseURI);
223
    }
224

    
225

    
226
    void XQueryProcessor::setUpdating(bool updating){
227
     
228
            jmethodID mID =
229
                    (jmethodID) SaxonProcessor::sxn_environ->env->GetMethodID(cppClass, "setUpdating",
230
                                    "(Z)V");
231
            if (!mID) {
232
            std::cerr << "Error: Saxonc library." << "setUpdating" << " not found\n"
233
                            << std::endl;
234

    
235
            } else {
236

    
237
                            SaxonProcessor::sxn_environ->env->CallObjectMethod(cppXQ, mID,
238
                                            (jboolean)updating);
239
            }
240

    
241
    }
242

    
243
    void XQueryProcessor::executeQueryToFile(const char * infilename, const char * ofilename, const char * query){
244
        setProperty("resources", proc->getResourcesDirectory());  
245

    
246
        jmethodID mID = (jmethodID)SaxonProcessor::sxn_environ->env->GetMethodID (cppClass,"executeQueryToFile", "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/Object;)V");
247
         if (!mID) {
248
        std::cerr<<"Error: MyClassInDll."<<"executeQueryToFile"<<" not found\n"<<std::endl;
249
    } else {
250
        jobjectArray stringArray = NULL;
251
        jobjectArray objectArray = NULL;
252

    
253
        int size = parameters.size() + properties.size();
254
        if(query!= NULL) size++;
255
        if(infilename!= NULL) size++;        
256
        if(size >0) {
257

    
258
           int i=0;
259
           jclass objectClass = lookForClass(SaxonProcessor::sxn_environ->env, "java/lang/Object");
260
           jclass stringClass = lookForClass(SaxonProcessor::sxn_environ->env, "java/lang/String");
261
           objectArray = SaxonProcessor::sxn_environ->env->NewObjectArray( (jint)size, objectClass, 0 );
262
           stringArray = SaxonProcessor::sxn_environ->env->NewObjectArray( (jint)size, stringClass, 0 );
263
           if(query!= NULL) {
264
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF("qs") );
265
                  SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF(query));
266
             i++;        
267
           }
268
           if(infilename!= NULL) {
269
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF("s") );
270
                  SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF(infilename));
271
             i++;        
272
           }
273
           for(std::map<std::string, XdmValue* >::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter, i++) {
274
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF( (iter->first).c_str() ) );
275
                bool checkCast = SaxonProcessor::sxn_environ->env->IsInstanceOf((iter->second)->getUnderlyingValue(), lookForClass(SaxonProcessor::sxn_environ->env, "net/sf/saxon/option/cpp/XdmValueForCpp") );
276

    
277
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, (jobject)((iter->second)->getUnderlyingValue()) );
278
           }
279
             for(std::map<std::string, std::string >::iterator iter=properties.begin(); iter!=properties.end(); ++iter, i++) {
280
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF( (iter->first).c_str()  ));
281
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, (jobject)(SaxonProcessor::sxn_environ->env->NewStringUTF((iter->second).c_str())) );
282
           }
283
        }
284

    
285
         SaxonProcessor::sxn_environ->env->CallObjectMethod(cppXQ, mID, SaxonProcessor::sxn_environ->env->NewStringUTF(cwdXQ.c_str()), SaxonProcessor::sxn_environ->env->NewStringUTF(ofilename), stringArray, objectArray );
286
          SaxonProcessor::sxn_environ->env->DeleteLocalRef(objectArray);
287
          SaxonProcessor::sxn_environ->env->DeleteLocalRef(stringArray);
288

    
289
        proc->checkAndCreateException(cppClass);
290
         
291
  }
292

    
293

    
294
   }
295

    
296

    
297
    XdmValue * XQueryProcessor::executeQueryToValue(const char * infilename, const char * query){
298
        setProperty("resources", proc->getResourcesDirectory()); 
299
 jmethodID mID = (jmethodID)SaxonProcessor::sxn_environ->env->GetMethodID (cppClass,"executeQueryToValue", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/Object;)Lnet/sf/saxon/s9api/XdmValue;");
300
 if (!mID) {
301
        std::cerr<<"Error: MyClassInDll."<<"executeQueryToValue"<<" not found\n"<<std::endl;
302
    } else {
303
        jobjectArray stringArray = NULL;
304
        jobjectArray objectArray = NULL;
305

    
306
        int size = parameters.size() + properties.size();
307
        if(query!= NULL) size++;
308
        if(infilename!= NULL) size++;
309
        if(size >0) {
310
           int i=0;
311
           jclass objectClass = lookForClass(SaxonProcessor::sxn_environ->env, "java/lang/Object");
312
           jclass stringClass = lookForClass(SaxonProcessor::sxn_environ->env, "java/lang/String");
313
           objectArray = SaxonProcessor::sxn_environ->env->NewObjectArray( (jint)size, objectClass, 0 );
314
           stringArray = SaxonProcessor::sxn_environ->env->NewObjectArray( (jint)size, stringClass, 0 );
315

    
316
           if(query!= NULL) {
317
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF("qs") );
318
                  SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF(query));
319
             i++;        
320
           }
321
           if(infilename!= NULL) {
322
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF("s") );
323
                  SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF(infilename));
324
             i++;        
325
           }
326
           for(std::map<std::string, XdmValue* >::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter, i++) {
327
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF( (iter->first).c_str() ) );
328
                bool checkCast = SaxonProcessor::sxn_environ->env->IsInstanceOf((iter->second)->getUnderlyingValue(), lookForClass(SaxonProcessor::sxn_environ->env, "net/sf/saxon/option/cpp/XdmValueForCpp") );
329

    
330
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, (jobject)((iter->second)->getUnderlyingValue()) );
331
           }
332
             for(std::map<std::string, std::string >::iterator iter=properties.begin(); iter!=properties.end(); ++iter, i++) {
333
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF( (iter->first).c_str()  ));
334
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, (jobject)(SaxonProcessor::sxn_environ->env->NewStringUTF((iter->second).c_str())) );
335
           }
336
        }
337

    
338
          jobject result = (jobject)(SaxonProcessor::sxn_environ->env->CallObjectMethod(cppXQ, mID, SaxonProcessor::sxn_environ->env->NewStringUTF(cwdXQ.c_str()), stringArray, objectArray ));
339
          SaxonProcessor::sxn_environ->env->DeleteLocalRef(objectArray);
340
          SaxonProcessor::sxn_environ->env->DeleteLocalRef(stringArray);
341
    if(result) {
342
                jclass atomicValueClass = lookForClass(SaxonProcessor::sxn_environ->env, "net/sf/saxon/s9api/XdmAtomicValue");
343
                jclass nodeClass = lookForClass(SaxonProcessor::sxn_environ->env, "net/sf/saxon/s9api/XdmNode");
344
                jclass functionItemClass = lookForClass(SaxonProcessor::sxn_environ->env, "net/sf/saxon/s9api/XdmFunctionItem");
345
                XdmValue * value = NULL;
346
                XdmItem * xdmItem = NULL;
347

    
348
                if(SaxonProcessor::sxn_environ->env->IsInstanceOf(result, atomicValueClass)           == JNI_TRUE) {
349
                                xdmItem = new XdmAtomicValue(result);
350
                                xdmItem->setProcessor(proc);
351
                                SaxonProcessor::sxn_environ->env->DeleteLocalRef(result);
352
                                return xdmItem;
353

    
354
                        } else if(SaxonProcessor::sxn_environ->env->IsInstanceOf(result, nodeClass)           == JNI_TRUE) {
355
                                xdmItem = new XdmNode(result);
356
                                xdmItem->setProcessor(proc);
357
                                SaxonProcessor::sxn_environ->env->DeleteLocalRef(result);
358
                                return xdmItem;
359
                        
360
                        } else if (SaxonProcessor::sxn_environ->env->IsInstanceOf(result, functionItemClass)           == JNI_TRUE) {
361
                /*xdmItem =  new XdmFunctionItem(result);
362
                xdmItem->setProcessor(proc);
363
                SaxonProcessor::sxn_environ->env->DeleteLocalRef(result);*/
364
                return NULL;// xdmItem;
365
                        } else {
366
                                value = new XdmValue(result, true);
367
                                value->setProcessor(proc);
368
                                for(int z=0;z<value->size();z++) {
369
                                        value->itemAt(z)->setProcessor(proc);
370
                                }
371
                                return value;
372
                        }
373
                        value = new XdmValue();
374
                        value->setProcessor(proc);
375
                        xdmItem->setProcessor(proc);
376
                        value->addXdmItem(xdmItem);
377
                        return value;
378
     } else {
379
           
380
        proc->checkAndCreateException(cppClass);                
381
             } 
382
  }
383
  return NULL;
384

    
385
}
386

    
387
    const char * XQueryProcessor::executeQueryToString(const char * infilename, const char * query){
388
        setProperty("resources", proc->getResourcesDirectory()); 
389
 jmethodID mID = (jmethodID)SaxonProcessor::sxn_environ->env->GetMethodID (cppClass,"executeQueryToString", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;");
390
 if (!mID) {
391
        std::cerr<<"Error: MyClassInDll."<<"executeQueryToString"<<" not found\n"<<std::endl;
392
    } else {
393
        jobjectArray stringArray = NULL;
394
        jobjectArray objectArray = NULL;
395

    
396
        int size = parameters.size() + properties.size();
397
        if(query!= NULL) size++;
398
        if(infilename!= NULL) size++;
399
        if(size >0) {
400
           int i=0;
401
           jclass objectClass = lookForClass(SaxonProcessor::sxn_environ->env, "java/lang/Object");
402
           jclass stringClass = lookForClass(SaxonProcessor::sxn_environ->env, "java/lang/String");
403
           objectArray = SaxonProcessor::sxn_environ->env->NewObjectArray( (jint)size, objectClass, 0 );
404
           stringArray = SaxonProcessor::sxn_environ->env->NewObjectArray( (jint)size, stringClass, 0 );
405

    
406
           if(query!= NULL) {
407
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF("qs") );
408
                  SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF(query));
409
             i++;        
410
           }
411
           if(infilename!= NULL) {
412
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF("s") );
413
                  SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF(infilename));
414
             i++;        
415
           }
416
           for(std::map<std::string, XdmValue* >::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter, i++) {
417
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF( (iter->first).c_str() ) );
418
                bool checkCast = SaxonProcessor::sxn_environ->env->IsInstanceOf((iter->second)->getUnderlyingValue(), lookForClass(SaxonProcessor::sxn_environ->env, "net/sf/saxon/option/cpp/XdmValueForCpp") );
419
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, (jobject)((iter->second)->getUnderlyingValue()) );
420
           }
421
             for(std::map<std::string, std::string >::iterator iter=properties.begin(); iter!=properties.end(); ++iter, i++) {
422
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( stringArray, i, SaxonProcessor::sxn_environ->env->NewStringUTF( (iter->first).c_str()  ));
423
             SaxonProcessor::sxn_environ->env->SetObjectArrayElement( objectArray, i, (jobject)(SaxonProcessor::sxn_environ->env->NewStringUTF((iter->second).c_str())) );
424
           }
425
        }
426

    
427
          jstring result = (jstring)(SaxonProcessor::sxn_environ->env->CallObjectMethod(cppXQ, mID, SaxonProcessor::sxn_environ->env->NewStringUTF(cwdXQ.c_str()), stringArray, objectArray ));
428
          SaxonProcessor::sxn_environ->env->DeleteLocalRef(objectArray);
429
          SaxonProcessor::sxn_environ->env->DeleteLocalRef(stringArray);
430

    
431
          if(result) {
432
             const char * str = SaxonProcessor::sxn_environ->env->GetStringUTFChars(result, NULL);
433
            //return "result should be ok";            
434
            return str;
435
           } else {
436
                proc->checkAndCreateException(cppClass);
437
                           
438
                     }
439
  }
440
  return NULL;
441

    
442

    
443
    }
444

    
445

    
446
    const char * XQueryProcessor::runQueryToString(){
447
        return executeQueryToString(NULL, NULL);        
448

    
449
    }
450

    
451

    
452
    XdmValue * XQueryProcessor::runQueryToValue(){
453
        return executeQueryToValue(NULL, NULL);
454
   }
455

    
456
    void XQueryProcessor::runQueryToFile(){
457
        executeQueryToFile(NULL, NULL, NULL);
458
   }
459

    
460
    void XQueryProcessor::setQueryFile(const char * ofile){
461
           //outputfile1 = std::string(ofile); 
462
           setProperty("q", ofile);
463
    }
464

    
465
   void XQueryProcessor::setQueryContent(const char* content){
466
          // outputfile1 = std::string(content); 
467
           setProperty("qs", content);
468
  }
469

    
470

    
471

    
472
void XQueryProcessor::exceptionClear(){
473
        if(proc->exception != NULL) {
474
                delete proc->exception;
475
                proc->exception = NULL;        
476
                SaxonProcessor::sxn_environ->env->ExceptionClear();
477
        }
478

    
479
   
480
 
481
}
482

    
483
bool XQueryProcessor::exceptionOccurred(){
484
        return proc->exceptionOccurred();
485

    
486
}
487

    
488

    
489
const char * XQueryProcessor::getErrorCode(int i) {
490
        if(proc->exception == NULL) {return NULL;}
491
        return proc->exception->getErrorCode(i);
492
}
493

    
494
const char * XQueryProcessor::getErrorMessage(int i ){
495
        if(proc->exception == NULL) {return NULL;}
496
        return proc->exception->getErrorMessage(i);
497
}
498

    
499
const char* XQueryProcessor::checkException(){
500
        /*if(proc->exception == NULL) {
501
                proc->exception = proc->checkForException(SaxonProcessor::sxn_environ->env, cppClass, cppXQ);
502
        }
503
        return proc->exception;*/
504
        return proc->checkException(cppXQ);
505
}
506

    
507

    
508

    
509
int XQueryProcessor::exceptionCount(){
510
        if(proc->exception != NULL){
511
                return proc->exception->count();
512
        }
513
        return 0;
514
}
(19-19/50)