4bce7aef3e60a55d3c7ed80afdafc4d81a556d96
[utils] / security / impl / 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.persistence.JpaMergeSupport;
23 import org.wamblee.security.authentication.UserAccessor;
24 import org.wamblee.security.authentication.UserAdministration;
25 import org.wamblee.security.authorization.AbstractAuthorizationService;
26 import org.wamblee.security.authorization.AbstractAuthorizationRule;
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 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  User administration.
86      * @param aRefresh
87      *            Whether or not to refresh the state of the service at the
88      *            start of every operation.
89      */
90     public JpaAuthorizationService(String aName, EntityManager aEntityManager,
91         UserAccessor aAccessor, UserAdministration aUserAdmin, long aRefreshInterval) {
92         entityManager = aEntityManager;
93         refreshInterval = aRefreshInterval;
94         lastRefreshTime = System.currentTimeMillis();
95         userAccessor = aAccessor;
96         userAdmin = aUserAdmin;
97         name = aName;
98     }
99     
100     @Override
101     public void setUserAccessor(UserAccessor aUserAccessor) {
102         userAccessor = aUserAccessor;   
103     }
104     
105     @Override
106     public void setUserAdministration(UserAdministration aUserAdmin) {
107         userAdmin = aUserAdmin;   
108     }
109
110     private AuthorizationService refreshByReload() {
111         if ( userAdmin == null ) { 
112             throw new IllegalArgumentException("useradmin is null");
113         }
114         AuthorizationService svc; 
115         try {
116             svc = entityManager.createNamedQuery(
117                 AbstractAuthorizationService.QUERY_FIND_BY_NAME,
118                 AbstractAuthorizationService.class).setParameter(
119                     DefaultAuthorizationService.NAME_PARAM, name).getSingleResult();
120             svc.setUserAccessor(userAccessor);
121             svc.setUserAdministration(userAdmin);
122         } catch (NonUniqueResultException e) {
123             throw new IllegalArgumentException(
124                 "Returned more than one service for name '" + name + "'");
125         } catch (NoResultException e) {
126             svc = new DefaultAuthorizationService(userAccessor, userAdmin, name);
127             entityManager.persist(svc);
128         }
129         return svc;
130     }
131
132     /*
133      * (non-Javadoc)
134      * 
135      * @see
136      * org.wamblee.security.authorization.AuthorizationService#isAllowed(java
137      * .lang.Object, org.wamblee.security.authorization.Operation)
138      */
139     public boolean isAllowed(Object aResource, Operation aOperation) {
140         refresh();
141
142         return service.isAllowed(aResource, aOperation);
143     }
144
145     /*
146      * (non-Javadoc)
147      * 
148      * @see org.wamblee.security.authorization.AuthorizationService#check(T,
149      * org.wamblee.security.authorization.Operation)
150      */
151     public <T> T check(T aResource, Operation aOperation) {
152         refresh();
153
154         return service.check(aResource, aOperation);
155     }
156
157     /*
158      * (non-Javadoc)
159      * 
160      * @see org.wamblee.security.authorization.AuthorizationService#getRules()
161      */
162     public AuthorizationRule[] getRules() {
163         refresh();
164
165         return service.getRules();
166     }
167
168     /*
169      * (non-Javadoc)
170      * 
171      * @see
172      * org.wamblee.security.authorization.AuthorizationService#appendRule(org
173      * .wamblee.security.authorization.AuthorizationRule)
174      */
175     public void appendRule(AuthorizationRule aRule) {
176         AuthorizationService svc = refreshByReload();
177         svc.appendRule(aRule);
178         // Setting service to null will force reload the next time the 
179         // service is used. This deals effectively with the case where the 
180         // current transaction would roll back and the change would not have been made. 
181         setService(null);
182     }
183     
184     private synchronized AuthorizationService getService() { 
185         return service; 
186     }
187     
188     private synchronized void setService(AuthorizationService aSvc) { 
189         service = aSvc; 
190     }
191     
192     /*
193      * (non-Javadoc)
194      * 
195      * @see
196      * org.wamblee.security.authorization.AuthorizationService#removeRule(int)
197      */
198     public void removeRule(int aIndex) {
199         AuthorizationService svc = refreshByReload(); 
200         svc.removeRule(aIndex);
201         setService(null); 
202     }
203
204     /*
205      * (non-Javadoc)
206      * 
207      * @see
208      * org.wamblee.security.authorization.AuthorizationService#insertRuleAfter
209      * (int, org.wamblee.security.authorization.AuthorizationRule)
210      */
211     public void insertRuleAfter(int aIndex, AuthorizationRule aRule) {
212         AuthorizationService svc = refreshByReload(); 
213         svc.insertRuleAfter(aIndex, aRule);
214         setService(null);
215     }
216
217     /**
218      * Refreshes the state of the service through hibernate.
219      */
220     private synchronized void refresh() {
221         long time = System.currentTimeMillis();
222
223         if (service == null || (time - lastRefreshTime) > refreshInterval) {
224             service = refreshByReload();
225             lastRefreshTime = time;
226         }
227     }
228 }