/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */
package foam.nanos.auth;

import foam.core.X;
import foam.nanos.session.Session;
import java.security.Permission;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import javax.security.auth.AuthPermission;

/**
 * Decorator to add Caching to AuthService.
 * Stores cache in user Session so that memory is freed when user logs out.
 **/
public class CachingAuthService
  extends ProxyAuthService
{

  protected static String CACHE_KEY = "CachingAuthService.PermissionCache";

  protected static Map getPermissionMap(X x) {
    Map map = (Map) x.get(CACHE_KEY);

    if ( map == null ) {
      Session session = (Session) x.get(Session.class);
      map = new ConcurrentHashMap();
      session.setContext(session.getContext().put(CACHE_KEY, map));
    }

    return map;
  }

  public static void purgeCache(X x) {
    getPermissionMap(x).clear();
  }

  public CachingAuthService(AuthService delegate) {
    setDelegate(delegate);
  }

  @Override
  public boolean checkPermission(foam.core.X x, java.security.Permission permission) {
    if ( x == null || permission == null ) return false;

    Map map = getPermissionMap(x);

    if ( map.containsKey(permission.getName()) ) {
      return ((Boolean) map.get(permission.getName())).booleanValue();
    }

    boolean permissionCheck = getDelegate().checkPermission(x, permission);

    map.put(permission.getName(), permissionCheck);

    return permissionCheck;
  }

  @Override
  public boolean check(foam.core.X x, String permission) {
    return checkPermission(x, new AuthPermission(permission));
  }
}

@@ -162,16 +162,43 @@
 core.X;%0A
+import foam.core.XFactory;%0A
 import f
@@ -370,16 +370,546 @@
 ssion;%0A%0A
+%0A/** Only return value if the session context hasn't changed. **/%0Aclass SessionContextCacheFactory%0A  implements XFactory%0A%7B%0A  protected X      sessionX_;%0A  protected Object value_;%0A%0A  public SessionContextCacheFactory(Object value) %7B%0A    value_ = value;%0A  %7D%0A%0A  public Object create(X x) %7B%0A    Session session = (Session) x.get(Session.class);%0A    if ( session == null ) return null;%0A    if ( sessionX_ == null ) sessionX_ = session.getContext();%0A    if ( sessionX_ != session.getContext() ) return null;%0A    return value_;%0A  %7D%0A%7D%0A%0A%0A
 /**%0A * D
@@ -1223,123 +1223,140 @@
     
-Map map = (Map) x.get(CACHE_KEY);%0A%0A    if ( map == null ) %7B%0A      Session session = (Session) x.get(Session.class);
+Session session = (Session) x.get(Session.class);%0A    Map map = (Map) session.getContext().get(CACHE_KEY);%0A%0A    if ( map == null ) %7B
 %0A   
@@ -1442,25 +1442,81 @@
 .put
-(CACHE_KEY, 
+Factory(%0A        CACHE_KEY,%0A        new SessionContextCacheFactory(
 map))
+)
 ;%0A  

Purge CachingAutService cache if user session Context changes.