@Override public final void service(final HttpServletRequest req, final HttpServletResponse res) throws IOException { final HTTPContext http = new HTTPContext(req, res, this); final boolean restxq = this instanceof RestXqServlet; try { http.authorize(); run(http); http.log(SC_OK, ""); } catch (final HTTPException ex) { http.status(ex.getStatus(), Util.message(ex), restxq); } catch (final LoginException ex) { http.status(SC_UNAUTHORIZED, Util.message(ex), restxq); } catch (final IOException | QueryException ex) { http.status(SC_BAD_REQUEST, Util.message(ex), restxq); } catch (final ProcException ex) { http.status(SC_BAD_REQUEST, Text.INTERRUPTED, restxq); } catch (final Exception ex) { final String msg = Util.bug(ex); Util.errln(msg); http.status(SC_INTERNAL_SERVER_ERROR, Util.info(UNEXPECTED, msg), restxq); } finally { if (Prop.debug) { Util.outln("_ REQUEST _________________________________" + Prop.NL + req); final Enumeration<String> en = req.getHeaderNames(); while (en.hasMoreElements()) { final String key = en.nextElement(); Util.outln(Text.LI + key + Text.COLS + req.getHeader(key)); } Util.out("_ RESPONSE ________________________________" + Prop.NL + res); } } }
/** * Assumes that this command is successful. * * @param cmd command reference * @param s session */ private static void ok(final Command cmd, final Session s) { try { s.execute(cmd); } catch (final IOException ex) { fail(Util.message(ex)); } }
/** * Adds the string representation of an object: * * <ul> * <li>objects of type {@link Throwable} are converted to a string representation via {@link * Util#message}. * <li>objects of type {@link Class} are converted via {@link Util#className(Class)}. * <li>{@code null} references are replaced by the string {@code "null"}. * <li>byte arrays are directly inserted as tokens. * <li>for all other typed, {@link Object#toString} is called. * </ul> * * The specified string may contain {@code "%"} characters as place holders. All place holders * will be replaced by the specified extensions. If a digit is specified after the place holder * character, it will be interpreted as insertion position. * * @param object string to be extended * @param ext optional extensions * @return self reference */ public TokenBuilder addExt(final Object object, final Object... ext) { final byte[] t; if (object instanceof byte[]) { t = (byte[]) object; } else { final String s; if (object == null) { s = "null"; } else if (object instanceof Throwable) { s = Util.message((Throwable) object); } else if (object instanceof Class<?>) { s = Util.className((Class<?>) object); } else { s = object.toString(); } t = token(s); } for (int i = 0, e = 0; i < t.length; ++i) { if (t[i] != '%' || e == ext.length) { addByte(t[i]); } else { final byte c = i + 1 < t.length ? t[i + 1] : 0; final boolean d = c >= '1' && c <= '9'; if (d) ++i; final int n = d ? c - '1' : e++; final Object o = n < ext.length ? ext[n] : null; addExt(o); } } return this; }
/** * Assumes that this command is successful. * * @param cmd command reference * @return result as string */ protected final String ok(final Command cmd) { try { return session.execute(cmd); } catch (final IOException ex) { fail(Util.message(ex)); return null; } }
/** Stops a session. */ @After public final void stopSession() { try { if (cleanup) session.execute(new DropDB(NAME)); session.close(); } catch (final IOException ex) { fail(Util.message(ex)); } }
/** * Performs a search. * * @param sc search context * @param jump jump to next hit */ final void search(final SearchContext sc, final boolean jump) { try { rend.search(sc); if (!sc.search.isEmpty()) gui.status.setText(Util.info(Text.STRINGS_FOUND_X, sc.nr())); if (jump) jump(SearchDir.CURRENT, false); } catch (final Exception ex) { final String msg = Util.message(ex).replaceAll(Prop.NL + ".*", ""); gui.status.setError(Text.REGULAR_EXPR + Text.COLS + msg); } }
/** * Returns the serialization parameters. * * @param ctx context * @return serialization parameters */ public String parameters(final Context ctx) { try { qp(args[0], ctx); parse(null); return qp.qc.serParams().toString(); } catch (final QueryException ex) { error(Util.message(ex)); } finally { qp = null; } return SerializerMode.DEFAULT.get().toString(); }
/** Clean up method. */ @After public void cleanUp() { try { testSession.close(); adminSession.execute(new DropDB(RENAMED)); adminSession.execute(new DropDB(NAME)); adminSession.close(); // give the server some time to clean up the sessions before next test Performance.sleep(100); } catch (final Exception ex) { fail(Util.message(ex)); } }
/** Command test. */ @Test public final void run() { final IOFile io = new IOFile("test.xq"); no(new Run(io.path())); try { io.write(token("// li")); } catch (final Exception ex) { fail(Util.message(ex)); } no(new Run(io.path())); ok(new CreateDB(NAME, FILE)); ok(new Run(io.path())); io.delete(); }
/** * Replaces the text. * * @param rc replace context */ final void replace(final ReplaceContext rc) { try { final int[] select = rend.replace(rc); if (rc.text != null) { final boolean sel = editor.selected(); setText(rc.text); editor.select(select[0], select[sel ? 1 : 0]); release(Action.CHECK); } gui.status.setText(Text.STRINGS_REPLACED); } catch (final Exception ex) { final String msg = Util.message(ex).replaceAll(Prop.NL + ".*", ""); gui.status.setError(Text.REGULAR_EXPR + Text.COLS + msg); } }
/** * Sets a status and sends an info message. * * @param code status code * @param message info message * @param error treat as error (use web server standard output) * @throws IOException I/O exception */ public void status(final int code, final String message, final boolean error) throws IOException { try { log(message, code); res.resetBuffer(); if (code == SC_UNAUTHORIZED) res.setHeader(WWW_AUTHENTICATE, BASIC); if (error && code >= SC_BAD_REQUEST) { res.sendError(code, message); } else { res.setStatus(code); if (message != null) res.getOutputStream().write(token(message)); } } catch (final IllegalStateException ex) { log(Util.message(ex), SC_INTERNAL_SERVER_ERROR); } }
/** * Lists resources of the specified database. * * @return success flag * @throws IOException I/O exception */ private boolean listDB() throws IOException { final String db = args[0]; final String path = args[1] != null ? args[1] : ""; if (!Databases.validName(db)) return error(NAME_INVALID_X, db); final Table table = new Table(); table.description = RESOURCES; table.header.add(INPUT_PATH); table.header.add(TYPE); table.header.add(MimeTypes.CONTENT_TYPE); table.header.add(SIZE); try { // add xml documents final Data data = Open.open(db, context); final Resources res = data.resources; final IntList il = res.docs(path); final int ds = il.size(); for (int i = 0; i < ds; i++) { final int pre = il.get(i); final TokenList tl = new TokenList(3); final byte[] file = data.text(pre, true); tl.add(file); tl.add(DataText.M_XML); tl.add(MimeTypes.APP_XML); tl.add(data.size(pre, Data.DOC)); table.contents.add(tl); } // add binary resources for (final byte[] file : res.binaries(path)) { final String f = string(file); final TokenList tl = new TokenList(3); tl.add(file); tl.add(DataText.M_RAW); tl.add(MimeTypes.get(f)); tl.add(data.meta.binary(f).length()); table.contents.add(tl); } Close.close(data, context); } catch (final IOException ex) { return error(Util.message(ex)); } out.println(table.sort().finish()); return true; }
@Override protected boolean run() { // close existing database new Close().run(context); final String db = args[0]; if (!Databases.validName(db)) return error(NAME_INVALID_X, db); try { final Data data = open(db, context); context.openDB(data); if (data.meta.oldindex()) info(H_INDEX_FORMAT); if (data.meta.corrupt) info(DB_CORRUPT); return info(DB_OPENED_X, db, perf); } catch (final IOException ex) { return error(Util.message(ex)); } }
/** Set up method. */ @Before public void setUp() { try { adminSession = createClient(); if (server.context.users.get(NAME) != null) { ok(new DropUser(NAME), adminSession); } ok(new CreateUser(NAME, NAME), adminSession); ok(new CreateDB(RENAMED), adminSession); server.context.soptions.set(StaticOptions.REPOPATH, REPO); testSession = createClient(NAME, NAME); ok(new CreateDB(NAME, "<xml/>"), adminSession); ok(new Close(), adminSession); } catch (final Exception ex) { fail(Util.message(ex)); } }
@Override protected boolean run() { final boolean create = context.user.has(Perm.CREATE); String path = MetaData.normPath(args[0]); if (path == null || path.endsWith(".")) return error(NAME_INVALID_X, args[0]); if (in == null) { final IO io = IO.get(args[1]); if (!io.exists() || io.isDir()) return error(RES_NOT_FOUND_X, create ? io : args[1]); in = io.inputSource(); // set/add name of document if ((path.isEmpty() || path.endsWith("/")) && !(io instanceof IOContent)) path += io.name(); } // ensure that the final name is not empty if (path.isEmpty()) return error(NAME_INVALID_X, path); // ensure that the name is not empty and contains no trailing dots final Data data = context.data(); if (data.inMemory()) return error(NO_MAINMEM); final IOFile file = data.meta.binary(path); if (path.isEmpty() || path.endsWith(".") || file == null || file.isDir()) return error(NAME_INVALID_X, create ? path : args[0]); // start update if (!data.startUpdate()) return error(DB_PINNED_X, data.meta.name); try { store(in, file); return info(QUERY_EXECUTED_X_X, "", perf); } catch (final IOException ex) { return error(FILE_NOT_STORED_X, Util.message(ex)); } finally { data.finishUpdate(); } }
@Override protected boolean run() { final Data data = context.data(); final MetaData meta = data.meta; size = meta.size; if (!startUpdate()) return false; boolean ok = true; try { // reassign autooptimize flag final boolean autoopt = options.get(MainOptions.AUTOOPTIMIZE); if (autoopt != data.meta.autoopt) { data.meta.autoopt = autoopt; data.meta.dirty = true; } optimize(data, this); ok = info(DB_OPTIMIZED_X, meta.name, perf); } catch (final IOException ex) { ok = error(Util.message(ex)); } finally { ok &= finishUpdate(); } return ok; }
/** * Evaluates the specified query. * * @param query query * @return success flag */ final boolean query(final String query) { final Performance p = new Performance(); String error; if (exception != null) { error = Util.message(exception); } else { try { long hits = 0; final boolean run = options.get(MainOptions.RUNQUERY); final boolean serial = options.get(MainOptions.SERIALIZE); final int runs = Math.max(1, options.get(MainOptions.RUNS)); for (int r = 0; r < runs; ++r) { // reuse existing processor instance if (r != 0) qp = null; qp(query, context); parse(p); if (r == 0) plan(false); qp.compile(); info.compiling += p.time(); if (r == 0) plan(true); if (!run) continue; final PrintOutput po = r == 0 && serial ? out : new NullOutput(); try (final Serializer ser = qp.getSerializer(po)) { if (maxResults >= 0) { result = qp.cache(maxResults); info.evaluating += p.time(); result.serialize(ser); hits = result.size(); } else { hits = 0; final Iter ir = qp.iter(); info.evaluating += p.time(); for (Item it; (it = ir.next()) != null; ) { ser.serialize(it); ++hits; checkStop(); } } } qp.close(); info.serializing += p.time(); } // dump some query info // out.flush(); // remove string list if global locking is used and if query is updating if (soptions.get(StaticOptions.GLOBALLOCK) && qp.updating) { info.readLocked = null; info.writeLocked = null; } return info(info.toString(qp, out.size(), hits, options.get(MainOptions.QUERYINFO))); } catch (final QueryException | IOException ex) { exception = ex; error = Util.message(ex); } catch (final ProcException ex) { error = INTERRUPTED; } catch (final StackOverflowError ex) { Util.debug(ex); error = BASX_STACKOVERFLOW.desc; } catch (final RuntimeException ex) { extError(""); Util.debug(info()); throw ex; } finally { // close processor after exceptions if (qp != null) qp.close(); } } return extError(error); }
/** * Constructor, specifying an exception or error. {@link QueryError#BASX_GENERIC_X} will be set as * error code. * * @param cause exception or error */ public QueryException(final Throwable cause) { this(Util.message(cause)); }