]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-5657 Step 2, adding Tenant resource and associated files to support a RESTful...
authorPatrick Schmitz <pschmitz@berkeley.edu>
Fri, 7 Dec 2012 22:57:36 +0000 (14:57 -0800)
committerPatrick Schmitz <pschmitz@berkeley.edu>
Fri, 7 Dec 2012 22:57:36 +0000 (14:57 -0800)
services/account/client/src/main/java/org/collectionspace/services/client/TenantClient.java [new file with mode: 0644]
services/account/client/src/main/java/org/collectionspace/services/client/TenantFactory.java [new file with mode: 0644]
services/account/client/src/main/java/org/collectionspace/services/client/TenantProxy.java [new file with mode: 0644]
services/account/jaxb/src/main/resources/accounts_common.xsd
services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java [new file with mode: 0644]
services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java [new file with mode: 0644]
services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java [new file with mode: 0644]
services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java [new file with mode: 0644]
services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java [new file with mode: 0644]
services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantValidatorHandler.java [new file with mode: 0644]

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 (file)
index 0000000..a27e6c0
--- /dev/null
@@ -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<TenantsList, Tenant,
+               Tenant, TenantProxy> {
+    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<TenantProxy> getProxyClass() {
+               return TenantProxy.class;
+       }    
+
+       /*
+        * CRUD+L Methods
+        */
+       
+    /**
+     * @return response
+     * @see org.collectionspace.hello.client.TenantProxy#readList()
+     */
+    public ClientResponse<TenantsList> readList() {
+        return getProxy().readList();
+    }
+
+    public ClientResponse<TenantsList> 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<Tenant> 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<Response> 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<Tenant> 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 (file)
index 0000000..78d01ef
--- /dev/null
@@ -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 (file)
index 0000000..43bfbfb
--- /dev/null
@@ -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<TenantsList> {
+
+    @GET
+    @Produces({"application/xml"})
+    ClientResponse<TenantsList> readList();
+
+    @GET
+    @Produces({"application/xml"})
+    ClientResponse<TenantsList> readSearchList(
+                               @QueryParam("name") String name, 
+                               @QueryParam("disabled") String disabled);
+
+    //(C)reate
+    @POST
+    ClientResponse<Response> create(Tenant multipart);
+
+    //(R)ead
+    @GET
+    @Path("/{csid}")
+    ClientResponse<Tenant> read(@PathParam("id") String id);
+
+    //(U)pdate
+    @PUT
+    @Path("/{csid}")
+    ClientResponse<Tenant> update(@PathParam("id") String id, Tenant multipart);    
+}
index db61f45569d88e4247af2fe911a4656bbacfc562..ae82b32e2fa7800ea568c4bdd1681a59bbf383be 100644 (file)
             </xs:element>
         </xs:sequence>
     </xs:complexType>
+
+    <xs:element name="tenants-list">
+        <xs:complexType>
+            <xs:annotation>
+                <xs:documentation>
+                    TenantsList contains information about one or more
+                    tenants. An instance of this type could be returned on
+                    index and search operations.
+                </xs:documentation>
+                <xs:appinfo>
+                    <hj:ignored/>
+                </xs:appinfo>
+            </xs:annotation>
+            <xs:complexContent>
+                <xs:extension base="abstractCommonList">                    
+                           <xs:sequence>
+                               <xs:element name="tenant-list-item" maxOccurs="unbounded">
+                                   <xs:complexType>
+                                       <xs:annotation>
+                                           <xs:appinfo>
+                                               <hj:ignored/>
+                                           </xs:appinfo>
+                                       </xs:annotation>
+                                       <xs:sequence>
+                                           <xs:element name="id" type="xs:string" minOccurs="1"/>
+                                           <xs:element name="name" type="xs:string" minOccurs="1" />
+                                           <xs:element name="disabled" type="xs:boolean" minOccurs="1" />
+                                       </xs:sequence>
+                                   </xs:complexType>
+                               </xs:element>
+                           </xs:sequence>
+                </xs:extension>
+            </xs:complexContent>        
+        </xs:complexType>
+    </xs:element>
+
+
 </xs:schema>
 
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 (file)
index 0000000..9f891a5
--- /dev/null
@@ -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<Tenant> getCommonPartClass() {
+        return Tenant.class;
+    }
+
+    @Override
+    public ServiceContextFactory<Tenant, Tenant> getServiceContextFactory() {
+        return (ServiceContextFactory<Tenant, Tenant>) 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<Tenant, Tenant> 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 (file)
index 0000000..33be18a
--- /dev/null
@@ -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<Tenant, TenantsList, Tenant, List> {
+
+    private final Logger logger = LoggerFactory.getLogger(AccountDocumentHandler.class);
+    private Tenant tenant;
+    private TenantsList tenantList;
+
+    @Override
+    public void handleCreate(DocumentWrapper<Tenant> wrapDoc) throws Exception {
+    }
+
+    @Override
+    public void handleUpdate(DocumentWrapper<Tenant> wrapDoc) throws Exception {
+    }
+
+    @Override
+    public void completeUpdate(DocumentWrapper<Tenant> wrapDoc) throws Exception {
+        Tenant upAcc = wrapDoc.getWrappedObject();
+        getServiceContext().setOutput(upAcc);
+    }
+
+    @Override
+    public void handleGet(DocumentWrapper<Tenant> wrapDoc) throws Exception {
+        setCommonPart(extractCommonPart(wrapDoc));
+        getServiceContext().setOutput(tenant);
+    }
+
+    @Override
+    public void handleGetAll(DocumentWrapper<List> wrapDoc) throws Exception {
+        TenantsList tenList = extractCommonPartList(wrapDoc);
+        setCommonPartList(tenList);
+        getServiceContext().setOutput(getCommonPartList());
+    }
+
+    @Override
+    public Tenant extractCommonPart(
+            DocumentWrapper<Tenant> wrapDoc)
+            throws Exception {
+        return wrapDoc.getWrappedObject();
+    }
+
+    @Override
+    public void fillCommonPart(Tenant obj, DocumentWrapper<Tenant> wrapDoc)
+            throws Exception {
+        throw new UnsupportedOperationException("operation not relevant for TenantDocumentHandler");
+    }
+
+    @Override
+    public TenantsList extractCommonPartList(
+            DocumentWrapper<List> wrapDoc)
+            throws Exception {
+
+       TenantsList tenList = this.extractPagingInfo(new TenantsList(), wrapDoc);
+//        TenantsList accList = new TenantsList();
+        List<TenantListItem> 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 (file)
index 0000000..6bbc8b2
--- /dev/null
@@ -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<ParamBinding> buildWhereForSearch(StringBuilder queryStrBldr) {
+
+        List<ParamBinding> paramList = new ArrayList<ParamBinding>();
+        String name = null;
+        List<String> 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<String> 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<ParamBinding> buildWhere(StringBuilder queryStrBldr) {
+        return new ArrayList<ParamBinding>();
+    }
+
+    @Override
+    protected String addTenant(boolean append, List<ParamBinding> 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 (file)
index 0000000..5f45cf9
--- /dev/null
@@ -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<Tenant> wrapDoc =
+                    new DocumentWrapperImpl<Tenant>(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<String, Object> params = new HashMap<String, Object>();
+            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<Object> wrapDoc = new DocumentWrapperImpl<Object>(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<Tenant> wrapDoc =
+                    new DocumentWrapperImpl<Tenant>(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 (file)
index 0000000..cc52309
--- /dev/null
@@ -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 (file)
index 0000000..2a5b61e
--- /dev/null
@@ -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);
+        }
+    }
+
+
+}