/** * Constructor. * * @param value value * @param type item type * @param ii input info * @throws QueryException query exception */ private Dur(final byte[] value, final Type type, final InputInfo ii) throws QueryException { this(type); final String val = Token.string(value).trim(); final Matcher mt = DUR.matcher(val); if (!mt.matches() || val.endsWith("P") || val.endsWith("T")) throw dateError(value, XDURR, ii); yearMonth(value, mt, ii); dayTime(value, mt, 6, ii); }
/** * Initializes the yearMonth component. * * @param vl value * @param mt matcher * @param ii input info * @throws QueryException query exception */ void yearMonth(final byte[] vl, final Matcher mt, final InputInfo ii) throws QueryException { final long y = mt.group(2) != null ? toLong(mt.group(3), true, ii) : 0; final long m = mt.group(4) != null ? toLong(mt.group(5), true, ii) : 0; mon = y * 12 + m; double v = y * 12d + m; if (!mt.group(1).isEmpty()) { mon = -mon; v = -v; } if (v <= Long.MIN_VALUE || v >= Long.MAX_VALUE) throw DURRANGE_X_X.get(ii, type, vl); }
/** * Initializes the date format. * * @param d input * @param e example format * @param ii input info * @throws QueryException query exception */ final void date(final byte[] d, final String e, final InputInfo ii) throws QueryException { final Matcher mt = DATE.matcher(Token.string(d).trim()); if (!mt.matches()) throw dateError(d, e, ii); yea = toLong(mt.group(1), false, ii); // +1 is added to BC values to simplify computations if (yea < 0) yea++; mon = (byte) (Strings.toInt(mt.group(3)) - 1); day = (byte) (Strings.toInt(mt.group(4)) - 1); if (mon < 0 || mon >= 12 || day < 0 || day >= dpm(yea, mon)) throw dateError(d, e, ii); if (yea <= MIN_YEAR || yea > MAX_YEAR) throw DATERANGE_X_X.get(ii, type, chop(d, ii)); zone(mt, 5, d, ii); }
/** * Initializes the timezone. * * @param matcher matcher * @param pos first matching position * @param value value * @param ii input info * @throws QueryException query exception */ final void zone(final Matcher matcher, final int pos, final byte[] value, final InputInfo ii) throws QueryException { final String z = matcher.group(pos); if (z == null) return; if ("Z".equals(z)) { tz = 0; } else { final int th = Strings.toInt(matcher.group(pos + 2)); final int tm = Strings.toInt(matcher.group(pos + 3)); if (th > 14 || tm > 59 || th == 14 && tm != 0) throw INVALIDZONE_X.get(ii, value); final int mn = th * 60 + tm; tz = (short) ("-".equals(matcher.group(pos + 1)) ? -mn : mn); } }
/** * Initializes the time format. * * @param d input format * @param e expected format * @param ii input info * @throws QueryException query exception */ final void time(final byte[] d, final String e, final InputInfo ii) throws QueryException { final Matcher mt = TIME.matcher(Token.string(d).trim()); if (!mt.matches()) throw dateError(d, e, ii); hou = (byte) Strings.toInt(mt.group(1)); min = (byte) Strings.toInt(mt.group(2)); sec = toDecimal(mt.group(3), false, ii); if (min >= 60 || sec.compareTo(BD60) >= 0 || hou > 24 || hou == 24 && (min > 0 || sec.compareTo(BigDecimal.ZERO) > 0)) throw dateError(d, e, ii); zone(mt, 5, d, ii); if (hou == 24) { hou = 0; add(DAYSECONDS); } }
/** * Checks the specified template and adds a variable. * * @param tmp template string * @param type allowed type * @param declared variable declaration flags * @return resulting variable * @throws QueryException query exception */ private QNm checkVariable(final String tmp, final Type type, final boolean[] declared) throws QueryException { final Var[] args = function.args; final Matcher m = TEMPLATE.matcher(tmp); if (!m.find()) error(INV_TEMPLATE, tmp); final byte[] vn = token(m.group(1)); if (!XMLToken.isQName(vn)) error(INV_VARNAME, vn); final QNm qnm = new QNm(vn, context); int r = -1; while (++r < args.length && !args[r].name.eq(qnm)) ; if (r == args.length) error(UNKNOWN_VAR, vn); if (declared[r]) error(VAR_ASSIGNED, vn); final SeqType st = args[r].declaredType(); if (args[r].checksType() && !st.type.instanceOf(type)) error(INV_VARTYPE, vn, type); declared[r] = true; return qnm; }
/** * Initializes the dayTime component. * * @param vl value * @param mt matcher * @param p first matching position * @param ii input info * @throws QueryException query exception */ void dayTime(final byte[] vl, final Matcher mt, final int p, final InputInfo ii) throws QueryException { final long d = mt.group(p) != null ? toLong(mt.group(p + 1), true, ii) : 0; final long h = mt.group(p + 3) != null ? toLong(mt.group(p + 4), true, ii) : 0; final long m = mt.group(p + 5) != null ? toLong(mt.group(p + 6), true, ii) : 0; final BigDecimal s = mt.group(p + 7) != null ? toDecimal(mt.group(p + 8), true, ii) : BigDecimal.ZERO; sec = s.add(BigDecimal.valueOf(d).multiply(DAYSECONDS)) .add(BigDecimal.valueOf(h).multiply(BD3600)) .add(BigDecimal.valueOf(m).multiply(BD60)); if (!mt.group(1).isEmpty()) sec = sec.negate(); final double v = sec.doubleValue(); if (v <= Long.MIN_VALUE || v >= Long.MAX_VALUE) throw DURRANGE_X_X.get(ii, type, vl); }
/** * Binds the annotated variables. * * @param http http context * @param arg argument array * @throws QueryException query exception * @throws IOException I/O exception */ void bind(final HTTPContext http, final Expr[] arg) throws QueryException, IOException { // bind variables from segments for (int s = 0; s < path.size; s++) { final Matcher m = TEMPLATE.matcher(path.segment[s]); if (!m.find()) continue; final QNm qnm = new QNm(token(m.group(1)), context); bind(qnm, arg, new Atm(http.segment(s))); } // cache request body final String ct = http.contentType(); IOContent body = null; if (requestBody != null) { body = cache(http, null); try { // bind request body in the correct format body.name(http.method + IO.XMLSUFFIX); bind(requestBody, arg, Parser.item(body, context.context.prop, ct)); } catch (final IOException ex) { error(INPUT_CONV, ex); } } // bind query parameters final Map<String, String[]> params = http.params(); for (final RestXqParam rxp : queryParams) bind(rxp, arg, params.get(rxp.key)); // bind form parameters if (!formParams.isEmpty()) { if (MimeTypes.APP_FORM.equals(ct)) { // convert parameters encoded in a form body = cache(http, body); addParams(body.toString(), params); } for (final RestXqParam rxp : formParams) bind(rxp, arg, params.get(rxp.key)); } // bind header parameters for (final RestXqParam rxp : headerParams) { final StringList sl = new StringList(); final Enumeration<?> en = http.req.getHeaders(rxp.key); while (en.hasMoreElements()) { for (final String s : en.nextElement().toString().split(", *")) sl.add(s); } bind(rxp, arg, sl.toArray()); } // bind cookie parameters final Cookie[] ck = http.req.getCookies(); for (final RestXqParam rxp : cookieParams) { String v = null; if (ck != null) { for (final Cookie c : ck) { if (rxp.key.equals(c.getName())) v = c.getValue(); } } if (v == null) bind(rxp, arg); else bind(rxp, arg, v); } }