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