Package org.geoserver.geofence.cache

Source Code of org.geoserver.geofence.cache.CachedRuleReader$NoAuthException

/*
*  Copyright (C) 2007 - 2014 GeoSolutions S.A.S.
*  http://www.geo-solutions.it
*
*  GPLv3 + Classpath exception
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.geoserver.geofence.cache;

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geoserver.geofence.config.GeoFenceConfigurationManager;
import org.geoserver.geofence.services.RuleReaderService;
import org.geoserver.geofence.services.dto.AccessInfo;
import org.geoserver.geofence.services.dto.AuthUser;
import org.geoserver.geofence.services.dto.RuleFilter;
import org.geoserver.geofence.services.dto.ShortRule;
import org.geotools.util.logging.Logging;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.CacheStats;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

/**
* A delegating {@link RuleReaderService} with caching capabilities.
* <P/>
* Cache eviction policy is LRU.<br/>
* Cache coherence is handled by entry timeout.<br/>
* <p/>
*
* @author ETj (etj at geo-solutions.it)
*/
public class CachedRuleReader implements RuleReaderService {

    static final Logger LOGGER = Logging.getLogger(CachedRuleReader.class);

    private RuleReaderService realRuleReaderService;

    private LoadingCache<RuleFilter, AccessInfo> ruleCache;
    private LoadingCache<NamePw, AuthUser>       userCache;

    private final GeoFenceConfigurationManager configurationManager;

    /**
     * Latest configuration used
     */
    private CacheConfiguration cacheConfiguration = new CacheConfiguration();
   
    public CachedRuleReader(GeoFenceConfigurationManager configurationManager) {
        this.configurationManager = configurationManager;

        // pull config when initializing
        init();
    }


    /**
     * (Re)Init the cache, pulling the configuration from the configurationManager.
     *
     * Please use {@link #getCacheInitParams() } to set the cache parameters before
     * <code>init()</code>ting the cache
     */
    public final void init() {

        cacheConfiguration = configurationManager.getCacheConfiguration();

        ruleCache  = getCacheBuilder().build(new RuleLoader());
        userCache = getCacheBuilder().build(new UserLoader());
    }


    protected CacheBuilder getCacheBuilder() {
        CacheBuilder builder = CacheBuilder.newBuilder()
                .maximumSize(cacheConfiguration.getSize())
                .refreshAfterWrite(cacheConfiguration.getRefreshMilliSec(), TimeUnit.MILLISECONDS) // reloadable after x time
                .expireAfterWrite(cacheConfiguration.getExpireMilliSec(), TimeUnit.MILLISECONDS) // throw away entries too old
                .recordStats()
                ;
        //.expireAfterAccess(timeoutMillis, TimeUnit.MILLISECONDS)
        //                .removalListener(MY_LISTENER)
        // this should only be used while testing
        if(cacheConfiguration.getCustomTicker() != null) {
            LOGGER.log(Level.SEVERE, "Setting a custom Ticker in the cache {0}", cacheConfiguration.getCustomTicker().getClass().getName());
            builder.ticker(cacheConfiguration.getCustomTicker());
        }
        return builder;
    }



    private class RuleLoader extends CacheLoader<RuleFilter, AccessInfo> {

        @Override
        public AccessInfo load(RuleFilter filter) throws Exception {
            if(LOGGER.isLoggable(Level.FINE))
                LOGGER.log(Level.FINE, "Loading {0}", filter);
            return realRuleReaderService.getAccessInfo(filter);
        }

        @Override
        public ListenableFuture<AccessInfo> reload(final RuleFilter filter, AccessInfo accessInfo) throws Exception {
            if(LOGGER.isLoggable(Level.FINE))
                LOGGER.log(Level.FINE, "Reloading {0}", filter);

            // this is a sync implementation
            AccessInfo ret = realRuleReaderService.getAccessInfo(filter);
            return Futures.immediateFuture(ret);

            // next there is an asynchronous implementation, but in tests it seems to hang
//            return ListenableFutureTask.create(new Callable<AccessInfo>() {
//                @Override
//                public AccessInfo call() throws Exception {
//                    if(LOGGER.isLoggable(Level.FINE))
//                        LOGGER.log(Level.FINE, "Asynch reloading {0}", filter);
//                    return realRuleReaderService.getAccessInfo(filter);
//                }
//            });
        }
    }

    private class UserLoader extends CacheLoader<NamePw, AuthUser> {

        @Override
        public AuthUser load(NamePw user) throws NoAuthException {
            if(LOGGER.isLoggable(Level.FINE))
                LOGGER.log(Level.FINE, "Loading user '"+user.getName()+"'");
            AuthUser auth = realRuleReaderService.authorize(user.getName(), user.getPw());
            if(auth==null)
                throw new NoAuthException("Can't auth user ["+user.getName()+"]");
            return auth;
        }

        @Override
        public ListenableFuture<AuthUser> reload(final NamePw user, AuthUser authUser) throws NoAuthException {
            if(LOGGER.isLoggable(Level.FINE))
                LOGGER.log(Level.FINE, "Reloading user '"+user.getName()+"'");

            // this is a sync implementation
            AuthUser auth = realRuleReaderService.authorize(user.getName(), user.getPw());
            if(auth==null)
                throw new NoAuthException("Can't auth user ["+user.getName()+"]");
            return Futures.immediateFuture(auth);

            // todo: we may want a asynchronous implementation
        }
    }

    public void invalidateAll() {
        if(LOGGER.isLoggable(Level.WARNING))
            LOGGER.log(Level.WARNING, "Forcing cache invalidation");
        ruleCache.invalidateAll();
        userCache.invalidateAll();
    }

    /**
     * <B>Deprecated method are not cached.</B>
     *
     * @deprecated Use {@link #getAccessInfo(RuleFilter filter) }
     */
    @Override
    public AccessInfo getAccessInfo(String userName, String profileName, String instanceName, String sourceAddress, String service, String request, String workspace, String layer) {
        LOGGER.severe("DEPRECATED METHODS ARE NOT CACHED");
        return realRuleReaderService.getAccessInfo(userName, profileName, instanceName, sourceAddress, service, request, workspace, layer);
    }

    private AtomicLong dumpCnt = new AtomicLong(0);

    @Override
    public AccessInfo getAccessInfo(RuleFilter filter) {
        if(LOGGER.isLoggable(Level.FINE))
            LOGGER.log(Level.FINE, "Request for {0}", filter);

        if(LOGGER.isLoggable(Level.INFO))
            if(dumpCnt.incrementAndGet() % 10 == 0) {
                LOGGER.info("Rules  :"+ruleCache.stats());
                LOGGER.info("Users  :"+userCache.stats());
                LOGGER.fine("params :"+cacheConfiguration);
            }

        try {
            return ruleCache.get(filter);
        } catch (ExecutionException ex) {
            throw new RuntimeException(ex); // fixme: handle me
        }
    }

    /**
     * <B>Deprecated method are not cached.</B>
     *
     * @deprecated Use {@link #getMatchingRules(RuleFilter filter) }
     */
    @Override
    public List<ShortRule> getMatchingRules(String userName, String profileName, String instanceName, String sourceAddress, String service, String request, String workspace, String layer) {
        LOGGER.severe("DEPRECATED METHODS ARE NOT CACHED");
        return realRuleReaderService.getMatchingRules(userName, profileName, instanceName, sourceAddress, service, request, workspace, layer);
    }

    @Override
    public List<ShortRule> getMatchingRules(RuleFilter filter) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public AuthUser authorize(String username, String password) {
        try {
            return userCache.get(new NamePw(username, password));
//        } catch (NoAuthException ex) {
//            LOGGER.warning(ex.getMessage());
//            return null;
        } catch (ExecutionException ex) {
            LOGGER.warning(ex.getMessage());
            return null;
        }
       
    }


    //--------------------------------------------------------------------------
    public void setRealRuleReaderService(RuleReaderService realRuleReaderService) {
        this.realRuleReaderService = realRuleReaderService;
    }


    public CacheConfiguration getCacheInitParams() {
        return cacheConfiguration;
    }

    public CacheStats getStats() {
        return ruleCache.stats();
    }

    public CacheStats getUserStats() {
        return userCache.stats();
    }

    public long getCacheSize() {
        return ruleCache.size();
    }

    public long getUserCacheSize() {
        return userCache.size();
    }

    /**
     * May be useful if an external peer doesn't want to use the guava dep.
     */
    public String getStatsString() {
        return ruleCache.stats().toString();
    }

    @Override
    public String toString() {
        return getClass().getSimpleName()
                +"["
                + "Rule:"+ruleCache.stats()
                + " User:"+userCache.stats()
                + " " + cacheConfiguration
                + "]";
    }

    protected static class NamePw {
        private String name;
        private String pw;

        public NamePw() {
        }

        public NamePw(String name, String pw) {
            this.name = name;
            this.pw = pw;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getPw() {
            return pw;
        }

        public void setPw(String pw) {
            this.pw = pw;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 89 * hash + (this.name != null ? this.name.hashCode() : 0);
            hash = 89 * hash + (this.pw != null ? this.pw.hashCode() : 0);
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final NamePw other = (NamePw) obj;
            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
                return false;
            }
            if ((this.pw == null) ? (other.pw != null) : !this.pw.equals(other.pw)) {
                return false;
            }
            return true;
        }
    }

    class NoAuthException extends Exception {

        public NoAuthException() {
        }

        public NoAuthException(String message) {
            super(message);
        }

        public NoAuthException(String message, Throwable cause) {
            super(message, cause);
        }

        public NoAuthException(Throwable cause) {
            super(cause);
        }
   
    }
}
TOP

Related Classes of org.geoserver.geofence.cache.CachedRuleReader$NoAuthException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.