2
* Copyright 2006-2012 The FLWOR Foundation.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
16
package org.zorbaxquery.api.xqj;
18
import java.io.InputStream;
19
import java.io.Reader;
20
import java.io.StringWriter;
21
import java.io.Writer;
22
import java.nio.CharBuffer;
23
import java.util.TimeZone;
24
import javax.xml.namespace.QName;
25
import javax.xml.stream.XMLStreamReader;
26
import javax.xml.transform.Source;
27
import javax.xml.xquery.XQException;
28
import javax.xml.xquery.XQItem;
29
import javax.xml.xquery.XQItemType;
30
import javax.xml.xquery.XQResultSequence;
31
import javax.xml.xquery.XQSequence;
32
import javax.xml.xquery.XQSequenceType;
33
import javax.xml.xquery.XQStaticContext;
34
import org.w3c.dom.Node;
35
import org.zorbaxquery.api.XQuery;
36
import org.zorbaxquery.api.Zorba;
37
import javax.xml.xquery.XQConnection;
38
import java.util.Collection;
39
import java.util.ArrayList;
40
import javax.xml.stream.XMLOutputFactory;
41
import javax.xml.stream.XMLStreamWriter;
42
import javax.xml.transform.OutputKeys;
43
import javax.xml.transform.Transformer;
44
import javax.xml.transform.TransformerException;
45
import javax.xml.transform.TransformerFactory;
46
import javax.xml.transform.dom.DOMSource;
47
import javax.xml.transform.sax.SAXSource;
48
import javax.xml.transform.stax.StAXResult;
49
import javax.xml.transform.stax.StAXSource;
50
import javax.xml.transform.stream.StreamResult;
51
import javax.xml.transform.stream.StreamSource;
52
import org.zorbaxquery.api.DynamicContext;
53
import org.zorbaxquery.api.Item;
54
import org.zorbaxquery.api.Iterator;
55
import org.zorbaxquery.api.XmlDataManager;
57
public class XQPreparedExpression implements javax.xml.xquery.XQPreparedExpression {
60
private XQConnection connection;
61
private boolean closed;
62
private Collection<XQResultSequence> resultSequences = new ArrayList<XQResultSequence>();
63
private DynamicContext dynamicContext;
64
private XmlDataManager xmlDataManager;
65
private XQStaticContext staticContext;
66
private Collection<String> itemsBounded = new ArrayList<String>();
69
public XQPreparedExpression (XQConnection conn, String string) throws XQException {
70
if (conn.isClosed()) {
71
throw new XQException ("Connection is closed");
75
Zorba zorba = ((org.zorbaxquery.api.xqj.XQConnection)connection).getZorbaInstance();
77
query = zorba.compileQuery(string);
78
dynamicContext = query.getDynamicContext();
79
xmlDataManager = ((org.zorbaxquery.api.xqj.XQConnection)connection).getZorbaInstance().getXmlDataManager();
80
} catch (Exception e) {
81
throw new XQException ("Error creating new Prepared expression with static context: " + e.getLocalizedMessage());
85
public XQPreparedExpression (XQConnection conn, String string, XQStaticContext sc) throws XQException {
86
if (conn.isClosed()) {
87
throw new XQException ("Connection is closed");
91
Zorba zorba = ((org.zorbaxquery.api.xqj.XQConnection)connection).getZorbaInstance();
93
query = zorba.compileQuery(string, ((org.zorbaxquery.api.xqj.XQStaticContext)sc).getZorbaStaticContext());
94
dynamicContext = query.getDynamicContext();
95
xmlDataManager = ((org.zorbaxquery.api.xqj.XQConnection)connection).getZorbaInstance().getXmlDataManager();
96
} catch (Exception e) {
97
throw new XQException ("Error creating new Prepared expression with static context: " + e.getLocalizedMessage());
103
public void cancel() throws XQException {
104
isClosedXQException();
109
public boolean isClosed() {
114
public void close() throws XQException {
116
for (XQResultSequence sequence: resultSequences) {
125
public XQResultSequence executeQuery() throws XQException {
126
isClosedXQException();
127
XQResultSequence result = null;
129
result = new org.zorbaxquery.api.xqj.XQResultSequence(connection, query, true);
130
} catch (Exception e) {
131
throw new XQException("Error executing query: " + e.getLocalizedMessage());
133
resultSequences.add(result);
138
public QName[] getAllExternalVariables() throws XQException {
139
isClosedXQException();
140
Collection<QName> result = new ArrayList<QName>();
141
Iterator iter = new Iterator();
142
query.getExternalVariables(iter);
144
Item item = new Item();
145
while (iter.next(item)) {
146
result.add(new QName(item.getNamespace(), item.getLocalName(), item.getPrefix()));
150
return result.toArray(new QName[0]);
154
private boolean isExternal(String varName) {
156
Iterator iter = new Iterator();
157
query.getExternalVariables(iter);
159
Item item = new Item();
160
while (iter.next(item)) {
161
if (item.getLocalName().equalsIgnoreCase(varName)) {
171
public QName[] getAllUnboundExternalVariables() throws XQException {
172
isClosedXQException();
174
Collection<QName> result = new ArrayList<QName>();
175
Iterator iter = new Iterator();
176
query.getExternalVariables(iter);
177
Item item = new Item();
179
while (iter.next(item)) {
180
boolean found = false;
181
for (String key: itemsBounded){
182
if (item.getLocalName().equalsIgnoreCase(key)) {
187
result.add(new QName(item.getNamespace(), item.getLocalName(), item.getPrefix()));
192
return result.toArray(new QName[0]);
196
public XQSequenceType getStaticResultType() throws XQException {
197
isClosedXQException();
198
XQSequenceType result = new org.zorbaxquery.api.xqj.XQSequenceType(new org.zorbaxquery.api.xqj.XQItemType(XQItemType.XQITEMKIND_ITEM), XQSequenceType.OCC_ZERO_OR_MORE );
203
public XQSequenceType getStaticVariableType(QName varName) throws XQException {
204
isClosedXQException();
205
isNullXQException(varName);
206
XQSequenceType result = null;
207
Iterator iter = new Iterator();
208
query.getExternalVariables(iter);
210
Item item = new Item();
211
while (iter.next(item)) {
212
if ( item.getLocalName().equalsIgnoreCase(varName.getLocalPart()) &&
213
item.getNamespace().equalsIgnoreCase(varName.getNamespaceURI()) &&
214
item.getPrefix().equalsIgnoreCase(varName.getPrefix()) ) {
215
if (item.getType().getStringValue().equals("xs:QName")) {
216
result = new org.zorbaxquery.api.xqj.XQSequenceType(new org.zorbaxquery.api.xqj.XQItemType(XQItemType.XQITEMKIND_ITEM), XQItemType.OCC_ZERO_OR_MORE);
218
result = new org.zorbaxquery.api.xqj.XQSequenceType(new org.zorbaxquery.api.xqj.XQItemType(item), XQItemType.OCC_ZERO_OR_MORE);
226
throw new XQException("Item not found");
232
public XQStaticContext getStaticContext() throws XQException {
233
isClosedXQException();
234
if (staticContext==null) {
235
staticContext = new org.zorbaxquery.api.xqj.XQStaticContext(query);
237
return staticContext;
241
public TimeZone getImplicitTimeZone() throws XQException {
242
isClosedXQException();
243
Integer timeZone = (dynamicContext.getImplicitTimezone()/60); // in minutes
244
TimeZone result = TimeZone.getTimeZone("GMT"+timeZone.toString());
249
public void bindAtomicValue(QName varName, String value, XQItemType type) throws XQException {
250
isClosedXQException();
251
isNullXQException(varName);
252
isNullXQException(value);
253
isNullXQException(type);
254
if (!isExternal(varName.getLocalPart())) {
255
throw new XQException ("The bound variable must be declared external in the prepared expression.");
257
if (type.getItemKind()!=XQItemType.XQITEMKIND_ATOMIC) {
258
throw new XQException ("Item kind is not atomic.");
261
XQItem xqitem = connection.createItemFromAtomicValue(value, type);
262
Item item = ((org.zorbaxquery.api.xqj.XQItem)xqitem).getZorbaItem();
263
dynamicContext.setVariable(varName.getLocalPart(), item);
264
itemsBounded.add(varName.getLocalPart());
265
} catch (Exception e) {
266
throw new XQException ("Error binding the atomic value: " + e.getLocalizedMessage());
272
public void bindString(QName varName, String value, XQItemType type) throws XQException {
273
isClosedXQException();
274
isNullXQException(varName);
275
if (!isExternal(varName.getLocalPart())) {
276
throw new XQException ("The bound variable must be declared external in the prepared expression.");
278
isNullXQException(value);
280
type = ((org.zorbaxquery.api.xqj.XQConnection)connection).createAtomicType(XQItemType.XQBASETYPE_STRING);
283
Iterator iter = new Iterator();
284
boolean found = false;
285
query.getExternalVariables(iter);
286
Item tmpItem = new Item();
288
while (iter.next(tmpItem)) {
289
if (tmpItem.getStringValue().equalsIgnoreCase(varName.getLocalPart())) {
290
XQItem item = connection.createItemFromString(value, type);
291
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
292
itemsBounded.add(varName.getLocalPart());
299
throw new XQException ("The variable: " + varName.getLocalPart() + " doesn't exist.");
301
} catch (XQException e) {
303
} catch (Exception e) {
304
throw new XQException ("Error binding string to the defined type: " + e.getLocalizedMessage());
310
public void bindDocument(QName varName, String value, String baseURI, XQItemType type) throws XQException {
311
isClosedXQException();
312
isNullXQException(varName);
313
if (!isExternal(varName.getLocalPart())) {
314
throw new XQException ("The bound variable must be declared external in the prepared expression.");
316
isNullXQException(value);
317
if (!((type==null) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_ELEMENT) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_SCHEMA_ELEMENT))) {
318
throw new XQException ("Invalid type.");
321
type = connection.createDocumentElementType(connection.createElementType(null, XQItemType.XQBASETYPE_UNTYPED));
323
if (!isExternal(varName.getLocalPart())) {
324
throw new XQException ("Variable not found in context.");
327
Iterator iter = xmlDataManager.parseXML(value);
328
Item item = new Item();
330
dynamicContext.setVariable(varName.getLocalPart(), item);
331
itemsBounded.add(varName.getLocalPart());
332
} catch (Exception e) {
333
throw new XQException ("Error binding document: " + e.getLocalizedMessage());
339
public void bindDocument(QName varName, Reader value, String baseURI, XQItemType type) throws XQException {
340
isClosedXQException();
341
isNullXQException(varName);
342
if (!isExternal(varName.getLocalPart())) {
343
throw new XQException ("The bound variable must be declared external in the prepared expression.");
345
isNullXQException(value);
346
if (!((type==null) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_ELEMENT) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_SCHEMA_ELEMENT))) {
347
throw new XQException ("Invalid type.");
350
type = connection.createDocumentElementType(connection.createElementType(null, XQItemType.XQBASETYPE_UNTYPED));
352
StringBuffer string = new StringBuffer();
353
CharBuffer buffer = CharBuffer.allocate(1024);
354
Writer writer = new StringWriter();
357
while( value.read(buffer) >= 0 ) {
359
writer.append(buffer);
363
} catch (Exception ex) {
364
throw new XQException("Error preparing expression" + ex.getLocalizedMessage());
367
bindDocument(varName, writer.toString(), baseURI, type);
371
public void bindDocument(QName varName, InputStream value, String baseURI, XQItemType type) throws XQException {
372
isClosedXQException();
373
isNullXQException(varName);
374
if (!isExternal(varName.getLocalPart())) {
375
throw new XQException ("The bound variable must be declared external in the prepared expression.");
377
isNullXQException(value);
378
if (!((type==null) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_ELEMENT) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_SCHEMA_ELEMENT))) {
379
throw new XQException ("Invalid type.");
382
type = connection.createDocumentElementType(connection.createElementType(null, XQItemType.XQBASETYPE_UNTYPED));
384
StringBuffer out = new StringBuffer ();
386
byte[] b = new byte[4096];
387
for (int n; (n = value.read(b)) != -1;) {
388
out.append(new String(b, 0, n));
390
} catch (Exception ex) {
391
throw new XQException("Error preparing expression" + ex.getLocalizedMessage());
393
bindDocument(varName, out.toString(), baseURI, type);
397
public void bindDocument(QName varName, XMLStreamReader value, XQItemType type) throws XQException {
398
isClosedXQException();
399
isNullXQException(varName);
400
if (!isExternal(varName.getLocalPart())) {
401
throw new XQException ("The bound variable must be declared external in the prepared expression.");
403
isNullXQException(value);
404
if (!((type==null) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_ELEMENT) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_SCHEMA_ELEMENT))) {
405
throw new XQException ("Invalid type.");
408
type = connection.createDocumentElementType(connection.createElementType(null, XQItemType.XQBASETYPE_UNTYPED));
411
TransformerFactory tf = TransformerFactory.newInstance();
415
XMLOutputFactory xof = XMLOutputFactory.newInstance();
416
Writer writer = new StringWriter();
418
XMLStreamWriter xmlStreamWriter = xof.createXMLStreamWriter(writer);
419
t = tf.newTransformer();
420
source = new StAXSource(value);
421
result = new StAXResult(xmlStreamWriter);
422
t.transform(source, result);
423
} catch (Exception ex) {
424
throw new XQException("Error transforming xml expression" + ex.getLocalizedMessage());
426
bindDocument(varName, writer.toString(), null, type);
429
private String nodeToString(Node node) {
430
StringWriter sw = new StringWriter();
432
Transformer t = TransformerFactory.newInstance().newTransformer();
433
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
434
t.transform(new DOMSource(node), new StreamResult(sw));
435
} catch (TransformerException te) {
436
System.out.println("nodeToString Transformer Exception" + te.getLocalizedMessage());
438
return sw.toString();
442
public void bindDocument(QName varName, Source value, XQItemType type) throws XQException {
443
isClosedXQException();
444
isNullXQException(varName);
445
isNullXQException(value);
446
if (!((type==null) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_ELEMENT) || (type.getItemKind()==XQItemType.XQITEMKIND_DOCUMENT_SCHEMA_ELEMENT))) {
447
throw new XQException ("Invalid type.");
449
if (!isExternal(varName.getLocalPart())) {
450
throw new XQException ("The bound variable must be declared external in the prepared expression.");
453
type = connection.createDocumentElementType(connection.createElementType(null, XQItemType.XQBASETYPE_UNTYPED));
455
if (value instanceof StreamSource) {
456
bindDocument(varName, ((StreamSource)value).getReader(), null, type);
457
} else if (value instanceof SAXSource) {
458
bindDocument(varName, ((SAXSource)value).getInputSource().getCharacterStream(), null, type);
459
} else if (value instanceof DOMSource) {
460
bindDocument(varName, nodeToString(((DOMSource)value).getNode()), null, type);
462
throw new UnsupportedOperationException("Not supported yet.");
467
public void setImplicitTimeZone(TimeZone value) throws XQException {
468
isClosedXQException();
469
isNullXQException(value);
471
dynamicContext.setImplicitTimezone((value.getRawOffset()/60000));
472
} catch (Exception e) {
473
throw new XQException("Error setting implicit TimeZone: " + e.getLocalizedMessage());
478
public void bindItem(QName varName, XQItem value) throws XQException {
479
isClosedXQException();
480
isNullXQException(varName);
481
isNullXQException(value);
482
if (!isExternal(varName.getLocalPart())) {
483
throw new XQException ("The bound variable must be declared external in the prepared expression.");
486
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)value).getZorbaItem());
487
itemsBounded.add(varName.getLocalPart());
488
} catch (Exception e) {
489
throw new XQException ("Error binding item: " + varName.getLocalPart() + " with error: " + e.getLocalizedMessage());
494
public void bindSequence(QName varName, XQSequence value) throws XQException {
495
isClosedXQException();
496
isNullXQException(varName);
497
isNullXQException(value);
498
if (value.isClosed()) {
499
throw new XQException ("Sequence is closed.");
501
if (!isExternal(varName.getLocalPart())) {
502
throw new XQException ("The bound variable must be declared external in the prepared expression.");
505
if (!value.isOnItem()) {
508
Item item = new Item(((org.zorbaxquery.api.xqj.XQItem)value.getItem()).getZorbaItem());
509
//Item item2 = new Item(item);
510
//String val = item.getStringValue();
511
dynamicContext.setVariable(varName.getLocalPart(), item);
512
itemsBounded.add(varName.getLocalPart());
513
} catch (Exception e) {
514
throw new XQException ("Error binding item: " + varName.getLocalPart() + " with error: " + e.getLocalizedMessage());
519
public void bindObject(QName varName, Object value, XQItemType type) throws XQException {
520
isClosedXQException();
521
isNullXQException(varName);
522
isNullXQException(value);
523
if (!isExternal(varName.getLocalPart())) {
524
throw new XQException ("The bound variable must be declared external in the prepared expression.");
527
XQItem item = connection.createItemFromObject(value, type);
528
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
529
itemsBounded.add(varName.getLocalPart());
530
} catch (Exception e) {
531
throw new XQException ("Error binding object: " + e.getLocalizedMessage());
536
public void bindBoolean(QName varName, boolean value, XQItemType type) throws XQException {
537
isClosedXQException();
538
isNullXQException(varName);
539
if (!isExternal(varName.getLocalPart())) {
540
throw new XQException ("The bound variable must be declared external in the prepared expression.");
543
XQItem item = connection.createItemFromBoolean(value, type);
544
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
545
itemsBounded.add(varName.getLocalPart());
546
} catch (Exception e) {
547
throw new XQException ("Error binding object: " + e.getLocalizedMessage());
552
public void bindByte(QName varName, byte value, XQItemType type) throws XQException {
553
isClosedXQException();
554
isNullXQException(varName);
555
if (!isExternal(varName.getLocalPart())) {
556
throw new XQException ("The bound variable must be declared external in the prepared expression.");
559
XQItem item = connection.createItemFromByte(value, type);
560
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
561
itemsBounded.add(varName.getLocalPart());
562
} catch (Exception e) {
563
throw new XQException ("Error binding object: " + e.getLocalizedMessage());
568
public void bindDouble(QName varName, double value, XQItemType type) throws XQException {
569
isClosedXQException();
570
isNullXQException(varName);
571
if (!isExternal(varName.getLocalPart())) {
572
throw new XQException ("The bound variable must be declared external in the prepared expression.");
575
XQItem item = connection.createItemFromDouble(value, type);
576
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
577
itemsBounded.add(varName.getLocalPart());
578
} catch (Exception e) {
579
throw new XQException ("Error binding object: " + e.getLocalizedMessage());
584
public void bindFloat(QName varName, float value, XQItemType type) throws XQException {
585
isClosedXQException();
586
isNullXQException(varName);
587
if (!isExternal(varName.getLocalPart())) {
588
throw new XQException ("The bound variable must be declared external in the prepared expression.");
591
XQItem item = connection.createItemFromFloat(value, type);
592
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
593
itemsBounded.add(varName.getLocalPart());
594
} catch (Exception e) {
595
throw new XQException ("Error binding object: " + e.getLocalizedMessage());
600
public void bindInt(QName varName, int value, XQItemType type) throws XQException {
601
isClosedXQException();
602
isNullXQException(varName);
603
if (!isExternal(varName.getLocalPart())) {
604
throw new XQException ("The bound variable must be declared external in the prepared expression.");
607
XQItem item = connection.createItemFromInt(value, type);
608
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
609
itemsBounded.add(varName.getLocalPart());
610
} catch (Exception e) {
611
throw new XQException ("Error binding object: " + e.getLocalizedMessage());
616
public void bindLong(QName varName, long value, XQItemType type) throws XQException {
617
isClosedXQException();
618
isNullXQException(varName);
619
if (!isExternal(varName.getLocalPart())) {
620
throw new XQException ("The bound variable must be declared external in the prepared expression.");
623
XQItem item = connection.createItemFromLong(value, type);
624
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
625
itemsBounded.add(varName.getLocalPart());
626
} catch (Exception e) {
627
throw new XQException ("Error binding object: " + e.getLocalizedMessage());
632
public void bindNode(QName varName, Node value, XQItemType type) throws XQException {
633
isClosedXQException();
634
isNullXQException(value);
635
isNullXQException(varName);
636
if (!isExternal(varName.getLocalPart())) {
637
throw new XQException ("The bound variable must be declared external in the prepared expression.");
640
XQItem item = connection.createItemFromNode(value, type);
641
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
642
itemsBounded.add(varName.getLocalPart());
643
} catch (Exception e) {
644
throw new XQException ("Error binding object: " + e.getLocalizedMessage());
649
public void bindShort(QName varName, short value, XQItemType type) throws XQException {
650
isClosedXQException();
651
isNullXQException(varName);
652
if (!isExternal(varName.getLocalPart())) {
653
throw new XQException ("The bound variable must be declared external in the prepared expression.");
656
XQItem item = connection.createItemFromShort(value, type);
657
dynamicContext.setVariable(varName.getLocalPart(), ((org.zorbaxquery.api.xqj.XQItem)item).getZorbaItem());
658
itemsBounded.add(varName.getLocalPart());
659
} catch (Exception e) {
660
throw new XQException ("Error binding object: " + e.getLocalizedMessage());
664
private void isClosedXQException() throws XQException {
666
throw new XQException("This prepared expression is closed");
669
private void isNullXQException(Object value) throws XQException {
671
throw new XQException("Parameter shouldn't be null");