package org.basex.query.expr; import static org.basex.query.QueryText.*; import static org.basex.util.Token.*; import org.basex.query.QueryContext; import org.basex.query.QueryException; import org.basex.query.item.Empty; import org.basex.query.item.Int; import org.basex.query.item.QNm; import org.basex.query.item.SeqType; import org.basex.query.item.Str; import org.basex.query.item.Value; import org.basex.query.util.Err; import org.basex.query.util.Var; import org.basex.util.InputInfo; /** * Catch clause. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public final class Catch extends Single { /** Error QNames. */ private static final QNm[] QNM = { create(ECODE), create(EDESC), create(EVALUE), create(EMODULE), create(ELINENUM), create(ECOLNUM), create(EADD) }; /** Error types. */ private static final SeqType[] TYPES = { SeqType.QNM, SeqType.STR_ZO, SeqType.ITEM_ZM, SeqType.STR_ZO, SeqType.ITR_ZO, SeqType.ITR_ZO, SeqType.ITEM_ZM }; /** Error variables. */ private final Var[] vars = new Var[QNM.length]; /** Supported codes. */ private final QNm[] codes; /** * Constructor. * @param ii input info * @param c supported error codes * @param ctx query context */ public Catch(final InputInfo ii, final QNm[] c, final QueryContext ctx) { super(ii, null); codes = c; for(int i = 0; i < QNM.length; i++) vars[i] = Var.create(ctx, null, QNM[i], TYPES[i]); } @Override public Catch comp(final QueryContext ctx) throws QueryException { final int s = prepare(ctx); super.comp(ctx); ctx.vars.size(s); return this; } /** * Returns the value of the caught expression. * @param ctx query context * @param ex thrown exception * @return resulting item * @throws QueryException query exception */ Value value(final QueryContext ctx, final QueryException ex) throws QueryException { if(!find(ex.err(), ex.qname())) return null; final int s = prepare(ctx); try { int i = 0; final byte[] io = ex.file() == null ? EMPTY : token(ex.file().path()); final Value val = ex.value(); for(final Value v : new Value[] { ex.qname(), Str.get(ex.getLocalizedMessage()), val == null ? Empty.SEQ : val, Str.get(io), Int.get(ex.col()), Int.get(ex.line()), Empty.SEQ }) { vars[i++].bind(v, ctx); } return ctx.value(expr); } finally { ctx.vars.size(s); } } /** * Prepares the catch construction. * @param ctx query context * @return number of variables */ public int prepare(final QueryContext ctx) { final int s = ctx.vars.size(); for(final Var v : vars) ctx.vars.add(v); return s; } /** * Checks if one defined error matches the thrown error. * @param err error reference * @param code error code * @return result of check */ private boolean find(final Err err, final QNm code) { for(final QNm c : codes) { if(c != null) { final byte[] cu = c.uri(); if(err == null || cu.length != 0 && !eq(err.qname().uri(), cu)) continue; final byte[] nm = c.local(); if(nm.length != 0 && !eq(code.local(), nm)) continue; } return true; } return false; } @Override public boolean uses(final Use u) { return u == Use.VAR || super.uses(u); } @Override public String toString() { return "catch * { " + expr + " }"; } /** * Creates an error QName with the specified name. * @param n name * @return QName */ private static QNm create(final byte[] n) { return new QNm(concat(ERR, COLON, n), ERRORURI); } }