/** * Test sending of HTTP GET requests. * * @throws Exception exception */ @Test public void postGet() throws Exception { // GET1 - just send a GET request try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='get' href='" + REST_ROOT + "'/>"), ctx)) { final Value v = qp.value(); checkResponse(v, 2, HttpURLConnection.HTTP_OK); assertEquals(NodeType.DOC, v.itemAt(1).type); } // GET2 - with override-media-type='text/plain' try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='get' override-media-type='text/plain'/>", REST_ROOT), ctx)) { final Value v = qp.value(); checkResponse(v, 2, HttpURLConnection.HTTP_OK); assertEquals(AtomType.STR, v.itemAt(1).type); } // Get3 - with status-only='true' try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='get' status-only='true'/>", REST_ROOT), ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_OK); } }
/** * Checks the response to an HTTP request. * * @param v query result * @param itemsCount expected number of items * @param expStatus expected status */ private static void checkResponse(final Value v, final int itemsCount, final int expStatus) { assertEquals(itemsCount, v.size()); assertTrue(v.itemAt(0) instanceof FElem); final FElem response = (FElem) v.itemAt(0); assertNotNull(response.attributes()); if (!eq(response.attribute(STATUS), token(expStatus))) { fail("Expected: " + expStatus + "\nFound: " + response); } }
/** * Returns a string representation of all found arguments. * * @param args array with arguments * @return string representation */ static String foundArgs(final Value[] args) { // compose found arguments final StringBuilder sb = new StringBuilder(); for (final Value v : args) { if (sb.length() != 0) sb.append(", "); sb.append(v instanceof Jav ? Util.className(((Jav) v).toJava()) : v.seqType()); } return sb.toString(); }
/** * Returns a parameter. * * @param value value * @param name name * @param declared variable declaration flags * @return parameter * @throws QueryException HTTP exception */ private RestXqParam param(final Value value, final QNm name, final boolean[] declared) throws QueryException { // [CG] RESTXQ: allow identical field names? final long vs = value.size(); if (vs < 2) error(ANN_PARAMS, "%", name.string(), 2); // name of parameter final String key = toString(value.itemAt(0), name); // variable template final QNm qnm = checkVariable(toString(value.itemAt(1), name), declared); // default value final ValueBuilder vb = new ValueBuilder(); for (int v = 2; v < vs; v++) vb.add(value.itemAt(v)); return new RestXqParam(qnm, key, vb.value()); }
/** * Builds the thesaurus. * * @param value input nodes * @throws QueryException query exception */ private void build(final Value value) throws QueryException { final Value synonyms = nodes("*:synonym", value); if (synonyms.isEmpty()) return; final ThesNode term = node(text("*:term", value)); for (final Item synonym : synonyms) { final ThesNode sterm = node(text("*:term", synonym)); final byte[] rs = text("*:relationship", synonym); term.add(sterm, rs); final byte[] srs = RSHIPS.get(rs); if (srs != null) sterm.add(term, srs); build(synonyms); } }
/** * Adds items to the specified list. * * @param value value * @param name name * @param list list to add values to * @throws QueryException HTTP exception */ private void strings(final Value value, final QNm name, final StringList list) throws QueryException { final long vs = value.size(); for (int v = 0; v < vs; v++) list.add(toString(value.itemAt(v), name)); }
/** * Checks a function for RESTFful annotations. * * @return {@code true} if module contains relevant annotations * @throws QueryException query exception */ boolean analyze() throws QueryException { // parse all annotations final EnumSet<HTTPMethod> mth = EnumSet.noneOf(HTTPMethod.class); final boolean[] declared = new boolean[function.args.length]; boolean found = false; final int as = function.ann.size(); for (int a = 0; a < as; a++) { final QNm name = function.ann.names[a]; final Value value = function.ann.values[a]; final byte[] local = name.local(); final byte[] uri = name.uri(); final boolean rexq = eq(uri, QueryText.RESTXQURI); if (rexq) { if (eq(PATH, local)) { // annotation "path" if (path != null) error(ANN_TWICE, "%", name.string()); path = new RestXqPath(toString(value, name)); for (final String s : path) { if (s.trim().startsWith("{")) checkVariable(s, AtomType.AAT, declared); } } else if (eq(CONSUMES, local)) { // annotation "consumes" strings(value, name, consumes); } else if (eq(PRODUCES, local)) { // annotation "produces" strings(value, name, produces); } else if (eq(QUERY_PARAM, local)) { // annotation "query-param" queryParams.add(param(value, name, declared)); } else if (eq(FORM_PARAM, local)) { // annotation "form-param" formParams.add(param(value, name, declared)); } else if (eq(HEADER_PARAM, local)) { // annotation "header-param" headerParams.add(param(value, name, declared)); } else if (eq(COOKIE_PARAM, local)) { // annotation "cookie-param" cookieParams.add(param(value, name, declared)); } else { // method annotations final HTTPMethod m = HTTPMethod.get(string(local)); if (m == null) error(ANN_UNKNOWN, "%", name.string()); if (!value.isEmpty()) { // remember post/put variable if (requestBody != null) error(ANN_TWICE, "%", name.string()); if (m != POST && m != PUT) error(METHOD_VALUE, m); requestBody = checkVariable(toString(value, name), declared); } if (mth.contains(m)) error(ANN_TWICE, "%", name.string()); mth.add(m); } } else if (eq(uri, QueryText.OUTPUTURI)) { // serialization parameters final String key = string(local); final String val = toString(value, name); if (output.get(key) == null) error(UNKNOWN_SER, key); output.set(key, val); } found |= rexq; } if (!mth.isEmpty()) methods = mth; if (found) { if (path == null) error(ANN_MISSING, PATH); for (int i = 0; i < declared.length; i++) if (!declared[i]) error(VAR_UNDEFINED, function.args[i].name.string()); } return found; }