package org.basex.api.xqj;
import static org.basex.api.xqj.BXQText.*;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Result;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQException;
import javax.xml.xquery.XQItemType;
import javax.xml.xquery.XQResultItem;
import org.basex.io.out.ArrayOutput;
import org.basex.io.serial.SAXSerializer;
import org.basex.io.serial.Serializer;
import org.basex.query.QueryException;
import org.basex.query.item.ANode;
import org.basex.query.item.AtomType;
import org.basex.query.item.Bln;
import org.basex.query.item.Dbl;
import org.basex.query.item.Flt;
import org.basex.query.item.Item;
import org.basex.query.item.NodeType;
import org.basex.query.item.Type;
import org.basex.query.iter.ItemCache;
import org.basex.util.Token;
import org.basex.util.Util;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
/**
* Java XQuery API - Item.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
final class BXQItem extends BXQAbstract implements XQResultItem {
/** Connection. */
private final BXQConnection conn;
/** Item. */
final Item it;
/**
* Constructor.
* @param item item
* @throws XQException exception
*/
BXQItem(final Item item) throws XQException {
this(item, new BXQDataFactory(null, null), null);
}
/**
* Constructor.
* @param item item
* @param c close reference
* @param connection connection reference
*/
BXQItem(final Item item, final BXQAbstract c,
final BXQConnection connection) {
super(c);
conn = connection;
it = item;
}
@Override
public String getAtomicValue() throws XQException {
opened();
if(it.type.isNode()) throw new BXQException(ATOM);
try {
return Token.string(it.string(null));
} catch(final QueryException e) {
// function item
throw new BXQException(ATOM);
}
}
@Override
public boolean getBoolean() throws XQException {
return ((Bln) check(AtomType.BLN)).bool(null);
}
@Override
public byte getByte() throws XQException {
return (byte) castItr(AtomType.BYT);
}
@Override
public double getDouble() throws XQException {
return ((Dbl) check(AtomType.DBL)).dbl(null);
}
@Override
public float getFloat() throws XQException {
return ((Flt) check(AtomType.FLT)).flt(null);
}
@Override
public int getInt() throws XQException {
return (int) castItr(AtomType.INT);
}
@Override
public XMLStreamReader getItemAsStream() {
return new IterStreamReader(new ItemCache(new Item[] { it }, 1));
}
@Override
public String getItemAsString(final Properties props) throws XQException {
try {
final Type ip = it.type;
return ip.isNode() && ip != NodeType.TXT ? serialize() :
Token.string(it.string(null));
} catch(final QueryException e) {
throw new XQException(e.getMessage(), Token.string(e.qname().string()));
}
}
@Override
public XQItemType getItemType() throws XQException {
opened();
return new BXQItemType(it.type);
}
@Override
public long getLong() throws XQException {
return castItr(AtomType.LNG);
}
@Override
public Node getNode() throws XQException {
opened();
final Type ip = it.type;
if(!ip.isNode()) throw new BXQException(WRONG, NodeType.NOD, ip);
return ((ANode) it).toJava();
}
@Override
public URI getNodeUri() throws XQException {
opened();
final Type ip = it.type;
if(!ip.isNode()) throw new BXQException(NODE);
final ANode node = (ANode) it;
try {
return new URI(Token.string(node.baseURI()));
} catch(final URISyntaxException ex) {
throw new BXQException(ex);
}
}
@Override
public Object getObject() throws XQException {
opened();
try {
return it.toJava();
} catch(final QueryException ex) {
throw new BXQException(ex);
}
}
@Override
public short getShort() throws XQException {
return (short) castItr(AtomType.SHR);
}
@Override
public boolean instanceOf(final XQItemType type) throws XQException {
opened();
return it.type.instanceOf(((BXQItemType) type).getType());
}
@Override
public void writeItem(final OutputStream os, final Properties props)
throws XQException {
valid(os, OutputStream.class);
serialize(os);
}
@Override
public void writeItemToSAX(final ContentHandler sax) throws XQException {
valid(sax, ContentHandler.class);
writeItemToResult(new SAXResult(sax));
}
@Override
public XQConnection getConnection() throws XQException {
opened();
return conn;
}
@Override
public void writeItem(final Writer ow, final Properties props)
throws XQException {
valid(ow, Writer.class);
try {
ow.write(serialize());
} catch(final IOException ex) {
throw new BXQException(ex);
}
}
@Override
public void writeItemToResult(final Result result) throws XQException {
valid(result, Result.class);
// evaluate different result types...
if(result instanceof StreamResult) {
// StreamResult.. directly write result as string
writeItem(((StreamResult) result).getWriter(), null);
} else if(result instanceof SAXResult) {
try {
// SAXResult.. serialize result to underlying parser
final SAXSerializer ser = new SAXSerializer(null);
ser.setContentHandler(((SAXResult) result).getHandler());
serialize(it, ser);
ser.close();
} catch(final IOException ex) {
throw new BXQException(ex);
}
} else {
Util.notimplemented();
}
}
/**
* Serializes the item to the specified output stream.
* @param os output stream
* @throws XQException exception
*/
private void serialize(final OutputStream os) throws XQException {
try {
final Serializer ser = Serializer.get(os);
serialize(it, ser);
ser.close();
} catch(final IOException ex) {
throw new BXQException(ex);
}
}
/**
* Returns the serialized output.
* @return cached output
* @throws XQException exception
*/
private String serialize() throws XQException {
opened();
final ArrayOutput ao = new ArrayOutput();
serialize(ao);
return ao.toString();
}
/**
* Checks the specified data type; throws an error if the type is wrong.
* @param type expected type
* @return item
* @throws XQException xquery exception
*/
private Item check(final Type type) throws XQException {
opened();
final Type ip = it.type;
if(ip != type) throw new BXQException(WRONG, ip, type);
return it;
}
/**
* Casts the current item.
* @param type expected type
* @return cast item
* @throws XQException xquery exception
*/
private long castItr(final Type type) throws XQException {
opened();
try {
final double d = it.dbl(null);
if(!it.type.isNumber() || d != (long) d) throw new BXQException(NUM, d);
return type.cast(it, null, null).itr(null);
} catch(final QueryException ex) {
throw new BXQException(ex);
}
}
}