From a1e0ff82cd79d60562c09823b2b146fcbb696792 Mon Sep 17 00:00:00 2001 From: Patrick Schmitz Date: Fri, 7 Dec 2012 14:57:36 -0800 Subject: [PATCH] CSPACE-5657 Step 2, adding Tenant resource and associated files to support a RESTful service to control tenancy. --- .../services/client/TenantClient.java | 109 +++++++ .../services/client/TenantFactory.java | 63 ++++ .../services/client/TenantProxy.java | 74 +++++ .../src/main/resources/accounts_common.xsd | 37 +++ .../services/account/TenantResource.java | 142 +++++++++ .../storage/TenantDocumentHandler.java | 156 ++++++++++ .../account/storage/TenantJpaFilter.java | 98 ++++++ .../account/storage/TenantStorageClient.java | 288 ++++++++++++++++++ .../storage/TenantStorageConstants.java | 64 ++++ .../storage/TenantValidatorHandler.java | 118 +++++++ 10 files changed, 1149 insertions(+) create mode 100644 services/account/client/src/main/java/org/collectionspace/services/client/TenantClient.java create mode 100644 services/account/client/src/main/java/org/collectionspace/services/client/TenantFactory.java create mode 100644 services/account/client/src/main/java/org/collectionspace/services/client/TenantProxy.java create mode 100644 services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java create mode 100644 services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java create mode 100644 services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java create mode 100644 services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java create mode 100644 services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java create mode 100644 services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantValidatorHandler.java diff --git a/services/account/client/src/main/java/org/collectionspace/services/client/TenantClient.java b/services/account/client/src/main/java/org/collectionspace/services/client/TenantClient.java new file mode 100644 index 000000000..a27e6c099 --- /dev/null +++ b/services/account/client/src/main/java/org/collectionspace/services/client/TenantClient.java @@ -0,0 +1,109 @@ +/** + * TenantClient.java + * + * {Purpose of This Class} + * + * {Other Notes Relating to This Class (Optional)} + * + * $LastChangedBy: $ + * $LastChangedRevision: $ + * $LastChangedDate: $ + * + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + * + * http://www.collectionspace.org + * http://wiki.collectionspace.org + * + * Copyright (C) 2009 {Contributing Institution} + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ +package org.collectionspace.services.client; + +import javax.ws.rs.core.Response; +import org.jboss.resteasy.client.ClientResponse; + +import org.collectionspace.services.account.Tenant; +import org.collectionspace.services.account.TenantsList; + +/** + * A TenantClient. + + * @version $Revision:$ + */ +public class TenantClient extends AbstractServiceClientImpl { + public static final String SERVICE_NAME = "tenants"; + public static final String SERVICE_PATH_COMPONENT = SERVICE_NAME; + public static final String SERVICE_PATH = "/" + SERVICE_PATH_COMPONENT; + + @Override + public String getServiceName() { + return SERVICE_NAME; + } + + /* (non-Javadoc) + * @see org.collectionspace.services.client.AbstractServiceClientImpl#getServicePathComponent() + */ + @Override + public String getServicePathComponent() { + return SERVICE_NAME; + } + + @Override + public Class getProxyClass() { + return TenantProxy.class; + } + + /* + * CRUD+L Methods + */ + + /** + * @return response + * @see org.collectionspace.hello.client.TenantProxy#readList() + */ + public ClientResponse readList() { + return getProxy().readList(); + } + + public ClientResponse readSearchList(String name, String disabled) { + return getProxy().readSearchList(name, disabled); + } + + /** + * @param csid + * @return response + * @see org.collectionspace.hello.client.TenantProxy#getTenant(java.lang.String) + */ + public ClientResponse read(String id) { + return getProxy().read(id); + } + + /** + * @param multipart + * @param tenant + * @return response + * @see org.collectionspace.hello.client.TenantProxy#create(org.collectionspace.services.account.Tenant) + */ + public ClientResponse create(Tenant multipart) { + return getProxy().create(multipart); + } + + /** + * @param csid + * @param multipart + * @param tenant + * @return response + * @see org.collectionspace.hello.client.TenantProxy#updateTenant(java.lang.Long, org.collectionspace.services.account.Tenant) + */ + public ClientResponse update(String id, Tenant multipart) { + return getProxy().update(id, multipart); + } +} diff --git a/services/account/client/src/main/java/org/collectionspace/services/client/TenantFactory.java b/services/account/client/src/main/java/org/collectionspace/services/client/TenantFactory.java new file mode 100644 index 000000000..78d01ef0f --- /dev/null +++ b/services/account/client/src/main/java/org/collectionspace/services/client/TenantFactory.java @@ -0,0 +1,63 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.collectionspace.services.client; + +import org.collectionspace.services.account.Tenant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author + */ +public class TenantFactory { + static private final Logger logger = LoggerFactory.getLogger(TenantFactory.class); + + /** + * create tenant instance + * @param screenName + * @param userName + * @param passwd + * @param email + * @param tenantId add non-null tenant id else let service take tenant id of + * the authenticated user + * @param useScreenName + * @param invalidTenant + * @param useUser + * @param usePassword + * @return + */ + public static Tenant createTenantInstance(String id, + String name, boolean disabled) { + + Tenant tenant = new Tenant(); + tenant.setName(name); + tenant.setId(id); + tenant.setDisabled(disabled); + return tenant; + +} + +} diff --git a/services/account/client/src/main/java/org/collectionspace/services/client/TenantProxy.java b/services/account/client/src/main/java/org/collectionspace/services/client/TenantProxy.java new file mode 100644 index 000000000..43bfbfb66 --- /dev/null +++ b/services/account/client/src/main/java/org/collectionspace/services/client/TenantProxy.java @@ -0,0 +1,74 @@ +/** + * TenantProxy.java + * + * {Purpose of This Class} + * + * {Other Notes Relating to This Class (Optional)} + * + * $LastChangedBy: $ + * $LastChangedRevision: $ + * $LastChangedDate: $ + * + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + * + * http://www.collectionspace.org + * http://wiki.collectionspace.org + * + * Copyright (C) 2009 {Contributing Institution} + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ +package org.collectionspace.services.client; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; + +import org.collectionspace.services.account.Tenant; +import org.collectionspace.services.account.TenantsList; +import org.jboss.resteasy.client.ClientResponse; + +/** + * @version $Revision:$ + */ +@Path("/tenants/") +@Produces({"application/xml"}) +@Consumes({"application/xml"}) +public interface TenantProxy extends CollectionSpaceProxy { + + @GET + @Produces({"application/xml"}) + ClientResponse readList(); + + @GET + @Produces({"application/xml"}) + ClientResponse readSearchList( + @QueryParam("name") String name, + @QueryParam("disabled") String disabled); + + //(C)reate + @POST + ClientResponse create(Tenant multipart); + + //(R)ead + @GET + @Path("/{csid}") + ClientResponse read(@PathParam("id") String id); + + //(U)pdate + @PUT + @Path("/{csid}") + ClientResponse update(@PathParam("id") String id, Tenant multipart); +} diff --git a/services/account/jaxb/src/main/resources/accounts_common.xsd b/services/account/jaxb/src/main/resources/accounts_common.xsd index db61f4556..ae82b32e2 100644 --- a/services/account/jaxb/src/main/resources/accounts_common.xsd +++ b/services/account/jaxb/src/main/resources/accounts_common.xsd @@ -341,5 +341,42 @@ + + + + + + TenantsList contains information about one or more + tenants. An instance of this type could be returned on + index and search operations. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java b/services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java new file mode 100644 index 000000000..9f891a5ed --- /dev/null +++ b/services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java @@ -0,0 +1,142 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2012 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.collectionspace.services.account; + +import org.collectionspace.services.account.storage.TenantStorageClient; +import org.collectionspace.services.client.TenantClient; +import org.collectionspace.services.client.PayloadOutputPart; +import org.collectionspace.services.common.SecurityResourceBase; +import org.collectionspace.services.common.ServiceMessages; +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.jpa.JpaStorageUtils; +import org.jboss.resteasy.util.HttpResponseCodes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.UriInfo; + + +/** TenantResource provides RESTful interface to the tenant service + * + * The TenantResource is tied to the account package for historical + * reasons, and because it is toes so closely to the notion of accounts + * and IAM. + */ +@Path(TenantClient.SERVICE_PATH) +@Consumes("application/xml") +@Produces("application/xml") +public class TenantResource extends SecurityResourceBase { + + final Logger logger = LoggerFactory.getLogger(TenantResource.class); + final StorageClient storageClient = new TenantStorageClient(); + + @Override + protected String getVersionString() { + return "$LastChangedRevision: 1165 $"; + } + + @Override + public String getServiceName() { + return TenantClient.SERVICE_NAME; + } + + @Override + public Class getCommonPartClass() { + return Tenant.class; + } + + @Override + public ServiceContextFactory getServiceContextFactory() { + return (ServiceContextFactory) RemoteServiceContextFactory.get(); + } + + @Override + public StorageClient getStorageClient(ServiceContext ctx) { + //FIXME use ctx to identify storage client + return storageClient; + } + + @POST + public Response createTenant(Tenant input) { + return create(input); + } + + @GET + @Path("{csid}") + public Tenant getTenant(@PathParam("csid") String csid) { + return (Tenant)get(csid, Tenant.class); + } + + @GET + @Produces("application/xml") + public TenantsList getTenantList(@Context UriInfo ui) { + TenantsList result = (TenantsList)getList(ui, Tenant.class); + if(logger.isTraceEnabled()) { + PayloadOutputPart ppo = new PayloadOutputPart(TenantsList.class.getSimpleName(), + result); + System.out.println(ppo.asXML()); + } + return result; + } + + @PUT + @Path("{csid}") + public Tenant updateTenant(@PathParam("csid") String csid,Tenant theUpdate) { + return (Tenant)update(csid, theUpdate, Tenant.class); + } + + + @DELETE + @Path("{csid}") + public Response deleteTenant(@Context UriInfo uriInfo, @PathParam("csid") String csid) { + logger.debug("deleteTenant with csid=" + csid); + ensureCSID(csid, ServiceMessages.DELETE_FAILED); + try { + ServiceContext ctx = createServiceContext((Tenant) null, + Tenant.class, uriInfo); + getStorageClient(ctx).delete(ctx, csid); + return Response.status(HttpResponseCodes.SC_OK).build(); + } catch (Exception e) { + throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid); + } + + } +} diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java new file mode 100644 index 000000000..33be18a03 --- /dev/null +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java @@ -0,0 +1,156 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.account.storage; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.lang.StringUtils; +import org.collectionspace.services.account.Tenant; +import org.collectionspace.services.account.TenantsList; +import org.collectionspace.services.account.TenantListItem; + +import org.collectionspace.services.client.TenantClient; +import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler; +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.JaxbUtils; +import org.collectionspace.services.common.security.SecurityUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author + */ +public class TenantDocumentHandler + extends JpaDocumentHandler { + + private final Logger logger = LoggerFactory.getLogger(AccountDocumentHandler.class); + private Tenant tenant; + private TenantsList tenantList; + + @Override + public void handleCreate(DocumentWrapper wrapDoc) throws Exception { + } + + @Override + public void handleUpdate(DocumentWrapper wrapDoc) throws Exception { + } + + @Override + public void completeUpdate(DocumentWrapper wrapDoc) throws Exception { + Tenant upAcc = wrapDoc.getWrappedObject(); + getServiceContext().setOutput(upAcc); + } + + @Override + public void handleGet(DocumentWrapper wrapDoc) throws Exception { + setCommonPart(extractCommonPart(wrapDoc)); + getServiceContext().setOutput(tenant); + } + + @Override + public void handleGetAll(DocumentWrapper wrapDoc) throws Exception { + TenantsList tenList = extractCommonPartList(wrapDoc); + setCommonPartList(tenList); + getServiceContext().setOutput(getCommonPartList()); + } + + @Override + public Tenant extractCommonPart( + DocumentWrapper wrapDoc) + throws Exception { + return wrapDoc.getWrappedObject(); + } + + @Override + public void fillCommonPart(Tenant obj, DocumentWrapper wrapDoc) + throws Exception { + throw new UnsupportedOperationException("operation not relevant for TenantDocumentHandler"); + } + + @Override + public TenantsList extractCommonPartList( + DocumentWrapper wrapDoc) + throws Exception { + + TenantsList tenList = this.extractPagingInfo(new TenantsList(), wrapDoc); +// TenantsList accList = new TenantsList(); + List list = tenList.getTenantListItem(); + + for (Object obj : wrapDoc.getWrappedObject()) { + Tenant tenant = (Tenant) obj; + TenantListItem tenListItem = new TenantListItem(); + tenListItem.setId(tenant.getId()); + tenListItem.setName(tenant.getName()); + tenListItem.setDisabled(tenant.isDisabled()); + list.add(tenListItem); + } + return tenList; + } + + @Override + public Tenant getCommonPart() { + return tenant; + } + + @Override + public void setCommonPart(Tenant tenant) { + this.tenant = tenant; + } + + @Override + public TenantsList getCommonPartList() { + return tenantList; + } + + @Override + public void setCommonPartList(TenantsList tenantList) { + this.tenantList = tenantList; + } + + @Override + public String getQProperty( + String prop) { + return null; + } + + @Override + public DocumentFilter createDocumentFilter() { + DocumentFilter filter = new TenantJpaFilter(this.getServiceContext()); + return filter; + } + + /* (non-Javadoc) + * @see org.collectionspace.services.common.document.DocumentHandler#initializeDocumentFilter(org.collectionspace.services.common.context.ServiceContext) + */ + public void initializeDocumentFilter(ServiceContext ctx) { + // set a default document filter in this method + } +} diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java new file mode 100644 index 000000000..6bbc8b24b --- /dev/null +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java @@ -0,0 +1,98 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + */ +package org.collectionspace.services.account.storage; + +import java.util.ArrayList; +import java.util.List; +import org.collectionspace.services.common.storage.jpa.JpaDocumentFilter; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.security.SecurityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author + */ +public class TenantJpaFilter extends JpaDocumentFilter { + + private final Logger logger = LoggerFactory.getLogger(TenantJpaFilter.class); + + public TenantJpaFilter(ServiceContext ctx) { + super(ctx); + } + + @Override + public List buildWhereForSearch(StringBuilder queryStrBldr) { + + List paramList = new ArrayList(); + String name = null; + List nvals = getQueryParam(TenantStorageConstants.Q_NAME); + if (null != nvals && nvals.size() > 0) { + name = nvals.get(0); + } + boolean csAdmin = SecurityUtils.isCSpaceAdmin(); + if (null != name && !name.isEmpty()) { + queryStrBldr.append(" WHERE UPPER(a."); + queryStrBldr.append(TenantStorageConstants.NAME_FIELD); + queryStrBldr.append(") LIKE :"); + queryStrBldr.append(" :" + TenantStorageConstants.Q_NAME); + paramList.add(new ParamBinding( + TenantStorageConstants.Q_NAME, "%" + name.toUpperCase() + "%")); + } + + String includeDisabledStr = null; + List inclDisVals = getQueryParam(TenantStorageConstants.Q_INCLUDE_DISABLED); + if (null != inclDisVals && inclDisVals.size() > 0) { + includeDisabledStr = inclDisVals.get(0); + } + // Default is to exclude disabled tenants, unless they specify to include them + boolean includeDisabled = (null != includeDisabledStr && !includeDisabledStr.isEmpty() + && Boolean.parseBoolean(includeDisabledStr)); + // If excluding, then add a clause + if(!includeDisabled) { + queryStrBldr.append(" WHERE NOT a."); + queryStrBldr.append(TenantStorageConstants.DISABLED_FIELD); + } + + if (logger.isDebugEnabled()) { + String query = queryStrBldr.toString(); + logger.debug("query=" + query); + } + + return paramList; + } + + @Override + public List buildWhere(StringBuilder queryStrBldr) { + return new ArrayList(); + } + + @Override + protected String addTenant(boolean append, List paramList) { + // unused for tenants - special case + return ""; + } +} 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 new file mode 100644 index 000000000..5f45cf945 --- /dev/null +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java @@ -0,0 +1,288 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +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; +import org.collectionspace.services.common.document.DocumentException; +import org.collectionspace.services.common.document.DocumentFilter; +import org.collectionspace.services.common.document.DocumentHandler; +import org.collectionspace.services.common.document.DocumentHandler.Action; +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.JpaStorageClientImpl; +import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TenantStorageClient deals with both Account and CSIdP's + * state in persistent storage. The rationale behind creating this class is that + * this class manages persistence for both account and CSIP's user. Transactions + * are used where possible to perform the persistence operations atomically. + * @author + */ +public class TenantStorageClient extends JpaStorageClientImpl { + + private final Logger logger = LoggerFactory.getLogger(TenantStorageClient.class); + + public TenantStorageClient() { + } + + @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; + 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(); + tenant.setCreatedAtItem(new Date()); + em.persist(tenant); + em.getTransaction().commit(); + handler.complete(Action.CREATE, wrapDoc); + return (String) JaxbUtils.getValue(tenant, "getId"); + } catch (BadRequestException bre) { + if (em != null && em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + throw bre; + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Caught exception ", e); + } + boolean uniqueConstraint = false; + try { + if(em.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(); + } + if (uniqueConstraint) { + String msg = "TenantId exists. Non unique tenantId=" + tenant.getId(); + logger.error(msg); + throw new BadRequestException(msg); + } + throw new DocumentException(e); + } finally { + if (em != null) { + JpaStorageUtils.releaseEntityManagerFactory(emf); + } + } + } + + @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; + try { + handler.prepare(Action.GET); + Object o = null; + String whereClause = " where id = :id"; + HashMap params = new HashMap(); + params.put("id", id); + + 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; + throw new DocumentNotFoundException(msg); + } + DocumentWrapper wrapDoc = new DocumentWrapperImpl(o); + handler.handle(Action.GET, wrapDoc); + handler.complete(Action.GET, wrapDoc); + } catch (DocumentException de) { + throw de; + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + } finally { + if (emf != null) { + JpaStorageUtils.releaseEntityManagerFactory(emf); + } + } + } + + @Override + 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; + try { + handler.prepare(Action.UPDATE); + Tenant tenantReceived = (Tenant) handler.getCommonPart(); + emf = JpaStorageUtils.getEntityManagerFactory(); + em = emf.createEntityManager(); + em.getTransaction().begin(); + Tenant tenantFound = getTenant(em, id); + checkAllowedUpdates(tenantReceived, tenantFound); + DocumentWrapper wrapDoc = + new DocumentWrapperImpl(tenantFound); + handler.handle(Action.UPDATE, wrapDoc); + em.getTransaction().commit(); + handler.complete(Action.UPDATE, wrapDoc); + } catch (BadRequestException bre) { + if (em != null && em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + throw bre; + } catch (DocumentException de) { + if (em != null && em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + throw de; + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Caught exception ", e); + } + throw new DocumentException(e); + } finally { + if (emf != null) { + JpaStorageUtils.releaseEntityManagerFactory(emf); + } + } + } + + @Override + public void delete(ServiceContext ctx, String id) + throws DocumentNotFoundException, + DocumentException { + + 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(); + + } catch (DocumentException de) { + if (em != null && em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + throw de; + } catch (Exception e) { + 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); + } + } + } + + private Tenant getTenant(EntityManager em, String id) throws DocumentNotFoundException { + Tenant tenantFound = em.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; + } + + private boolean checkAllowedUpdates(Tenant toTenant, Tenant fromTenant) throws BadRequestException { + if (!fromTenant.getId().equals(toTenant.getId())) { + String msg = "Cannot change Tenant Id!"; + logger.error(msg); + throw new BadRequestException(msg); + } + return true; + } + +} diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java new file mode 100644 index 000000000..cc523092a --- /dev/null +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java @@ -0,0 +1,64 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *//** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.collectionspace.services.account.storage; + +/** + * TenantStorageConstants declares query params, etc. + * @author + */ +public class TenantStorageConstants { + + final public static String Q_NAME = "name"; + final public static String Q_INCLUDE_DISABLED= "inclDis"; + + final public static String NAME_FIELD = "name"; + final public static String DISABLED_FIELD = "disabled"; +} diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantValidatorHandler.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantValidatorHandler.java new file mode 100644 index 000000000..2a5b61e05 --- /dev/null +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantValidatorHandler.java @@ -0,0 +1,118 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *//** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.collectionspace.services.account.storage; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; +import org.collectionspace.services.account.Tenant; +import org.collectionspace.services.common.ServiceMessages; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.document.DocumentHandler.Action; +import org.collectionspace.services.common.document.DocumentNotFoundException; +import org.collectionspace.services.common.document.InvalidDocumentException; +import org.collectionspace.services.common.document.ValidatorHandler; +import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author + */ +public class TenantValidatorHandler implements ValidatorHandler { + + final Logger logger = LoggerFactory.getLogger(AccountValidatorHandler.class); + + @Override + public void validate(Action action, ServiceContext ctx) + throws InvalidDocumentException { + if (logger.isDebugEnabled()) { + logger.debug("validate() action=" + action.name()); + } + try { + Tenant tenant = (Tenant) ctx.getInput(); + StringBuilder msgBldr = new StringBuilder(ServiceMessages.VALIDATION_FAILURE); + boolean invalid = false; + + if (action.equals(Action.CREATE)) { + + //create specific validation here + if (StringUtils.isEmpty(tenant.getId())) { + invalid = true; + msgBldr.append("\nId : missing"); + } + if (StringUtils.isEmpty(tenant.getName())) { + invalid = true; + msgBldr.append("\nName : missing"); + } + } else if (action.equals(Action.UPDATE)) { + //update specific validation here + if (StringUtils.isEmpty(tenant.getName())) { + invalid = true; + msgBldr.append("\nName : missing"); + } + } + if (invalid) { + String msg = msgBldr.toString(); + logger.error(msg); + throw new InvalidDocumentException(msg); + } + } catch (InvalidDocumentException ide) { + throw ide; + } catch (Exception e) { + throw new InvalidDocumentException(e); + } + } + + +} -- 2.47.3