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.ArrayList;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.UUID;
31 import org.collectionspace.services.account.AccountTenant;
32 import org.collectionspace.services.account.AccountsCommon;
33 import org.collectionspace.services.account.AccountsCommonList;
34 import org.collectionspace.services.account.AccountListItem;
35 import org.collectionspace.services.account.AccountRoleSubResource;
36 import org.collectionspace.services.account.Status;
37 import org.collectionspace.services.authorization.AccountRole;
38 import org.collectionspace.services.authorization.PermissionRole;
39 import org.collectionspace.services.authorization.PermissionRoleSubResource;
40 import org.collectionspace.services.authorization.SubjectType;
41 import org.collectionspace.services.account.RoleValue;
42 import org.collectionspace.services.client.AccountClient;
43 import org.collectionspace.services.client.AccountRoleFactory;
44 import org.collectionspace.services.client.RoleClient;
45 import org.collectionspace.services.common.storage.TransactionContext;
46 import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler;
47 import org.collectionspace.services.common.api.Tools;
48 import org.collectionspace.services.common.context.ServiceContext;
49 import org.collectionspace.services.common.document.DocumentFilter;
50 import org.collectionspace.services.common.document.DocumentWrapper;
51 import org.collectionspace.services.common.document.JaxbUtils;
52 import org.collectionspace.services.common.security.SecurityUtils;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
61 public class AccountDocumentHandler
62 extends JpaDocumentHandler<AccountsCommon, AccountsCommonList, AccountsCommon, List<AccountsCommon>> {
64 private final Logger logger = LoggerFactory.getLogger(AccountDocumentHandler.class);
65 private AccountsCommon account;
66 private AccountsCommonList accountList;
69 public void handleCreate(DocumentWrapper<AccountsCommon> wrapDoc) throws Exception {
70 String id = UUID.randomUUID().toString();
71 AccountsCommon account = wrapDoc.getWrappedObject();
74 account.setStatus(Status.ACTIVE);
75 // We do not allow creation of locked accounts through the services.
76 account.setMetadataProtection(null);
77 account.setRolesProtection(null);
81 public void handleUpdate(DocumentWrapper<AccountsCommon> wrapDoc) throws Exception {
82 AccountsCommon accountFound = wrapDoc.getWrappedObject();
83 AccountsCommon accountReceived = getCommonPart();
84 // If marked as metadata immutable, do not do update
85 if (!AccountClient.IMMUTABLE.equals(accountFound.getMetadataProtection())) {
86 merge(accountReceived, accountFound);
89 // Update the accountroles if supplied
91 if (accountReceived.getRoleList() != null) { // if null, no <roleList> element was supplied so we don't do anything to the account-role relationships
93 // First, delete the existing accountroles
95 AccountRoleSubResource subResource =
96 new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
97 subResource.deleteAccountRole(getServiceContext(), accountFound.getCsid(), SubjectType.ROLE);
99 // Check to see if the payload has new roles to relate to the account
101 List<RoleValue> roleValueList = accountReceived.getRoleList().getRole();
102 if (roleValueList != null && roleValueList.size() > 0) {
104 // Next, create the new accountroles
106 AccountRole accountRole = AccountRoleFactory.createAccountRoleInstance(accountFound,
107 roleValueList, true, true);
108 String accountRoleCsid = subResource.createAccountRole(getServiceContext(), accountRole, SubjectType.ROLE);
110 // Finally, set the updated role list in the result
112 AccountRole newAccountRole = subResource.getAccountRole(getServiceContext(), accountFound.getCsid(), SubjectType.ROLE);
113 accountFound.setRoleList(AccountRoleFactory.convert(newAccountRole.getRole()));
119 * merge manually merges the from account to the to account
120 * -this method is created due to inefficiency of JPA EM merge
123 * @return merged account
125 private AccountsCommon merge(AccountsCommon from, AccountsCommon to) {
126 Date now = new Date();
127 to.setUpdatedAtItem(now);
128 if (from.getEmail() != null) {
129 to.setEmail(from.getEmail());
131 if (from.getPhone() != null) {
132 to.setPhone(from.getPhone());
134 if (from.getMobile() != null) {
135 to.setMobile(from.getMobile());
137 if (from.getScreenName() != null) {
138 to.setScreenName(from.getScreenName());
140 if (from.getStatus() != null) {
141 to.setStatus(from.getStatus());
143 if (from.getPersonRefName() != null) {
144 to.setPersonRefName(from.getPersonRefName());
146 // Note that we do not allow update of locks
147 //fixme update for tenant association
149 if (logger.isDebugEnabled()) {
150 logger.debug("merged account="
151 + JaxbUtils.toString(to, AccountsCommon.class));
158 * If the create payload included a list of role, relate them to the account.
160 public void completeCreate(DocumentWrapper<AccountsCommon> wrapDoc) throws Exception {
161 AccountsCommon accountsCommon = wrapDoc.getWrappedObject();
162 List<RoleValue> roleValueList = account.getRoleList() != null ? account.getRoleList().getRole() : null;
163 if (roleValueList != null && roleValueList.size() > 0) {
165 // To prevent new Accounts being created (especially low-level Spring Security accounts/SIDs), we'll first flush the current
166 // JPA context to ensure our Account can be successfully persisted.
168 TransactionContext jpaTransactionContext = this.getServiceContext().getCurrentTransactionContext();
169 jpaTransactionContext.flush();
171 AccountRoleSubResource subResource = new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
172 AccountRole accountRole = AccountRoleFactory.createAccountRoleInstance(accountsCommon, roleValueList, true, true);
173 subResource.createAccountRole(this.getServiceContext(), accountRole, SubjectType.ROLE);
178 public void completeUpdate(DocumentWrapper<AccountsCommon> wrapDoc) throws Exception {
179 AccountsCommon upAcc = wrapDoc.getWrappedObject();
180 getServiceContext().setOutput(upAcc);
184 public void handleGet(DocumentWrapper<AccountsCommon> wrapDoc) throws Exception {
185 setCommonPart(extractCommonPart(wrapDoc));
186 sanitize(getCommonPart());
187 getServiceContext().setOutput(account);
191 public void handleGetAll(DocumentWrapper<List<AccountsCommon>> wrapDoc) throws Exception {
192 AccountsCommonList accList = extractCommonPartList(wrapDoc);
193 setCommonPartList(accList);
194 getServiceContext().setOutput(getCommonPartList());
197 @SuppressWarnings("unchecked")
199 public AccountsCommon extractCommonPart(DocumentWrapper<AccountsCommon> wrapDoc) throws Exception {
200 AccountsCommon account = wrapDoc.getWrappedObject();
202 String includeRolesQueryParamValue = (String) getServiceContext().getQueryParams().getFirst(AccountClient.INCLUDE_ROLES_QP);
203 boolean includeRoles = Tools.isTrue(includeRolesQueryParamValue);
205 AccountRoleSubResource accountRoleResource = new AccountRoleSubResource(
206 AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
207 AccountRole accountRole = accountRoleResource.getAccountRole(getServiceContext(), account.getCsid(),
209 account.setRoleList(AccountRoleFactory.convert(accountRole.getRole()));
212 return wrapDoc.getWrappedObject();
216 public void fillCommonPart(AccountsCommon obj, DocumentWrapper<AccountsCommon> wrapDoc)
218 throw new UnsupportedOperationException("operation not relevant for AccountDocumentHandler");
222 public AccountsCommonList extractCommonPartList(
223 DocumentWrapper<List<AccountsCommon>> wrapDoc)
226 AccountsCommonList accList = this.extractPagingInfo(new AccountsCommonList(), wrapDoc);
227 // AccountsCommonList accList = new AccountsCommonList();
228 List<AccountListItem> list = accList.getAccountListItem();
230 for (Object obj : wrapDoc.getWrappedObject()) {
231 AccountsCommon account = (AccountsCommon) obj;
232 AccountListItem accListItem = new AccountListItem();
233 accListItem.setScreenName(account.getScreenName());
234 accListItem.setUserid(account.getUserId());
236 // Since accounts can be associated with more than 1 tenant, we only want to include
237 // the tenant information for the current service context.
239 String tenantInCtx = this.getServiceContext().getTenantId();
240 List<AccountTenant> associatedTenantList = account.getTenants();
241 for (AccountTenant associatedTenant : associatedTenantList) {
242 if (associatedTenant != null && associatedTenant.getTenantId() != null) {
243 if (associatedTenant.getTenantId().equalsIgnoreCase(tenantInCtx)) {
244 accListItem.setTenantid(associatedTenant.getTenantId());
250 accListItem.setTenants(account.getTenants());
251 accListItem.setEmail(account.getEmail());
252 accListItem.setStatus(account.getStatus());
253 String id = account.getCsid();
254 accListItem.setUri(getServiceContextPath() + id);
255 accListItem.setCsid(id);
256 list.add(accListItem);
262 public AccountsCommon getCommonPart() {
267 public void setCommonPart(AccountsCommon account) {
268 this.account = account;
272 public AccountsCommonList getCommonPartList() {
277 public void setCommonPartList(AccountsCommonList accountList) {
278 this.accountList = accountList;
282 public String getQProperty(
288 public DocumentFilter createDocumentFilter() {
289 DocumentFilter filter = new AccountJpaFilter(this.getServiceContext());
293 private void setTenant(AccountsCommon account) {
294 //set tenant only if not available from input
295 ServiceContext ctx = getServiceContext();
296 if (account.getTenants() == null || account.getTenants().size() == 0) {
297 if (ctx.getTenantId() != null) {
298 AccountTenant at = new AccountTenant();
299 at.setTenantId(ctx.getTenantId());
300 List<AccountTenant> atList = new ArrayList<AccountTenant>();
302 account.setTenants(atList);
308 * sanitize removes data not needed to be sent to the consumer
312 public void sanitize(DocumentWrapper<AccountsCommon> wrapDoc) {
313 AccountsCommon account = wrapDoc.getWrappedObject();
317 private void sanitize(AccountsCommon account) {
318 account.setPassword(null);
319 if (!SecurityUtils.isCSpaceAdmin()) {
320 account.setTenants(new ArrayList<AccountTenant>(0));
325 * @see org.collectionspace.services.common.document.DocumentHandler#initializeDocumentFilter(org.collectionspace.services.common.context.ServiceContext)
327 public void initializeDocumentFilter(ServiceContext<AccountsCommon, AccountsCommon> ctx) {
328 // set a default document filter in this method