From cc1010dd71f03c906ffe7477da10419ec4333890 Mon Sep 17 00:00:00 2001 From: remillet Date: Fri, 29 Dec 2017 14:24:24 -0800 Subject: [PATCH] DRYD-221: Refactor persistence of AuthN/AuthZ entities to support better transaction support. --- .../services/client/AccountFactory.java | 11 + .../services/client/AccountRoleFactory.java | 69 +++- .../src/main/resources/accounts_common.xsd | 22 ++ .../main/resources/db/postgresql/account.sql | 2 +- .../services/account/AccountResource.java | 58 ++- .../account/AccountRoleSubResource.java | 69 ++-- .../storage/AccountDocumentHandler.java | 50 ++- .../storage/AccountRoleDocumentHandler.java | 5 + .../account/storage/AccountStorageClient.java | 171 +++----- .../storage/AccountValidatorHandler.java | 4 + .../account/storage/TenantStorageClient.java | 154 +++----- .../storage/csidp/UserStorageClient.java | 48 ++- .../client/test/RoleServiceTest.java | 2 +- .../java/org/collectionspace/ImportAuthz.java | 15 +- .../driver/AuthorizationSeedDriver.java | 51 ++- .../importer/AuthorizationGen.java | 31 +- .../importer/AuthorizationSeed.java | 11 +- .../services/authorization/RoleResource.java | 110 ++++-- .../storage/RoleDocumentHandler.java | 59 +-- .../main/resources/authorization_common.xsd | 2 +- .../authorization/PermissionResource.java | 48 ++- .../PermissionRoleSubResource.java | 56 +-- .../storage/AuthorizationDelegate.java | 40 +- .../storage/PermissionDocumentHandler.java | 40 +- .../PermissionRoleDocumentHandler.java | 49 ++- .../services/common/SecurityResourceBase.java | 81 +++- .../services/common/ServiceMain.java | 12 +- .../AuthorizationCommon.java | 78 ++-- .../authorization_mgt/AuthorizationStore.java | 50 +-- .../authorization_mgt/PermissionRoleUtil.java | 50 ++- .../context/RemoteServiceContextImpl.java | 66 +++- .../common/context/ServiceContext.java | 12 +- .../common/storage/TransactionContext.java | 12 + .../storage/jpa/JPATransactionContext.java | 68 +++- .../jpa/JpaRelationshipStorageClient.java | 169 +++----- .../storage/jpa/JpaStorageClientImpl.java | 372 +++++++----------- .../common/storage/jpa/JpaStorageUtils.java | 208 +++++----- 37 files changed, 1251 insertions(+), 1104 deletions(-) diff --git a/services/account/client/src/main/java/org/collectionspace/services/client/AccountFactory.java b/services/account/client/src/main/java/org/collectionspace/services/client/AccountFactory.java index e464c8ff4..756f46d07 100644 --- a/services/account/client/src/main/java/org/collectionspace/services/client/AccountFactory.java +++ b/services/account/client/src/main/java/org/collectionspace/services/client/AccountFactory.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.UUID; import org.collectionspace.services.account.AccountTenant; import org.collectionspace.services.account.AccountsCommon; +import org.collectionspace.services.authorization.AccountValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -102,4 +103,14 @@ public class AccountFactory { } + static public AccountValue createAccountValue(AccountsCommon accountsCommon) { + AccountValue result = new AccountValue(); + + result.setAccountId(accountsCommon.getCsid()); + result.setScreenName(accountsCommon.getScreenName()); + result.setUserId(accountsCommon.getUserId()); + + return result; + } + } diff --git a/services/account/client/src/main/java/org/collectionspace/services/client/AccountRoleFactory.java b/services/account/client/src/main/java/org/collectionspace/services/client/AccountRoleFactory.java index 0e4d758a1..e8b207d2b 100644 --- a/services/account/client/src/main/java/org/collectionspace/services/client/AccountRoleFactory.java +++ b/services/account/client/src/main/java/org/collectionspace/services/client/AccountRoleFactory.java @@ -26,10 +26,15 @@ package org.collectionspace.services.client; import java.util.ArrayList; import java.util.Collection; +import java.util.List; + +import org.collectionspace.services.account.AccountsCommon; import org.collectionspace.services.authorization.AccountRole; import org.collectionspace.services.authorization.AccountValue; import org.collectionspace.services.authorization.SubjectType; + import org.collectionspace.services.authorization.RoleValue; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,30 +48,30 @@ public class AccountRoleFactory { /** * Creates the account role instance. * - * @param pv the pv - * @param rvs the rvs - * @param usePermId the use perm id + * @param accountValue the pv + * @param roleValueList the rvs + * @param useAccountId the use perm id * @param useRoleId the use role id * @return the account role */ - static public AccountRole createAccountRoleInstance(AccountValue pv, - Collection rvs, - boolean usePermId, + static public AccountRole createAccountRoleInstance(AccountValue accountValue, + Collection roleValueList, + boolean useAccountId, boolean useRoleId) { AccountRole accRole = new AccountRole(); //service consume is not required to provide subject as it is determined //from URI used accRole.setSubject(SubjectType.ROLE); - if (usePermId) { + if (useAccountId) { ArrayList pvs = new ArrayList(); - pvs.add(pv); + pvs.add(accountValue); accRole.setAccount(pvs); } if (useRoleId) { //FIXME is there a better way? ArrayList rvas = new ArrayList(); - for (RoleValue rv : rvs) { + for (RoleValue rv : roleValueList) { rvas.add(rv); } accRole.setRole(rvas); @@ -75,5 +80,51 @@ public class AccountRoleFactory { return accRole; } + /* + * Convert the Account service's RoleValue list to the AuthZ RoleValue list we need + */ + static public AccountRole createAccountRoleInstance(AccountsCommon accountsCommon, + Collection roleValueList, + boolean useAccountId, + boolean useRoleId) { + + Collection authzRoleValueList = new ArrayList(); + if (roleValueList != null && roleValueList.size() > 0) { + for (org.collectionspace.services.account.RoleValue rv : roleValueList) { + RoleValue authzRoleValue = new RoleValue(); + authzRoleValue.setDisplayName(rv.getDisplayName()); + authzRoleValue.setRoleId(rv.getRoleId()); + authzRoleValue.setRoleName(rv.getRoleName()); + authzRoleValue.setRoleRelationshipId(rv.getRoleRelationshipId()); + authzRoleValue.setTenantId(rv.getTenantId()); + authzRoleValueList.add(authzRoleValue); + } + } + AccountValue accountValue = AccountFactory.createAccountValue(accountsCommon); + return AccountRoleFactory.createAccountRoleInstance(accountValue, authzRoleValueList, useAccountId, useRoleId); + } + + /** + * Converts a standard RoleValue list to the type needed by the Account resource. + * @param roleValueList + * @return + */ + static public List convert(List roleValueList) { + List result = new ArrayList(); + + if (roleValueList != null && roleValueList.size() > 0) { + for (RoleValue rv : roleValueList) { + org.collectionspace.services.account.RoleValue accountRoleValue = new org.collectionspace.services.account.RoleValue(); + accountRoleValue.setDisplayName(rv.getDisplayName()); + accountRoleValue.setRoleId(rv.getRoleId()); + accountRoleValue.setRoleName(rv.getRoleName()); + accountRoleValue.setRoleRelationshipId(rv.getRoleRelationshipId()); + accountRoleValue.setTenantId(rv.getTenantId()); + result.add(accountRoleValue); + } + } + + return result; + } } diff --git a/services/account/jaxb/src/main/resources/accounts_common.xsd b/services/account/jaxb/src/main/resources/accounts_common.xsd index cdd208f3a..51a1e9083 100644 --- a/services/account/jaxb/src/main/resources/accounts_common.xsd +++ b/services/account/jaxb/src/main/resources/accounts_common.xsd @@ -54,6 +54,9 @@ + + userid + @@ -183,6 +186,7 @@ + @@ -196,6 +200,24 @@ + + + + RoleValue is used relationships + + + + + + + + + + + + + + diff --git a/services/account/pstore/src/main/resources/db/postgresql/account.sql b/services/account/pstore/src/main/resources/db/postgresql/account.sql index 74f75df23..307e9b0e0 100644 --- a/services/account/pstore/src/main/resources/db/postgresql/account.sql +++ b/services/account/pstore/src/main/resources/db/postgresql/account.sql @@ -3,7 +3,7 @@ DROP TABLE IF EXISTS accounts_common CASCADE; DROP TABLE IF EXISTS accounts_tenants CASCADE; DROP TABLE IF EXISTS tenants CASCADE; DROP SEQUENCE IF EXISTS hibernate_sequence; -create table accounts_common (csid varchar(128) not null, created_at timestamp not null, email varchar(255) not null, mobile varchar(255), person_ref_name varchar(255), phone varchar(255), screen_name varchar(128) not null, status varchar(15) not null, updated_at timestamp, userid varchar(128) not null, metadata_protection varchar(255), roles_protection varchar(255), primary key (csid)); +create table accounts_common (csid varchar(128) not null, created_at timestamp not null, email varchar(255) not null, mobile varchar(255), person_ref_name varchar(255), phone varchar(255), screen_name varchar(128) not null, status varchar(15) not null, updated_at timestamp, userid varchar(128) not null, metadata_protection varchar(255), roles_protection varchar(255), primary key (csid), unique (userid)); create table accounts_tenants (HJID int8 not null, tenant_id varchar(128) not null, TENANTS_ACCOUNTS_COMMON_CSID varchar(128), primary key (HJID)); create table tenants (id varchar(128) not null, created_at timestamp not null, name varchar(255) not null, config_md5hash varchar(255), authorities_initialized boolean not null, disabled boolean not null, updated_at timestamp, primary key (id)); alter table accounts_tenants add constraint FKFDA649B05A9CEEB5 foreign key (TENANTS_ACCOUNTS_COMMON_CSID) references accounts_common; diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java b/services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java index 38e678128..d7a86fb48 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java @@ -68,7 +68,6 @@ import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; @@ -111,12 +110,14 @@ public class AccountResource extends SecurityResourceBase { return AccountsCommon.class; } - @Override + @SuppressWarnings("unchecked") + @Override public ServiceContextFactory getServiceContextFactory() { return (ServiceContextFactory) RemoteServiceContextFactory.get(); } - @Override + @SuppressWarnings("rawtypes") + @Override public StorageClient getStorageClient(ServiceContext ctx) { //FIXME use ctx to identify storage client return storageClient; @@ -445,26 +446,34 @@ public class AccountResource extends SecurityResourceBase { public Response deleteAccount(@Context UriInfo uriInfo, @PathParam("csid") String csid) { logger.debug("deleteAccount with csid=" + csid); ensureCSID(csid, ServiceMessages.DELETE_FAILED); + try { AccountsCommon account = (AccountsCommon)get(csid, AccountsCommon.class); // If marked as metadata immutable, do not delete - if(AccountClient.IMMUTABLE.equals(account.getMetadataProtection())) { + if (AccountClient.IMMUTABLE.equals(account.getMetadataProtection())) { Response response = Response.status(Response.Status.FORBIDDEN).entity("Account: "+csid+" is immutable.").type("text/plain").build(); return response; } - //FIXME ideally the following two ops should be in the same tx CSPACE-658 - //delete all relationships - AccountRoleSubResource subResource = new AccountRoleSubResource("accounts/accountroles"); - subResource.deleteAccountRole(csid, SubjectType.ROLE); + // + // We need to delete the account and the account/role relationships in a + // single transaction + // ServiceContext ctx = createServiceContext((AccountsCommon) null, AccountsCommon.class, uriInfo); - getStorageClient(ctx).delete(ctx, csid); - return Response.status(HttpResponseCodes.SC_OK).build(); + ctx.openConnection(); + try { + AccountRoleSubResource subResource = new AccountRoleSubResource("accounts/accountroles"); + subResource.deleteAccountRole(ctx, csid, SubjectType.ROLE); + getStorageClient(ctx).delete(ctx, csid); + } finally { + ctx.closeConnection(); + } } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid); } + return Response.status(HttpResponseCodes.SC_OK).build(); } @POST @@ -473,7 +482,7 @@ public class AccountResource extends SecurityResourceBase { @PathParam("csid") String accCsid, AccountRole input) { if (method != null) { - if ("delete".equalsIgnoreCase(method)) { + if ("delete".equalsIgnoreCase(method)) { // How would this ever be true? return deleteAccountRole(accCsid, input); } } @@ -482,14 +491,14 @@ public class AccountResource extends SecurityResourceBase { try { AccountsCommon account = (AccountsCommon)get(accCsid, AccountsCommon.class); // If marked as roles immutable, do not create - if(AccountClient.IMMUTABLE.equals(account.getRolesProtection())) { + if (AccountClient.IMMUTABLE.equals(account.getRolesProtection())) { Response response = Response.status(Response.Status.FORBIDDEN).entity("Roles for Account: "+accCsid+" are immutable.").type("text/plain").build(); return response; } AccountRoleSubResource subResource = new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE); - String accrolecsid = subResource.createAccountRole(input, SubjectType.ROLE); + String accrolecsid = subResource.createAccountRole((ServiceContext)null, input, SubjectType.ROLE); UriBuilder path = UriBuilder.fromResource(AccountResource.class); path.path(accCsid + "/accountroles/" + accrolecsid); Response response = Response.created(path.build()).build(); @@ -511,7 +520,7 @@ public class AccountResource extends SecurityResourceBase { AccountRoleSubResource subResource = new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE); //get relationships for an account - result = subResource.getAccountRoleRel(accCsid, SubjectType.ROLE, accrolecsid); + result = subResource.getAccountRoleRel((ServiceContext)null, accCsid, SubjectType.ROLE, accrolecsid); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.GET_FAILED, accCsid); } @@ -526,14 +535,16 @@ public class AccountResource extends SecurityResourceBase { logger.debug("getAccountRole with accCsid=" + accCsid); ensureCSID(accCsid, ServiceMessages.GET_FAILED+ "accountroles account "); AccountRole result = null; + try { AccountRoleSubResource subResource = new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE); //get relationships for an account - result = subResource.getAccountRole(accCsid, SubjectType.ROLE); + result = subResource.getAccountRole((ServiceContext)null, accCsid, SubjectType.ROLE); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.GET_FAILED, accCsid); } + checkResult(result, accCsid, ServiceMessages.GET_FAILED); return result; } @@ -542,6 +553,7 @@ public class AccountResource extends SecurityResourceBase { @Path("{csid}/accountperms") public AccountPermission getAccountPerm(@PathParam("csid") String accCsid) { logger.debug("getAccountPerm with accCsid=" + accCsid); + ensureCSID(accCsid, ServiceMessages.GET_FAILED+ "getAccountPerm account "); AccountPermission result = null; try { @@ -550,12 +562,14 @@ public class AccountResource extends SecurityResourceBase { throw bigReThrow(e, ServiceMessages.GET_FAILED, accCsid); } checkResult(result, accCsid, ServiceMessages.GET_FAILED); + return result; } public Response deleteAccountRole(String accCsid, AccountRole input) { logger.debug("deleteAccountRole with accCsid=" + accCsid); ensureCSID(accCsid, ServiceMessages.DELETE_FAILED+ "accountroles account "); + try { AccountsCommon account = (AccountsCommon)get(accCsid, AccountsCommon.class); // If marked as roles immutable, do not delete @@ -567,11 +581,12 @@ public class AccountResource extends SecurityResourceBase { AccountRoleSubResource subResource = new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE); //delete all relationships for an account - subResource.deleteAccountRole(accCsid, SubjectType.ROLE, input); - return Response.status(HttpResponseCodes.SC_OK).build(); + subResource.deleteAccountRole((ServiceContext)null, accCsid, SubjectType.ROLE, input); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, accCsid); } + + return Response.status(HttpResponseCodes.SC_OK).build(); } @DELETE @@ -579,10 +594,11 @@ public class AccountResource extends SecurityResourceBase { public Response deleteAccountRole(@PathParam("csid") String accCsid) { logger.debug("deleteAccountRole: All roles related to account with accCsid=" + accCsid); ensureCSID(accCsid, ServiceMessages.DELETE_FAILED+ "accountroles account "); + try { // If marked as roles immutable, do not delete AccountsCommon account = (AccountsCommon)get(accCsid, AccountsCommon.class); - if(AccountClient.IMMUTABLE.equals(account.getRolesProtection())) { + if (AccountClient.IMMUTABLE.equals(account.getRolesProtection())) { Response response = Response.status(Response.Status.FORBIDDEN).entity("Roles for Account: "+accCsid+" are immutable.").type("text/plain").build(); return response; @@ -590,10 +606,12 @@ public class AccountResource extends SecurityResourceBase { AccountRoleSubResource subResource = new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE); //delete all relationships for an account - subResource.deleteAccountRole(accCsid, SubjectType.ROLE); - return Response.status(HttpResponseCodes.SC_OK).build(); + subResource.deleteAccountRole((ServiceContext)null, accCsid, SubjectType.ROLE); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, accCsid); } + + return Response.status(HttpResponseCodes.SC_OK).build(); + } } diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/AccountRoleSubResource.java b/services/account/service/src/main/java/org/collectionspace/services/account/AccountRoleSubResource.java index 811df57b6..9d3dce195 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/AccountRoleSubResource.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/AccountRoleSubResource.java @@ -30,21 +30,19 @@ import javax.persistence.PersistenceException; import org.collectionspace.authentication.AuthN; import org.collectionspace.services.account.storage.AccountRoleDocumentHandler; -//import org.collectionspace.services.authorization.AccountRolesList; -//import org.collectionspace.services.authorization.AccountRolesList.AccountRoleListItem; import org.collectionspace.services.authorization.AccountRole; import org.collectionspace.services.authorization.AccountRoleRel; import org.collectionspace.services.authorization.Role; import org.collectionspace.services.authorization.RoleValue; import org.collectionspace.services.authorization.SubjectType; -import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon; import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl; import org.collectionspace.services.common.context.RemoteServiceContextFactory; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.context.ServiceContextFactory; import org.collectionspace.services.common.document.DocumentHandler; import org.collectionspace.services.common.storage.StorageClient; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaRelationshipStorageClient; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; import org.collectionspace.services.common.context.ServiceContextProperties; @@ -56,6 +54,7 @@ import org.slf4j.LoggerFactory; * AccountRoleSubResource is used to manage account-role relationship * @author */ +@SuppressWarnings("rawtypes") public class AccountRoleSubResource // extends AbstractCollectionSpaceResourceImpl { extends AbstractCollectionSpaceResourceImpl { @@ -108,9 +107,9 @@ public class AccountRoleSubResource /* (non-Javadoc) * @see org.collectionspace.services.common.CollectionSpaceResource#getServiceContextFactory() */ - @Override + @SuppressWarnings("unchecked") + @Override public ServiceContextFactory getServiceContextFactory() { -// public ServiceContextFactory getServiceContextFactory() { return RemoteServiceContextFactory.get(); } @@ -124,9 +123,21 @@ public class AccountRoleSubResource * * @throws Exception the exception */ - private ServiceContext createServiceContext(AccountRole input, + private ServiceContext createServiceContext( + ServiceContext parentCtx, + AccountRole input, SubjectType subject) throws Exception { ServiceContext ctx = createServiceContext(input); + JPATransactionContext parentTransactionContext = parentCtx != null ? (JPATransactionContext)parentCtx.getCurrentTransactionContext() : null; + // + // If the parent context has an active JPA connection then we'll use it. + // + if (parentTransactionContext != null) { + ctx.setTransactionContext(parentTransactionContext); + } + // + // Set other context values + // ctx.setDocumentType(AccountRole.class.getPackage().getName()); //persistence unit ctx.setProperty(ServiceContextProperties.ENTITY_NAME, AccountRoleRel.class.getName()); ctx.setProperty(ServiceContextProperties.ENTITY_CLASS, AccountRoleRel.class); @@ -162,7 +173,7 @@ public class AccountRoleSubResource * @return * @throws Exception */ - public String createAccountRole(AccountRole input, SubjectType subject) + public String createAccountRole(ServiceContext parentCtx, AccountRole input, SubjectType subject) throws Exception { // @@ -185,7 +196,7 @@ public class AccountRoleSubResource // The Spring role relationship may already exist, if it does then we'll get a PersistenceException that // we'll just ignore. try { - ServiceContext ctx = createServiceContext(input, subject); + ServiceContext ctx = createServiceContext(parentCtx, input, subject); DocumentHandler handler = createDocumentHandler(ctx); getStorageClient(ctx).create(ctx, handler); } catch (PersistenceException e) { @@ -202,7 +213,7 @@ public class AccountRoleSubResource // Now we'll add the account relationships for the original incoming roles. // input.setRole(inputRoleValues); - ServiceContext ctx = createServiceContext(input, subject); + ServiceContext ctx = createServiceContext(parentCtx, input, subject); DocumentHandler handler = createDocumentHandler(ctx); String bogusCsid = getStorageClient(ctx).create(ctx, handler); @@ -217,14 +228,14 @@ public class AccountRoleSubResource * @return * @throws Exception */ - public AccountRole getAccountRole( + public AccountRole getAccountRole(ServiceContext parentCtx, String csid, SubjectType subject) throws Exception { if (logger.isDebugEnabled()) { logger.debug("getAccountRole with csid=" + csid); } AccountRole result = null; - ServiceContext ctx = createServiceContext((AccountRole) null, subject); + ServiceContext ctx = createServiceContext(parentCtx, (AccountRole) null, subject); DocumentHandler handler = createDocumentHandler(ctx); getStorageClient(ctx).get(ctx, csid, handler); result = (AccountRole) ctx.getOutput(); @@ -241,27 +252,19 @@ public class AccountRoleSubResource * @return the account role * @throws Exception the exception */ - public AccountRoleRel getAccountRoleRel(String csid, + public AccountRoleRel getAccountRoleRel( + ServiceContext parentCtx, + String csid, SubjectType subject, String accountRoleCsid) throws Exception { if (logger.isDebugEnabled()) { logger.debug("getAccountRole with csid=" + csid); } -// AccountRolesList result = new AccountRolesList(); - ServiceContext ctx = createServiceContext((AccountRole) null, subject); + ServiceContext ctx = createServiceContext(parentCtx, (AccountRole)null, subject); AccountRoleDocumentHandler handler = (AccountRoleDocumentHandler)createDocumentHandler(ctx); handler.setAccountRoleCsid(accountRoleCsid); - //getStorageClient(ctx).get(ctx, csid, handler); AccountRoleRel accountRoleRel = (AccountRoleRel)JpaStorageUtils.getEntity(new Long(accountRoleCsid).longValue(), AccountRoleRel.class); -// List accountRoleList = result.getAccountRoleListItems(); -// AccountRoleListItem listItem = new AccountRoleListItem(); -// // fill the item -// listItem.setCsid(accountRoleRel.getHjid().toString()); -// listItem.setRoleId(accountRoleRel.getRoleId()); -// listItem.setRoleName(accountRoleRel.getRoleName()); - // add item to result list -// result = (AccountRolesList) ctx.getOutput(); return accountRoleRel; } @@ -273,14 +276,16 @@ public class AccountRoleSubResource * @param subject the subject * @throws Exception the exception */ - public void x_deleteAccountRole(String csid, + public void x_deleteAccountRole( + ServiceContext parentCtx, + String csid, SubjectType subject) throws Exception { if (logger.isDebugEnabled()) { logger.debug("deleteAccountRole with csid=" + csid); } - AccountRole toDelete = getAccountRole(csid, subject); - deleteAccountRole(csid, subject, toDelete); + AccountRole toDelete = getAccountRole(parentCtx, csid, subject); + deleteAccountRole(parentCtx, csid, subject, toDelete); } /** @@ -291,13 +296,15 @@ public class AccountRoleSubResource * @return * @throws Exception */ - public void deleteAccountRole(String csid, + public void deleteAccountRole( + ServiceContext parentCtx, + String csid, SubjectType subject) throws Exception { if (logger.isDebugEnabled()) { logger.debug("deleteAccountRole with csid=" + csid); } - ServiceContext ctx = createServiceContext((AccountRole) null, subject); + ServiceContext ctx = createServiceContext(parentCtx, (AccountRole) null, subject); getStorageClient(ctx).delete(ctx, csid); } @@ -310,10 +317,12 @@ public class AccountRoleSubResource * @return * @throws Exception */ - public void deleteAccountRole(String csid, SubjectType subject, AccountRole input) + public void deleteAccountRole( + ServiceContext parentCtx, + String csid, SubjectType subject, AccountRole input) throws Exception { - ServiceContext ctx = createServiceContext(input, subject); + ServiceContext ctx = createServiceContext(parentCtx, input, subject); DocumentHandler handler = createDocumentHandler(ctx); getStorageClient(ctx).delete(ctx, csid, handler); } diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java index 1c7d796f7..daa2245cc 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java @@ -32,9 +32,15 @@ import org.collectionspace.services.account.AccountTenant; import org.collectionspace.services.account.AccountsCommon; import org.collectionspace.services.account.AccountsCommonList; import org.collectionspace.services.account.AccountListItem; +import org.collectionspace.services.account.AccountRoleSubResource; import org.collectionspace.services.account.Status; - +import org.collectionspace.services.authorization.AccountRole; +import org.collectionspace.services.authorization.AccountValue; +import org.collectionspace.services.authorization.SubjectType; +import org.collectionspace.services.account.RoleValue; import org.collectionspace.services.client.AccountClient; +import org.collectionspace.services.client.AccountFactory; +import org.collectionspace.services.client.AccountRoleFactory; import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.DocumentFilter; @@ -50,7 +56,7 @@ import org.slf4j.LoggerFactory; * @author */ public class AccountDocumentHandler - extends JpaDocumentHandler { + extends JpaDocumentHandler> { private final Logger logger = LoggerFactory.getLogger(AccountDocumentHandler.class); private AccountsCommon account; @@ -73,9 +79,32 @@ public class AccountDocumentHandler AccountsCommon accountFound = wrapDoc.getWrappedObject(); AccountsCommon accountReceived = getCommonPart(); // If marked as metadata immutable, do not do update - if(!AccountClient.IMMUTABLE.equals(accountFound.getMetadataProtection())) { + if (!AccountClient.IMMUTABLE.equals(accountFound.getMetadataProtection())) { merge(accountReceived, accountFound); } + // + // Update the accountroles if supplied + // + List roleValueList = accountReceived.getRole(); + if (roleValueList != null && roleValueList.size() > 0) { + AccountRoleSubResource subResource = + new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE); + // + // First, delete the exist accountroles + // + subResource.deleteAccountRole(getServiceContext(), accountFound.getCsid(), SubjectType.ROLE); + // + // Next, create the new accountroles + // + AccountRole accountRole = AccountRoleFactory.createAccountRoleInstance(accountFound, + roleValueList, true, true); + String accountRoleCsid = subResource.createAccountRole(getServiceContext(), accountRole, SubjectType.ROLE); + // + // Finally, set the updated role list in the result + // + AccountRole newAccountRole = subResource.getAccountRole(getServiceContext(), accountFound.getCsid(), SubjectType.ROLE); + accountFound.setRole(AccountRoleFactory.convert(newAccountRole.getRole())); + } } /** @@ -116,6 +145,17 @@ public class AccountDocumentHandler return to; } + @Override + public void completeCreate(DocumentWrapper wrapDoc) throws Exception { + AccountsCommon accountsCommon = wrapDoc.getWrappedObject(); + List roleValueList = account.getRole(); + if (roleValueList != null && roleValueList.size() > 0) { + AccountRoleSubResource subResource = new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE); + AccountRole accountRole = AccountRoleFactory.createAccountRoleInstance(accountsCommon, roleValueList, true, true); + String accountRoleCsid = subResource.createAccountRole(this.getServiceContext(), accountRole, SubjectType.ROLE); + } + } + @Override public void completeUpdate(DocumentWrapper wrapDoc) throws Exception { AccountsCommon upAcc = wrapDoc.getWrappedObject(); @@ -131,7 +171,7 @@ public class AccountDocumentHandler } @Override - public void handleGetAll(DocumentWrapper wrapDoc) throws Exception { + public void handleGetAll(DocumentWrapper> wrapDoc) throws Exception { AccountsCommonList accList = extractCommonPartList(wrapDoc); setCommonPartList(accList); getServiceContext().setOutput(getCommonPartList()); @@ -152,7 +192,7 @@ public class AccountDocumentHandler @Override public AccountsCommonList extractCommonPartList( - DocumentWrapper wrapDoc) + DocumentWrapper> wrapDoc) throws Exception { AccountsCommonList accList = this.extractPagingInfo(new AccountsCommonList(), wrapDoc); diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountRoleDocumentHandler.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountRoleDocumentHandler.java index d6ee4c05e..9ea090609 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountRoleDocumentHandler.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountRoleDocumentHandler.java @@ -202,6 +202,11 @@ public class AccountRoleDocumentHandler // return result; } + @Override + public void prepareCreate() throws Exception { + // Ensure the roles exist + } + public void fillCommonPart(AccountRole ar, DocumentWrapper> wrapDoc, boolean handleDelete) diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java index ea517d1a2..ffdf5398d 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountStorageClient.java @@ -25,8 +25,6 @@ package org.collectionspace.services.account.storage; import java.util.Date; import java.util.HashMap; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; import org.collectionspace.services.account.AccountsCommon; import org.collectionspace.services.account.storage.csidp.UserStorageClient; @@ -41,6 +39,7 @@ import org.collectionspace.services.common.document.DocumentNotFoundException; import org.collectionspace.services.common.document.DocumentWrapper; import org.collectionspace.services.common.document.DocumentWrapperImpl; import org.collectionspace.services.common.document.JaxbUtils; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; @@ -54,6 +53,7 @@ import org.slf4j.LoggerFactory; * are used where possible to permorme the persistence operations atomically. * @author */ +@SuppressWarnings({ "rawtypes", "unchecked" }) public class AccountStorageClient extends JpaStorageClientImpl { private final Logger logger = LoggerFactory.getLogger(AccountStorageClient.class); @@ -62,63 +62,51 @@ public class AccountStorageClient extends JpaStorageClientImpl { public AccountStorageClient() { } - @Override + @Override public String create(ServiceContext ctx, DocumentHandler handler) throws BadRequestException, DocumentException { - - if (ctx == null) { - throw new IllegalArgumentException( - "AccountStorageClient.create : ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "AccountStorageClient.create: handler is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; - AccountsCommon account = (AccountsCommon) handler.getCommonPart(); + String result = null; + + AccountsCommon account = null; + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { + account = (AccountsCommon) handler.getCommonPart(); handler.prepare(Action.CREATE); DocumentWrapper wrapDoc = new DocumentWrapperImpl(account); handler.handle(Action.CREATE, wrapDoc); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - em.getTransaction().begin(); - //if userid and password are given, add to default id provider - if (account.getUserId() != null && - isForCSIdP(account.getPassword())) { - User user = userStorageClient.create(account.getUserId(), - account.getPassword()); - em.persist(user); + jpaConnectionContext.beginTransaction(); + // + // If userid and password are given, add to default id provider + // + if (account.getUserId() != null && isForCSpaceIdentityProvider(account.getPassword())) { + User user = userStorageClient.create(account.getUserId(), account.getPassword()); + jpaConnectionContext.persist(user); } -// if (accountReceived.getTenant() != null) { -// UserTenant ut = createTenantAssoc(accountReceived); -// em.persist(ut); -// } + account.setCreatedAtItem(new Date()); - em.persist(account); - em.getTransaction().commit(); + jpaConnectionContext.persist(account); + handler.complete(Action.CREATE, wrapDoc); - return (String) JaxbUtils.getValue(account, "getCsid"); + jpaConnectionContext.commitTransaction(); + + result = (String)JaxbUtils.getValue(account, "getCsid"); } catch (BadRequestException bre) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw bre; } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } boolean uniqueConstraint = false; - if (userStorageClient.get(em, account.getUserId()) != null) { + if (userStorageClient.get(ctx, account.getUserId()) != null) { //might be unique constraint violation uniqueConstraint = true; } - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + + jpaConnectionContext.markForRollback(); + if (uniqueConstraint) { String msg = "UserId exists. Non unique userId=" + account.getUserId(); logger.error(msg); @@ -126,28 +114,21 @@ public class AccountStorageClient extends JpaStorageClientImpl { } throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } + + return result; } @Override public void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { - if (ctx == null) { - throw new IllegalArgumentException( - "get: ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "get: handler is missing"); - } DocumentFilter docFilter = handler.getDocumentFilter(); if (docFilter == null) { docFilter = handler.createDocumentFilter(); } + JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection(); try { handler.prepare(Action.GET); Object o = null; @@ -156,7 +137,7 @@ public class AccountStorageClient extends JpaStorageClientImpl { params.put("csid", id); params.put("tenantId", ctx.getTenantId()); - o = JpaStorageUtils.getEntity( + o = JpaStorageUtils.getEntity(jpaTransactionContext, "org.collectionspace.services.account.AccountsCommon", whereClause, params); if (null == o) { String msg = "could not find entity with id=" + id; @@ -172,64 +153,50 @@ public class AccountStorageClient extends JpaStorageClientImpl { logger.debug("Caught exception ", e); } throw new DocumentException(e); + } finally { + ctx.closeConnection(); } + } @Override public void update(ServiceContext ctx, String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException { - if (ctx == null) { - throw new IllegalArgumentException( - "AccountStorageClient.update : ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "AccountStorageClient.update: handler is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { + jpaConnectionContext.beginTransaction(); + handler.prepare(Action.UPDATE); AccountsCommon accountReceived = (AccountsCommon) handler.getCommonPart(); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - em.getTransaction().begin(); - AccountsCommon accountFound = getAccount(em, id); + AccountsCommon accountFound = getAccount(jpaConnectionContext, id); checkAllowedUpdates(accountReceived, accountFound); //if userid and password are given, add to default id provider // Note that this ignores the immutable flag, as we allow // password changes. - if (accountReceived.getUserId() != null - && isForCSIdP(accountReceived.getPassword())) { - userStorageClient.update(em, + if (accountReceived.getUserId() != null && isForCSpaceIdentityProvider(accountReceived.getPassword())) { + userStorageClient.update(jpaConnectionContext, accountReceived.getUserId(), accountReceived.getPassword()); } DocumentWrapper wrapDoc = new DocumentWrapperImpl(accountFound); handler.handle(Action.UPDATE, wrapDoc); - em.getTransaction().commit(); handler.complete(Action.UPDATE, wrapDoc); + + jpaConnectionContext.commitTransaction(); } catch (BadRequestException bre) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw bre; } catch (DocumentException de) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw de; } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Caught exception ", e); - } + jpaConnectionContext.markForRollback(); throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } @@ -241,54 +208,38 @@ public class AccountStorageClient extends JpaStorageClientImpl { if (logger.isDebugEnabled()) { logger.debug("deleting entity with id=" + id); } - if (ctx == null) { - throw new IllegalArgumentException( - "AccountStorageClient.delete : ctx is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - - AccountsCommon accountFound = getAccount(em, id); - em.getTransaction().begin(); + AccountsCommon accountFound = getAccount(jpaConnectionContext, id); + jpaConnectionContext.beginTransaction(); //if userid gives any indication about the id provider, it should //be used to avoid delete - userStorageClient.delete(em, accountFound.getUserId()); - em.remove(accountFound); - em.getTransaction().commit(); - + userStorageClient.delete(jpaConnectionContext, accountFound.getUserId()); + jpaConnectionContext.remove(accountFound); + jpaConnectionContext.commitTransaction(); } catch (DocumentException de) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw de; } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } - private AccountsCommon getAccount(EntityManager em, String id) throws DocumentNotFoundException { - AccountsCommon accountFound = em.find(AccountsCommon.class, id); + private AccountsCommon getAccount(JPATransactionContext jpaConnectionContext, String id) throws DocumentNotFoundException { + AccountsCommon accountFound = (AccountsCommon) jpaConnectionContext.find(AccountsCommon.class, id); if (accountFound == null) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } String msg = "could not find account with id=" + id; logger.error(msg); throw new DocumentNotFoundException(msg); } + return accountFound; } @@ -311,7 +262,7 @@ public class AccountStorageClient extends JpaStorageClientImpl { * @param bpass * @return */ - private boolean isForCSIdP(byte[] bpass) { + private boolean isForCSpaceIdentityProvider(byte[] bpass) { return bpass != null && bpass.length > 0; } // private UserTenant createTenantAssoc(AccountsCommon accountReceived) { diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountValidatorHandler.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountValidatorHandler.java index 438e9495f..bec10d722 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountValidatorHandler.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountValidatorHandler.java @@ -102,6 +102,10 @@ public class AccountValidatorHandler implements ValidatorHandler { invalid = true; msgBldr.append("\nuserId : missing"); } + if (account.getPassword() == null || account.getPassword().length == 0) { + invalid = true; + msgBldr.append("\npassword : missing"); + } if (account.getEmail() == null || account.getEmail().isEmpty()) { invalid = true; msgBldr.append("\nemail : missing"); diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java index 6822527f6..da43ba694 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java @@ -25,8 +25,7 @@ package org.collectionspace.services.account.storage; import java.util.Date; import java.util.HashMap; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; + import org.collectionspace.services.account.Tenant; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.BadRequestException; @@ -38,6 +37,7 @@ import org.collectionspace.services.common.document.DocumentNotFoundException; import org.collectionspace.services.common.document.DocumentWrapper; import org.collectionspace.services.common.document.DocumentWrapperImpl; import org.collectionspace.services.common.document.JaxbUtils; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; @@ -51,6 +51,7 @@ import org.slf4j.LoggerFactory; * are used where possible to perform the persistence operations atomically. * @author */ +@SuppressWarnings({"rawtypes", "unchecked"}) public class TenantStorageClient extends JpaStorageClientImpl { private final Logger logger = LoggerFactory.getLogger(TenantStorageClient.class); @@ -58,41 +59,28 @@ public class TenantStorageClient extends JpaStorageClientImpl { public TenantStorageClient() { } - @Override + @Override public String create(ServiceContext ctx, DocumentHandler handler) throws BadRequestException, DocumentException { - - /* - if (ctx == null) { - throw new IllegalArgumentException( - "TenantStorageClient.create : ctx is missing"); - } - */ - if (handler == null) { - throw new IllegalArgumentException( - "TenantStorageClient.create: handler is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; + String result = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); Tenant tenant = (Tenant) handler.getCommonPart(); try { handler.prepare(Action.CREATE); DocumentWrapper wrapDoc = new DocumentWrapperImpl(tenant); handler.handle(Action.CREATE, wrapDoc); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - em.getTransaction().begin(); + jpaConnectionContext.beginTransaction(); tenant.setCreatedAtItem(new Date()); - em.persist(tenant); - em.getTransaction().commit(); + jpaConnectionContext.persist(tenant); handler.complete(Action.CREATE, wrapDoc); - return (String) JaxbUtils.getValue(tenant, "getId"); + jpaConnectionContext.commitTransaction(); + + result = (String)JaxbUtils.getValue(tenant, "getId"); } catch (BadRequestException bre) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw bre; } catch (Exception e) { if (logger.isDebugEnabled()) { @@ -100,16 +88,14 @@ public class TenantStorageClient extends JpaStorageClientImpl { } boolean uniqueConstraint = false; try { - if(em.find(Tenant.class, tenant.getId()) != null) { + if(jpaConnectionContext.find(Tenant.class, tenant.getId()) != null) { //might be unique constraint violation uniqueConstraint = true; } } catch(Exception ignored) { //Ignore - we just care if exists } - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); if (uniqueConstraint) { String msg = "TenantId exists. Non unique tenantId=" + tenant.getId(); logger.error(msg); @@ -117,31 +103,21 @@ public class TenantStorageClient extends JpaStorageClientImpl { } throw new DocumentException(e); } finally { - if (em != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } + + return result; } - @Override + @Override public void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { - /* - if (ctx == null) { - throw new IllegalArgumentException( - "get: ctx is missing"); - } - */ - if (handler == null) { - throw new IllegalArgumentException( - "get: handler is missing"); - } DocumentFilter docFilter = handler.getDocumentFilter(); if (docFilter == null) { docFilter = handler.createDocumentFilter(); } - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { handler.prepare(Action.GET); Object o = null; @@ -152,10 +128,7 @@ public class TenantStorageClient extends JpaStorageClientImpl { o = JpaStorageUtils.getEntity( "org.collectionspace.services.account.Tenant", whereClause, params); if (null == o) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - String msg = "could not find entity with id=" + id; + String msg = "Could not find entity with id=" + id; throw new DocumentNotFoundException(msg); } DocumentWrapper wrapDoc = new DocumentWrapperImpl(o); @@ -169,9 +142,7 @@ public class TenantStorageClient extends JpaStorageClientImpl { } throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } @@ -179,50 +150,35 @@ public class TenantStorageClient extends JpaStorageClientImpl { public void update(ServiceContext ctx, String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException { - /* - if (ctx == null) { - throw new IllegalArgumentException( - "TenantStorageClient.update : ctx is missing"); - } - */ - if (handler == null) { - throw new IllegalArgumentException( - "TenantStorageClient.update: handler is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { handler.prepare(Action.UPDATE); + Tenant tenantReceived = (Tenant) handler.getCommonPart(); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - em.getTransaction().begin(); - Tenant tenantFound = getTenant(em, id); + jpaConnectionContext.beginTransaction(); + Tenant tenantFound = getTenant(jpaConnectionContext, id); checkAllowedUpdates(tenantReceived, tenantFound); DocumentWrapper wrapDoc = new DocumentWrapperImpl(tenantFound); handler.handle(Action.UPDATE, wrapDoc); - em.getTransaction().commit(); handler.complete(Action.UPDATE, wrapDoc); + + jpaConnectionContext.commitTransaction(); } catch (BadRequestException bre) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw bre; } catch (DocumentException de) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw de; } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } + jpaConnectionContext.markForRollback(); throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } @@ -234,53 +190,35 @@ public class TenantStorageClient extends JpaStorageClientImpl { if (logger.isDebugEnabled()) { logger.debug("deleting entity with id=" + id); } - /* - if (ctx == null) { - throw new IllegalArgumentException( - "TenantStorageClient.delete : ctx is missing"); - } - */ - EntityManagerFactory emf = null; - EntityManager em = null; - try { - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - - Tenant tenantFound = getTenant(em, id); - em.getTransaction().begin(); - em.remove(tenantFound); - em.getTransaction().commit(); + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); + try { + Tenant tenantFound = getTenant(jpaConnectionContext, id); + jpaConnectionContext.beginTransaction(); + jpaConnectionContext.remove(tenantFound); + jpaConnectionContext.commitTransaction(); } catch (DocumentException de) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw de; } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } - private Tenant getTenant(EntityManager em, String id) throws DocumentNotFoundException { - Tenant tenantFound = em.find(Tenant.class, id); + private Tenant getTenant(JPATransactionContext jpaConnectionContext, String id) throws DocumentNotFoundException { + Tenant tenantFound = (Tenant) jpaConnectionContext.find(Tenant.class, id); if (tenantFound == null) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } String msg = "could not find account with id=" + id; logger.error(msg); throw new DocumentNotFoundException(msg); } + return tenantFound; } diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/csidp/UserStorageClient.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/csidp/UserStorageClient.java index 2345ec102..b274c21bc 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/csidp/UserStorageClient.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/csidp/UserStorageClient.java @@ -28,13 +28,17 @@ package org.collectionspace.services.account.storage.csidp; import java.util.Date; -import javax.persistence.EntityManager; import javax.persistence.Query; + import org.collectionspace.services.authentication.User; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.BadRequestException; import org.collectionspace.services.common.document.DocumentNotFoundException; import org.collectionspace.services.common.document.JaxbUtils; +import org.collectionspace.services.common.document.TransactionException; import org.collectionspace.services.common.security.SecurityUtils; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -67,18 +71,35 @@ public class UserStorageClient { * @param em EntityManager * @param userId */ - public User get(EntityManager em, String userId) throws DocumentNotFoundException { - User userFound = em.find(User.class, userId); + public User get(JPATransactionContext jpaTransactionContext, String userId) throws DocumentNotFoundException { + User userFound = (User) jpaTransactionContext.find(User.class, userId); if (userFound == null) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - String msg = "could not find user with userId=" + userId; + String msg = "Could not find user with userId=" + userId; logger.error(msg); throw new DocumentNotFoundException(msg); } + return userFound; } + + @SuppressWarnings("rawtypes") + public User get(ServiceContext ctx, String userId) throws DocumentNotFoundException, TransactionException { + User userFound = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); + try { + userFound = (User) jpaConnectionContext.find(User.class, userId); + if (userFound == null) { + String msg = "could not find user with userId=" + userId; + logger.error(msg); + throw new DocumentNotFoundException(msg); + } + } finally { + ctx.closeConnection(); + } + + return userFound; + } /** * updateUser for given userId @@ -86,16 +107,16 @@ public class UserStorageClient { * @param userId * @param password */ - public void update(EntityManager em, String userId, byte[] password) + public void update(JPATransactionContext jpaTransactionContext, String userId, byte[] password) throws DocumentNotFoundException, Exception { - User userFound = get(em, userId); + User userFound = get(jpaTransactionContext, userId); if (userFound != null) { userFound.setPasswd(getEncPassword(userId, password)); userFound.setUpdatedAtItem(new Date()); if (logger.isDebugEnabled()) { logger.debug("updated user=" + JaxbUtils.toString(userFound, User.class)); } - em.persist(userFound); + jpaTransactionContext.persist(userFound); } } @@ -105,7 +126,7 @@ public class UserStorageClient { * @param userId * @throws Exception if user for given userId not found */ - public void delete(EntityManager em, String userId) + public void delete(JPATransactionContext jpaTransactionContext, String userId) throws DocumentNotFoundException, Exception { //if userid gives any indication about the id provider, it should //be used to avoid the following approach @@ -113,13 +134,10 @@ public class UserStorageClient { usrDelStr.append(User.class.getCanonicalName()); usrDelStr.append(" WHERE username = :username"); //TODO: add tenant id - Query usrDel = em.createQuery(usrDelStr.toString()); + Query usrDel = jpaTransactionContext.createQuery(usrDelStr.toString()); usrDel.setParameter("username", userId); int usrDelCount = usrDel.executeUpdate(); if (usrDelCount != 1) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } String msg = "could not find user with username=" + userId; logger.error(msg); throw new DocumentNotFoundException(msg); diff --git a/services/authorization-mgt/client/src/test/java/org/collectionspace/services/authorization/client/test/RoleServiceTest.java b/services/authorization-mgt/client/src/test/java/org/collectionspace/services/authorization/client/test/RoleServiceTest.java index b6a9b0c6f..9ac0801ea 100644 --- a/services/authorization-mgt/client/src/test/java/org/collectionspace/services/authorization/client/test/RoleServiceTest.java +++ b/services/authorization-mgt/client/src/test/java/org/collectionspace/services/authorization/client/test/RoleServiceTest.java @@ -231,7 +231,7 @@ public class RoleServiceTest extends AbstractServiceTestImpl permRoleRels = new ArrayList(); for (PermissionRole pr : authzGen.getDefaultPermissionRoles()) { String tenantId = getTenantId(pr); - PermissionRoleUtil.buildPermissionRoleRel(em, pr, SubjectType.ROLE, permRoleRels, false /*not for delete*/, tenantId); + PermissionRoleUtil.buildPermissionRoleRel(jpaTransactionContext, pr, SubjectType.ROLE, permRoleRels, false /*not for delete*/, tenantId); } for (PermissionRoleRel permRoleRel : permRoleRels) { - authzStore.store(em, permRoleRel); + authzStore.store(jpaTransactionContext, permRoleRel); } - em.getTransaction().commit(); - em.close(); + jpaTransactionContext.commitTransaction(); if (logger.isInfoEnabled()) { logger.info("All Authorization metadata persisted."); } } catch (Exception e) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaTransactionContext.markForRollback(); if (logger.isDebugEnabled()) { logger.debug("Caught exception and rolling back permission creation: ", e); } throw e; } finally { - if (em != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + jpaTransactionContext.close(); } } diff --git a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java index 7ead52095..23510b009 100644 --- a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java +++ b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java @@ -46,6 +46,7 @@ import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon import org.collectionspace.services.common.config.ServicesConfigReaderImpl; import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; import org.collectionspace.services.common.security.SecurityUtils; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.config.service.ServiceBindingType; import org.collectionspace.services.config.tenant.TenantBindingType; @@ -109,7 +110,7 @@ public class AuthorizationGen { * @see initialize * @return */ - public void createDefaultPermissions() { + public void createDefaultPermissions(JPATransactionContext jpaTransactionContext) { for (String tenantId : tenantBindings.keySet()) { List adminPerms = createDefaultAdminPermissions(tenantId, AUTHZ_IS_ENTITY_PROXY); adminPermList.addAll(adminPerms); @@ -129,7 +130,7 @@ public class AuthorizationGen { * @return */ public List createDefaultAdminPermissions(String tenantId, boolean isEntityProxy) { - ArrayList apcList = new ArrayList(); + ArrayList result = new ArrayList(); TenantBindingType tbinding = tenantBindings.get(tenantId); for (ServiceBindingType sbinding : tbinding.getServiceBindings()) { @@ -138,22 +139,20 @@ public class AuthorizationGen { if (isEntityProxy == true) { resourceName = SecurityUtils.getResourceEntity(resourceName); } - Permission perm = buildAdminPermission(tbinding.getId(), - resourceName); - apcList.add(perm); + Permission perm = buildAdminPermission(tbinding.getId(), resourceName); + result.add(perm); //add permissions for alternate paths if (isEntityProxy == false) { List uriPaths = sbinding.getUriPath(); for (String uriPath : uriPaths) { - perm = buildAdminPermission(tbinding.getId(), - uriPath.toLowerCase()); - apcList.add(perm); + perm = buildAdminPermission(tbinding.getId(), uriPath.toLowerCase()); + result.add(perm); } } } - return apcList; + return result; } /** @@ -248,20 +247,20 @@ public class AuthorizationGen { * createDefaultRoles creates default admin and reader roles * for each tenant found in the given tenant binding file */ - public void createDefaultRoles() { + public void createDefaultRoles(JPATransactionContext jpaTransactionContext) { for (String tenantId : tenantBindings.keySet()) { - Role arole = buildTenantAdminRole(tenantId); + Role arole = buildTenantAdminRole(jpaTransactionContext, tenantId); adminRoles.add(arole); - Role rrole = buildTenantReaderRole(tenantId); + Role rrole = buildTenantReaderRole(jpaTransactionContext, tenantId); readerRoles.add(rrole); } } - private Role buildTenantAdminRole(String tenantId) { + private Role buildTenantAdminRole(JPATransactionContext jpaTransactionContext, String tenantId) { String type = "admin"; - Role result = AuthorizationCommon.getRole(tenantId, AuthorizationCommon.ROLE_TENANT_ADMINISTRATOR); + Role result = AuthorizationCommon.getRole(jpaTransactionContext, tenantId, AuthorizationCommon.ROLE_TENANT_ADMINISTRATOR); if (result == null) { // the role doesn't exist already, so we need to create it @@ -272,9 +271,9 @@ public class AuthorizationGen { return result; } - private Role buildTenantReaderRole(String tenantId) { + private Role buildTenantReaderRole(JPATransactionContext jpaTransactionContext, String tenantId) { String type = "read only"; - Role result = AuthorizationCommon.getRole(tenantId, AuthorizationCommon.ROLE_TENANT_READER); + Role result = AuthorizationCommon.getRole(jpaTransactionContext, tenantId, AuthorizationCommon.ROLE_TENANT_READER); if (result == null) { // the role doesn't exist already, so we need to create it diff --git a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationSeed.java b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationSeed.java index fa59a890e..bd849dc15 100644 --- a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationSeed.java +++ b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationSeed.java @@ -39,6 +39,7 @@ import org.collectionspace.services.authorization.PermissionRole; import org.collectionspace.services.authorization.perms.PermissionsList; import org.collectionspace.services.authorization.PermissionsRolesList; import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; /** * AuthorizationSeed seeds authorizations (permission, role) into authz provider database @@ -55,7 +56,7 @@ public class AuthorizationSeed { * @param permRoleFileName permission role file name * @throws Exception */ - public void seedPermissions(String permFileName, String permRoleFileName) throws Exception { + public void seedPermissions(JPATransactionContext jpaTransactionContext, String permFileName, String permRoleFileName) throws Exception { PermissionsRolesList permRoleList = (PermissionsRolesList) fromFile(PermissionsRolesList.class, permRoleFileName); @@ -69,7 +70,7 @@ public class AuthorizationSeed { logger.debug("read permissions from " + permFileName); } - seedPermissions(permList, permRoleList); + seedPermissions(jpaTransactionContext, permList, permRoleList); } /** @@ -78,10 +79,10 @@ public class AuthorizationSeed { * @param permRoleList * @throws Exception */ - public void seedPermissions(PermissionsList permList, PermissionsRolesList permRoleList) + public void seedPermissions(JPATransactionContext jpaTransactionContext, PermissionsList permList, PermissionsRolesList permRoleList) throws Exception { - seedPermissions(permList.getPermission(), permRoleList.getPermissionRole()); + seedPermissions(jpaTransactionContext, permList.getPermission(), permRoleList.getPermissionRole()); } /** @@ -90,7 +91,7 @@ public class AuthorizationSeed { * @param permRoleList * @throws Exception */ - public void seedPermissions(List permList, List permRoleList) + public void seedPermissions(JPATransactionContext jpaTransactionContext, List permList, List permRoleList) throws Exception { if (logger.isInfoEnabled() == true) { logger.info("Started seeding Spring Security Tables..."); diff --git a/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/RoleResource.java b/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/RoleResource.java index cf9283c38..bde34a397 100644 --- a/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/RoleResource.java +++ b/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/RoleResource.java @@ -31,6 +31,7 @@ import org.collectionspace.services.common.context.RemoteServiceContextFactory; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.context.ServiceContextFactory; import org.collectionspace.services.common.storage.StorageClient; +import org.collectionspace.services.common.storage.TransactionContext; import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl; import org.collectionspace.services.common.CSWebApplicationException; @@ -55,6 +56,7 @@ import javax.ws.rs.core.UriInfo; @Path(RoleClient.SERVICE_PATH) @Consumes("application/xml") @Produces("application/xml") +@SuppressWarnings("unchecked") public class RoleResource extends SecurityResourceBase { final Logger logger = LoggerFactory.getLogger(RoleResource.class); @@ -106,16 +108,18 @@ public class RoleResource extends SecurityResourceBase { @PathParam("csid") String accCsid) { logger.debug("getAccountRole with accCsid=" + accCsid); ensureCSID(accCsid, ServiceMessages.GET_FAILED+ "accountroles role "); + AccountRole result = null; try { AccountRoleSubResource subResource = new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE); //get relationships for a role - result = subResource.getAccountRole(accCsid, SubjectType.ACCOUNT); + result = subResource.getAccountRole((ServiceContext)null, accCsid, SubjectType.ACCOUNT); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.GET_FAILED, accCsid); } checkResult(result, accCsid, ServiceMessages.GET_FAILED); + return result; } @@ -128,50 +132,65 @@ public class RoleResource extends SecurityResourceBase { @PUT @Path("{csid}") public Role updateRole(@PathParam("csid") String csid, Role theUpdate) { + Role result = null; + try { Role role = (Role)get(csid, Role.class); // If marked as metadata immutable, do not update - if(RoleClient.IMMUTABLE.equals(role.getMetadataProtection())) { + if (RoleClient.IMMUTABLE.equals(role.getMetadataProtection())) { Response response = Response.status(Response.Status.FORBIDDEN).entity("Role: "+csid+" is immutable.").type("text/plain").build(); throw new CSWebApplicationException(response); } - return (Role)update(csid, theUpdate, Role.class); + result = (Role)update(csid, theUpdate, Role.class); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.UPDATE_FAILED, csid); } + + return result; } - @DELETE + @DELETE @Path("{csid}") - public Response deleteRole(@PathParam("csid") String csid) { + public Response deleteRole(@PathParam("csid") String csid, @Context UriInfo ui) { logger.debug("deleteRole with csid=" + csid); ensureCSID(csid, ServiceMessages.DELETE_FAILED + "deleteRole "); try { - Role role = (Role)get(csid, Role.class); - // If marked as metadata immutable, do not delete - if(RoleClient.IMMUTABLE.equals(role.getMetadataProtection())) { - Response response = - Response.status(Response.Status.FORBIDDEN).entity("Role: "+csid+" is immutable.").type("text/plain").build(); - return response; - } - //FIXME ideally the following three operations should be in the same tx CSPACE-658 - //delete all relationships for this permission - PermissionRoleSubResource permRoleResource = - new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); - permRoleResource.deletePermissionRole(csid, SubjectType.PERMISSION); - //delete all the account/role relationships associate with this role - AccountRoleSubResource accountRoleResource = - new AccountRoleSubResource(AccountRoleSubResource.ROLE_ACCOUNTROLE_SERVICE); - accountRoleResource.deleteAccountRole(csid, SubjectType.ACCOUNT); - //finally, delete the role itself ServiceContext ctx = createServiceContext((Role) null, Role.class); - ((JpaStorageClientImpl) getStorageClient(ctx)).deleteWhere(ctx, csid); - return Response.status(HttpResponseCodes.SC_OK).build(); + ctx.openConnection(); // ensure we do all this in one transaction + try { + Role role = (Role)get(csid, Role.class); + // If marked as metadata immutable, do not delete + if (RoleClient.IMMUTABLE.equals(role.getMetadataProtection())) { + Response response = + Response.status(Response.Status.FORBIDDEN).entity("Role: "+csid+" is immutable.").type("text/plain").build(); + return response; + } + // + // delete all the permission/role relationships + // + PermissionRoleSubResource permRoleResource = + new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); + permRoleResource.deletePermissionRole(ctx, csid, SubjectType.PERMISSION); + // + //delete all the account/role relationships associate with this role + // + AccountRoleSubResource accountRoleResource = + new AccountRoleSubResource(AccountRoleSubResource.ROLE_ACCOUNTROLE_SERVICE); + accountRoleResource.deleteAccountRole(ctx, csid, SubjectType.ACCOUNT); + // + //finally, delete the role itself + // + ((JpaStorageClientImpl) getStorageClient(ctx)).deleteWhere(ctx, csid); + } finally { + ctx.closeConnection(); + } } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid); } + + return Response.status(HttpResponseCodes.SC_OK).build(); } @POST @@ -183,26 +202,29 @@ public class RoleResource extends SecurityResourceBase { return deleteRolePermission(roleCsid, input); } } + logger.debug("createRolePermission with roleCsid=" + roleCsid); ensureCSID(roleCsid, ServiceMessages.PUT_FAILED + "permroles role "); + Response response = null; try { Role role = (Role)get(roleCsid, Role.class); // If marked as metadata immutable, do not delete - if(RoleClient.IMMUTABLE.equals(role.getPermsProtection())) { - Response response = + if (RoleClient.IMMUTABLE.equals(role.getPermsProtection())) { + response = Response.status(Response.Status.FORBIDDEN).entity("Role: "+roleCsid+" is immutable.").type("text/plain").build(); return response; } PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); - String permrolecsid = subResource.createPermissionRole(input, SubjectType.PERMISSION); + String permrolecsid = subResource.createPermissionRole((ServiceContext)null, input, SubjectType.PERMISSION); UriBuilder path = UriBuilder.fromResource(RoleResource.class); path.path(roleCsid + "/permroles/" + permrolecsid); - Response response = Response.created(path.build()).build(); - return response; + response = Response.created(path.build()).build(); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, roleCsid); } + + return response; } @GET @@ -211,16 +233,18 @@ public class RoleResource extends SecurityResourceBase { @PathParam("csid") String roleCsid) { logger.debug("getRolePermission with roleCsid=" + roleCsid); ensureCSID(roleCsid, ServiceMessages.GET_FAILED + "permroles role "); + PermissionRole result = null; try { PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); //get relationships for a role - result = subResource.getPermissionRole(roleCsid, SubjectType.PERMISSION); + result = subResource.getPermissionRole((ServiceContext)null, roleCsid, SubjectType.PERMISSION); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.GET_FAILED, roleCsid); } checkResult(result, roleCsid, ServiceMessages.GET_FAILED); + return result; } @@ -231,38 +255,44 @@ public class RoleResource extends SecurityResourceBase { @PathParam("id") String permrolecsid) { logger.debug("getRolePermission with roleCsid=" + roleCsid); ensureCSID(roleCsid, ServiceMessages.GET_FAILED + "permroles role "); + PermissionRoleRel result = null; try { PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); //get relationships for a role - result = subResource.getPermissionRoleRel(roleCsid, SubjectType.PERMISSION, permrolecsid); + result = subResource.getPermissionRoleRel((ServiceContext)null, roleCsid, SubjectType.PERMISSION, permrolecsid); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.GET_FAILED, roleCsid); } checkResult(result, roleCsid, ServiceMessages.GET_FAILED); + return result; } public Response deleteRolePermission(String roleCsid, PermissionRole input) { logger.debug("deleteRolePermission with roleCsid=" + roleCsid); ensureCSID(roleCsid, ServiceMessages.DELETE_FAILED + "permroles role "); + + Response result = null; try { Role role = (Role)get(roleCsid, Role.class); // If marked as metadata immutable, do not delete - if(RoleClient.IMMUTABLE.equals(role.getPermsProtection())) { - Response response = - Response.status(Response.Status.FORBIDDEN).entity("Role: "+roleCsid+" is immutable.").type("text/plain").build(); + if (RoleClient.IMMUTABLE.equals(role.getPermsProtection())) { + Response response = Response.status(Response.Status.FORBIDDEN).entity( + "Role: "+roleCsid+" is immutable.").type("text/plain").build(); return response; } PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); //delete all relationships for a permission - subResource.deletePermissionRole(roleCsid, SubjectType.PERMISSION, input); - return Response.status(HttpResponseCodes.SC_OK).build(); + subResource.deletePermissionRole((ServiceContext)null, roleCsid, SubjectType.PERMISSION, input); + result = Response.status(HttpResponseCodes.SC_OK).build(); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, roleCsid); } + + return result; } @DELETE @@ -271,10 +301,11 @@ public class RoleResource extends SecurityResourceBase { @PathParam("csid") String roleCsid) { logger.debug("deleteRolePermission with roleCsid=" + roleCsid); ensureCSID(roleCsid, ServiceMessages.DELETE_FAILED + "permroles role "); + try { Role role = (Role)get(roleCsid, Role.class); // If marked as metadata immutable, do not delete - if(RoleClient.IMMUTABLE.equals(role.getPermsProtection())) { + if (RoleClient.IMMUTABLE.equals(role.getPermsProtection())) { Response response = Response.status(Response.Status.FORBIDDEN).entity("Role: "+roleCsid+" is immutable.").type("text/plain").build(); return response; @@ -282,10 +313,11 @@ public class RoleResource extends SecurityResourceBase { PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); //delete all relationships for a permission - subResource.deletePermissionRole(roleCsid, SubjectType.PERMISSION); - return Response.status(HttpResponseCodes.SC_OK).build(); + subResource.deletePermissionRole((ServiceContext)null, roleCsid, SubjectType.PERMISSION); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, roleCsid); } + + return Response.status(HttpResponseCodes.SC_OK).build(); } } diff --git a/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/RoleDocumentHandler.java b/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/RoleDocumentHandler.java index 77b3ca387..cd777062f 100644 --- a/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/RoleDocumentHandler.java +++ b/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/RoleDocumentHandler.java @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; -import org.collectionspace.services.account.AccountsCommonList; import org.collectionspace.services.authorization.PermissionRole; import org.collectionspace.services.authorization.PermissionRoleSubResource; import org.collectionspace.services.authorization.PermissionValue; @@ -40,13 +39,14 @@ import org.collectionspace.services.client.PermissionRoleFactory; import org.collectionspace.services.client.RoleClient; import org.collectionspace.services.client.RoleFactory; import org.collectionspace.services.common.api.Tools; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.BadRequestException; import org.collectionspace.services.common.document.DocumentFilter; import org.collectionspace.services.common.document.DocumentWrapper; import org.collectionspace.services.common.document.JaxbUtils; import org.collectionspace.services.common.security.SecurityUtils; import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler; -import org.collectionspace.services.jaxb.AbstractCommonList; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,6 +54,7 @@ import org.slf4j.LoggerFactory; * Document handler for Role * @author */ +@SuppressWarnings("unchecked") public class RoleDocumentHandler extends JpaDocumentHandler> { private final Logger logger = LoggerFactory.getLogger(RoleDocumentHandler.class); @@ -80,26 +81,11 @@ public class RoleDocumentHandler role.setCsid(id); // We do not allow creation of locked roles through the services. role.setMetadataProtection(null); - role.setPermsProtection(null); + role.setPermsProtection(null); } - @Override - public void completeCreate(DocumentWrapper wrapDoc) throws Exception { - Role role = wrapDoc.getWrappedObject(); - List permValueList = role.getPermission(); - if (permValueList != null && permValueList.size() > 0) { - // create and persist a permrole instance - // The caller of this method needs to ensure a valid and active EM (EntityManager) instance is in the Service context - RoleValue roleValue = RoleFactory.createRoleValueInstance(role); - PermissionRole permRole = PermissionRoleFactory.createPermissionRoleInstance(SubjectType.PERMISSION, roleValue, - permValueList, true, true); - PermissionRoleSubResource subResource = - new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); - String permrolecsid = subResource.createPermissionRole(permRole, SubjectType.PERMISSION); - } - } - - @Override + @SuppressWarnings("rawtypes") + @Override public void handleUpdate(DocumentWrapper wrapDoc) throws Exception { Role roleFound = wrapDoc.getWrappedObject(); Role roleReceived = getCommonPart(); @@ -112,25 +98,26 @@ public class RoleDocumentHandler // // Update perms is supplied. // + ServiceContext ctx = this.getServiceContext(); List permValueList = roleReceived.getPermission(); - if (permValueList != null) { + if (permValueList != null && permValueList.size() > 0) { PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); // // First, delete the existing permroles // - subResource.deletePermissionRole(roleFound.getCsid(), SubjectType.PERMISSION); + subResource.deletePermissionRole(ctx, roleFound.getCsid(), SubjectType.PERMISSION); // // Next, create the new permroles // RoleValue roleValue = RoleFactory.createRoleValueInstance(roleFound); PermissionRole permRole = PermissionRoleFactory.createPermissionRoleInstance(SubjectType.PERMISSION, roleValue, permValueList, true, true); - subResource.createPermissionRole(permRole, SubjectType.PERMISSION); + subResource.createPermissionRole(ctx, permRole, SubjectType.PERMISSION); // // Finally, set the updated perm list in the result // - PermissionRole newPermRole = subResource.getPermissionRole(roleFound.getCsid(), SubjectType.PERMISSION); + PermissionRole newPermRole = subResource.getPermissionRole(ctx, roleFound.getCsid(), SubjectType.PERMISSION); roleFound.setPermission(newPermRole.getPermission()); } } @@ -168,6 +155,26 @@ public class RoleDocumentHandler return to; } + + @Override + public void completeCreate(DocumentWrapper wrapDoc) throws Exception { + Role role = wrapDoc.getWrappedObject(); + // + // If there are perms in the payload, create the required role/perm relationships. + // + List permValueList = role.getPermission(); + if (permValueList != null && permValueList.size() > 0) { + // create and persist a permrole instance + // The caller of this method needs to ensure a valid and active EM (EntityManager) instance is in the Service context + RoleValue roleValue = RoleFactory.createRoleValueInstance(role); + PermissionRole permRole = PermissionRoleFactory.createPermissionRoleInstance(SubjectType.PERMISSION, roleValue, + permValueList, true, true); + PermissionRoleSubResource subResource = + new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); + subResource.createPermissionRole(getServiceContext(), permRole, SubjectType.PERMISSION); + } + + } @Override public void completeUpdate(DocumentWrapper wrapDoc) throws Exception { @@ -190,7 +197,7 @@ public class RoleDocumentHandler getServiceContext().setOutput(getCommonPartList()); } - @Override + @Override public Role extractCommonPart( DocumentWrapper wrapDoc) throws Exception { @@ -201,7 +208,7 @@ public class RoleDocumentHandler if (includePerms) { PermissionRoleSubResource permRoleResource = new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE); - PermissionRole permRole = permRoleResource.getPermissionRole(role.getCsid(), SubjectType.PERMISSION); + PermissionRole permRole = permRoleResource.getPermissionRole(getServiceContext(), role.getCsid(), SubjectType.PERMISSION); role.setPermission(permRole.getPermission()); } diff --git a/services/authorization/jaxb/src/main/resources/authorization_common.xsd b/services/authorization/jaxb/src/main/resources/authorization_common.xsd index aedbb2ffc..9eb30df73 100644 --- a/services/authorization/jaxb/src/main/resources/authorization_common.xsd +++ b/services/authorization/jaxb/src/main/resources/authorization_common.xsd @@ -17,7 +17,7 @@ xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:hj="http://hyperjaxb3.jvnet.org/ejb/schemas/customizations" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" - xmlns:ns="http://collectionspace.org/services/authorization" + xmlns:ans="http://collectionspace.org/services/authorization" xmlns="http://collectionspace.org/services/authorization" targetNamespace="http://collectionspace.org/services/authorization" version="0.1" diff --git a/services/common/src/main/java/org/collectionspace/services/authorization/PermissionResource.java b/services/common/src/main/java/org/collectionspace/services/authorization/PermissionResource.java index 825657420..4d8479597 100644 --- a/services/common/src/main/java/org/collectionspace/services/authorization/PermissionResource.java +++ b/services/common/src/main/java/org/collectionspace/services/authorization/PermissionResource.java @@ -38,6 +38,8 @@ import org.collectionspace.services.common.context.RemoteServiceContextFactory; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.context.ServiceContextFactory; import org.collectionspace.services.common.storage.StorageClient; +import org.collectionspace.services.common.storage.TransactionContext; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl; import org.jboss.resteasy.util.HttpResponseCodes; import org.slf4j.Logger; @@ -80,30 +82,31 @@ public class PermissionResource extends SecurityResourceBase { return Permission.class; } - @Override + @SuppressWarnings("unchecked") + @Override public ServiceContextFactory getServiceContextFactory() { return RemoteServiceContextFactory.get(); } @Override - public StorageClient getStorageClient(ServiceContext ctx) { + public StorageClient getStorageClient(@SuppressWarnings("rawtypes") ServiceContext ctx) { //FIXME use ctx to identify storage client return storageClient; } @POST - public Response createPermission(Permission input) { - return create(input); + public Response createPermission(JPATransactionContext jpaTransactionContext, Permission input) { + return create(jpaTransactionContext, input); } - public Permission createPermissionFromInstance(Permission input) { + public Permission createPermissionFromInstance(JPATransactionContext jpaTransactionContext, Permission input) { Permission result = null; String permCsid = null; - Response response = createPermission(input); + Response response = createPermission(jpaTransactionContext, input); if (response.getStatus() == Response.Status.CREATED.getStatusCode()) { permCsid = CollectionSpaceClientUtils.extractId(response); - result = getPermission(permCsid); + result = (Permission)get(jpaTransactionContext, permCsid, Permission.class); } return result; @@ -133,33 +136,38 @@ public class PermissionResource extends SecurityResourceBase { return (Permission)update(csid, theUpdate, Permission.class); } - @DELETE + @SuppressWarnings("unchecked") + @DELETE @Path("{csid}") - public Response deletePermission(@PathParam("csid") String csid) { + public Response deletePermission(@PathParam("csid") String csid) throws Exception { logger.debug("deletePermission with csid=" + csid); ensureCSID(csid, ServiceMessages.DELETE_FAILED + "permission "); + + ServiceContext ctx = createServiceContext((Permission) null, Permission.class); + TransactionContext transactionContext = ctx.openConnection(); try { //FIXME ideally the following two ops should be in the same tx CSPACE-658 //delete all relationships for this permission PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE); - subResource.deletePermissionRole(csid, SubjectType.ROLE); + subResource.deletePermissionRole(ctx, csid, SubjectType.ROLE); //NOTE for delete permissions in the authz provider //at the PermissionRoleSubResource/DocHandler level, there is no visibility //if permission is deleted, so do it here, however, //this is a very dangerous operation as it deletes the Spring ACL instead of ACE(s) //the ACL might be needed for other ACEs roles... - AuthorizationDelegate.deletePermissions(csid); + AuthorizationDelegate.deletePermissions((JPATransactionContext)transactionContext, csid); - ServiceContext ctx = createServiceContext((Permission) null, Permission.class); getStorageClient(ctx).delete(ctx, csid); return Response.status(HttpResponseCodes.SC_OK).build(); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid); + } finally { + ctx.closeConnection(); } } - @POST + @POST @Path("{csid}/permroles") public Response createPermissionRole(@QueryParam("_method") String method, @PathParam("csid") String permCsid, @@ -174,7 +182,7 @@ public class PermissionResource extends SecurityResourceBase { try { PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE); - String permrolecsid = subResource.createPermissionRole(input, SubjectType.ROLE); + String permrolecsid = subResource.createPermissionRole((ServiceContext)null, input, SubjectType.ROLE); UriBuilder path = UriBuilder.fromResource(PermissionResource.class); path.path(permCsid + "/permroles/" + permrolecsid); Response response = Response.created(path.build()).build(); @@ -184,7 +192,7 @@ public class PermissionResource extends SecurityResourceBase { } } - @GET + @GET @Path("{csid}/permroles/{id}") public PermissionRoleRel getPermissionRole( @PathParam("csid") String permCsid, @@ -196,7 +204,7 @@ public class PermissionResource extends SecurityResourceBase { PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE); //get relationships for a permission - result = subResource.getPermissionRoleRel(permCsid, SubjectType.ROLE, permrolecsid); + result = subResource.getPermissionRoleRel((ServiceContext)null, permCsid, SubjectType.ROLE, permrolecsid); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.GET_FAILED, permCsid); } @@ -204,7 +212,7 @@ public class PermissionResource extends SecurityResourceBase { return result; } - @GET + @GET @Path("{csid}/permroles") public PermissionRole getPermissionRole( @PathParam("csid") String permCsid) { @@ -215,7 +223,7 @@ public class PermissionResource extends SecurityResourceBase { PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE); //get relationships for a permission - result = subResource.getPermissionRole(permCsid, SubjectType.ROLE); + result = subResource.getPermissionRole((ServiceContext)null, permCsid, SubjectType.ROLE); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.GET_FAILED, permCsid); } @@ -230,7 +238,7 @@ public class PermissionResource extends SecurityResourceBase { PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE); //delete all relationships for a permission - subResource.deletePermissionRole(permCsid, SubjectType.ROLE, input); + subResource.deletePermissionRole((ServiceContext)null, permCsid, SubjectType.ROLE, input); return Response.status(HttpResponseCodes.SC_OK).build(); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, permCsid); @@ -247,7 +255,7 @@ public class PermissionResource extends SecurityResourceBase { PermissionRoleSubResource subResource = new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE); //delete all relationships for a permission - subResource.deletePermissionRole(permCsid, SubjectType.ROLE); + subResource.deletePermissionRole((ServiceContext)null, permCsid, SubjectType.ROLE); return Response.status(HttpResponseCodes.SC_OK).build(); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED, permCsid); diff --git a/services/common/src/main/java/org/collectionspace/services/authorization/PermissionRoleSubResource.java b/services/common/src/main/java/org/collectionspace/services/authorization/PermissionRoleSubResource.java index a410eb4d5..4d02fd137 100644 --- a/services/common/src/main/java/org/collectionspace/services/authorization/PermissionRoleSubResource.java +++ b/services/common/src/main/java/org/collectionspace/services/authorization/PermissionRoleSubResource.java @@ -35,6 +35,7 @@ import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.context.ServiceContextFactory; import org.collectionspace.services.common.document.DocumentHandler; import org.collectionspace.services.common.storage.StorageClient; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaRelationshipStorageClient; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; import org.collectionspace.services.common.context.ServiceContextProperties; @@ -46,6 +47,7 @@ import org.slf4j.LoggerFactory; * PermissionRoleSubResource is used to manage permission-role relationship * @author */ +@SuppressWarnings("rawtypes") public class PermissionRoleSubResource extends AbstractCollectionSpaceResourceImpl { @@ -97,7 +99,8 @@ public class PermissionRoleSubResource /* (non-Javadoc) * @see org.collectionspace.services.common.CollectionSpaceResource#getServiceContextFactory() */ - @Override + @SuppressWarnings("unchecked") + @Override public ServiceContextFactory getServiceContextFactory() { return RemoteServiceContextFactory.get(); } @@ -112,9 +115,21 @@ public class PermissionRoleSubResource * * @throws Exception the exception */ - private ServiceContext createServiceContext(PermissionRole input, + private ServiceContext createServiceContext( + ServiceContext parentCtx, + PermissionRole input, SubjectType subject) throws Exception { ServiceContext ctx = createServiceContext(input); + JPATransactionContext parentTransactionContext = parentCtx != null ? (JPATransactionContext)parentCtx.getCurrentTransactionContext() : null; + // + // If the parent context has an active JPA connection then we'll use it. + // + if (parentTransactionContext != null) { + ctx.setTransactionContext(parentTransactionContext); + } + // + // Set other context values + // ctx.setDocumentType(PermissionRole.class.getPackage().getName()); //persistence unit ctx.setProperty(ServiceContextProperties.ENTITY_NAME, PermissionRoleRel.class.getName()); ctx.setProperty(ServiceContextProperties.ENTITY_CLASS, PermissionRoleRel.class); @@ -154,10 +169,10 @@ public class PermissionRoleSubResource * @return * @throws Exception */ - public String createPermissionRole(PermissionRole input, SubjectType subject) + public String createPermissionRole(ServiceContext parentCtx, PermissionRole input, SubjectType subject) throws Exception { - ServiceContext ctx = createServiceContext(input, subject); + ServiceContext ctx = createServiceContext(parentCtx, input, subject); DocumentHandler handler = createDocumentHandler(ctx); return getStorageClient(ctx).create(ctx, handler); } @@ -171,28 +186,22 @@ public class PermissionRoleSubResource * @return the permission role rel * @throws Exception the exception */ - public PermissionRoleRel getPermissionRoleRel(String csid, + public PermissionRoleRel getPermissionRoleRel( + ServiceContext parentCtx, + String csid, SubjectType subject, String permissionRoleCsid) throws Exception { if (logger.isDebugEnabled()) { logger.debug("getAccountRole with csid=" + csid); } -// AccountRolesList result = new AccountRolesList(); - ServiceContext ctx = createServiceContext((PermissionRole) null, subject); + + ServiceContext ctx = createServiceContext(parentCtx, (PermissionRole) null, subject); PermissionRoleDocumentHandler handler = (PermissionRoleDocumentHandler)createDocumentHandler(ctx); handler.setPermissionRoleCsid(permissionRoleCsid); //getStorageClient(ctx).get(ctx, csid, handler); PermissionRoleRel permissionRoleRel = (PermissionRoleRel)JpaStorageUtils.getEntity( new Long(permissionRoleCsid).longValue(), PermissionRoleRel.class); -// List accountRoleList = result.getAccountRoleListItems(); -// AccountRoleListItem listItem = new AccountRoleListItem(); -// // fill the item -// listItem.setCsid(accountRoleRel.getHjid().toString()); -// listItem.setRoleId(accountRoleRel.getRoleId()); -// listItem.setRoleName(accountRoleRel.getRoleName()); - // add item to result list -// result = (AccountRolesList) ctx.getOutput(); return permissionRoleRel; } @@ -206,13 +215,15 @@ public class PermissionRoleSubResource * @throws Exception */ public PermissionRole getPermissionRole( - String csid, SubjectType subject) throws Exception { + ServiceContext parentCtx, + String csid, + SubjectType subject) throws Exception { if (logger.isDebugEnabled()) { logger.debug("getPermissionRole with csid=" + csid); } PermissionRole result = null; - ServiceContext ctx = createServiceContext((PermissionRole) null, subject); + ServiceContext ctx = createServiceContext(parentCtx, (PermissionRole) null, subject); DocumentHandler handler = createDocumentHandler(ctx); getStorageClient(ctx).get(ctx, csid, handler); result = (PermissionRole) ctx.getOutput(); @@ -228,14 +239,15 @@ public class PermissionRoleSubResource * @return * @throws Exception */ - public void deletePermissionRole(String csid, + public void deletePermissionRole(ServiceContext parentCtx, + String csid, SubjectType subject) throws Exception { if (logger.isDebugEnabled()) { logger.debug("deletePermissionRole with csid=" + csid); } - PermissionRole permRole = this.getPermissionRole(csid, subject); - this.deletePermissionRole(csid, subject, permRole); + PermissionRole permRole = this.getPermissionRole(parentCtx, csid, subject); + deletePermissionRole(parentCtx, csid, subject, permRole); } /** @@ -247,13 +259,13 @@ public class PermissionRoleSubResource * @return * @throws Exception */ - public void deletePermissionRole(String csid, + public void deletePermissionRole(ServiceContext parentCtx, String csid, SubjectType subject, PermissionRole input) throws Exception { if (logger.isDebugEnabled()) { logger.debug("deletePermissionRole(input) with csid=" + csid); } - ServiceContext ctx = createServiceContext(input, subject); + ServiceContext ctx = createServiceContext(parentCtx, input, subject); DocumentHandler handler = createDocumentHandler(ctx); getStorageClient(ctx).delete(ctx, csid, handler); } diff --git a/services/common/src/main/java/org/collectionspace/services/authorization/storage/AuthorizationDelegate.java b/services/common/src/main/java/org/collectionspace/services/authorization/storage/AuthorizationDelegate.java index c8f863aab..0adcb0186 100644 --- a/services/common/src/main/java/org/collectionspace/services/authorization/storage/AuthorizationDelegate.java +++ b/services/common/src/main/java/org/collectionspace/services/authorization/storage/AuthorizationDelegate.java @@ -44,6 +44,7 @@ import org.collectionspace.services.authorization.URIResourceImpl; import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.DocumentNotFoundException; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,25 +67,27 @@ public class AuthorizationDelegate { * @see PermissionRole */ public static void addPermissions(ServiceContext ctx, PermissionRole pr) throws Exception { + JPATransactionContext jpaTransactionContext = (JPATransactionContext) ctx.getCurrentTransactionContext(); + SubjectType subject = PermissionRoleUtil.getRelationSubject(ctx, pr); AuthZ authz = AuthZ.get(); if (subject.equals(SubjectType.ROLE)) { PermissionValue pv = pr.getPermission().get(0); - Permission p = getPermission(pv.getPermissionId()); + Permission p = getPermission(jpaTransactionContext, pv.getPermissionId()); if (p == null) { String msg = "addPermissions: No permission found for id=" + pv.getPermissionId(); logger.error(msg); throw new DocumentNotFoundException(msg); } CSpaceResource[] resources = getResources(p); - String[] roles = getRoles(pr.getRole()); + String[] roles = getRoles(jpaTransactionContext, pr.getRole()); for (CSpaceResource res : resources) { boolean grant = p.getEffect().equals(EffectType.PERMIT) ? true : false; authz.addPermissions(res, roles, grant); } } else if (SubjectType.PERMISSION.equals(subject)) { RoleValue rv = pr.getRole().get(0); - Role r = getRole(rv.getRoleId()); + Role r = getRole(jpaTransactionContext, rv.getRoleId()); if (r == null) { String msg = "addPermissions: No role found for id=" + rv.getRoleId(); logger.error(msg); @@ -94,7 +97,7 @@ public class AuthorizationDelegate { // This needs to use the qualified name, not the display name String[] roles = {r.getRoleName()}; for (PermissionValue pv : pr.getPermission()) { - Permission p = getPermission(pv.getPermissionId()); + Permission p = getPermission(jpaTransactionContext, pv.getPermissionId()); if (p == null) { String msg = "addPermissions: No permission found for id=" + pv.getPermissionId(); logger.error(msg); @@ -118,20 +121,22 @@ public class AuthorizationDelegate { */ public static void deletePermissions(ServiceContext ctx, PermissionRole pr) throws Exception { + JPATransactionContext jpaTransactionContext = (JPATransactionContext) ctx.getCurrentTransactionContext(); + SubjectType subject = PermissionRoleUtil.getRelationSubject(ctx, pr); AuthZ authz = AuthZ.get(); if (subject.equals(SubjectType.ROLE)) { List permissionValues = pr.getPermission(); if (permissionValues != null & permissionValues.size() > 0) { PermissionValue pv = permissionValues.get(0); - Permission p = getPermission(pv.getPermissionId()); + Permission p = getPermission(jpaTransactionContext, pv.getPermissionId()); if (p == null) { String msg = "deletePermissions: No permission found for id=" + pv.getPermissionId(); logger.error(msg); throw new DocumentNotFoundException(msg); } CSpaceResource[] resources = getResources(p); - String[] roles = getRoles(pr.getRole()); + String[] roles = getRoles(jpaTransactionContext, pr.getRole()); for (CSpaceResource res : resources) { authz.deletePermissions(res, roles); } @@ -140,7 +145,7 @@ public class AuthorizationDelegate { List roleValues = pr.getRole(); if (roleValues != null && roleValues.size() > 0) { RoleValue rv = roleValues.get(0); - Role r = getRole(rv.getRoleId()); + Role r = getRole(jpaTransactionContext, rv.getRoleId()); if (r == null) { String msg = "deletePermissions: No role found for id=" + rv.getRoleId(); logger.error(msg); @@ -150,7 +155,7 @@ public class AuthorizationDelegate { // This needs to use the qualified name, not the display name String[] roles = {r.getRoleName()}; for (PermissionValue pv : pr.getPermission()) { - Permission p = getPermission(pv.getPermissionId()); + Permission p = getPermission(jpaTransactionContext, pv.getPermissionId()); if (p == null) { String msg = "deletePermissions: No permission found for id=" + pv.getPermissionId(); logger.error(msg); @@ -175,8 +180,8 @@ public class AuthorizationDelegate { //the Spring ACL instead of ACE(s) that is associated with each role //the ACL might be needed for other ACEs (including those for ROLE_ADMINISTRATOR, //ROLE_TENANT_ADMINISTRATOR, etc.)... - static public void deletePermissions(String permCsid) throws Exception { - Permission p = getPermission(permCsid); + static public void deletePermissions(JPATransactionContext jpaTransactionContext, String permCsid) throws Exception { + Permission p = getPermission(jpaTransactionContext, permCsid); if (p == null) { String msg = "deletePermissions: No permission found for id=" + permCsid; logger.error(msg); @@ -202,11 +207,11 @@ public class AuthorizationDelegate { * @return string array with role names * @see RoleValue */ - private static String[] getRoles(List rvl) + private static String[] getRoles(JPATransactionContext jpaTransactionContext, List rvl) throws DocumentNotFoundException { List rvls = new ArrayList(); for (RoleValue rv : rvl) { - Role r = getRole(rv.getRoleId()); + Role r = getRole(jpaTransactionContext, rv.getRoleId()); if (r == null) { String msg = "getRoles: No role found for id=" + rv.getRoleId(); logger.error(msg); @@ -215,6 +220,7 @@ public class AuthorizationDelegate { } rvls.add(r.getRoleName()); } + return rvls.toArray(new String[0]); } @@ -242,17 +248,15 @@ public class AuthorizationDelegate { return rl.toArray(new CSpaceResource[0]); } - private static Permission getPermission(String permCsid) + private static Permission getPermission(JPATransactionContext jpaTransactionContext, String permCsid) throws DocumentNotFoundException { - Permission p = (Permission) JpaStorageUtils.getEntity(permCsid, + Permission p = (Permission) JpaStorageUtils.getEntity(jpaTransactionContext, permCsid, Permission.class); return p; } - private static Role getRole(String roleCsid) - throws DocumentNotFoundException { - Role r = (Role) JpaStorageUtils.getEntity(roleCsid, - Role.class); + private static Role getRole(JPATransactionContext jpaTransactionContext, String roleCsid) throws DocumentNotFoundException { + Role r = (Role) JpaStorageUtils.getEntity(jpaTransactionContext, roleCsid, Role.class); return r; } diff --git a/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionDocumentHandler.java b/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionDocumentHandler.java index 156ad27f6..d618ea453 100644 --- a/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionDocumentHandler.java +++ b/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionDocumentHandler.java @@ -28,25 +28,27 @@ import java.util.List; import java.util.UUID; import javax.persistence.EntityExistsException; -import javax.persistence.EntityManager; import javax.persistence.NoResultException; +import org.collectionspace.services.client.PermissionClient; +import org.collectionspace.services.client.PermissionClient.ActionCompare; + import org.collectionspace.services.authorization.perms.ActionType; import org.collectionspace.services.authorization.CSpaceAction; -import org.collectionspace.services.authorization.RolesList; import org.collectionspace.services.authorization.perms.Permission; import org.collectionspace.services.authorization.perms.PermissionAction; import org.collectionspace.services.authorization.perms.PermissionsList; -import org.collectionspace.services.client.PermissionClient; -import org.collectionspace.services.client.PermissionClient.ActionCompare; import org.collectionspace.services.authorization.URIResourceImpl; -import org.collectionspace.services.common.authorization_mgt.AuthorizationStore; + +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.BadRequestException; import org.collectionspace.services.common.document.DocumentException; import org.collectionspace.services.common.document.DocumentFilter; import org.collectionspace.services.common.document.DocumentWrapper; import org.collectionspace.services.common.document.JaxbUtils; +import org.collectionspace.services.common.document.TransactionException; import org.collectionspace.services.common.security.SecurityUtils; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; @@ -57,6 +59,7 @@ import org.slf4j.LoggerFactory; * Document handler for Permission * @author */ +@SuppressWarnings("rawtypes") public class PermissionDocumentHandler extends JpaDocumentHandler> { @@ -132,12 +135,14 @@ public class PermissionDocumentHandler } } - private Permission findExistingPermission(EntityManager em, Permission perm) { + private Permission findExistingPermission(Permission perm) throws TransactionException { Permission result = null; - String tenantId = getServiceContext().getTenantId(); // we need a tenant ID - + + ServiceContext ctx = getServiceContext(); + String tenantId = ctx.getTenantId(); // we need a tenant ID + JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection(); try { - result = (Permission)JpaStorageUtils.getEntityByDualKeys(em, + result = (Permission)JpaStorageUtils.getEntityByDualKeys(jpaTransactionContext, Permission.class.getName(), PermissionStorageConstants.RESOURCE_NAME, perm.getResourceName(), PermissionStorageConstants.ACTION_GROUP, perm.getActionGroup(), @@ -148,6 +153,8 @@ public class PermissionDocumentHandler perm.getResourceName(), perm.getActionGroup(), tenantId); logger.trace(msg); } + } finally { + ctx.closeConnection(); } return result; @@ -158,10 +165,8 @@ public class PermissionDocumentHandler // // First check to see if an equivalent permission exists // - Permission permission = wrapDoc.getWrappedObject(); - - EntityManager em = (EntityManager) this.getServiceContext().getProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY); - Permission existingPermission = findExistingPermission(em, permission); + Permission permission = wrapDoc.getWrappedObject(); + Permission existingPermission = findExistingPermission(permission); if (existingPermission == null) { String id = UUID.randomUUID().toString(); @@ -224,7 +229,8 @@ public class PermissionDocumentHandler return to; } - @Override + @SuppressWarnings("unchecked") + @Override public void completeUpdate(DocumentWrapper wrapDoc) throws Exception { Permission upAcc = wrapDoc.getWrappedObject(); getServiceContext().setOutput(upAcc); @@ -234,14 +240,16 @@ public class PermissionDocumentHandler //new based on new actions and effect } - @Override + @SuppressWarnings("unchecked") + @Override public void handleGet(DocumentWrapper wrapDoc) throws Exception { setCommonPart(extractCommonPart(wrapDoc)); sanitize(getCommonPart()); getServiceContext().setOutput(permission); } - @Override + @SuppressWarnings("unchecked") + @Override public void handleGetAll(DocumentWrapper> wrapDoc) throws Exception { PermissionsList permissionsList = extractCommonPartList(wrapDoc); setCommonPartList(permissionsList); diff --git a/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionRoleDocumentHandler.java b/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionRoleDocumentHandler.java index 990c73201..392671bb6 100644 --- a/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionRoleDocumentHandler.java +++ b/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionRoleDocumentHandler.java @@ -26,8 +26,6 @@ package org.collectionspace.services.authorization.storage; import java.util.ArrayList; import java.util.List; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; import javax.persistence.NoResultException; import org.collectionspace.services.authorization.PermissionRole; @@ -36,14 +34,18 @@ import org.collectionspace.services.authorization.PermissionValue; import org.collectionspace.services.authorization.PermissionsRolesList; import org.collectionspace.services.authorization.RoleValue; import org.collectionspace.services.authorization.SubjectType; -import org.collectionspace.services.authorization.perms.Permission; + import org.collectionspace.services.common.authorization_mgt.AuthorizationRoleRel; import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.DocumentFilter; import org.collectionspace.services.common.document.DocumentWrapper; +import org.collectionspace.services.common.document.TransactionException; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaDocumentFilter; import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -87,12 +89,12 @@ public class PermissionRoleDocumentHandler filterOutExisting(wrapDoc); } - private boolean permRoleRelExists(EntityManager em, PermissionRoleRel permRoleRel) { + private boolean permRoleRelExists(JPATransactionContext jpaTransactionContext, PermissionRoleRel permRoleRel) throws TransactionException { boolean result = false; PermissionRoleRel queryResult = null; try { - queryResult = (PermissionRoleRel) JpaStorageUtils.getEntityByDualKeys(em, + queryResult = (PermissionRoleRel) JpaStorageUtils.getEntityByDualKeys(jpaTransactionContext, PermissionRoleRel.class.getName(), PermissionStorageConstants.PERMREL_ROLE_ID, permRoleRel.getRoleId(), PermissionStorageConstants.PERMREL_PERM_ID, permRoleRel.getPermissionId()); @@ -112,41 +114,33 @@ public class PermissionRoleDocumentHandler * @param wrapDoc * @throws Exception */ - private void filterOutExisting(DocumentWrapper> wrapDoc) throws Exception { + @SuppressWarnings("rawtypes") + private void filterOutExisting(DocumentWrapper> wrapDoc) throws Exception { List permRoleRelList = wrapDoc.getWrappedObject(); - EntityManagerFactory emf = null; - EntityManager em = null; + ServiceContext ctx = getServiceContext(); + JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection(); try { - emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT); - em = emf.createEntityManager(); - em.getTransaction().begin(); + jpaTransactionContext.beginTransaction(); for (PermissionRoleRel permRoleRel : permRoleRelList) { - if (permRoleRelExists(em, permRoleRel) == true) { + if (permRoleRelExists(jpaTransactionContext, permRoleRel) == true) { // // Remove the item from the list since it already exists // permRoleRelList.remove(permRoleRel); } } - - em.getTransaction().commit(); - em.close(); + jpaTransactionContext.commitTransaction(); } catch (Exception e) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaTransactionContext.markForRollback(); if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } throw e; } finally { - if (em != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } - } /* (non-Javadoc) @@ -177,7 +171,8 @@ public class PermissionRoleDocumentHandler /* (non-Javadoc) * @see org.collectionspace.services.common.document.AbstractDocumentHandlerImpl#handleGet(org.collectionspace.services.common.document.DocumentWrapper) */ - @Override + @SuppressWarnings("unchecked") + @Override public void handleGet(DocumentWrapper> wrapDoc) throws Exception { setCommonPart(extractCommonPart(wrapDoc)); getServiceContext().setOutput(permissionRole); @@ -263,7 +258,8 @@ public class PermissionRoleDocumentHandler * @param handleDelete the handle delete * @throws Exception the exception */ - public void fillCommonPart(PermissionRole pr, + @SuppressWarnings("rawtypes") + public void fillCommonPart(PermissionRole pr, DocumentWrapper> wrapDoc, boolean handleDelete) throws Exception { @@ -276,8 +272,9 @@ public class PermissionRoleDocumentHandler //subject mismatch should have been checked during validation } - String tenantId = this.getServiceContext().getTenantId(); - PermissionRoleUtil.buildPermissionRoleRel(pr, subject, prrl, handleDelete, tenantId); + ServiceContext ctx = this.getServiceContext(); + String tenantId = ctx.getTenantId(); + PermissionRoleUtil.buildPermissionRoleRel(ctx, pr, subject, prrl, handleDelete, tenantId); } /* (non-Javadoc) diff --git a/services/common/src/main/java/org/collectionspace/services/common/SecurityResourceBase.java b/services/common/src/main/java/org/collectionspace/services/common/SecurityResourceBase.java index 9bf20714f..05f0c893d 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/SecurityResourceBase.java +++ b/services/common/src/main/java/org/collectionspace/services/common/SecurityResourceBase.java @@ -3,35 +3,66 @@ package org.collectionspace.services.common; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.DocumentFilter; import org.collectionspace.services.common.document.DocumentHandler; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; +@SuppressWarnings({ "unchecked", "rawtypes" }) public abstract class SecurityResourceBase extends AbstractCollectionSpaceResourceImpl { final Logger logger = LoggerFactory.getLogger(SecurityResourceBase.class); public Response create(Object input) { - try { - ServiceContext ctx = createServiceContext(input, input.getClass()); - DocumentHandler handler = createDocumentHandler(ctx); - String csid = getStorageClient(ctx).create(ctx, handler); - UriBuilder path = UriBuilder.fromResource(this.getClass()); - path.path("" + csid); - Response response = Response.created(path.build()).build(); - return response; - } catch (Exception e) { - throw bigReThrow(e, ServiceMessages.POST_FAILED+"create in "+this.getClass().getName()); - } + Response response = null; + + try { + ServiceContext ctx = createServiceContext(input, input.getClass()); + DocumentHandler handler = createDocumentHandler(ctx); + String csid = getStorageClient(ctx).create(ctx, handler); + UriBuilder path = UriBuilder.fromResource(this.getClass()); + path.path("" + csid); + response = Response.created(path.build()).build(); + } catch (Exception e) { + throw bigReThrow(e, ServiceMessages.POST_FAILED+"create in "+this.getClass().getName()); } + + return response; + } + + public Response create(JPATransactionContext jpaTransactionContext, Object input) { + Response response = null; + + try { + ServiceContext ctx = createServiceContext(jpaTransactionContext, input, input.getClass()); + DocumentHandler handler = createDocumentHandler(ctx); + String csid = getStorageClient(ctx).create(ctx, handler); + UriBuilder path = UriBuilder.fromResource(this.getClass()); + path.path("" + csid); + response = Response.created(path.build()).build(); + } catch (Exception e) { + throw bigReThrow(e, ServiceMessages.POST_FAILED+"create in "+this.getClass().getName()); + } + + return response; + } + + private ServiceContext createServiceContext(JPATransactionContext jpaTransactionContext, Object input, + Class clazz) throws Exception { + ServiceContext result = createServiceContext(input, clazz); + + if (jpaTransactionContext != null) { + result.setTransactionContext(jpaTransactionContext); + } + + return result; + } - public Object get(String csid, Class objectClass) { + public Object get(String csid, Class objectClass) { return get((UriInfo)null, csid, objectClass); } @@ -50,8 +81,24 @@ public abstract class SecurityResourceBase extends AbstractCollectionSpaceResour checkResult(result, csid, ServiceMessages.GET_FAILED); return result; } + + public Object get(JPATransactionContext jpaTransactionContext, String csid, Class objectClass) { + logger.debug("get with csid=" + csid); + ensureCSID(csid, ServiceMessages.GET_FAILED + "csid"); + Object result = null; + try { + ServiceContext ctx = createServiceContext(jpaTransactionContext, (Object) null, objectClass); + DocumentHandler handler = createDocumentHandler(ctx); + getStorageClient(ctx).get(ctx, csid, handler); + result = ctx.getOutput(); + } catch (Exception e) { + throw bigReThrow(e, ServiceMessages.GET_FAILED, csid); + } + checkResult(result, csid, ServiceMessages.GET_FAILED); + return result; + } - public Object getList(UriInfo ui, Class objectClass) { + public Object getList(UriInfo ui, Class objectClass) { try { ServiceContext ctx = createServiceContext((Object) null, objectClass, ui); DocumentHandler handler = createDocumentHandler(ctx); @@ -69,11 +116,11 @@ public abstract class SecurityResourceBase extends AbstractCollectionSpaceResour } } - public Object update(String csid, Object theUpdate, Class objectClass) { + public Object update(String csid, Object theUpdate, Class objectClass) { return update((UriInfo)null, csid, theUpdate, objectClass); } - public Object update(UriInfo ui, String csid, Object theUpdate, Class objectClass) { + public Object update(UriInfo ui, String csid, Object theUpdate, Class objectClass) { if (logger.isDebugEnabled()) { logger.debug("updateRole with csid=" + csid); } diff --git a/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java b/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java index 263e01774..901113619 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java +++ b/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java @@ -36,7 +36,7 @@ import org.collectionspace.services.common.init.AddIndices; import org.collectionspace.services.common.init.IInitHandler; import org.collectionspace.services.common.storage.DatabaseProductType; import org.collectionspace.services.common.storage.JDBCTools; - +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.config.service.InitHandler.Params.Field; import org.collectionspace.services.config.ClientType; import org.collectionspace.services.config.ServiceConfig; @@ -238,19 +238,23 @@ public class ServiceMain { // Create all the tenant records, default user accounts, roles, and permissions. Since some of our "cspace" database config files // for Spring need to be created at build time, the "cspace" database already will be suffixed with the // correct 'cspaceInstanceId' so we don't need to pass it to the JDBCTools methods. - // + // + JPATransactionContext jpaTransactionContext = new JPATransactionContext(); try { + jpaTransactionContext.beginTransaction(); DatabaseProductType databaseProductType = JDBCTools.getDatabaseProductType(JDBCTools.CSPACE_DATASOURCE_NAME, cspaceDatabaseName); - AuthorizationCommon.createTenants(tenantBindingConfigReader, databaseProductType, cspaceDatabaseName); - AuthorizationCommon.createDefaultWorkflowPermissions(tenantBindingConfigReader, databaseProductType, cspaceDatabaseName); + AuthorizationCommon.createDefaultWorkflowPermissions(jpaTransactionContext, tenantBindingConfigReader, databaseProductType, cspaceDatabaseName); AuthorizationCommon.createDefaultAccounts(tenantBindingConfigReader, databaseProductType, cspaceDatabaseName); AuthorizationCommon.persistTenantBindingsMD5Hash(tenantBindingConfigReader, databaseProductType, cspaceDatabaseName); + jpaTransactionContext.commitTransaction(); } catch (Exception e) { logger.error("Default create/update of tenants, accounts, roles and permissions setup failed with exception(s): " + e.getLocalizedMessage(), e); throw e; + } finally { + jpaTransactionContext.close(); } // // Log tenant status -shows all tenants' info and active status. diff --git a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java index af328f7c1..028085649 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java +++ b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java @@ -49,6 +49,7 @@ import org.collectionspace.services.common.document.DocumentHandler; import org.collectionspace.services.common.security.SecurityUtils; import org.collectionspace.services.common.storage.DatabaseProductType; import org.collectionspace.services.common.storage.JDBCTools; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; import org.collectionspace.services.config.service.ServiceBindingType; @@ -68,7 +69,7 @@ import org.springframework.security.acls.model.AlreadyExistsException; public class AuthorizationCommon { - final public static String REFRESH_AUTZ_PROP = "refreshAuthZOnStartup"; + final public static String REFRESH_AUTHZ_PROP = "refreshAuthZOnStartup"; // // For token generation and password reset @@ -162,20 +163,21 @@ public class AuthorizationCommon { return tenantConfigMD5HashTable.put(tenantId, md5hash); } - public static Role getRole(String tenantId, String displayName) { + @Deprecated + public static Role xgetRole(String tenantId, String displayName) { Role role = null; String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName); - role = AuthorizationStore.getRoleByName(roleName, tenantId); + //role = AuthorizationStore.getRoleByName(roleName, tenantId); return role; } - public static Role getRole(EntityManager em, String tenantId, String displayName) { + public static Role getRole(JPATransactionContext jpaTransactionContext, String tenantId, String displayName) { Role role = null; String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName); - role = AuthorizationStore.getRoleByName(em, roleName, tenantId); + role = AuthorizationStore.getRoleByName(jpaTransactionContext, roleName, tenantId); return role; } @@ -349,7 +351,7 @@ public class AuthorizationCommon { return result; } - private static PermissionRole createPermissionRole(EntityManager em, + private static PermissionRole createPermissionRole( Permission permission, Role role, boolean enforceTenancy) throws Exception @@ -899,6 +901,7 @@ public class AuthorizationCommon { /* * Using the tenant bindings, ensure there are corresponding Tenant records (db columns). */ + //FIXME: This code should be using JPA objects and JPATransactionContext, not raw SQL. public static void createTenants( TenantBindingConfigReaderImpl tenantBindingConfigReader, DatabaseProductType databaseProductType, @@ -927,6 +930,14 @@ public class AuthorizationCommon { } } + /** + * + * @param tenantBindingConfigReader + * @param databaseProductType + * @param cspaceDatabaseName + * @throws Exception + */ + //FIXME: This code should be using the JPA objects and JPATransactionContext, not raw SQL. public static void createDefaultAccounts( TenantBindingConfigReaderImpl tenantBindingConfigReader, DatabaseProductType databaseProductType, @@ -1084,7 +1095,9 @@ public class AuthorizationCommon { * @param cspaceDatabaseName * @throws Exception */ - public static void createDefaultWorkflowPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader, + public static void createDefaultWorkflowPermissions( + JPATransactionContext jpaTransactionContext, + TenantBindingConfigReaderImpl tenantBindingConfigReader, DatabaseProductType databaseProductType, String cspaceDatabaseName) throws Exception //FIXME: REM - 4/11/2012 - Rename to createWorkflowPermissions { @@ -1092,12 +1105,7 @@ public class AuthorizationCommon { AuthZ.get().login(); //login to Spring Security manager - EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT); - EntityManager em = null; - try { - em = emf.createEntityManager(); - Hashtable tenantBindings = tenantBindingConfigReader.getTenantBindings(); for (String tenantId : tenantBindings.keySet()) { logger.info(String.format("Creating/verifying workflow permissions for tenant ID=%s.", tenantId)); @@ -1106,8 +1114,8 @@ public class AuthorizationCommon { continue; // skip the rest of the loop and go to the next tenant } - Role adminRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_ADMINISTRATOR); - Role readonlyRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_READER); + Role adminRole = AuthorizationCommon.getRole(jpaTransactionContext, tenantBinding.getId(), ROLE_TENANT_ADMINISTRATOR); + Role readonlyRole = AuthorizationCommon.getRole(jpaTransactionContext, tenantBinding.getId(), ROLE_TENANT_READER); if (adminRole == null || readonlyRole == null) { String msg = String.format("One or more of the required default CollectionSpace administrator roles is missing or was never created. If you're setting up a new instance of CollectionSpace, shutdown the Tomcat server and run the 'ant import' command from the root/top level CollectionSpace 'Services' source directory. Then try restarting Tomcat."); @@ -1116,25 +1124,27 @@ public class AuthorizationCommon { } for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) { - String prop = ServiceBindingUtils.getPropertyValue(serviceBinding, REFRESH_AUTZ_PROP); + String prop = ServiceBindingUtils.getPropertyValue(serviceBinding, REFRESH_AUTHZ_PROP); if (prop == null ? true : Boolean.parseBoolean(prop)) { - try { - em.getTransaction().begin(); + try { + jpaTransactionContext.beginTransaction(); TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding); HashSet transitionVerbList = getTransitionVerbList(tenantBinding, serviceBinding); for (String transitionVerb : transitionVerbList) { // // Create the permission for the admin role Permission adminPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_CRUDL); - persist(em, adminPerm, adminRole, true, ACTIONGROUP_CRUDL); + persist(jpaTransactionContext, adminPerm, adminRole, true, ACTIONGROUP_CRUDL); // // Create the permission for the read-only role Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_RL); - persist(em, readonlyPerm, readonlyRole, true, ACTIONGROUP_RL); // Persist/store the permission and permrole records and related Spring Security info + persist(jpaTransactionContext, readonlyPerm, readonlyRole, true, ACTIONGROUP_RL); // Persist/store the permission and permrole records and related Spring Security info } - em.getTransaction().commit(); + jpaTransactionContext.commitTransaction(); } catch (IllegalStateException e) { logger.fine(e.getLocalizedMessage()); //We end up here if there is no document handler for the service -this is ok for some of the services. + } catch (Exception x) { + jpaTransactionContext.markForRollback(); } } else { logger.warning("AuthZ refresh service binding property is set to FALSE so default permissions will NOT be refreshed for: " @@ -1142,17 +1152,10 @@ public class AuthorizationCommon { } } } - em.close(); } catch (Exception e) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaTransactionContext.markForRollback(); logger.fine("Caught exception and rolling back permission creation: " + e.getMessage()); throw e; - } finally { - if (em != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } } } @@ -1223,7 +1226,10 @@ public class AuthorizationCommon { return result; } - private static PermissionRoleRel findPermRoleRel(EntityManager em, String permissionId, String RoleId) { + private static PermissionRoleRel findPermRoleRel( + JPATransactionContext jpaTransactionContext, + String permissionId, + String RoleId) { PermissionRoleRel result = null; try { @@ -1232,7 +1238,7 @@ public class AuthorizationCommon { params.put("id", permissionId); params.put("roleId", RoleId); - result = (PermissionRoleRel) JpaStorageUtils.getEntity(em, + result = (PermissionRoleRel) JpaStorageUtils.getEntity(jpaTransactionContext, PermissionRoleRel.class.getCanonicalName(), whereClause, params); } catch (Exception e) { //Do nothing. Will return null; @@ -1244,21 +1250,21 @@ public class AuthorizationCommon { /* * Persists the Permission, PermissionRoleRel, and Spring Security table entries all in one transaction */ - private static void persist(EntityManager em, Permission permission, Role role, boolean enforceTenancy, ActionGroup actionGroup) throws Exception { + private static void persist(JPATransactionContext jpaTransactionContext, Permission permission, Role role, boolean enforceTenancy, ActionGroup actionGroup) throws Exception { AuthorizationStore authzStore = new AuthorizationStore(); // First persist the Permission record - authzStore.store(em, permission); + authzStore.store(jpaTransactionContext, permission); // If the PermRoleRel doesn't already exists then relate the permission and the role in a new PermissionRole (the service payload) // Create a PermissionRoleRel (the database relation table for the permission and role) - PermissionRoleRel permRoleRel = findPermRoleRel(em, permission.getCsid(), role.getCsid()); + PermissionRoleRel permRoleRel = findPermRoleRel(jpaTransactionContext, permission.getCsid(), role.getCsid()); if (permRoleRel == null) { - PermissionRole permRole = createPermissionRole(em, permission, role, enforceTenancy); + PermissionRole permRole = createPermissionRole(permission, role, enforceTenancy); List permRoleRels = new ArrayList(); - PermissionRoleUtil.buildPermissionRoleRel(em, permRole, SubjectType.ROLE, permRoleRels, + PermissionRoleUtil.buildPermissionRoleRel(jpaTransactionContext, permRole, SubjectType.ROLE, permRoleRels, false /*not for delete*/, role.getTenantId()); for (PermissionRoleRel prr : permRoleRels) { - authzStore.store(em, prr); + authzStore.store(jpaTransactionContext, prr); } Profiler profiler = new Profiler(AuthorizationCommon.class, 2); profiler.start(); diff --git a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationStore.java b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationStore.java index be9c907af..6a4b72ac0 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationStore.java +++ b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationStore.java @@ -36,6 +36,7 @@ import org.collectionspace.services.authorization.PermissionRoleRel; import org.collectionspace.services.authorization.perms.Permission; import org.collectionspace.services.authorization.storage.RoleStorageConstants; import org.collectionspace.services.common.document.JaxbUtils; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,11 +51,14 @@ public class AuthorizationStore { private final static String PERSISTENCE_UNIT = "org.collectionspace.services.authorization"; public final static String ENTITY_MANAGER_PROP_KEY = EntityManager.class.getCanonicalName(); - static public Role getRoleByName(String roleName, String tenantId) { + static public Role getRoleByName( + JPATransactionContext jpaTransactionContext, + String roleName, + String tenantId) { Role theRole = null; try { - theRole = (Role)JpaStorageUtils.getEnityByKey(Role.class.getName(), + theRole = (Role)JpaStorageUtils.getEnityByKey(jpaTransactionContext, Role.class.getName(), RoleStorageConstants.ROLE_NAME, roleName, tenantId); } catch (Throwable e) { if (logger.isTraceEnabled() == true) { @@ -65,27 +69,14 @@ public class AuthorizationStore { return theRole; } - static public Role getRoleByName(EntityManager em, String roleName, String tenantId) { - Role theRole = null; - - try { - theRole = (Role)JpaStorageUtils.getEnityByKey(em, Role.class.getName(), - RoleStorageConstants.ROLE_NAME, roleName, tenantId); - } catch (Throwable e) { - if (logger.isTraceEnabled() == true) { - logger.trace("Could not retrieve role with name =" + roleName, e); - } - } - - return theRole; - } - - - static public PermissionRoleRel getPermRoleRel(EntityManager em, String permId, String roleId) { + static public PermissionRoleRel getPermRoleRel( + JPATransactionContext jpaTransactionContext, + String permId, + String roleId) { PermissionRoleRel permRoleRel = null; try { - permRoleRel = (PermissionRoleRel)JpaStorageUtils.getEntityByDualKeys(em, + permRoleRel = (PermissionRoleRel)JpaStorageUtils.getEntityByDualKeys(jpaTransactionContext, PermissionRoleRel.class.getName(), RoleStorageConstants.PERM_ROLE_REL_PERM_ID, permId, RoleStorageConstants.PERM_ROLE_REL_ROLE_ID, roleId); @@ -155,27 +146,27 @@ public class AuthorizationStore { } } - private boolean exists(EntityManager em, Object entity) { + private boolean exists(JPATransactionContext jpaTransactionContext, Object entity) { boolean result = false; try { - if(entity instanceof Role) { + if (entity instanceof Role) { // If find by name, exists Role roleEntity = (Role)entity; String roleName = roleEntity.getRoleName(); String tenantId = roleEntity.getTenantId(); - if(getRoleByName(em, roleName, tenantId)!=null) { + if (getRoleByName(jpaTransactionContext, roleName, tenantId)!=null) { result = true; logger.trace("Role {} already exists in tenant {}.", roleName, tenantId); } else { logger.trace("Role {} does not exist in tenant {}.", roleName, tenantId); } - } else if(entity instanceof PermissionRoleRel) { + } else if (entity instanceof PermissionRoleRel) { // If find by name, exists PermissionRoleRel permRoleEntity = (PermissionRoleRel)entity; String roleId = permRoleEntity.getRoleId(); String permId = permRoleEntity.getPermissionId(); - if(getPermRoleRel(em, permId, roleId)!=null) { + if (getPermRoleRel(jpaTransactionContext, permId, roleId) != null) { result = true; logger.trace("PermRoleRel for {}, {} already exists.", permId, roleId); } else { @@ -183,7 +174,7 @@ public class AuthorizationStore { } } else { // Default case; also best test for Permission String csid = (String)JaxbUtils.getValue(entity, "getCsid"); - Object existingEntity = em.find(entity.getClass(), csid); + Object existingEntity = jpaTransactionContext.find(entity.getClass(), csid); if (existingEntity != null) { result = true; logger.trace("Entity with csid {} already exists.", csid); @@ -197,11 +188,12 @@ public class AuthorizationStore { return result; } + /* * Use this method if you've already started a transaction with an EntityManager */ - public String store(EntityManager em, Object entity) throws Exception { - boolean entityExists = exists(em, entity); + public String store(JPATransactionContext jpaTransactionContext, Object entity) throws Exception { + boolean entityExists = exists(jpaTransactionContext, entity); /* * Logging moved to exists, for better detail if (entityExists == true) { @@ -217,7 +209,7 @@ public class AuthorizationStore { // PLS: Question: why merge? what might be new to change, and is this really a good idea? // Shouldn't we define them once and leave them alone? } else { - em.persist(entity); + jpaTransactionContext.persist(entity); } // look for a CSID diff --git a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/PermissionRoleUtil.java b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/PermissionRoleUtil.java index 27c374cdb..d73f37656 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/PermissionRoleUtil.java +++ b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/PermissionRoleUtil.java @@ -32,8 +32,10 @@ import javax.persistence.NoResultException; import org.collectionspace.services.common.document.DocumentException; import org.collectionspace.services.common.document.DocumentNotFoundException; +import org.collectionspace.services.common.document.TransactionException; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.context.ServiceContextProperties; +import org.collectionspace.services.common.storage.jpa.JPATransactionContext; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; import org.collectionspace.services.authorization.perms.ActionType; @@ -102,7 +104,7 @@ public class PermissionRoleUtil { * @param prrl persistent entities built are inserted into this list * @param toDelete the to delete */ - static public void buildPermissionRoleRel(EntityManager em, + static public void buildPermissionRoleRel(JPATransactionContext jpaTransactionContext, PermissionRole pr, SubjectType subject, List prrl, @@ -114,7 +116,7 @@ public class PermissionRoleUtil { if (permissionValues != null && permissionValues.size() > 0) { PermissionValue pv = permissionValues.get(0); for (RoleValue rv : pr.getRole()) { - PermissionRoleRel prr = buildPermissonRoleRel(em, pv, rv, subject, handleDelete, tenantId); + PermissionRoleRel prr = buildPermissonRoleRel(jpaTransactionContext, pv, rv, subject, handleDelete, tenantId); prrl.add(prr); } } @@ -123,42 +125,34 @@ public class PermissionRoleUtil { if (roleValues != null && roleValues.size() > 0) { RoleValue rv = roleValues.get(0); for (PermissionValue pv : pr.getPermission()) { - PermissionRoleRel prr = buildPermissonRoleRel(em, pv, rv, subject, handleDelete, tenantId); + PermissionRoleRel prr = buildPermissonRoleRel(jpaTransactionContext, pv, rv, subject, handleDelete, tenantId); prrl.add(prr); } } } } - static public void buildPermissionRoleRel( + static public void buildPermissionRoleRel( + ServiceContext ctx, PermissionRole pr, SubjectType subject, List prrl, boolean handleDelete, String tenantId) throws Exception { - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection(); try { - emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT); - em = emf.createEntityManager(); - em.getTransaction().begin(); - - buildPermissionRoleRel(em, pr, subject, prrl, handleDelete, tenantId); - - em.getTransaction().commit(); - em.close(); + jpaTransactionContext.beginTransaction(); + buildPermissionRoleRel(jpaTransactionContext, pr, subject, prrl, handleDelete, tenantId); + jpaTransactionContext.commitTransaction(); } catch (Exception e) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaTransactionContext.markForRollback(); if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } throw e; } finally { - if (em != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } @@ -166,7 +160,7 @@ public class PermissionRoleUtil { * Try to find a persisted Permission record using a PermissionValue instance. * */ - static private Permission lookupPermission(EntityManager em, PermissionValue permissionValue, String tenantId) { + static private Permission lookupPermission(JPATransactionContext jpaTransactionContext, PermissionValue permissionValue, String tenantId) throws TransactionException { Permission result = null; String actionGroup = permissionValue.getActionGroup() != null ? permissionValue.getActionGroup().trim() : null; @@ -177,7 +171,7 @@ public class PermissionRoleUtil { // if (permissionId != null && !permissionId.isEmpty()) { try { - result = (Permission)JpaStorageUtils.getEntity(em, permissionId, Permission.class); + result = (Permission)JpaStorageUtils.getEntity(jpaTransactionContext, permissionId, Permission.class); } catch (Throwable e) { String msg = String.format("Searched for but couldn't find a permission with CSID='%s'.", permissionId); @@ -189,7 +183,7 @@ public class PermissionRoleUtil { // If there was no permission ID, then we can try to find the permission with the resource name and action group tuple // try { - result = (Permission)JpaStorageUtils.getEntityByDualKeys(em, + result = (Permission)JpaStorageUtils.getEntityByDualKeys(jpaTransactionContext, Permission.class.getName(), PermissionStorageConstants.RESOURCE_NAME, permissionValue.getResourceName(), PermissionStorageConstants.ACTION_GROUP, permissionValue.getActionGroup(), @@ -217,14 +211,14 @@ public class PermissionRoleUtil { * @return the permission role rel * @throws DocumentException */ - static private PermissionRoleRel buildPermissonRoleRel(EntityManager em, PermissionValue permissionValue, + static private PermissionRoleRel buildPermissonRoleRel(JPATransactionContext jpaTransactionContext, PermissionValue permissionValue, RoleValue roleValue, SubjectType subject, boolean handleDelete, // if 'true' then we're deleting not building a permission-role record String tenantId) throws DocumentException { PermissionRoleRel result = null; - Permission permission = lookupPermission(em, permissionValue, tenantId); + Permission permission = lookupPermission(jpaTransactionContext, permissionValue, tenantId); // // If we couldn't find an existing permission and we're not processing a DELETE request, we need to create @@ -237,7 +231,7 @@ public class PermissionRoleUtil { permission.setEffect(EffectType.PERMIT); // By default, CollectionSpace currently (11/2017) supports only PERMIT List actionList = createPermActionList(permissionValue.getActionGroup()); permission.setAction(actionList); - permission = createPermission(permission); + permission = createPermission(jpaTransactionContext, permission); if (permission == null) { String errMsg = "Could not create new permission for new permission-role relationship."; throw new DocumentException(errMsg); @@ -278,11 +272,11 @@ public class PermissionRoleUtil { return result; } - private static Permission createPermission(Permission permission) { + private static Permission createPermission(JPATransactionContext jpaTransactionContext, Permission permission) { Permission result = null; PermissionResource permissionResource = new PermissionResource(); // Get the PermissionResource singleton instance (RESTEasy ensures it is a singleton) - result = permissionResource.createPermissionFromInstance(permission); + result = permissionResource.createPermissionFromInstance(jpaTransactionContext, permission); return result; } diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java b/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java index a1c1ebd7c..d10ab1caf 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java @@ -61,8 +61,16 @@ public class RemoteServiceContextImpl /** The output. */ private OT output; /** The target of the HTTP request **/ - JaxRsContext jaxRsContext; + // + // Reference count for things like JPA connections + // + private int transactionConnectionRefCount = 0; + + // + // RESTEasy context + // + JaxRsContext jaxRsContext; ResourceMap resourceMap = null; @Override @@ -255,42 +263,58 @@ public class RemoteServiceContextImpl // Transaction management methods // - private TransactionContext getCurrentTransactionContext() { + @Override + public TransactionContext getCurrentTransactionContext() { return (TransactionContext) this.getProperty(StorageClient.SC_TRANSACTION_CONTEXT_KEY); } @Override - public void releaseConnection() throws TransactionException { - if (isTransactionContextShared() == true) { - throw new TransactionException("Attempted to release a shared storage connection. Only the originator can release the connection"); + synchronized public void closeConnection() throws TransactionException { + if (transactionConnectionRefCount == 0) { + throw new TransactionException("Attempted to release a connection that doesn't exist or has already been released."); } - - TransactionContext transactionCtx = getCurrentTransactionContext(); - if (transactionCtx != null) { - transactionCtx.close(); - this.setProperty(StorageClient.SC_TRANSACTION_CONTEXT_KEY, null); + + if (isTransactionContextShared() == true) { + // + // If it's a shared connection, we can't close it. Just reduce the refcount by 1 + // + String warnMsg = "Attempted to release a shared storage connection. Only the originator can release the connection"; + logger.warn(warnMsg); + transactionConnectionRefCount--; } else { - throw new TransactionException("Attempted to release a non-existent storage connection. Transaction context missing from service context."); + TransactionContext transactionCtx = getCurrentTransactionContext(); + if (transactionCtx != null) { + if (--transactionConnectionRefCount == 0) { + transactionCtx.close(); + this.setProperty(StorageClient.SC_TRANSACTION_CONTEXT_KEY, null); + } + } else { + throw new TransactionException("Attempted to release a non-existent storage connection. Transaction context missing from service context."); + } } } @Override - public TransactionContext openConnection() throws TransactionException { + synchronized public TransactionContext openConnection() throws TransactionException { TransactionContext result = getCurrentTransactionContext(); - if (result != null) { - throw new TransactionException("Attempted to open a new connection when a current connection is still part of the current service context. The current connection must be closed with the releaseConnection() method."); + + if (result == null) { + result = new JPATransactionContext(this); + this.setProperty(StorageClient.SC_TRANSACTION_CONTEXT_KEY, result); } - - result = new JPATransactionContext(this); - this.setProperty(StorageClient.SC_TRANSACTION_CONTEXT_KEY, result); - + transactionConnectionRefCount++; + return result; } @Override - public void setTransactionContext(TransactionContext transactionCtx) { - // TODO Auto-generated method stub - + public void setTransactionContext(TransactionContext transactionCtx) throws TransactionException { + TransactionContext currentTransactionCtx = this.getCurrentTransactionContext(); + if (currentTransactionCtx == null) { + setProperty(StorageClient.SC_TRANSACTION_CONTEXT_KEY, transactionCtx); + } else if (currentTransactionCtx != transactionCtx) { + throw new TransactionException("Transaction context already set from service context."); + } } /** diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java index ccdf5c3b8..36bb6a2a6 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java @@ -423,17 +423,25 @@ public interface ServiceContext { /** * */ - public void releaseConnection() throws TransactionException; // Assumes there's been a call to getConnection. + public void closeConnection() throws TransactionException; // Assumes there's been a call to getConnection. /** + * @throws TransactionException * */ - public void setTransactionContext(TransactionContext transactionCtx); // For sharing a transaction context with another service context. + void setTransactionContext(TransactionContext transactionCtx) throws TransactionException; // For sharing a transaction context with another service context. /** * */ public boolean isTransactionContextShared() throws TransactionException; + + /** + * + * @return + */ + TransactionContext getCurrentTransactionContext(); + } diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/TransactionContext.java b/services/common/src/main/java/org/collectionspace/services/common/storage/TransactionContext.java index 41bf9a3a2..3a1ca5e7d 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/TransactionContext.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/TransactionContext.java @@ -1,5 +1,7 @@ package org.collectionspace.services.common.storage; +import javax.persistence.Query; + import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.TransactionException; @@ -22,4 +24,14 @@ public abstract class TransactionContext { abstract public void commitTransaction() throws TransactionException; abstract public boolean isTransactionActive() throws TransactionException; + + abstract public void persist(Object entity); + + abstract public Object find(Class entityClass, Object primaryKey); + + abstract public Object find(Class entityClass, String id); + + abstract public Query createQuery(String qlString); + + abstract public void remove(Object entity); } diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JPATransactionContext.java b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JPATransactionContext.java index 6e747f319..33045098d 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JPATransactionContext.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JPATransactionContext.java @@ -2,26 +2,35 @@ package org.collectionspace.services.common.storage.jpa; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; +import javax.persistence.Query; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.TransactionException; import org.collectionspace.services.common.storage.TransactionContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @SuppressWarnings("rawtypes") public class JPATransactionContext extends TransactionContext { + /** The logger. */ + private final Logger logger = LoggerFactory.getLogger(TransactionContext.class); + + private int transactionRefCount = 0; + private Boolean commitSuccessful = null; + EntityManagerFactory emf; EntityManager em; - @SuppressWarnings("unused") - private JPATransactionContext() { - // Don't allow anyone to create an empty instance - } - public JPATransactionContext(ServiceContext ctx) { emf = JpaStorageUtils.getEntityManagerFactory(); em = emf.createEntityManager(); this.ctx = ctx; } + + public JPATransactionContext() { + emf = JpaStorageUtils.getEntityManagerFactory(); + em = emf.createEntityManager(); + } protected EntityManagerFactory getEntityManagerFactory() { return emf; @@ -38,7 +47,12 @@ public class JPATransactionContext extends TransactionContext { @Override public void markForRollback() { - em.getTransaction().setRollbackOnly(); + if (em.getTransaction().isActive() == true) { + em.getTransaction().setRollbackOnly(); + } else { + String msg = "Attemped to mark an inactive transaction for rollback."; + logger.warn(msg); + } } @Override @@ -54,13 +68,47 @@ public class JPATransactionContext extends TransactionContext { } @Override - public void beginTransaction() { - em.getTransaction().begin(); + synchronized public void beginTransaction() { + if (transactionRefCount == 0) { + em.getTransaction().begin(); + } + transactionRefCount++; + } + + @Override + public void persist(Object entity) { + em.persist(entity); + } + + @Override + public Object find(Class entityClass, Object primaryKey) { + return em.find(entityClass, primaryKey); + } + + @Override + public Object find(Class entityClass, String id) { + return em.find(entityClass, id); + } + + @Override + public Query createQuery(String qlString) { + return em.createQuery(qlString); + } + + @Override + public void remove(Object entity) { + em.remove(entity); } @Override - public void commitTransaction() { - em.getTransaction().commit(); + public void commitTransaction() throws TransactionException { + if (transactionRefCount == 0) { + throw new JPATransactionException("There is no active transaction to commit."); + } + if (--transactionRefCount == 0) { + em.getTransaction().commit(); + commitSuccessful = Boolean.TRUE; + } } @Override diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaRelationshipStorageClient.java b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaRelationshipStorageClient.java index ad86f0088..368b17963 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaRelationshipStorageClient.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaRelationshipStorageClient.java @@ -28,10 +28,7 @@ import org.collectionspace.services.common.context.ServiceContextProperties; import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.UUID; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; import javax.persistence.NoResultException; import javax.persistence.PersistenceException; import javax.persistence.Query; @@ -65,6 +62,7 @@ import org.slf4j.LoggerFactory; * delete deletes all subjects for the given object in relationship * @author */ +@SuppressWarnings({ "rawtypes", "unchecked" }) public class JpaRelationshipStorageClient extends JpaStorageClientImpl { private final Logger logger = LoggerFactory.getLogger(JpaRelationshipStorageClient.class); @@ -99,57 +97,44 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { * @throws BadRequestException * @throws DocumentException */ - @Override + @Override public String create(ServiceContext ctx, DocumentHandler handler) throws BadRequestException, DocumentException { - - if (ctx == null) { - throw new IllegalArgumentException( - "create : ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "create: handler is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; + String result = null; + + JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection(); try { + jpaTransactionContext.beginTransaction(); handler.prepare(Action.CREATE); List rl = new ArrayList(); DocumentWrapper> wrapDoc = new DocumentWrapperImpl>(rl); handler.handle(Action.CREATE, wrapDoc); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - em.getTransaction().begin(); for (T r : rl) { JaxbUtils.setValue(r, "setCreatedAtItem", Date.class, new Date()); - em.persist(r); + jpaTransactionContext.persist(r); } - em.getTransaction().commit(); handler.complete(Action.CREATE, wrapDoc); - return UUID.randomUUID().toString(); //filler, not useful + jpaTransactionContext.commitTransaction(); + result = "-1"; // meaningless result } catch (BadRequestException bre) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaTransactionContext.markForRollback(); throw bre; } catch (PersistenceException pe) { + jpaTransactionContext.markForRollback(); throw pe; } catch (Exception e) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaTransactionContext.markForRollback(); if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } throw new DocumentException(e); } finally { - if (em != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } + + return result; } /** @@ -164,20 +149,14 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { @Override public void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { - if (ctx == null) { - throw new IllegalArgumentException( - "get: ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "get: handler is missing"); - } + if (getObject(ctx, id) == null) { String msg = "get: " + "could not find the object with id=" + id; logger.error(msg); throw new DocumentNotFoundException(msg); } + String objectId = getObjectId(ctx); if (logger.isDebugEnabled()) { logger.debug("get: using objectId=" + objectId); @@ -190,8 +169,8 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { if (docFilter == null) { docFilter = handler.createDocumentFilter(); } - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { handler.prepare(Action.GET); StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM "); @@ -203,35 +182,27 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { if ((null != where) && (where.length() > 0)) { queryStrBldr.append(" AND " + where); } - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); + String queryStr = queryStrBldr.toString(); //for debugging if (logger.isDebugEnabled()) { logger.debug("get: jql=" + queryStr.toString()); } - Query q = em.createQuery(queryStr); + Query q = jpaConnectionContext.createQuery(queryStr); q.setParameter("objectId", id); List rl = new ArrayList(); + jpaConnectionContext.beginTransaction(); try { - //require transaction for get? - em.getTransaction().begin(); rl = q.getResultList(); - em.getTransaction().commit(); } catch (NoResultException nre) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - String msg = "get(1): " - + " could not find relationships for object class=" + String msg = "get(1): " + " could not find relationships for object class=" + objectClass.getName() + " id=" + id; if (logger.isDebugEnabled()) { logger.debug(msg, nre); } } if (rl.size() == 0) { - String msg = "get(2): " - + " could not find relationships for object class=" + String msg = "get(2): " + " could not find relationships for object class=" + objectClass.getName() + " id=" + id; if (logger.isDebugEnabled()) { logger.debug(msg); @@ -241,17 +212,17 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { new DocumentWrapperImpl>(rl); handler.handle(Action.GET, wrapDoc); handler.complete(Action.GET, wrapDoc); + jpaConnectionContext.commitTransaction(); } catch (DocumentException de) { - throw de; + jpaConnectionContext.markForRollback(); } catch (Exception e) { + jpaConnectionContext.markForRollback(); if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } @@ -285,11 +256,11 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { * @return the relationship * @throws DocumentNotFoundException the document not found exception */ - private T getRelationship(EntityManager em, T relationship) + private T getRelationship(JPATransactionContext jpaTransactionContext, T relationship) throws DocumentNotFoundException { Long id = getId(relationship); - T relationshipFound = (T)em.find(relationship.getClass(), id); + T relationshipFound = (T)jpaTransactionContext.find(relationship.getClass(), id); if (relationshipFound == null) { String msg = "Could not find relationship with id=" + id; if (logger.isErrorEnabled() == true) { @@ -297,6 +268,7 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { } throw new DocumentNotFoundException(msg); } + return relationshipFound; } @@ -313,16 +285,12 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { throws DocumentNotFoundException, DocumentException { - if (ctx == null) { - throw new IllegalArgumentException( - "delete : ctx is missing"); - } if (getObject(ctx, id) == null) { - String msg = "delete : " - + "could not find the object with id=" + id; + String msg = "delete : " + "could not find the object with id=" + id; logger.error(msg); throw new DocumentNotFoundException(msg); } + String objectId = getObjectId(ctx); if (logger.isDebugEnabled()) { logger.debug("delete: using objectId=" + objectId); @@ -331,22 +299,20 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { if (logger.isDebugEnabled()) { logger.debug("delete: using object class=" + objectClass.getName()); } - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { StringBuilder deleteStr = new StringBuilder("DELETE FROM "); String entityName = getEntityName(ctx); deleteStr.append(entityName); deleteStr.append(" WHERE " + objectId + " = :objectId"); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); if (logger.isDebugEnabled()) { logger.debug("delete: jql=" + deleteStr.toString()); } - Query q = em.createQuery(deleteStr.toString()); + Query q = jpaConnectionContext.createQuery(deleteStr.toString()); q.setParameter("objectId", id); int rcount = 0; - em.getTransaction().begin(); + jpaConnectionContext.beginTransaction(); if (logger.isDebugEnabled() == true) { logger.debug(q.toString()); } @@ -355,20 +321,15 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { logger.debug("deleted " + rcount + " relationships for entity " + entityName + " with objectId=" + objectId); } - em.getTransaction().commit(); - + jpaConnectionContext.commitTransaction(); } catch (Exception e) { + jpaConnectionContext.markForRollback(); if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } @@ -388,49 +349,32 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { throws DocumentNotFoundException, DocumentException { boolean result = true; - if (ctx == null) { - throw new IllegalArgumentException( - "delete : ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "delete : handler is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; + JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection(); try { + jpaTransactionContext.beginTransaction(); handler.prepare(Action.DELETE); List rl = new ArrayList(); - DocumentWrapper> wrapDoc = - new DocumentWrapperImpl>(rl); + DocumentWrapper> wrapDoc = new DocumentWrapperImpl>(rl); handler.handle(Action.DELETE, wrapDoc); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - em.getTransaction().begin(); - //the following could be much more efficient if done with a single - //sql/jql + // + //the following could be much more efficient if done with a single sql/jql + // for (T r : rl) { - em.remove(getRelationship(em, r)); + jpaTransactionContext.remove(getRelationship(jpaTransactionContext, r)); } - em.getTransaction().commit(); handler.complete(Action.DELETE, wrapDoc); // Delete from the Spring Security tables. Would be better if this was part of the earlier transaction. + jpaTransactionContext.commitTransaction(); } catch (DocumentException de) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaTransactionContext.markForRollback(); throw de; } catch (Exception e) { + jpaTransactionContext.markForRollback(); if (logger.isDebugEnabled()) { logger.debug("delete(ctx, ix, handler): Caught exception ", e); } - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } return result; @@ -443,9 +387,9 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { */ protected String getObjectId(ServiceContext ctx) { String objectId = (String) ctx.getProperty(ServiceContextProperties.OBJECT_ID); + if (objectId == null) { - String msg = ServiceContextProperties.OBJECT_ID - + " property is missing in the context"; + String msg = ServiceContextProperties.OBJECT_ID + " property is missing in the context"; logger.error(msg); throw new IllegalArgumentException(msg); } @@ -460,12 +404,13 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { */ protected Class getObjectClass(ServiceContext ctx) { Class objectClass = (Class) ctx.getProperty(ServiceContextProperties.OBJECT_CLASS); + if (objectClass == null) { - String msg = ServiceContextProperties.OBJECT_CLASS - + " property is missing in the context"; + String msg = ServiceContextProperties.OBJECT_CLASS + " property is missing in the context"; logger.error(msg); throw new IllegalArgumentException(msg); } + return objectClass; } @@ -478,6 +423,6 @@ public class JpaRelationshipStorageClient extends JpaStorageClientImpl { protected Object getObject(ServiceContext ctx, String id) throws DocumentNotFoundException { Class objectClass = getObjectClass(ctx); - return JpaStorageUtils.getEntity(id, objectClass); + return JpaStorageUtils.getEntity((JPATransactionContext)ctx.getCurrentTransactionContext(), id, objectClass); } } diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClientImpl.java b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClientImpl.java index 5ade3641c..88367d02b 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClientImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClientImpl.java @@ -20,15 +20,9 @@ package org.collectionspace.services.common.storage.jpa; import java.util.Date; import java.util.List; -import javax.persistence.RollbackException; -import javax.xml.datatype.XMLGregorianCalendar; - -import java.sql.BatchUpdateException; - import javax.persistence.EntityExistsException; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; import javax.persistence.Query; +import javax.persistence.RollbackException; import org.collectionspace.services.common.document.BadRequestException; import org.collectionspace.services.common.document.DocumentException; @@ -41,14 +35,12 @@ import org.collectionspace.services.common.document.DocumentWrapperImpl; import org.collectionspace.services.common.document.JaxbUtils; import org.collectionspace.services.common.document.TransactionException; import org.collectionspace.services.common.storage.StorageClient; +import org.collectionspace.services.common.storage.TransactionContext; import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier; -import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier; import org.collectionspace.services.common.context.ServiceContextProperties; -import org.collectionspace.services.common.api.GregorianCalendarDateTimeUtils; -import org.collectionspace.services.common.authorization_mgt.AuthorizationStore; import org.collectionspace.services.common.context.ServiceContext; -import org.collectionspace.services.common.query.QueryContext; import org.collectionspace.services.lifecycle.TransitionDef; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -105,77 +97,60 @@ public class JpaStorageClientImpl implements StorageClient { /* (non-Javadoc) * @see org.collectionspace.services.common.storage.StorageClient#create(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler) */ - @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override public String create(ServiceContext ctx, DocumentHandler handler) throws BadRequestException, DocumentException { - if (ctx == null) { - throw new IllegalArgumentException( - "create: ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "create: handler is missing"); - } - - boolean rollbackTransaction = false; - EntityManagerFactory emf = null; - EntityManager em = null; + String result = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { handler.prepare(Action.CREATE); Object entity = handler.getCommonPart(); DocumentWrapper wrapDoc = new DocumentWrapperImpl(entity); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - em.getTransaction().begin(); { //begin of transaction block - ctx.setProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY, em); - try { - handler.handle(Action.CREATE, wrapDoc); - JaxbUtils.setValue(entity, "setCreatedAtItem", Date.class, new Date()); - em.persist(entity); - } catch (EntityExistsException ee) { - // - // We found an existing matching entity in the store, so we don't need to create one. Just update the transient 'entity' instance with the existing persisted entity we found. - // An entity's document handler class will throw this exception only if attempting to create (but not actually creating) duplicate is ok -e.g., Permission records. - // - entity = wrapDoc.getWrappedObject(); // the handler should have reset the wrapped transient object with the existing persisted entity we just found. - } + jpaConnectionContext.beginTransaction(); + try { + handler.handle(Action.CREATE, wrapDoc); + JaxbUtils.setValue(entity, "setCreatedAtItem", Date.class, new Date()); + jpaConnectionContext.persist(entity); + } catch (EntityExistsException ee) { + // + // We found an existing matching entity in the store, so we don't need to create one. Just update the transient 'entity' instance with the existing persisted entity we found. + // An entity's document handler class will throw this exception only if attempting to create (but not actually creating) duplicate is ok -e.g., Permission records. + // + entity = wrapDoc.getWrappedObject(); // the handler should have reset the wrapped transient object with the existing persisted entity we just found. } - em.getTransaction().commit(); handler.complete(Action.CREATE, wrapDoc); - return (String) JaxbUtils.getValue(entity, "getCsid"); + jpaConnectionContext.commitTransaction(); + + result = (String)JaxbUtils.getValue(entity, "getCsid"); } catch (BadRequestException bre) { - rollbackTransaction = true; + jpaConnectionContext.markForRollback(); throw bre; } catch (DocumentException de) { - rollbackTransaction = true; + jpaConnectionContext.markForRollback(); throw de; + } catch (RollbackException rbe) { + //jpaConnectionContext.markForRollback(); + throw DocumentException.createDocumentException(rbe); } catch (Exception e) { - rollbackTransaction = true; - if (logger.isDebugEnabled()) { - logger.debug("Caught exception ", e); - } + jpaConnectionContext.markForRollback(); + logger.debug("Caught exception ", e); throw DocumentException.createDocumentException(e); } finally { - ctx.setProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY, null); - if (em != null) { - if (rollbackTransaction == true) { - if (em.getTransaction().isActive() == true) { - em.getTransaction().rollback(); - } - } - // Don't call this unless "em" is not null -hence the check above. - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } + return result; } /* (non-Javadoc) * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler) */ - @Override + @SuppressWarnings("rawtypes") + @Override public void get(ServiceContext ctx, List csidList, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { throw new UnsupportedOperationException(); @@ -184,29 +159,18 @@ public class JpaStorageClientImpl implements StorageClient { /* (non-Javadoc) * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler) */ - @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override public void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { - if (ctx == null) { - throw new IllegalArgumentException( - "get: ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "get: handler is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection(); try { handler.prepare(Action.GET); Object o = null; - o = JpaStorageUtils.getEntity(getEntityName(ctx), id, - ctx.getTenantId()); + o = JpaStorageUtils.getEntity(jpaTransactionContext, getEntityName(ctx), id, ctx.getTenantId()); if (null == o) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - String msg = "could not find entity with id=" + id; + String msg = "Could not find entity with id=" + id; throw new DocumentNotFoundException(msg); } DocumentWrapper wrapDoc = new DocumentWrapperImpl(o); @@ -220,16 +184,15 @@ public class JpaStorageClientImpl implements StorageClient { } throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } /* (non-Javadoc) * @see org.collectionspace.services.common.storage.StorageClient#getAll(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler) */ - @Override + @SuppressWarnings("rawtypes") + @Override public void getAll(ServiceContext ctx, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { throw new UnsupportedOperationException("use getFiltered instead"); @@ -238,17 +201,17 @@ public class JpaStorageClientImpl implements StorageClient { /* (non-Javadoc) * @see org.collectionspace.services.common.storage.StorageClient#getFiltered(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler) */ - @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override public void getFiltered(ServiceContext ctx, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { - QueryContext queryContext = new QueryContext(ctx, handler); DocumentFilter docFilter = handler.getDocumentFilter(); if (docFilter == null) { docFilter = handler.createDocumentFilter(); } - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { handler.prepare(Action.GET_ALL); StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM "); @@ -256,10 +219,8 @@ public class JpaStorageClientImpl implements StorageClient { queryStrBldr.append(" a"); List params = docFilter.buildWhereForSearch(queryStrBldr); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); String queryStr = queryStrBldr.toString(); //for debugging - Query q = em.createQuery(queryStr); + Query q = jpaConnectionContext.createQuery(queryStr); //bind parameters for (DocumentFilter.ParamBinding p : params) { q.setParameter(p.getName(), p.getValue()); @@ -271,17 +232,14 @@ public class JpaStorageClientImpl implements StorageClient { q.setMaxResults(docFilter.getPageSize()); } - //FIXME is transaction required for get? - em.getTransaction().begin(); + jpaConnectionContext.beginTransaction(); List list = q.getResultList(); - long totalItems = getTotalItems(em, ctx, handler); // Find out how many items our query would find independent of the paging restrictions - em.getTransaction().commit(); - + long totalItems = getTotalItems(jpaConnectionContext, ctx, handler); // Find out how many items our query would find independent of the paging restrictions docFilter.setTotalItemsResult(totalItems); // Save the items total in the doc filter for later reporting - DocumentWrapper wrapDoc = new DocumentWrapperImpl(list); handler.handle(Action.GET_ALL, wrapDoc); handler.complete(Action.GET_ALL, wrapDoc); + jpaConnectionContext.commitTransaction(); } catch (DocumentException de) { throw de; } catch (Exception e) { @@ -290,16 +248,15 @@ public class JpaStorageClientImpl implements StorageClient { } throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } /* * Return the COUNT for a query to find the total number of matches independent of the paging restrictions. */ - private long getTotalItems(EntityManager em, ServiceContext ctx, DocumentHandler handler) { + @SuppressWarnings("rawtypes") + private long getTotalItems(JPATransactionContext jpaTransactionContext, ServiceContext ctx, DocumentHandler handler) { long result = -1; DocumentFilter docFilter = handler.getDocumentFilter(); @@ -309,7 +266,7 @@ public class JpaStorageClientImpl implements StorageClient { List params = docFilter.buildWhereForSearch(queryStrBldr); String queryStr = queryStrBldr.toString(); - Query q = em.createQuery(queryStr); + Query q = jpaTransactionContext.createQuery(queryStr); //bind parameters for (DocumentFilter.ParamBinding p : params) { q.setParameter(p.getName(), p.getValue()); @@ -323,51 +280,39 @@ public class JpaStorageClientImpl implements StorageClient { /* (non-Javadoc) * @see org.collectionspace.services.common.storage.StorageClient#update(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler) */ - @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override public void update(ServiceContext ctx, String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException { - if (ctx == null) { - throw new IllegalArgumentException( - "update: ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "update: handler is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; + + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { + jpaConnectionContext.beginTransaction(); + handler.prepare(Action.UPDATE); Object entityReceived = handler.getCommonPart(); - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - em.getTransaction().begin(); - Object entityFound = getEntity(em, id, entityReceived.getClass()); + Object entityFound = getEntity(ctx, id, entityReceived.getClass()); DocumentWrapper wrapDoc = new DocumentWrapperImpl(entityFound); handler.handle(Action.UPDATE, wrapDoc); JaxbUtils.setValue(entityFound, "setUpdatedAtItem", Date.class, new Date()); - em.getTransaction().commit(); handler.complete(Action.UPDATE, wrapDoc); + + jpaConnectionContext.commitTransaction(); } catch (BadRequestException bre) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw bre; } catch (DocumentException de) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw de; } catch (Exception e) { + jpaConnectionContext.markForRollback(); if (logger.isDebugEnabled()) { logger.debug("Caught exception ", e); } throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } @@ -377,55 +322,33 @@ public class JpaStorageClientImpl implements StorageClient { * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String) */ @Override - public void delete(ServiceContext ctx, String id) + public void delete(@SuppressWarnings("rawtypes") ServiceContext ctx, String id) throws DocumentNotFoundException, DocumentException { - if (logger.isDebugEnabled()) { - logger.debug("delete(ctx, id): deleting entity with id=" + id); - } - - if (ctx == null) { - throw new IllegalArgumentException( - "delete(ctx, id): ctx is missing"); - } - EntityManagerFactory emf = null; - EntityManager em = null; + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { - - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - - em.getTransaction().begin(); - Object entityFound = getEntity(ctx, em, id); + jpaConnectionContext.beginTransaction(); + Object entityFound = getEntity(ctx, id); if (entityFound == null) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); String msg = "delete(ctx, id): could not find entity with id=" + id; logger.error(msg); throw new DocumentNotFoundException(msg); } - em.remove(entityFound); - em.getTransaction().commit(); - + jpaConnectionContext.remove(entityFound); + jpaConnectionContext.commitTransaction(); } catch (DocumentException de) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw de; } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("delete(ctx, id): Caught exception ", e); } - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } @@ -437,62 +360,42 @@ public class JpaStorageClientImpl implements StorageClient { * @throws DocumentNotFoundException * @throws DocumentException */ - public void deleteWhere(ServiceContext ctx, String id) + public void deleteWhere(@SuppressWarnings("rawtypes") ServiceContext ctx, String id) throws DocumentNotFoundException, DocumentException { - if (ctx == null) { - throw new IllegalArgumentException( - "deleteWhere(ctx, id) : ctx is missing"); - } - - if (logger.isDebugEnabled()) { - logger.debug("deleteWhere(ctx, id): deleting entity with id=" + id); - } - EntityManagerFactory emf = null; - EntityManager em = null; + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { StringBuilder deleteStr = new StringBuilder("DELETE FROM "); deleteStr.append(getEntityName(ctx)); deleteStr.append(" WHERE csid = :csid and tenantId = :tenantId"); //TODO: add tenant csidReceived - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - Query q = em.createQuery(deleteStr.toString()); + Query q = jpaConnectionContext.createQuery(deleteStr.toString()); q.setParameter("csid", id); q.setParameter("tenantId", ctx.getTenantId()); int rcount = 0; - em.getTransaction().begin(); + jpaConnectionContext.beginTransaction(); rcount = q.executeUpdate(); if (rcount != 1) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); String msg = "deleteWhere(ctx, id) could not find entity with id=" + id; logger.error(msg); throw new DocumentNotFoundException(msg); } - em.getTransaction().commit(); - + jpaConnectionContext.commitTransaction(); } catch (DocumentException de) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw de; } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("deleteWhere(ctx, id) Caught exception ", e); } - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } } @@ -501,60 +404,39 @@ public class JpaStorageClientImpl implements StorageClient { * cost: a get before delete * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String) */ - @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override public boolean delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { boolean result = true; - if (ctx == null) { - throw new IllegalArgumentException( - "delete(ctx, ix, handler): ctx is missing"); - } - if (handler == null) { - throw new IllegalArgumentException( - "delete(ctx, ix, handler): handler is missing"); - } - - EntityManagerFactory emf = null; - EntityManager em = null; + JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection(); try { + jpaConnectionContext.beginTransaction(); handler.prepare(Action.DELETE); - - emf = JpaStorageUtils.getEntityManagerFactory(); - em = emf.createEntityManager(); - - em.getTransaction().begin(); - Object entityFound = getEntity(ctx, em, id); + Object entityFound = getEntity(ctx, id); if (entityFound == null) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); String msg = "delete(ctx, ix, handler) could not find entity with id=" + id; logger.error(msg); throw new DocumentNotFoundException(msg); } DocumentWrapper wrapDoc = new DocumentWrapperImpl(entityFound); handler.handle(Action.DELETE, wrapDoc); - em.remove(entityFound); - em.getTransaction().commit(); + jpaConnectionContext.remove(entityFound); handler.complete(Action.DELETE, wrapDoc); + jpaConnectionContext.commitTransaction(); } catch (DocumentException de) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - throw de; + jpaConnectionContext.markForRollback(); + throw de; } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("delete(ctx, ix, handler): Caught exception ", e); } - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } + jpaConnectionContext.markForRollback(); throw new DocumentException(e); } finally { - if (emf != null) { - JpaStorageUtils.releaseEntityManagerFactory(emf); - } + ctx.closeConnection(); } return result; @@ -567,7 +449,7 @@ public class JpaStorageClientImpl implements StorageClient { * * @return the entityReceived name */ - protected String getEntityName(ServiceContext ctx) { + protected String getEntityName(@SuppressWarnings("rawtypes") ServiceContext ctx) { Object o = ctx.getProperty(ServiceContextProperties.ENTITY_NAME); if (o == null) { throw new IllegalArgumentException(ServiceContextProperties.ENTITY_NAME @@ -581,23 +463,22 @@ public class JpaStorageClientImpl implements StorageClient { /** * getEntity returns persistent entity for given id. it assumes that * service context has property ServiceContextProperties.ENTITY_CLASS set - * rolls back the transaction if not found * @param ctx service context - * @param em entity manager * @param csid received * @return - * @throws DocumentNotFoundException and rollsback the transaction if active + * @throws DocumentNotFoundException + * @throws TransactionException */ - protected Object getEntity(ServiceContext ctx, EntityManager em, String id) - throws DocumentNotFoundException { - Class entityClazz = (Class) ctx.getProperty(ServiceContextProperties.ENTITY_CLASS); + protected Object getEntity(@SuppressWarnings("rawtypes") ServiceContext ctx, String id) + throws DocumentNotFoundException, TransactionException { + Class entityClazz = (Class) ctx.getProperty(ServiceContextProperties.ENTITY_CLASS); if (entityClazz == null) { - String msg = ServiceContextProperties.ENTITY_CLASS - + " property is missing in the context"; + String msg = ServiceContextProperties.ENTITY_CLASS + " property is missing in the context"; logger.error(msg); throw new IllegalArgumentException(msg); } - return getEntity(em, id, entityClazz); + + return getEntity(ctx, id, entityClazz); } /** @@ -608,28 +489,36 @@ public class JpaStorageClientImpl implements StorageClient { * @param entityClazz * @return * @throws DocumentNotFoundException and rollsback the transaction if active + * @throws TransactionException */ - protected Object getEntity(EntityManager em, String id, Class entityClazz) - throws DocumentNotFoundException { - Object entityFound = JpaStorageUtils.getEntity(em, id, entityClazz); - if (entityFound == null) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - String msg = "could not find entity of type=" + entityClazz.getName() - + " with id=" + id; - logger.error(msg); - throw new DocumentNotFoundException(msg); - } + protected Object getEntity(@SuppressWarnings("rawtypes") ServiceContext ctx, String id, Class entityClazz) + throws DocumentNotFoundException, TransactionException { + Object entityFound = null; + + JPATransactionContext jpaTransactionConnection = (JPATransactionContext)ctx.openConnection(); + try { + entityFound = JpaStorageUtils.getEntity(jpaTransactionConnection.getEntityManager(), id, entityClazz); + if (entityFound == null) { + String msg = "could not find entity of type=" + entityClazz.getName() + + " with id=" + id; + logger.error(msg); + throw new DocumentNotFoundException(msg); + } + } finally { + ctx.closeConnection(); + } + return entityFound; } - - @Override + + @SuppressWarnings("rawtypes") + @Override public void get(ServiceContext ctx, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { throw new UnsupportedOperationException(); } + @SuppressWarnings("rawtypes") @Override public void doWorkflowTransition(ServiceContext ctx, String id, DocumentHandler handler, TransitionDef transitionDef) @@ -638,6 +527,7 @@ public class JpaStorageClientImpl implements StorageClient { // Do nothing. JPA services do not support workflow. } + @SuppressWarnings("rawtypes") @Override public void deleteWithWhereClause(ServiceContext ctx, String whereClause, DocumentHandler handler) throws DocumentNotFoundException, @@ -645,6 +535,7 @@ public class JpaStorageClientImpl implements StorageClient { throw new UnsupportedOperationException(); } + @SuppressWarnings("rawtypes") @Override public boolean synchronize(ServiceContext ctx, Object specifier, DocumentHandler handler) throws DocumentNotFoundException, @@ -654,6 +545,7 @@ public class JpaStorageClientImpl implements StorageClient { return true; } + @SuppressWarnings("rawtypes") @Override public boolean synchronizeItem(ServiceContext ctx, AuthorityItemSpecifier itemSpecifier, DocumentHandler handler) throws DocumentNotFoundException, diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java index fa459de0b..d3ff99c34 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java @@ -46,9 +46,11 @@ import org.collectionspace.services.authorization.PermissionRoleRel; import org.collectionspace.services.authorization.PermissionValue; import org.collectionspace.services.authorization.URIResourceImpl; import org.collectionspace.services.common.authorization_mgt.AuthorizationRoleRel; +import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.DocumentNotFoundException; import org.collectionspace.services.common.security.UnauthorizedException; import org.collectionspace.services.common.document.JaxbUtils; +import org.collectionspace.services.common.document.TransactionException; import org.collectionspace.services.common.security.SecurityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,6 +59,7 @@ import org.slf4j.LoggerFactory; * Utilities for JpaStorage * @author */ +@SuppressWarnings({"rawtypes", "unchecked"}) public class JpaStorageUtils { final private static Logger logger = LoggerFactory.getLogger(JpaStorageUtils.class); @@ -88,8 +91,9 @@ public class JpaStorageUtils { return result; } - - public static Object getEntity(String id, Class entityClazz) { + + @Deprecated + public static Object getEntity(String id, Class entityClazz) { EntityManagerFactory emf = null; EntityManager em = null; Object entityFound = null; @@ -135,6 +139,7 @@ public class JpaStorageUtils { * @param entityClazz * @return */ + @Deprecated public static Object getEntity(EntityManager em, String id, Class entityClazz) throws DocumentNotFoundException { if (entityClazz == null) { String msg = "Not constructed with JpaStorageClientImpl(entityClazz) ctor"; @@ -144,7 +149,18 @@ public class JpaStorageUtils { //FIXME: it would be nice to verify tenantid as well return em.find(entityClazz, id); } + + public static Object getEntity(JPATransactionContext jpaTransactionContext, String id, Class entityClazz) throws DocumentNotFoundException { + if (entityClazz == null) { + String msg = "Not constructed with JpaStorageClientImpl(entityClazz) ctor"; + logger.error(msg); + throw new UnsupportedOperationException(msg); + } + //FIXME: it would be nice to verify tenantid as well + return jpaTransactionContext.find(entityClazz, id); + } + @Deprecated private static String getUserId(String csid) throws DocumentNotFoundException { String result = null; @@ -312,58 +328,80 @@ public class JpaStorageUtils { return result; } - public static Object getEnityByKey(EntityManager em, String entityName, String key, String value, - String tenantId) { - Object result = null; - - if (entityName == null) { - throw new IllegalArgumentException("entityName is required"); - } - if (key == null) { - throw new IllegalArgumentException("id is required"); - } - if (tenantId == null) { - throw new IllegalArgumentException("tenantId is required"); - } + public static Object getEnityByKey(JPATransactionContext jpaTransactionContext, String entityName, String key, String value, + String tenantId) throws TransactionException { + Object result = null; - boolean useTenantId = useTenantId(tenantId); - StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM "); - queryStrBldr.append(entityName); - queryStrBldr.append(" a"); - queryStrBldr.append(" WHERE " + key + " = :" + key); - if (useTenantId == true) { - queryStrBldr.append(" AND tenantId = :tenantId"); - } - String queryStr = queryStrBldr.toString(); //for debugging - Query q = em.createQuery(queryStr); - q.setParameter(key, value); - if (useTenantId == true) { - q.setParameter("tenantId", tenantId); + try { + boolean useTenantId = useTenantId(tenantId); + StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM "); + queryStrBldr.append(entityName); + queryStrBldr.append(" a"); + queryStrBldr.append(" WHERE " + key + " = :" + key); + if (useTenantId == true) { + queryStrBldr.append(" AND tenantId = :tenantId"); + } + String queryStr = queryStrBldr.toString(); //for debugging + Query q = jpaTransactionContext.createQuery(queryStr); + q.setParameter(key, value); + if (useTenantId == true) { + q.setParameter("tenantId", tenantId); + } + result = q.getSingleResult(); + } catch (NoResultException nre) { + if (logger.isDebugEnabled()) { + logger.debug("Could not find entity with key ={" + key + "=" + value + "}", nre); + } + //returns null + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Could not find entity with id=" + key, e); + } + //returns null } - result = q.getSingleResult(); - + return result; } - - public static Object getEntityByDualKeys(EntityManager em, String entityName, + + /** + * + * @param em + * @param entityName + * @param key1 + * @param value1 + * @param key2 + * @param value2 + * @return + * @throws TransactionException + */ + public static Object getEntityByDualKeys( + JPATransactionContext jpaTransactionContext, + String entityName, String key1, String value1, - String key2, String value2) { - return getEntityByDualKeys(em, entityName, key1, value1, key2, value2, null); + String key2, String value2) throws TransactionException { + return getEntityByDualKeys(jpaTransactionContext, entityName, key1, value1, key2, value2, null); } - public static Object getEntityByDualKeys(EntityManager em, String entityName, + /** + * + * @param em + * @param entityName + * @param key1 + * @param value1 + * @param key2 + * @param value2 + * @param tenantId + * @return + * @throws TransactionException + */ + public static Object getEntityByDualKeys( + JPATransactionContext jpaTransactionContext, + String entityName, String key1, String value1, String key2, String value2, - String tenantId) { + String tenantId) throws TransactionException { Object result = null; - if (entityName == null) { - throw new IllegalArgumentException("entityName is required"); - } - if (key1 == null || key2 == null) { - throw new IllegalArgumentException("key names are required"); - } - boolean useTenantId = useTenantId(tenantId); StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM "); queryStrBldr.append(entityName); @@ -374,7 +412,7 @@ public class JpaStorageUtils { queryStrBldr.append(" AND tenantId = :tenantId"); } String queryStr = queryStrBldr.toString(); //for debugging - Query q = em.createQuery(queryStr); + Query q = jpaTransactionContext.createQuery(queryStr); q.setParameter(key1, value1); q.setParameter(key2, value2); if (useTenantId == true) { @@ -385,44 +423,21 @@ public class JpaStorageUtils { return result; } - public static Object getEnityByKey(String entityName, String key, String value, - String tenantId) { - EntityManagerFactory emf = null; - EntityManager em = null; - Object o = null; - - try { - emf = getEntityManagerFactory(); - em = emf.createEntityManager(); - o = getEnityByKey(em, entityName, key, value, tenantId); - } catch (NoResultException nre) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - if (logger.isDebugEnabled()) { - logger.debug("Could not find entity with key ={" + key + "=" + value + "}", nre); - } - //returns null - } catch (Exception e) { - if (em != null && em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - if (logger.isDebugEnabled()) { - logger.debug("Could not find entity with id=" + key, e); - } - //returns null - } finally { - if (em != null) { - releaseEntityManagerFactory(emf); - } - } - - return o; - } - - public static Object getEntity(String entityName, String id, - String tenantId) { - return getEnityByKey(entityName, CSID_LABEL, id, tenantId); + /** + * + * @param ctx + * @param entityName + * @param id + * @param tenantId + * @return + * @throws TransactionException + */ + public static Object getEntity( + JPATransactionContext jpaTransactionContext, + String entityName, + String id, + String tenantId) throws TransactionException { + return getEnityByKey(jpaTransactionContext, entityName, CSID_LABEL, id, tenantId); } /** @@ -490,17 +505,34 @@ public class JpaStorageUtils { return o; } - public static Object getEntity(EntityManager em, String entityName, + public static Object getEntity(JPATransactionContext jpaTransactionContext, String entityName, String whereClause, HashMap paramBindings) { Object result = null; - if (entityName == null) { - throw new IllegalArgumentException("entityName is required"); + StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM "); + queryStrBldr.append(entityName); + queryStrBldr.append(" a"); + queryStrBldr.append(" " + whereClause); + + String queryStr = queryStrBldr.toString(); //for debugging + Query q = jpaTransactionContext.createQuery(queryStr); + for (String paramName : paramBindings.keySet()) { + q.setParameter(paramName, paramBindings.get(paramName)); } - if (whereClause == null) { - throw new IllegalArgumentException("whereClause is required"); + + result = q.getSingleResult(); + + if (result == null) { + logger.debug("Call to getEntity() returned empty set."); } - + + return result; + } + + public static Object getEntity(EntityManager em, String entityName, + String whereClause, HashMap paramBindings) { + Object result = null; + StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM "); queryStrBldr.append(entityName); queryStrBldr.append(" a"); -- 2.47.3