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
/**
* Authorization service to use.
*/
- private AuthorizationService service;
+ private ComputedValue<AuthorizationService> service;
/**
* Hibernate template to use.
*/
private UserAccessor userAccessor;
+ /**
+ * User administration.
+ */
+ private UserAdministration userAdmin;
+
/**
* Name of the service.
*/
* 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<AuthorizationService> computation = new Computation<AuthorizationService>() {
+ @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<AuthorizationService>(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;
}
/*
* .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);
}
/*
* org.wamblee.security.authorization.Operation)
*/
public <T> T check(T aResource, Operation aOperation) {
- initialize();
- refresh();
-
- return service.check(aResource, aOperation);
+ return service.get().check(aResource, aOperation);
}
/*
* @see org.wamblee.security.authorization.AuthorizationService#getRules()
*/
public AuthorizationRule[] getRules() {
- initialize();
- refresh();
-
- return service.getRules();
+ return service.get().getRules();
}
/*
* .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)
*
* 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);
}
/*
* (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);
}
}