如何使用Monadic Bind简化此Apache Tomcat代码?

时间:2015-12-24 09:09:54

标签: java haskell bind monads nested-if

commentator writes

  

一些不错的标志"大于标志" Tomcat中的代码。需要健康剂量的(>> =)。

查看the AuthenticatorBase.java class from Apache Tomcat

/**
 * Enforce the security restrictions in the web application deployment
 * descriptor of our associated Context.
 *
 * @param request Request to be processed
 * @param response Response to be processed
 *
 * @exception IOException if an input/output error occurs
 * @exception ServletException if thrown by a processing element
 */
@Override
public void invoke(Request request, Response response)
    throws IOException, ServletException {

    if (log.isDebugEnabled())
        log.debug("Security checking request " +
            request.getMethod() + " " + request.getRequestURI());
    LoginConfig config = this.context.getLoginConfig();

    // Have we got a cached authenticated Principal to record?
    if (cache) {
        Principal principal = request.getUserPrincipal();
        if (principal == null) {
            Session session = request.getSessionInternal(false);
            if (session != null) {
                principal = session.getPrincipal();
                if (principal != null) {
                    if (log.isDebugEnabled())
                        log.debug("We have cached auth type " +
                            session.getAuthType() +
                            " for principal " +
                            session.getPrincipal());
                    request.setAuthType(session.getAuthType());
                    request.setUserPrincipal(principal);
                }
            }
        }
    }

我必须承认,我不知道如何应用它。我知道有可能有一种方法可以将if-tree重构为monadic绑定,但我不知道该怎么做。

假设:

  • 这不是关于语言,而是关于逻辑结构。你可以在Haskell或Scala或Clojure中表示这个if-tree,它仍然代表相同的if-logic。

我的问题是:如何使用Monadic Bind简化此Apache Tomcat代码?

1 个答案:

答案 0 :(得分:1)

嗯,这里你有副作用(request.set...),并且当你没有时,绑定更有用。使用ifPresent就足够了:

Optional.ofNullable(principal).ifPresent(principal ->
  Optional.ofNullable(request.getSessionInternal(false)).ifPresent(session ->
    Optional.ofNullable(session.getPrincipal).ifPresent(principal -> {
      if (log.isDebugEnabled())
        log.debug(...);
      request.setAuthType(session.getAuthType());
      request.setUserPrincipal(principal);
    })));

这可能看起来不像是胜利;如果Optional.ofNullable(...)request.getSessionInternal已经返回session.getPrincipal,则必须重复Optional

你可以写一个像Optional.ofNullable(...).ifPresent一样的方法:

public static <T> void ifNotNull(T value, Consumer<? super T> consumer) {
  if (value != null) { consumer.accept(value); }
}

ifNotNull(principal, principal ->
  ifNotNull(request.getSessionInternal(false), session ->
    ifNotNull(session.getPrincipal, principal -> {
      if (log.isDebugEnabled())
        log.debug(...);
      request.setAuthType(session.getAuthType());
      request.setUserPrincipal(principal);
    })));

(注意:我不确定我是否完全记得Java语法,但我还没有使用它一段时间。)