--- /dev/null
+/*
+ * 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.persistence.JpaMergeSupport;
+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
+ * {@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 AuthorizationService service;
+
+ /**
+ * Hibernate template to use.
+ */
+ private EntityManager entityManager;
+
+ /**
+ * User accessor.
+ */
+ private UserAccessor userAccessor;
+
+ /**
+ * 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 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) {
+ entityManager = aEntityManager;
+ refreshInterval = aRefreshInterval;
+ lastRefreshTime = System.currentTimeMillis();
+ userAccessor = aAccessor;
+ name = aName;
+ }
+
+ @Override
+ public void setUserAccessor(UserAccessor aUserAccessor) {
+ userAccessor = aUserAccessor;
+ }
+
+ /**
+ * Initialize service if needed.
+ *
+ */
+ private void initialize() {
+ if (service == null) {
+ refreshByReload();
+ }
+ }
+
+ private void refreshByReload() {
+ try {
+ service = entityManager.createNamedQuery(
+ AbstractAuthorizationService.QUERY_FIND_BY_NAME,
+ AbstractAuthorizationService.class).setParameter(
+ AbstractAuthorizationService.NAME_PARAM, name).getSingleResult();
+ service.setUserAccessor(userAccessor);
+ } 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);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.wamblee.security.authorization.AuthorizationService#isAllowed(java
+ * .lang.Object, org.wamblee.security.authorization.Operation)
+ */
+ public boolean isAllowed(Object aResource, Operation aOperation) {
+ initialize();
+ refresh();
+
+ return service.isAllowed(aResource, aOperation);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.AuthorizationService#check(T,
+ * org.wamblee.security.authorization.Operation)
+ */
+ public <T> T check(T aResource, Operation aOperation) {
+ initialize();
+ refresh();
+
+ return service.check(aResource, aOperation);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.AuthorizationService#getRules()
+ */
+ public AuthorizationRule[] getRules() {
+ initialize();
+ refresh();
+
+ return service.getRules();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.wamblee.security.authorization.AuthorizationService#appendRule(org
+ * .wamblee.security.authorization.AuthorizationRule)
+ */
+ public void appendRule(AuthorizationRule aRule) {
+ initialize();
+ refresh();
+ service.appendRule(aRule);
+ save();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.wamblee.security.authorization.AuthorizationService#removeRule(int)
+ */
+ public void removeRule(int aIndex) {
+ initialize();
+ refresh();
+ service.removeRule(aIndex);
+ save();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.wamblee.security.authorization.AuthorizationService#insertRuleAfter
+ * (int, org.wamblee.security.authorization.AuthorizationRule)
+ */
+ public void insertRuleAfter(int aIndex, AuthorizationRule aRule) {
+ initialize();
+ refresh();
+ service.insertRuleAfter(aIndex, aRule);
+ save();
+ }
+
+ /**
+ * Refreshes the state of the service through hibernate.
+ */
+ private synchronized void refresh() {
+ long time = System.currentTimeMillis();
+
+ if ((time - lastRefreshTime) > refreshInterval) {
+ 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);
+ }
+}