package org.basex.server;
import static org.basex.core.Text.*;
import static org.basex.io.serial.SerializerProp.*;
import java.io.IOException;
import java.io.OutputStream;
import org.basex.core.BaseXException;
import org.basex.core.Context;
import org.basex.core.Progress;
import org.basex.io.out.EncodingOutput;
import org.basex.io.out.PrintOutput;
import org.basex.io.serial.Serializer;
import org.basex.io.serial.SerializerProp;
import org.basex.query.QueryException;
import org.basex.query.QueryProcessor;
import org.basex.query.item.Item;
import org.basex.query.iter.Iter;
import org.basex.util.Performance;
import org.basex.util.TokenBuilder;
/**
* Server-side query session in the client-server architecture.
*
* @author BaseX Team 2005-12, BSD License
* @author Andreas Weiler
* @author Christian Gruen
*/
final class QueryListener extends Progress {
/** Performance. */
private final Performance perf = new Performance();
/** Query processor. */
private final QueryProcessor qp;
/** Database context. */
private final Context ctx;
/** Query info. */
private String info = "";
/** Serialization options. */
private SerializerProp options;
/**
* Constructor.
* @param qu query string
* @param c database context
*/
QueryListener(final String qu, final Context c) {
qp = new QueryProcessor(qu, c);
ctx = c;
}
/**
* Binds an object to a global variable.
* @param n name of variable
* @param o object to be bound
* @param t type
* @throws IOException query exception
*/
void bind(final String n, final Object o, final String t) throws IOException {
try {
qp.bind(n, o, t);
} catch(final QueryException ex) {
throw new BaseXException(ex);
}
}
/**
* Returns the query info.
* @return query info
*/
String info() {
return info;
}
/**
* Returns the serialization options.
* @return serialization options
* @throws IOException Exception
*/
String options() throws IOException {
init();
return options.toString();
}
/**
* Executes the query.
* @param iter iterative evaluation
* @param out output stream
* @param enc encode stream
* @throws IOException Exception
*/
void execute(final boolean iter, final OutputStream out, final boolean enc)
throws IOException {
boolean mon = false;
try {
init();
ctx.register(qp.ctx.updating);
mon = true;
// create serializer
final Iter ir = qp.iter();
final boolean wrap = !options.get(S_WRAP_PREFIX).isEmpty();
// iterate through results
final PrintOutput po =
PrintOutput.get(enc ? new EncodingOutput(out) : out);
if(iter && wrap) po.write(1);
final Serializer ser = Serializer.get(po, options);
int c = 0;
for(Item it; (it = ir.next()) != null;) {
if(iter && !wrap) {
po.write(it.type.id());
ser.reset();
}
ser.openResult();
it.serialize(ser);
ser.closeResult();
if(iter && !wrap) {
po.flush();
out.write(0);
}
c++;
}
ser.close();
if(iter && wrap) out.write(0);
// generate query info
final int up = qp.updates();
final TokenBuilder tb = new TokenBuilder();
tb.addExt(HITS_X_CC + "% %" + NL, c, c == 1 ? ITEM : ITEMS);
tb.addExt(UPDATED_CC + "% %" + NL, up, up == 1 ? ITEM : ITEMS);
tb.addExt(TOTAL_TIME_CC + '%', perf);
info = tb.toString();
} catch(final QueryException ex) {
throw new BaseXException(ex);
} finally {
try { qp.close(); } catch(final QueryException ex) { }
if(mon) ctx.unregister(qp.ctx.updating);
}
}
/**
* Parses the query and retrieves the serialization options.
* @throws IOException Exception
*/
private void init() throws IOException {
if(options != null) return;
try {
qp.parse();
} catch(final QueryException ex) {
throw new BaseXException(ex);
}
options = qp.ctx.serProp(false);
}
}