/** * Compares two nodes for their unique order. * * @param node1 first node * @param node2 node to be compared * @return {@code 0} if the nodes are identical, or {@code 1}/{@code -1} if the first node appears * after/before the second */ static int diff(final ANode node1, final ANode node2) { // cache parents of first node final ANodeList nl = new ANodeList(); for (ANode n = node1; n != null; n = n.parent()) { if (n == node2) return 1; nl.add(n); } // find lowest common ancestor ANode c2 = node2; LOOP: for (ANode n = node2; (n = n.parent()) != null; ) { final int is = nl.size(); for (int i = 1; i < is; i++) { if (n == node1) return -1; if (!nl.get(i).is(n)) continue; // check which node appears as first LCA child final ANode c1 = nl.get(i - 1); final BasicNodeIter ir = n.children(); for (ANode c; (c = ir.next()) != null; ) { if (c.is(c1)) return -1; if (c.is(c2)) return 1; } break LOOP; } c2 = n; } // subtraction is used instead of comparison to support overflow of node id return node1.id - node2.id < 0 ? -1 : 1; }
/** * Parses a jar descriptor. * * @param io XML input * @return jar descriptor container * @throws QueryException query exception */ public JarDesc parse(final IO io) throws QueryException { final JarDesc desc = new JarDesc(); try { final ANode node = new DBNode(io).children().next(); for (final ANode next : node.children()) { if (next.type != NodeType.ELM) continue; final QNm name = next.qname(); // ignore namespace to improve compatibility if (eq(JAR, name.local())) desc.jars.add(next.string()); else if (eq(CLASS, name.local())) desc.classes.add(next.string()); // [CG] Packaging: add warning if unknown elements are encountered } if (desc.jars.isEmpty()) throw BXRE_JARDESC_X.get(info, NOJARS); else if (desc.classes.isEmpty()) throw BXRE_JARDESC_X.get(info, NOCLASSES); return desc; } catch (final IOException ex) { throw BXRE_JARFAIL_X.get(info, ex); } }
/** * Evaluates the specified function and creates a response. * * @throws Exception exception (including unexpected ones) */ void create() throws Exception { // bind variables final StaticFunc sf = function.function; final Expr[] args = new Expr[sf.args.length]; function.bind(http, args, error); // wrap function with a function call final MainModule mm = new MainModule(sf, args); // assign main module and http context and register process query.mainModule(mm); query.http(http); query.context.register(query); String redirect = null, forward = null; RestXqRespBuilder resp = null; try { // compile and evaluate query query.compile(); final Iter iter = query.iter(); Item item = iter.next(); // handle response element if (item != null && item instanceof ANode) { final ANode node = (ANode) item; // send redirect to browser if (REST_REDIRECT.eq(node)) { final ANode ch = node.children().next(); if (ch == null || ch.type != NodeType.TXT) throw function.error(NO_VALUE, node.name()); redirect = string(ch.string()).trim(); return; } // server-side forwarding if (REST_FORWARD.eq(node)) { final ANode ch = node.children().next(); if (ch == null || ch.type != NodeType.TXT) throw function.error(NO_VALUE, node.name()); forward = string(ch.string()).trim(); return; } if (REST_RESPONSE.eq(node)) { resp = new RestXqRespBuilder(); resp.build(node, function, iter, http); return; } } // HEAD method must return a single response element if (function.methods.size() == 1 && function.methods.contains(HTTPMethod.HEAD.name())) throw function.error(HEAD_METHOD); // serialize result final SerializerOptions sp = function.output; http.sopts(sp); http.initResponse(); final Serializer ser = Serializer.get(http.res.getOutputStream(), sp); for (; item != null; item = iter.next()) ser.serialize(item); ser.close(); } finally { query.close(); query.context.unregister(query); if (redirect != null) { http.res.sendRedirect(redirect); } else if (forward != null) { http.req.getRequestDispatcher(forward).forward(http.req, http.res); } else if (resp != null) { if (resp.status != 0) http.status(resp.status, resp.message, resp.error); http.res.getOutputStream().write(resp.cache.toArray()); } } }
/** * Adds children of a sub node. * * @param ch child nodes * @param nb node cache */ static void addDesc(final BasicNodeIter ch, final ANodeList nb) { for (ANode n; (n = ch.next()) != null; ) { nb.add(n.finish()); addDesc(n.children(), nb); } }