2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.account.storage;
26 import java.util.Date;
27 import javax.persistence.EntityManager;
28 import javax.persistence.EntityManagerFactory;
29 import javax.persistence.Query;
30 import org.collectionspace.services.account.AccountsCommon;
31 import org.collectionspace.services.account.storage.csidp.UserStorageClient;
32 import org.collectionspace.services.authentication.User;
33 import org.collectionspace.services.common.context.ServiceContext;
34 import org.collectionspace.services.common.document.BadRequestException;
35 import org.collectionspace.services.common.document.DocumentException;
36 import org.collectionspace.services.common.document.DocumentHandler;
37 import org.collectionspace.services.common.document.DocumentHandler.Action;
38 import org.collectionspace.services.common.document.DocumentNotFoundException;
39 import org.collectionspace.services.common.document.DocumentWrapper;
40 import org.collectionspace.services.common.document.DocumentWrapperImpl;
41 import org.collectionspace.services.common.document.JaxbUtils;
42 import org.collectionspace.services.common.security.SecurityUtils;
43 import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
44 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 * AccountStorageClient deals with both Account and CSIP's
51 * state in persistent storage. The rationale behind creating this class is that
52 * this class manages pesistence for both account and CSIP's user. Transactions
53 * are used where possible to permorme the persistence operations atomically.
56 public class AccountStorageClient extends JpaStorageClientImpl {
58 private final Logger logger = LoggerFactory.getLogger(AccountStorageClient.class);
59 private UserStorageClient userStorageClient = new UserStorageClient();
61 public AccountStorageClient() {
65 public String create(ServiceContext ctx,
66 DocumentHandler handler) throws BadRequestException,
70 throw new IllegalArgumentException(
71 "AccountStorageClient.create : ctx is missing");
73 if (handler == null) {
74 throw new IllegalArgumentException(
75 "AccountStorageClient.create: handler is missing");
77 EntityManagerFactory emf = null;
78 EntityManager em = null;
79 AccountsCommon account = (AccountsCommon) handler.getCommonPart();
81 handler.prepare(Action.CREATE);
82 DocumentWrapper<AccountsCommon> wrapDoc =
83 new DocumentWrapperImpl<AccountsCommon>(account);
84 handler.handle(Action.CREATE, wrapDoc);
85 emf = JpaStorageUtils.getEntityManagerFactory();
86 em = emf.createEntityManager();
87 em.getTransaction().begin();
88 //if userid and password are given, add to default id provider
89 if (account.getUserId() != null && isForCSIdP(account.getPassword())) {
90 User user = userStorageClient.create(account.getUserId(),
91 account.getPassword());
94 // if (accountReceived.getTenant() != null) {
95 // UserTenant ut = createTenantAssoc(accountReceived);
98 account.setCreatedAtItem(new Date());
100 em.getTransaction().commit();
101 handler.complete(Action.CREATE, wrapDoc);
102 return (String) JaxbUtils.getValue(account, "getCsid");
103 } catch (BadRequestException bre) {
104 if (em != null && em.getTransaction().isActive()) {
105 em.getTransaction().rollback();
108 } catch (Exception e) {
109 if (logger.isDebugEnabled()) {
110 logger.debug("Caught exception ", e);
112 boolean uniqueConstraint = false;
113 if (userStorageClient.get(em, account.getUserId()) != null) {
114 //might be unique constraint violation
115 uniqueConstraint = true;
117 if (em != null && em.getTransaction().isActive()) {
118 em.getTransaction().rollback();
120 if (uniqueConstraint) {
121 String msg = "UserId exists. Non unique userId=" + account.getUserId();
123 throw new BadRequestException(msg);
125 throw new DocumentException(e);
128 JpaStorageUtils.releaseEntityManagerFactory(emf);
134 public void update(ServiceContext ctx, String id, DocumentHandler handler)
135 throws BadRequestException, DocumentNotFoundException,
138 throw new IllegalArgumentException(
139 "AccountStorageClient.update : ctx is missing");
141 if (handler == null) {
142 throw new IllegalArgumentException(
143 "AccountStorageClient.update: handler is missing");
145 EntityManagerFactory emf = null;
146 EntityManager em = null;
148 handler.prepare(Action.UPDATE);
149 AccountsCommon accountReceived = (AccountsCommon) handler.getCommonPart();
150 emf = JpaStorageUtils.getEntityManagerFactory();
151 em = emf.createEntityManager();
152 em.getTransaction().begin();
153 AccountsCommon accountFound = getAccount(em, id);
154 checkAllowedUpdates(accountReceived, accountFound);
155 //if userid and password are given, add to default id provider
156 if (accountReceived.getUserId() != null
157 && isForCSIdP(accountReceived.getPassword())) {
158 userStorageClient.update(em,
159 accountReceived.getUserId(),
160 accountReceived.getPassword());
162 DocumentWrapper<AccountsCommon> wrapDoc =
163 new DocumentWrapperImpl<AccountsCommon>(accountFound);
164 handler.handle(Action.UPDATE, wrapDoc);
165 em.getTransaction().commit();
166 handler.complete(Action.UPDATE, wrapDoc);
167 } catch (BadRequestException bre) {
168 if (em != null && em.getTransaction().isActive()) {
169 em.getTransaction().rollback();
172 } catch (DocumentException de) {
173 if (em != null && em.getTransaction().isActive()) {
174 em.getTransaction().rollback();
177 } catch (Exception e) {
178 if (logger.isDebugEnabled()) {
179 logger.debug("Caught exception ", e);
181 throw new DocumentException(e);
184 JpaStorageUtils.releaseEntityManagerFactory(emf);
190 public void delete(ServiceContext ctx, String id)
191 throws DocumentNotFoundException,
194 if (logger.isDebugEnabled()) {
195 logger.debug("deleting entity with id=" + id);
198 throw new IllegalArgumentException(
199 "AccountStorageClient.delete : ctx is missing");
201 EntityManagerFactory emf = null;
202 EntityManager em = null;
204 emf = JpaStorageUtils.getEntityManagerFactory();
205 em = emf.createEntityManager();
207 AccountsCommon accountFound = getAccount(em, id);
208 em.getTransaction().begin();
209 //if userid gives any indication about the id provider, it should
210 //be used to avoid delete
211 userStorageClient.delete(em, accountFound.getUserId());
212 em.remove(accountFound);
213 em.getTransaction().commit();
215 } catch (DocumentException de) {
216 if (em != null && em.getTransaction().isActive()) {
217 em.getTransaction().rollback();
220 } catch (Exception e) {
221 if (logger.isDebugEnabled()) {
222 logger.debug("Caught exception ", e);
224 if (em != null && em.getTransaction().isActive()) {
225 em.getTransaction().rollback();
227 throw new DocumentException(e);
230 JpaStorageUtils.releaseEntityManagerFactory(emf);
235 private AccountsCommon getAccount(EntityManager em, String id) throws DocumentNotFoundException {
236 AccountsCommon accountFound = em.find(AccountsCommon.class, id);
237 if (accountFound == null) {
238 if (em != null && em.getTransaction().isActive()) {
239 em.getTransaction().rollback();
241 String msg = "could not find account with id=" + id;
243 throw new DocumentNotFoundException(msg);
248 private boolean checkAllowedUpdates(AccountsCommon toAccount, AccountsCommon fromAccount) throws BadRequestException {
249 if (!fromAccount.getUserId().equals(toAccount.getUserId())) {
250 String msg = "userId=" + toAccount.getUserId() + " of existing account does not match "
251 + "the userId=" + fromAccount.getUserId()
252 + " with csid=" + fromAccount.getCsid();
254 if (logger.isDebugEnabled()) {
255 logger.debug(msg + " found userid=" + fromAccount.getUserId());
257 throw new BadRequestException(msg);
263 * isForCSIdP deteremines if the create/update is also needed for CS IdP
267 private boolean isForCSIdP(byte[] bpass) {
268 return bpass != null && bpass.length > 0;
270 // private UserTenant createTenantAssoc(AccountsCommon accountReceived) {
271 // UserTenant userTenant = new UserTenant();
272 // userTenant.setUserId(accountReceived.getUserId());
273 // List<AccountsCommon.Tenant> atl = accountReceived.getTenant();
274 // List<UserTenant.Tenant> utl =
275 // new ArrayList<UserTenant.Tenant>();
276 // for (AccountsCommon.Tenant at : atl) {
277 // UserTenant.Tenant ut = new UserTenant.Tenant();
278 // ut.setId(at.getId());
279 // ut.setName(at.getName());
282 // userTenant.setTenant(utl);
283 // return userTenant;