All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.basex.http.ws.WsFunction Maven / Gradle / Ivy

The newest version!
package org.basex.http.ws;

import static org.basex.query.QueryError.*;
import static org.basex.util.Token.*;

import java.util.*;

import org.basex.core.*;
import org.basex.http.web.*;
import org.basex.query.*;
import org.basex.query.ann.*;
import org.basex.query.expr.*;
import org.basex.query.func.*;
import org.basex.query.util.list.*;
import org.basex.query.value.*;
import org.basex.query.value.item.*;
import org.basex.util.*;

/**
 * This class represents a single WebSocket function.
 *
 * @author BaseX Team 2005-24, BSD License
 * @author Johannes Finckh
 */
public final class WsFunction extends WebFunction {
  /** Path of the function. */
  public WsPath path;
  /** Message parameter. */
  private WebParam message;

  /**
   * Constructor.
   * @param function associated user function
   * @param module web module
   * @param qc query context
   */
  public WsFunction(final StaticFunc function, final WebModule module, final QueryContext qc) {
    super(function, module, qc);
  }

  @Override
  public boolean parseAnnotations(final Context ctx) throws QueryException {
    final boolean[] declared = new boolean[function.arity()];
    // counter for annotations that should occur only once
    boolean found = false;
    AnnList starts = AnnList.EMPTY;

    for(final Ann ann : function.anns) {
      final Annotation def = ann.definition;
      if(def == null || !eq(def.uri, QueryText.WS_URI)) continue;

      found = true;
      final Value value = ann.value();
      switch(def) {
        case _WS_HEADER_PARAM:
          final String name = toString(value.itemAt(0));
          final QNm var = checkVariable(toString(value.itemAt(1)), declared);
          final long vs = value.size();
          final ItemList items = new ItemList(vs - 2);
          for(int v = 2; v < vs; v++) items.add(value.itemAt(v));
          headerParams.add(new WebParam(var, name, items.value()));
          break;
        case _WS_CLOSE:
        case _WS_CONNECT:
          path = new WsPath(toString(value.itemAt(0)));
          starts = starts.attach(ann);
          break;
        case _WS_ERROR:
        case _WS_MESSAGE:
          final QNm msg = checkVariable(toString(value.itemAt(1)), declared);
          message = new WebParam(msg, "message", null);
          path = new WsPath(toString(value.itemAt(0)));
          starts = starts.attach(ann);
          break;
        default:
          break;
      }
    }
    return checkParsed(found, starts, declared);
  }

  /**
   * Binds the function parameters.
   * @param msg message (can be {@code null}; otherwise string or byte array)
   * @param values header values
   * @param qc query context
   * @return arguments
   * @throws QueryException query exception
   */
  Expr[] bind(final Object msg, final Map values,
      final QueryContext qc) throws QueryException {

    final Expr[] args = new Expr[function.arity()];
    if(msg != null) values.put("message", msg instanceof byte[] ?
      B64.get((byte[]) msg) : Str.get((String) msg));

    for(final WebParam param : headerParams) {
      bind(param.var, args, values.get(param.name), qc, "Value of \"" + param.name + '"');
    }
    if(message != null) {
      bind(message.var, args, values.get(message.name), qc, "Message");
    }
    return args;
  }

  /**
   * Checks if an WebSocket request matches this annotation and path.
   * @param definition annotation definition (can be {@code null})
   * @param pth path to compare to (can be {@code null})
   * @return boolean result of check
   */
  public boolean matches(final Annotation definition, final WsPath pth) {
    for(final Ann ann : function.anns) {
      if((definition == null || ann.definition == definition) &&
          (pth == null || path.compareTo(pth) == 0)) return true;
    }
    return false;
  }

  @Override
  public int compareTo(final WebFunction func) {
    return func instanceof WsFunction ? path.compareTo(((WsFunction) func).path) : 1;
  }

  /**
   * Creates an exception with the specified message.
   * @param msg message
   * @param ext error extension
   * @return exception
   */
  @Override
  public QueryException error(final String msg, final Object... ext) {
    return error(function.info, msg, ext);
  }

  // PRIVATE METHODS ==============================================================================

  /**
   * Creates an exception with the specific message.
   * @param info input info (can be {@code null})
   * @param msg error message
   * @param ext error extension
   * @return exception
   */
  private static QueryException error(final InputInfo info, final String msg, final Object... ext) {
    return BASEX_WS_X.get(info, Util.info(msg, ext));
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy