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