X-Git-Url: http://wamblee.org/gitweb/?a=blobdiff_plain;f=security%2Fimpl%2Fsrc%2Fmain%2Fjava%2Forg%2Fwamblee%2Fsecurity%2Fauthorization%2Fjpa%2FJpaAuthorizationService.java;h=333781c62e19bfa40ce0f2195d302bd870dfce88;hb=0edcb342c82db516dc7e9332b07213063c53372a;hp=57d29636c06cb261cb4d2e5e175b7706a37d4add;hpb=692be9f5aeb0f3a89c693339b1810a9f1844a2fe;p=utils diff --git a/security/impl/src/main/java/org/wamblee/security/authorization/jpa/JpaAuthorizationService.java b/security/impl/src/main/java/org/wamblee/security/authorization/jpa/JpaAuthorizationService.java index 57d29636..333781c6 100644 --- a/security/impl/src/main/java/org/wamblee/security/authorization/jpa/JpaAuthorizationService.java +++ b/security/impl/src/main/java/org/wamblee/security/authorization/jpa/JpaAuthorizationService.java @@ -19,14 +19,17 @@ 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; -import org.wamblee.usermgt.UserAccessor; /** * Authorization service with persistent storage. This is a wrapper for @@ -40,7 +43,7 @@ public class JpaAuthorizationService implements AuthorizationService { /** * Authorization service to use. */ - private AuthorizationService service; + private ComputedValue service; /** * Hibernate template to use. @@ -52,6 +55,11 @@ public class JpaAuthorizationService implements AuthorizationService { */ private UserAccessor userAccessor; + /** + * User administration. + */ + private UserAdministration userAdmin; + /** * Name of the service. */ @@ -76,50 +84,66 @@ public class JpaAuthorizationService implements AuthorizationService { * 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, long aRefreshInterval) { + 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; + userAccessor = aUserAccessor; } - /** - * Initialize service if needed. - * - */ - private void initialize() { - if (service == null) { - service = refreshByReload(); - } + @Override + public void setUserAdministration(UserAdministration aUserAdmin) { + userAdmin = aUserAdmin; } private AuthorizationService refreshByReload() { - AuthorizationService service; + AuthorizationService svc; try { - service = entityManager.createNamedQuery( + svc = entityManager.createNamedQuery( AbstractAuthorizationService.QUERY_FIND_BY_NAME, AbstractAuthorizationService.class).setParameter( - DefaultAuthorizationService.NAME_PARAM, name).getSingleResult(); - service.setUserAccessor(userAccessor); + 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) { - service = new DefaultAuthorizationService(userAccessor, name); - entityManager.persist(service); + svc = new DefaultAuthorizationService(userAccessor, userAdmin, name); + entityManager.persist(svc); } - return service; + return svc; } /* @@ -130,10 +154,7 @@ public class JpaAuthorizationService implements AuthorizationService { * .lang.Object, org.wamblee.security.authorization.Operation) */ public boolean isAllowed(Object aResource, Operation aOperation) { - initialize(); - refresh(); - - return service.isAllowed(aResource, aOperation); + return service.get().isAllowed(aResource, aOperation); } /* @@ -143,10 +164,7 @@ public class JpaAuthorizationService implements AuthorizationService { * org.wamblee.security.authorization.Operation) */ public T check(T aResource, Operation aOperation) { - initialize(); - refresh(); - - return service.check(aResource, aOperation); + return service.get().check(aResource, aOperation); } /* @@ -155,10 +173,7 @@ public class JpaAuthorizationService implements AuthorizationService { * @see org.wamblee.security.authorization.AuthorizationService#getRules() */ public AuthorizationRule[] getRules() { - initialize(); - refresh(); - - return service.getRules(); + return service.get().getRules(); } /* @@ -169,12 +184,15 @@ public class JpaAuthorizationService implements AuthorizationService { * .wamblee.security.authorization.AuthorizationRule) */ public void appendRule(AuthorizationRule aRule) { - initialize(); - refresh(); - service.appendRule(aRule); - save(); // service might still be detached as service is cached. + 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) * @@ -182,10 +200,9 @@ public class JpaAuthorizationService implements AuthorizationService { * org.wamblee.security.authorization.AuthorizationService#removeRule(int) */ public void removeRule(int aIndex) { - initialize(); - refresh(); - service.removeRule(aIndex); - save(); // service might still be detached as service is cached. + AuthorizationService svc = refreshByReload(); + svc.removeRule(aIndex); + service.set(null); } /* @@ -196,30 +213,8 @@ public class JpaAuthorizationService implements AuthorizationService { * (int, org.wamblee.security.authorization.AuthorizationRule) */ public void insertRuleAfter(int aIndex, AuthorizationRule aRule) { - initialize(); - refresh(); - service.insertRuleAfter(aIndex, aRule); - save(); // service might still be detached as service is cached. - } - - /** - * Refreshes the state of the service through hibernate. - */ - private synchronized void refresh() { - long time = System.currentTimeMillis(); - - if ((time - lastRefreshTime) > refreshInterval) { - service = refreshByReload(); - lastRefreshTime = time; - } - } - - /** - * Saves any changes to the service state if necessary. - */ - private void save() { - AuthorizationService merged = entityManager.merge(service); - entityManager.flush(); - JpaMergeSupport.merge(merged, service); + AuthorizationService svc = refreshByReload(); + svc.insertRuleAfter(aIndex, aRule); + service.set(null); } }