/* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wamblee.security.authorization.jpa; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.NonUniqueResultException; import org.wamblee.cache.ComputedValue; import org.wamblee.cache.ComputedValue.Computation; import org.wamblee.persistence.JpaMergeSupport; import org.wamblee.security.authentication.UserAccessor; import org.wamblee.security.authentication.UserAdministration; import org.wamblee.security.authorization.AbstractAuthorizationService; import org.wamblee.security.authorization.AbstractAuthorizationRule; import org.wamblee.security.authorization.AuthorizationRule; import org.wamblee.security.authorization.AuthorizationService; import org.wamblee.security.authorization.DefaultAuthorizationService; import org.wamblee.security.authorization.Operation; /** * Authorization service with persistent storage. This is a wrapper for * {@link org.wamblee.security.authorization.DefaultAuthorizationService} which * refreshes the state of the service at certain time intervals. * * @author Erik Brakkee */ public class JpaAuthorizationService implements AuthorizationService { /** * Authorization service to use. */ private ComputedValue service; /** * Hibernate template to use. */ private EntityManager entityManager; /** * User accessor. */ private UserAccessor userAccessor; /** * User administration. */ private UserAdministration userAdmin; /** * Name of the service. */ private String name; /** * Refresh interval in milliseconds. */ private final long refreshInterval; /** * Last refresh time. */ private long lastRefreshTime; /** * Constructs the persistent service. * * @param aName * Name of the service. * @param aEntityManager * Entity manager. * @param aAccessor * User accessor. * @param aUserAdmin * User administration. * @param aRefresh * Whether or not to refresh the state of the service at the * start of every operation. */ public JpaAuthorizationService(String aName, EntityManager aEntityManager, UserAccessor aAccessor, UserAdministration aUserAdmin, long aRefreshInterval) { entityManager = aEntityManager; refreshInterval = aRefreshInterval; lastRefreshTime = System.currentTimeMillis(); userAccessor = aAccessor; userAdmin = aUserAdmin; name = aName; Computation computation = new Computation() { @Override public boolean isOutOfDate() { long time = System.currentTimeMillis(); return service.getCached() == null || (time - lastRefreshTime) > refreshInterval; } @Override public AuthorizationService compute() { AuthorizationService svc = refreshByReload(); lastRefreshTime = System.currentTimeMillis(); return svc; } }; service = new ComputedValue(this, computation); } @Override public void setUserAccessor(UserAccessor aUserAccessor) { userAccessor = aUserAccessor; } @Override public void setUserAdministration(UserAdministration aUserAdmin) { userAdmin = aUserAdmin; } private AuthorizationService refreshByReload() { AuthorizationService svc; try { svc = entityManager.createNamedQuery( AbstractAuthorizationService.QUERY_FIND_BY_NAME, AbstractAuthorizationService.class).setParameter( DefaultAuthorizationService.NAME_PARAM, name).getSingleResult(); svc.setUserAccessor(userAccessor); svc.setUserAdministration(userAdmin); } catch (NonUniqueResultException e) { throw new IllegalArgumentException( "Returned more than one service for name '" + name + "'"); } catch (NoResultException e) { svc = new DefaultAuthorizationService(userAccessor, userAdmin, name); entityManager.persist(svc); } return svc; } /* * (non-Javadoc) * * @see * org.wamblee.security.authorization.AuthorizationService#isAllowed(java * .lang.Object, org.wamblee.security.authorization.Operation) */ public boolean isAllowed(Object aResource, Operation aOperation) { return service.get().isAllowed(aResource, aOperation); } /* * (non-Javadoc) * * @see org.wamblee.security.authorization.AuthorizationService#check(T, * org.wamblee.security.authorization.Operation) */ public T check(T aResource, Operation aOperation) { return service.get().check(aResource, aOperation); } /* * (non-Javadoc) * * @see org.wamblee.security.authorization.AuthorizationService#getRules() */ public AuthorizationRule[] getRules() { return service.get().getRules(); } /* * (non-Javadoc) * * @see * org.wamblee.security.authorization.AuthorizationService#appendRule(org * .wamblee.security.authorization.AuthorizationRule) */ public void appendRule(AuthorizationRule aRule) { AuthorizationService svc = refreshByReload(); svc.appendRule(aRule); // Setting service to null will force reload the next time the // service is used. This deals effectively with the case where the // current transaction would roll back and the change would not have // been made. service.set(null); } /* * (non-Javadoc) * * @see * org.wamblee.security.authorization.AuthorizationService#removeRule(int) */ public void removeRule(int aIndex) { AuthorizationService svc = refreshByReload(); svc.removeRule(aIndex); service.set(null); } /* * (non-Javadoc) * * @see * org.wamblee.security.authorization.AuthorizationService#insertRuleAfter * (int, org.wamblee.security.authorization.AuthorizationRule) */ public void insertRuleAfter(int aIndex, AuthorizationRule aRule) { AuthorizationService svc = refreshByReload(); svc.insertRuleAfter(aIndex, aRule); service.set(null); } }