public String authenticateAction(String actionname, Map actionconfig) {
    HttpServletRequest request = RequestContext.getHttpRequest();
    String failureaction = null;
    boolean authenticated = false;

    List authlist = null;
    if (actionconfig.containsKey("Authentication")) {
      // action-specific authenticator
      authlist = (List) CfgUtils.lookup(actionconfig, "[authentication][authenticators]");
    } else {
      // exec global authenticators
      /*-trc-*/ Lg.trc("get GLOBAL authenticators");
      authlist =
          (List) CfgUtils.lookup(WebConfig, "[global defaults][authentication][authenticator]");
    }

    if (authlist != null) {
      for (int i = 0; i < authlist.size(); i++) {
        /*-trc-*/ Lg.trc("exec auth #%d", i);
        Map auth = (Map) authlist.get(i);
        IAuthenticator authenticator = null;
        try {
          /*-trc-*/ Lg.trc("instantiating auth plugin %s", auth != null ? auth.get("class") : null);
          authenticator = (IAuthenticator) PluginLoader.loadPlugin((String) auth.get("class"));
        } catch (Exception e) {
          /*-ERROR-*/ Lg.err("Load of Authenticator plugin threw an error", e);
          EEx.create("CfgErr-AuthCreateError", "Load of Authenticator plugin threw an error", e);
        }

        try {
          /*-trc-*/ Lg.trc("EXEC AUTH plugin");
          authenticated =
              authenticator.authenticate((Map) auth.get("config"), actionname, actionconfig);
          /*-trc-*/ Lg.trc("AUTH EXEC result: %b", authenticated);
          if (!authenticated) {
            /*-trc-*/ Lg.trc("auth failure --> store original action, failing plugin, and context");
            if (auth.containsKey("authfailaction")) {
              failureaction = (String) auth.get("authfailaction");
              /*-trc-*/ Lg.trc(
                  "auth failure --> redirecting to auth plugin-specific action %s to handle failed authentication",
                  failureaction);
            } else {
              // TODO: ?more granularity?
              // use global action
              failureaction =
                  (String)
                      CfgUtils.lookup(
                          WebConfig, "[global defaults][authentication][authfailaction]");
              /*-trc-*/ Lg.trc(
                  "auth failure --> redirecting to globally specified action %s to handle failed authentication",
                  failureaction);
            }

            i = authlist.size(); // stop checking authentication
          }
        } catch (Exception e) {
          /*-ERROR-*/ Lg.err(
              "Execution of authorization check of %s threw error",
              auth != null ? auth.get("AuthClass") : null, e);
          EEx.create(
              "AuthCheckErr",
              "Execution of authorization check of %s threw error",
              auth != null ? auth.get("AuthClass") : null,
              e);
        }
      }
    }

    return failureaction;
  }
  public String executeAction(
      String actionname, Map actionconfig, String responsediv, ActionContext actioncontext) {
    /*-INFO-*/ Lg.inf("Process request"); // TODO: more in-depth trace logging on the request
    HttpServletRequest request = RequestContext.getHttpRequest();
    Map progitcontext = new HashMap();

    // execute action (action will have been overridden with an erroraction in error/login redirect
    // situations)
    /*-trc-*/ Lg.trc("begin progit execution for action %s", actionname);
    List progits = (List) actionconfig.get("Processing");
    for (int i = 0; i < progits.size(); i++) {
      /*-trc-*/ Lg.trc("progit #%d", i);
      Map progitdef = (Map) progits.get(i);
      IProgit progit = null;

      // progit class load
      String progitclass = (String) progitdef.get("Class");
      /*-trc-*/ Lg.trc("instantiating progit %s", progitclass);
      try {
        progit = (IProgit) PluginLoader.loadPlugin(progitclass);
      } catch (Exception e) {
        /*-ERROR-*/ Lg.err("progit load error for %s", progitclass, e);
        throw EEx.create(
            "CfgErr-ActionClass",
            "Controller Action plugin instantiation error: %s",
            progitclass,
            e);
      }

      /*-trc-*/ Lg.trc("set progit config in actioncontext");
      actioncontext.setPluginConfig((Map) progitdef.get("Config"));

      // progit exec
      /*-trc-*/ Lg.trc("EXECUTING");
      try {
        // process the progit args
        Map progitargs = (Map) progitdef.get("Args");
        if (progitargs != null) {
          /*-trc-*/ Lg.trc("process progit arguments");
          Map argmap = new HashMap();
          for (int arg = 0; arg < progitargs.size(); arg++) {
            /*-trc-*/ Lg.trc("  arg #%d", arg);
            Arg argdef = (Arg) progitargs.get(arg);
            String contextkey = Is.empty(argdef.Key) ? argdef.Name : argdef.Key;
            if (Is.empty(argdef.Source) || "literal".equals(argdef.Source)) {
              /*-trc-*/ Lg.trc(
                  "  literal key: %s val: %s", contextkey, argdef != null ? argdef.Value : null);
              argmap.put(contextkey, argdef.Value);
            } else if ("http".equals(argdef.Source)) {
              String[] vals = request.getParameterValues(argdef.Name);
              if (vals != null && vals.length == 1) {
                /*-trc-*/ Lg.trc("  http key: %s val: %s", contextkey, vals[0]);
                argmap.put(contextkey, vals[0]);
              } else {
                /*-trc-*/ if (Lg.trc()) {
                  String s = "";
                  if (vals != null) for (int ss = 0; ss < vals.length; ss++) s += vals[ss];
                  Lg.trc("  http key: %s val: ", contextkey, s);
                }
                argmap.put(contextkey, vals);
              }
            } else if ("input".equals(argdef.Source)) {
              /*-trc-*/ Lg.trc("  input key: %s val: %s", contextkey, responsediv);
              argmap.put(contextkey, responsediv);
            } else if ("global".equals(argdef.Source)) {
              ServletConfig srvcfg = getServletConfig();
              Object val = srvcfg.getServletContext().getAttribute(argdef.Name);
              /*-trc-*/ Lg.trc("  global key: %s val: %s", contextkey, val.toString());
              argmap.put(contextkey, val);
            } else if ("resource".equals(argdef.Source)) {
              String content =
                  ResourceLoader.loadResource(
                      argdef.LocalUrl, argdef.Url, argdef.File, argdef.Resource);
              /*-trc-*/ Lg.trc("  resource key: %s val: %s", contextkey, content);
              argmap.put(contextkey, content);
            } else if ("context".equals(argdef.Source)) { // remap a context key
              Object o = actioncontext.getProcessingContextMap().get(argdef.Name);
              /*-trc-*/ Lg.trc("  context key: %s val: %s", contextkey, o);
              argmap.put(contextkey, o);
            } else if ("config".equals(argdef.Source)) { // load a config key
              argmap.put(contextkey, ((Map) ((Map) progitdef).get("Config")).get(argdef.Name));
            } else if ("action".equals(argdef.Source)) {
              // TODO...
            } else if ("pathinfo".equals(argdef.Source)) {
              String extrapathinfo = this.getActionPathInfo(request);
              /*-trc-*/ Lg.trc("  pathinfo key: %s val: %s", contextkey, extrapathinfo);
              argmap.put(contextkey, extrapathinfo);
            }
          }
          /*-trc-*/ Lg.trc("set argmap in action context");
          actioncontext.setArgMap(argmap);
        } else {
          actioncontext.setArgMap(null);
        }
        try {
          /*-trc-*/ Lg.trc("====EXEC PROGIT====");
          responsediv = progit.execute(progitdef, actioncontext, responsediv);
          /*-trc-*/ Lg.trc("===PROGIT EXEC DONE===");
          actioncontext.setPluginConfig(null);
        } catch (Exception e) {
          /*-ERROR-*/ Lg.err("progit exec error for %s", progitclass, e);
          throw ErrorService.packageActionError(
              actionname,
              i,
              actioncontext,
              "ActionExecErr",
              "progit exec error for %s",
              progitclass,
              e);
        }

        // check for jumps/redirects
        //                if (context.redirectaction != null) {
        //                    // REDIRECT!!!! -- TODO: may need to do authenticators for the new
        // action, lots of open questions here...
        //                    /*-trc-*/Lg.trc("redirecting to action %s",context.redirectaction);
        //                    // god this is sooooo beautifully dangerous and wrong: reset and
        // repoint the for loop...
        //                   action =
        // (LSActionHandler)WebConfig.Actions.get(context.redirectaction);
        //                   i = -1; // The devil commands it!
        //                   context.redirectaction = null;
        //                }
      } catch (Exception e) {
        /*-ERROR-*/ Lg.err("progit load error for %s", progitclass, e);
        throw ErrorService.packageActionError(
            actionname,
            i,
            actioncontext,
            "ActionExecErr",
            "Action exec of %s in action %s threw error",
            progitclass,
            e);
      }
    }

    return responsediv;
  }