예제 #1
0
  /**
   * Adds a local function.
   *
   * @param fun function instance
   * @param ii input info
   * @return function id
   * @throws QueryException query exception
   */
  public int add(final UserFunc fun, final InputInfo ii) throws QueryException {
    final QNm name = fun.name;
    final byte[] uri = name.uri();
    if (uri.length == 0) FUNNONS.thrw(ii, name.string());

    if (NSGlobal.reserved(uri)) {
      if (fun.declared) NAMERES.thrw(ii, name.string());
      funError(name, ii);
    }

    final byte[] ln = name.local();
    for (int l = 0; l < funcs.length; ++l) {
      final QNm qn = funcs[l].name;
      final byte[] u = qn.uri();
      final byte[] nm = qn.local();

      if (eq(ln, nm) && eq(uri, u) && fun.args.length == funcs[l].args.length) {
        // declare function that has been called before
        if (!funcs[l].declared) {
          funcs[l] = fun;
          return l;
        }
        // duplicate declaration
        FUNCDEFINED.thrw(ii, fun.name.string());
      }
    }
    // add function skeleton
    funcs = Array.add(funcs, fun);
    calls = Array.add(calls, new UserFuncCall[0]);
    return funcs.length - 1;
  }
예제 #2
0
  /**
   * 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);
    }
  }
예제 #3
0
  /**
   * Finds similar function names and throws an error message.
   *
   * @param name function name
   * @param ii input info
   * @throws QueryException query exception
   */
  public void funError(final QNm name, final InputInfo ii) throws QueryException {
    // find global function
    Functions.get().error(name, ii);

    // find similar local function
    final Levenshtein ls = new Levenshtein();
    final byte[] nm = lc(name.local());
    for (final UserFunc f : funcs) {
      if (ls.similar(nm, lc(f.name.local()), 0)) {
        FUNSIMILAR.thrw(ii, name.string(), f.name.string());
      }
    }
  }
예제 #4
0
 /**
  * Throws an error if one of the pre-defined functions is similar to the specified function name.
  *
  * @param name function name
  * @param ii input info
  * @throws QueryException query exception
  */
 public void error(final QNm name, final InputInfo ii) throws QueryException {
   // compare specified name with names of predefined functions
   final byte[] ln = name.local();
   final Levenshtein ls = new Levenshtein();
   for (int k = 1; k < size; ++k) {
     final int i = indexOf(keys[k], '}');
     final byte[] u = substring(keys[k], 2, i);
     final byte[] l = substring(keys[k], i + 1);
     if (eq(ln, l)) {
       final byte[] ur = name.uri();
       FUNSIMILAR.thrw(
           ii,
           new TokenBuilder(NSGlobal.prefix(ur)).add(':').add(l),
           new TokenBuilder(NSGlobal.prefix(u)).add(':').add(l));
     } else if (ls.similar(ln, l, 0)) {
       FUNSIMILAR.thrw(ii, name.string(), l);
     }
   }
 }
예제 #5
0
  /**
   * Returns a new Java function instance.
   *
   * @param name function name
   * @param args arguments
   * @param qc query context
   * @param sc static context
   * @param ii input info
   * @return Java function or {@code null}
   * @throws QueryException query exception
   */
  static JavaMapping get(
      final QNm name,
      final Expr[] args,
      final QueryContext qc,
      final StaticContext sc,
      final InputInfo ii)
      throws QueryException {

    final byte[] uri = name.uri();
    // check if URI starts with "java:" prefix (if yes, module must be Java code)
    final boolean java = startsWith(uri, JAVAPREF);

    // rewrite function name: convert dashes to upper-case initials
    final String local = camelCase(string(name.local()));

    // check imported Java modules
    final String path = camelCase(toPath(java ? substring(uri, JAVAPREF.length) : uri));

    final ModuleLoader modules = qc.resources.modules();
    final Object jm = modules.findImport(path);
    if (jm != null) {
      final Method meth = getModMethod(jm, path, local, args.length, qc, ii);
      if (meth != null) return new JavaModuleFunc(sc, ii, jm, meth, args);
    }

    // only allowed with administrator permissions
    if (!qc.context.user.has(Perm.ADMIN)) return null;

    // check addressed class
    try {
      return new JavaFunc(sc, ii, modules.findClass(path), local, args);
    } catch (final ClassNotFoundException ex) {
      // only throw exception if "java:" prefix was explicitly specified
      if (java) throw FUNCJAVA_X.get(ii, path);
    } catch (final Throwable th) {
      throw JAVAINIT_X.get(ii, th);
    }

    // no function found
    return null;
  }
예제 #6
0
  /**
   * Returns an instance of a with the specified name and number of arguments, or {@code null}.
   *
   * @param name name of the function
   * @param args optional arguments
   * @param dyn compile-/run-time flag
   * @param ctx query context
   * @param ii input info
   * @return function instance
   * @throws QueryException query exception
   */
  public static TypedFunc get(
      final QNm name,
      final Expr[] args,
      final boolean dyn,
      final QueryContext ctx,
      final InputInfo ii)
      throws QueryException {

    // get namespace and local name
    // parse data type constructors
    if (eq(name.uri(), XSURI)) {
      final byte[] ln = name.local();
      final AtomType type = AtomType.find(name, false);
      if (type == null) {
        final Levenshtein ls = new Levenshtein();
        for (final AtomType t : AtomType.values()) {
          if (t.par != null
              && t != AtomType.NOT
              && t != AtomType.AAT
              && t != AtomType.BIN
              && ls.similar(lc(ln), lc(t.string()), 0))
            FUNSIMILAR.thrw(ii, name.string(), t.string());
        }
      }
      // no constructor function found, or abstract type specified
      if (type == null || type == AtomType.NOT || type == AtomType.AAT) {
        FUNCUNKNOWN.thrw(ii, name.string());
      }

      if (args.length != 1) FUNCTYPE.thrw(ii, name.string());
      final SeqType to = SeqType.get(type, Occ.ZERO_ONE);
      return TypedFunc.constr(new Cast(ii, args[0], to), to);
    }

    // pre-defined functions
    final StandardFunc fun = Functions.get().get(name, args, ii);
    if (fun != null) {
      if (!ctx.sc.xquery3 && fun.xquery3()) FEATURE30.thrw(ii);
      for (final Function f : Function.UPDATING) {
        if (fun.sig == f) {
          ctx.updating(true);
          break;
        }
      }
      return new TypedFunc(fun, fun.sig.type(args.length));
    }

    // user-defined function
    final TypedFunc tf = ctx.funcs.get(name, args, ii);
    if (tf != null) return tf;

    // Java function (only allowed with administrator permissions)
    final JavaMapping jf = JavaMapping.get(name, args, ctx, ii);
    if (jf != null) return TypedFunc.java(jf);

    // add user-defined function that has not been declared yet
    if (!dyn && FuncType.find(name) == null) return ctx.funcs.add(name, args, ii, ctx);

    // no function found
    return null;
  }
예제 #7
0
  /**
   * 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;
  }