(no commit message)
[utils] / security / usermgt / src / main / java / org / wamblee / security / authorization / jpa / JpaAuthorizationService.java
1 /*
2  * Copyright 2005-2010 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.wamblee.security.authorization.jpa;
17
18 import javax.persistence.EntityManager;
19 import javax.persistence.NoResultException;
20 import javax.persistence.NonUniqueResultException;
21
22 import org.wamblee.cache.ComputedValue;
23 import org.wamblee.cache.ComputedValue.Computation;
24 import org.wamblee.security.authentication.UserAccessor;
25 import org.wamblee.security.authentication.UserAdministration;
26 import org.wamblee.security.authorization.AbstractAuthorizationService;
27 import org.wamblee.security.authorization.AuthorizationRule;
28 import org.wamblee.security.authorization.AuthorizationService;
29 import org.wamblee.security.authorization.DefaultAuthorizationService;
30 import org.wamblee.security.authorization.Operation;
31
32 /**
33  * Authorization service with persistent storage. This is a wrapper for
34  * {@link org.wamblee.security.authorization.DefaultAuthorizationService} which
35  * refreshes the state of the service at certain time intervals.
36  * 
37  * @author Erik Brakkee
38  */
39 public class JpaAuthorizationService implements AuthorizationService {
40
41     /**
42      * Authorization service to use.
43      */
44     private ComputedValue<AuthorizationService> service;
45
46     /**
47      * Hibernate template to use.
48      */
49     private EntityManager entityManager;
50
51     /**
52      * User accessor.
53      */
54     private UserAccessor userAccessor;
55
56     /**
57      * User administration.
58      */
59     private UserAdministration userAdmin;
60
61     /**
62      * Name of the service.
63      */
64     private String name;
65
66     /**
67      * Refresh interval in milliseconds.
68      */
69     private final long refreshInterval;
70
71     /**
72      * Last refresh time.
73      */
74     private long lastRefreshTime;
75
76     /**
77      * Constructs the persistent service.
78      * 
79      * @param aName
80      *            Name of the service.
81      * @param aEntityManager
82      *            Entity manager.
83      * @param aAccessor
84      *            User accessor.
85      * @param aUserAdmin
86      *            User administration.
87      * @param aRefresh
88      *            Whether or not to refresh the state of the service at the
89      *            start of every operation.
90      */
91     public JpaAuthorizationService(String aName, EntityManager aEntityManager,
92         UserAccessor aAccessor, UserAdministration aUserAdmin,
93         long aRefreshInterval) {
94         entityManager = aEntityManager;
95         refreshInterval = aRefreshInterval;
96         lastRefreshTime = System.currentTimeMillis();
97         userAccessor = aAccessor;
98         userAdmin = aUserAdmin;
99         name = aName;
100         Computation<AuthorizationService> computation = new Computation<AuthorizationService>() {
101             @Override
102             public boolean isOutOfDate() {
103                 long time = System.currentTimeMillis();
104                 return service.getCached() == null ||
105                     (time - lastRefreshTime) > refreshInterval;
106             }
107
108             @Override
109             public AuthorizationService compute() {
110                 AuthorizationService svc = refreshByReload();
111                 lastRefreshTime = System.currentTimeMillis();
112                 return svc;
113             }
114         };
115         service = new ComputedValue<AuthorizationService>(this, computation);
116     }
117
118     @Override
119     public void setUserAccessor(UserAccessor aUserAccessor) {
120         userAccessor = aUserAccessor;
121     }
122
123     @Override
124     public void setUserAdministration(UserAdministration aUserAdmin) {
125         userAdmin = aUserAdmin;
126     }
127
128     private AuthorizationService refreshByReload() {
129         AuthorizationService svc;
130         try {
131             svc = entityManager.createNamedQuery(
132                 AbstractAuthorizationService.QUERY_FIND_BY_NAME,
133                 AbstractAuthorizationService.class).setParameter(
134                 DefaultAuthorizationService.NAME_PARAM, name).getSingleResult();
135             svc.setUserAccessor(userAccessor);
136             svc.setUserAdministration(userAdmin);
137         } catch (NonUniqueResultException e) {
138             throw new IllegalArgumentException(
139                 "Returned more than one service for name '" + name + "'");
140         } catch (NoResultException e) {
141             svc = new DefaultAuthorizationService(userAccessor, userAdmin, name);
142             entityManager.persist(svc);
143         }
144         return svc;
145     }
146
147     /*
148      * (non-Javadoc)
149      * 
150      * @see
151      * org.wamblee.security.authorization.AuthorizationService#isAllowed(java
152      * .lang.Object, org.wamblee.security.authorization.Operation)
153      */
154     public boolean isAllowed(Object aResource, Operation aOperation) {
155         return service.get().isAllowed(aResource, aOperation);
156     }
157
158     /*
159      * (non-Javadoc)
160      * 
161      * @see org.wamblee.security.authorization.AuthorizationService#check(T,
162      * org.wamblee.security.authorization.Operation)
163      */
164     public <T> T check(T aResource, Operation aOperation) {
165         return service.get().check(aResource, aOperation);
166     }
167
168     /*
169      * (non-Javadoc)
170      * 
171      * @see org.wamblee.security.authorization.AuthorizationService#getRules()
172      */
173     public AuthorizationRule[] getRules() {
174         return service.get().getRules();
175     }
176
177     /*
178      * (non-Javadoc)
179      * 
180      * @see
181      * org.wamblee.security.authorization.AuthorizationService#appendRule(org
182      * .wamblee.security.authorization.AuthorizationRule)
183      */
184     public void appendRule(AuthorizationRule aRule) {
185         AuthorizationService svc = refreshByReload();
186         svc.appendRule(aRule);
187         // Setting service to null will force reload the next time the
188         // service is used. This deals effectively with the case where the
189         // current transaction would roll back and the change would not have
190         // been made.
191         service.set(null);
192     }
193     
194     /*
195      * (non-Javadoc)
196      * 
197      * @see
198      * org.wamblee.security.authorization.AuthorizationService#removeRule(int)
199      */
200     public void removeRule(int aIndex) {
201         AuthorizationService svc = refreshByReload();
202         svc.removeRule(aIndex);
203         service.set(null);
204     }
205
206     /*
207      * (non-Javadoc)
208      * 
209      * @see
210      * org.wamblee.security.authorization.AuthorizationService#insertRuleAfter
211      * (int, org.wamblee.security.authorization.AuthorizationRule)
212      */
213     public void insertRuleAfter(int aIndex, AuthorizationRule aRule) {
214         AuthorizationService svc = refreshByReload();
215         svc.insertRuleAfter(aIndex, aRule);
216         service.set(null);
217     }
218 }